mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-08-19 11:40:56 +00:00
Switch to generated localized string symbols (#607)
* Switch to string symbols * Names * Cleanup packages * Cleanup packages * Remove namespace * More cleanup * Fix extra param. * Use swiftbuild
This commit is contained in:
parent
83ecc15332
commit
9749cd6f3e
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@ -23,10 +23,7 @@ jobs:
|
|||||||
- name: Set Environment
|
- name: Set Environment
|
||||||
run: sudo xcrun xcode-select -s /Applications/Xcode_26_beta_5.app
|
run: sudo xcrun xcode-select -s /Applications/Xcode_26_beta_5.app
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
run: swift build --build-system swiftbuild --package-path Sources/Packages
|
||||||
pushd Sources/Packages
|
|
||||||
swift test
|
|
||||||
popd
|
|
||||||
build:
|
build:
|
||||||
# runs-on: macOS-latest
|
# runs-on: macOS-latest
|
||||||
runs-on: macos-15
|
runs-on: macos-15
|
||||||
|
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@ -11,7 +11,4 @@ jobs:
|
|||||||
- name: Set Environment
|
- name: Set Environment
|
||||||
run: sudo xcrun xcode-select -s /Applications/Xcode_26_beta_5.app
|
run: sudo xcrun xcode-select -s /Applications/Xcode_26_beta_5.app
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
run: swift build --build-system swiftbuild --package-path Sources/Packages
|
||||||
pushd Sources/Packages
|
|
||||||
swift test
|
|
||||||
popd
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@ import PackageDescription
|
|||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "SecretivePackages",
|
name: "SecretivePackages",
|
||||||
|
defaultLocalization: "en",
|
||||||
platforms: [
|
platforms: [
|
||||||
.macOS(.v14)
|
.macOS(.v14)
|
||||||
],
|
],
|
||||||
@ -34,6 +35,7 @@ let package = Package(
|
|||||||
.target(
|
.target(
|
||||||
name: "SecretKit",
|
name: "SecretKit",
|
||||||
dependencies: [],
|
dependencies: [],
|
||||||
|
resources: [localization],
|
||||||
swiftSettings: swiftSettings
|
swiftSettings: swiftSettings
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
@ -44,16 +46,19 @@ let package = Package(
|
|||||||
.target(
|
.target(
|
||||||
name: "SecureEnclaveSecretKit",
|
name: "SecureEnclaveSecretKit",
|
||||||
dependencies: ["SecretKit"],
|
dependencies: ["SecretKit"],
|
||||||
|
resources: [localization],
|
||||||
swiftSettings: swiftSettings
|
swiftSettings: swiftSettings
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "SmartCardSecretKit",
|
name: "SmartCardSecretKit",
|
||||||
dependencies: ["SecretKit"],
|
dependencies: ["SecretKit"],
|
||||||
|
resources: [localization],
|
||||||
swiftSettings: swiftSettings
|
swiftSettings: swiftSettings
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "SecretAgentKit",
|
name: "SecretAgentKit",
|
||||||
dependencies: ["SecretKit", "SecretAgentKitHeaders"],
|
dependencies: ["SecretKit", "SecretAgentKitHeaders"],
|
||||||
|
resources: [localization],
|
||||||
swiftSettings: swiftSettings
|
swiftSettings: swiftSettings
|
||||||
),
|
),
|
||||||
.systemLibrary(
|
.systemLibrary(
|
||||||
@ -66,6 +71,7 @@ let package = Package(
|
|||||||
.target(
|
.target(
|
||||||
name: "Brief",
|
name: "Brief",
|
||||||
dependencies: [],
|
dependencies: [],
|
||||||
|
resources: [localization],
|
||||||
swiftSettings: swiftSettings
|
swiftSettings: swiftSettings
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
@ -75,6 +81,10 @@ let package = Package(
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var localization: Resource {
|
||||||
|
.process("../../Localizable.xcstrings")
|
||||||
|
}
|
||||||
|
|
||||||
var swiftSettings: [PackageDescription.SwiftSetting] {
|
var swiftSettings: [PackageDescription.SwiftSetting] {
|
||||||
[
|
[
|
||||||
.swiftLanguageMode(.v6),
|
.swiftLanguageMode(.v6),
|
||||||
|
1
Sources/Packages/Sources/Localization/Stub.swift
Normal file
1
Sources/Packages/Sources/Localization/Stub.swift
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -50,16 +50,16 @@ extension SecureEnclave {
|
|||||||
func persistAuthentication(secret: Secret, forDuration duration: TimeInterval) async throws {
|
func persistAuthentication(secret: Secret, forDuration duration: TimeInterval) async throws {
|
||||||
let newContext = LAContext()
|
let newContext = LAContext()
|
||||||
newContext.touchIDAuthenticationAllowableReuseDuration = duration
|
newContext.touchIDAuthenticationAllowableReuseDuration = duration
|
||||||
newContext.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
|
newContext.localizedCancelTitle = String(localized: .authContextRequestDenyButton)
|
||||||
|
|
||||||
let formatter = DateComponentsFormatter()
|
let formatter = DateComponentsFormatter()
|
||||||
formatter.unitsStyle = .spellOut
|
formatter.unitsStyle = .spellOut
|
||||||
formatter.allowedUnits = [.hour, .minute, .day]
|
formatter.allowedUnits = [.hour, .minute, .day]
|
||||||
|
|
||||||
if let durationString = formatter.string(from: duration) {
|
if let durationString = formatter.string(from: duration) {
|
||||||
newContext.localizedReason = String(localized: "auth_context_persist_for_duration_\(secret.name)_\(durationString)")
|
newContext.localizedReason = String(localized: .authContextPersistForDuration(secretName: secret.name, duration: durationString))
|
||||||
} else {
|
} else {
|
||||||
newContext.localizedReason = String(localized: "auth_context_persist_for_duration_unknown_\(secret.name)")
|
newContext.localizedReason = String(localized: .authContextPersistForDurationUnknown(secretName: secret.name))
|
||||||
}
|
}
|
||||||
let success = try await newContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: newContext.localizedReason)
|
let success = try await newContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: newContext.localizedReason)
|
||||||
guard success else { return }
|
guard success else { return }
|
||||||
|
@ -15,7 +15,7 @@ extension SecureEnclave {
|
|||||||
CryptoKit.SecureEnclave.isAvailable
|
CryptoKit.SecureEnclave.isAvailable
|
||||||
}
|
}
|
||||||
public let id = UUID()
|
public let id = UUID()
|
||||||
public let name = String(localized: "secure_enclave")
|
public let name = String(localized: .secureEnclave)
|
||||||
private let persistentAuthenticationHandler = PersistentAuthenticationHandler()
|
private let persistentAuthenticationHandler = PersistentAuthenticationHandler()
|
||||||
|
|
||||||
/// Initializes a Store.
|
/// Initializes a Store.
|
||||||
@ -105,10 +105,10 @@ extension SecureEnclave {
|
|||||||
context = existing.context
|
context = existing.context
|
||||||
} else {
|
} else {
|
||||||
let newContext = LAContext()
|
let newContext = LAContext()
|
||||||
newContext.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
|
newContext.localizedCancelTitle = String(localized: .authContextRequestDenyButton)
|
||||||
context = newContext
|
context = newContext
|
||||||
}
|
}
|
||||||
context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)")
|
context.localizedReason = String(localized: .authContextRequestSignatureDescription(appName: provenance.origin.displayName, secretName: secret.name))
|
||||||
let attributes = KeychainDictionary([
|
let attributes = KeychainDictionary([
|
||||||
kSecClass: kSecClassKey,
|
kSecClass: kSecClassKey,
|
||||||
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
||||||
@ -138,8 +138,8 @@ extension SecureEnclave {
|
|||||||
|
|
||||||
public func verify(signature: Data, for data: Data, with secret: Secret) throws -> Bool {
|
public func verify(signature: Data, for data: Data, with secret: Secret) throws -> Bool {
|
||||||
let context = LAContext()
|
let context = LAContext()
|
||||||
context.localizedReason = String(localized: "auth_context_request_verify_description_\(secret.name)")
|
context.localizedReason = String(localized: .authContextRequestVerifyDescription(secretName: secret.name))
|
||||||
context.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
|
context.localizedCancelTitle = String(localized: .authContextRequestDenyButton)
|
||||||
let attributes = KeychainDictionary([
|
let attributes = KeychainDictionary([
|
||||||
kSecClass: kSecClassKey,
|
kSecClass: kSecClassKey,
|
||||||
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
||||||
@ -240,7 +240,7 @@ extension SecureEnclave.Store {
|
|||||||
nil)!
|
nil)!
|
||||||
|
|
||||||
let wrapped: [SecureEnclave.Secret] = publicTyped.map {
|
let wrapped: [SecureEnclave.Secret] = publicTyped.map {
|
||||||
let name = $0[kSecAttrLabel] as? String ?? String(localized: "unnamed_secret")
|
let name = $0[kSecAttrLabel] as? String ?? String(localized: .unnamedSecret)
|
||||||
let id = $0[kSecAttrApplicationLabel] as! Data
|
let id = $0[kSecAttrApplicationLabel] as! Data
|
||||||
let publicKeyRef = $0[kSecValueRef] as! SecKey
|
let publicKeyRef = $0[kSecValueRef] as! SecKey
|
||||||
let publicKeyAttributes = SecKeyCopyAttributes(publicKeyRef) as! [CFString: Any]
|
let publicKeyAttributes = SecKeyCopyAttributes(publicKeyRef) as! [CFString: Any]
|
||||||
|
@ -9,7 +9,7 @@ extension SmartCard {
|
|||||||
|
|
||||||
@MainActor @Observable fileprivate final class State {
|
@MainActor @Observable fileprivate final class State {
|
||||||
var isAvailable = false
|
var isAvailable = false
|
||||||
var name = String(localized: "smart_card")
|
var name = String(localized: .smartCard)
|
||||||
var secrets: [Secret] = []
|
var secrets: [Secret] = []
|
||||||
let watcher = TKTokenWatcher()
|
let watcher = TKTokenWatcher()
|
||||||
var tokenID: String? = nil
|
var tokenID: String? = nil
|
||||||
@ -63,8 +63,8 @@ extension SmartCard {
|
|||||||
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) async throws -> Data {
|
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) async throws -> Data {
|
||||||
guard let tokenID = await state.tokenID else { fatalError() }
|
guard let tokenID = await state.tokenID else { fatalError() }
|
||||||
let context = LAContext()
|
let context = LAContext()
|
||||||
context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)")
|
context.localizedReason = String(localized: .authContextRequestSignatureDescription(appName: provenance.origin.displayName, secretName: secret.name))
|
||||||
context.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
|
context.localizedCancelTitle = String(localized: .authContextRequestDenyButton)
|
||||||
let attributes = KeychainDictionary([
|
let attributes = KeychainDictionary([
|
||||||
kSecClass: kSecClassKey,
|
kSecClass: kSecClassKey,
|
||||||
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
||||||
@ -162,7 +162,7 @@ extension SmartCard.Store {
|
|||||||
@MainActor private func loadSecrets() {
|
@MainActor private func loadSecrets() {
|
||||||
guard let tokenID = state.tokenID else { return }
|
guard let tokenID = state.tokenID else { return }
|
||||||
|
|
||||||
let fallbackName = String(localized: "smart_card")
|
let fallbackName = String(localized: .smartCard)
|
||||||
if let driverName = state.watcher.tokenInfo(forTokenID: tokenID)?.driverName {
|
if let driverName = state.watcher.tokenInfo(forTokenID: tokenID)?.driverName {
|
||||||
state.name = driverName
|
state.name = driverName
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +180,7 @@ extension SmartCard.Store {
|
|||||||
SecItemCopyMatching(attributes, &untyped)
|
SecItemCopyMatching(attributes, &untyped)
|
||||||
guard let typed = untyped as? [[CFString: Any]] else { return }
|
guard let typed = untyped as? [[CFString: Any]] else { return }
|
||||||
let wrapped = typed.map {
|
let wrapped = typed.map {
|
||||||
let name = $0[kSecAttrLabel] as? String ?? String(localized: "unnamed_secret")
|
let name = $0[kSecAttrLabel] as? String ?? String(localized: .unnamedSecret)
|
||||||
let tokenID = $0[kSecAttrApplicationLabel] as! Data
|
let tokenID = $0[kSecAttrApplicationLabel] as! Data
|
||||||
let algorithm = Algorithm(secAttr: $0[kSecAttrKeyType] as! NSNumber)
|
let algorithm = Algorithm(secAttr: $0[kSecAttrKeyType] as! NSNumber)
|
||||||
let keySize = $0[kSecAttrKeySizeInBits] as! Int
|
let keySize = $0[kSecAttrKeySizeInBits] as! Int
|
||||||
@ -207,8 +207,8 @@ extension SmartCard.Store {
|
|||||||
/// - Warning: Encryption functions are deliberately only exposed on a library level, and are not exposed in Secretive itself to prevent users from data loss. Any pull requests which expose this functionality in the app will not be merged.
|
/// - Warning: Encryption functions are deliberately only exposed on a library level, and are not exposed in Secretive itself to prevent users from data loss. Any pull requests which expose this functionality in the app will not be merged.
|
||||||
public func encrypt(data: Data, with secret: SecretType) throws -> Data {
|
public func encrypt(data: Data, with secret: SecretType) throws -> Data {
|
||||||
let context = LAContext()
|
let context = LAContext()
|
||||||
context.localizedReason = String(localized: "auth_context_request_encrypt_description_\(secret.name)")
|
context.localizedReason = String(localized: .authContextRequestEncryptDescription(secretName: secret.name))
|
||||||
context.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
|
context.localizedCancelTitle = String(localized: .authContextRequestDenyButton)
|
||||||
let attributes = KeychainDictionary([
|
let attributes = KeychainDictionary([
|
||||||
kSecAttrKeyType: secret.algorithm.secAttrKeyType,
|
kSecAttrKeyType: secret.algorithm.secAttrKeyType,
|
||||||
kSecAttrKeySizeInBits: secret.keySize,
|
kSecAttrKeySizeInBits: secret.keySize,
|
||||||
@ -236,8 +236,8 @@ extension SmartCard.Store {
|
|||||||
public func decrypt(data: Data, with secret: SecretType) async throws -> Data {
|
public func decrypt(data: Data, with secret: SecretType) async throws -> Data {
|
||||||
guard let tokenID = await state.tokenID else { fatalError() }
|
guard let tokenID = await state.tokenID else { fatalError() }
|
||||||
let context = LAContext()
|
let context = LAContext()
|
||||||
context.localizedReason = String(localized: "auth_context_request_decrypt_description_\(secret.name)")
|
context.localizedReason = String(localized: .authContextRequestDecryptDescription(secretName: secret.name))
|
||||||
context.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
|
context.localizedCancelTitle = String(localized: .authContextRequestDenyButton)
|
||||||
let attributes = KeychainDictionary([
|
let attributes = KeychainDictionary([
|
||||||
kSecClass: kSecClassKey,
|
kSecClass: kSecClassKey,
|
||||||
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
||||||
|
@ -10,8 +10,8 @@ final class Notifier: Sendable {
|
|||||||
private let notificationDelegate = NotificationDelegate()
|
private let notificationDelegate = NotificationDelegate()
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let updateAction = UNNotificationAction(identifier: Constants.updateActionIdentitifier, title: String(localized: "update_notification_update_button"), options: [])
|
let updateAction = UNNotificationAction(identifier: Constants.updateActionIdentitifier, title: String(localized: .updateNotificationUpdateButton), options: [])
|
||||||
let ignoreAction = UNNotificationAction(identifier: Constants.ignoreActionIdentitifier, title: String(localized: "update_notification_ignore_button"), options: [])
|
let ignoreAction = UNNotificationAction(identifier: Constants.ignoreActionIdentitifier, title: String(localized: .updateNotificationIgnoreButton), options: [])
|
||||||
let updateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction, ignoreAction], intentIdentifiers: [], options: [])
|
let updateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction, ignoreAction], intentIdentifiers: [], options: [])
|
||||||
let criticalUpdateCategory = UNNotificationCategory(identifier: Constants.criticalUpdateCategoryIdentitifier, actions: [updateAction], intentIdentifiers: [], options: [])
|
let criticalUpdateCategory = UNNotificationCategory(identifier: Constants.criticalUpdateCategoryIdentitifier, actions: [updateAction], intentIdentifiers: [], options: [])
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ final class Notifier: Sendable {
|
|||||||
Measurement(value: 24, unit: UnitDuration.hours)
|
Measurement(value: 24, unit: UnitDuration.hours)
|
||||||
]
|
]
|
||||||
|
|
||||||
let doNotPersistAction = UNNotificationAction(identifier: Constants.doNotPersistActionIdentitifier, title: String(localized: "persist_authentication_decline_button"), options: [])
|
let doNotPersistAction = UNNotificationAction(identifier: Constants.doNotPersistActionIdentitifier, title: String(localized: .persistAuthenticationDeclineButton), options: [])
|
||||||
var allPersistenceActions = [doNotPersistAction]
|
var allPersistenceActions = [doNotPersistAction]
|
||||||
|
|
||||||
let formatter = DateComponentsFormatter()
|
let formatter = DateComponentsFormatter()
|
||||||
@ -41,7 +41,7 @@ final class Notifier: Sendable {
|
|||||||
|
|
||||||
let persistAuthenticationCategory = UNNotificationCategory(identifier: Constants.persistAuthenticationCategoryIdentitifier, actions: allPersistenceActions, intentIdentifiers: [], options: [])
|
let persistAuthenticationCategory = UNNotificationCategory(identifier: Constants.persistAuthenticationCategoryIdentitifier, actions: allPersistenceActions, intentIdentifiers: [], options: [])
|
||||||
if persistAuthenticationCategory.responds(to: Selector(("actionsMenuTitle"))) {
|
if persistAuthenticationCategory.responds(to: Selector(("actionsMenuTitle"))) {
|
||||||
persistAuthenticationCategory.setValue(String(localized: "persist_authentication_accept_button"), forKey: "_actionsMenuTitle")
|
persistAuthenticationCategory.setValue(String(localized: .persistAuthenticationAcceptButton), forKey: "_actionsMenuTitle")
|
||||||
}
|
}
|
||||||
UNUserNotificationCenter.current().setNotificationCategories([updateCategory, criticalUpdateCategory, persistAuthenticationCategory])
|
UNUserNotificationCenter.current().setNotificationCategories([updateCategory, criticalUpdateCategory, persistAuthenticationCategory])
|
||||||
UNUserNotificationCenter.current().delegate = notificationDelegate
|
UNUserNotificationCenter.current().delegate = notificationDelegate
|
||||||
@ -64,8 +64,8 @@ final class Notifier: Sendable {
|
|||||||
await notificationDelegate.state.setPending(secret: secret, store: store)
|
await notificationDelegate.state.setPending(secret: secret, store: store)
|
||||||
let notificationCenter = UNUserNotificationCenter.current()
|
let notificationCenter = UNUserNotificationCenter.current()
|
||||||
let notificationContent = UNMutableNotificationContent()
|
let notificationContent = UNMutableNotificationContent()
|
||||||
notificationContent.title = String(localized: "signed_notification_title_\(provenance.origin.displayName)")
|
notificationContent.title = String(localized: .signedNotificationTitle(appName: provenance.origin.displayName))
|
||||||
notificationContent.subtitle = String(localized: "signed_notification_description_\(secret.name)")
|
notificationContent.subtitle = String(localized: .signedNotificationDescription(secretName: secret.name))
|
||||||
notificationContent.userInfo[Constants.persistSecretIDKey] = secret.id.description
|
notificationContent.userInfo[Constants.persistSecretIDKey] = secret.id.description
|
||||||
notificationContent.userInfo[Constants.persistStoreIDKey] = store.id.description
|
notificationContent.userInfo[Constants.persistStoreIDKey] = store.id.description
|
||||||
notificationContent.interruptionLevel = .timeSensitive
|
notificationContent.interruptionLevel = .timeSensitive
|
||||||
@ -85,11 +85,11 @@ final class Notifier: Sendable {
|
|||||||
let notificationContent = UNMutableNotificationContent()
|
let notificationContent = UNMutableNotificationContent()
|
||||||
if update.critical {
|
if update.critical {
|
||||||
notificationContent.interruptionLevel = .critical
|
notificationContent.interruptionLevel = .critical
|
||||||
notificationContent.title = String(localized: "update_notification_update_critical_title_\(update.name)")
|
notificationContent.title = String(localized: .updateNotificationUpdateCriticalTitle(updateName: update.name))
|
||||||
} else {
|
} else {
|
||||||
notificationContent.title = String(localized: "update_notification_update_normal_title_\(update.name)")
|
notificationContent.title = String(localized: .updateNotificationUpdateNormalTitle(updateName: update.name))
|
||||||
}
|
}
|
||||||
notificationContent.subtitle = String(localized: "update_notification_update_description")
|
notificationContent.subtitle = String(localized: .updateNotificationUpdateDescription)
|
||||||
notificationContent.body = update.body
|
notificationContent.body = update.body
|
||||||
notificationContent.categoryIdentifier = update.critical ? Constants.criticalUpdateCategoryIdentitifier : Constants.updateCategoryIdentitifier
|
notificationContent.categoryIdentifier = update.critical ? Constants.criticalUpdateCategoryIdentitifier : Constants.updateCategoryIdentitifier
|
||||||
let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
|
let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
|
||||||
|
@ -18,8 +18,9 @@
|
|||||||
5003EF612780081600DF2006 /* SmartCardSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF602780081600DF2006 /* SmartCardSecretKit */; };
|
5003EF612780081600DF2006 /* SmartCardSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF602780081600DF2006 /* SmartCardSecretKit */; };
|
||||||
5003EF632780081B00DF2006 /* SecureEnclaveSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF622780081B00DF2006 /* SecureEnclaveSecretKit */; };
|
5003EF632780081B00DF2006 /* SecureEnclaveSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF622780081B00DF2006 /* SecureEnclaveSecretKit */; };
|
||||||
5003EF652780081B00DF2006 /* SmartCardSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF642780081B00DF2006 /* SmartCardSecretKit */; };
|
5003EF652780081B00DF2006 /* SmartCardSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF642780081B00DF2006 /* SmartCardSecretKit */; };
|
||||||
|
5008C23E2E525D8900507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; };
|
||||||
5008C2402E52792400507AC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
|
5008C2402E52792400507AC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
|
||||||
500B93C32B478D8400E157DE /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 500B93C22B478D8400E157DE /* Localizable.xcstrings */; };
|
5008C2412E52D18700507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; };
|
||||||
501421622781262300BBAA70 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501421612781262300BBAA70 /* Brief */; };
|
501421622781262300BBAA70 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501421612781262300BBAA70 /* Brief */; };
|
||||||
501421652781268000BBAA70 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
501421652781268000BBAA70 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; };
|
50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; };
|
||||||
@ -51,7 +52,6 @@
|
|||||||
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B8550C24138C4F009958AC /* DeleteSecretView.swift */; };
|
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B8550C24138C4F009958AC /* DeleteSecretView.swift */; };
|
||||||
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */; };
|
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */; };
|
||||||
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A42407A76D00AF2719 /* SecretDetailView.swift */; };
|
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A42407A76D00AF2719 /* SecretDetailView.swift */; };
|
||||||
50E9CF422B51D596004AB36D /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 500B93C22B478D8400E157DE /* Localizable.xcstrings */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -102,7 +102,7 @@
|
|||||||
50020BAF24064869003D4025 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
50020BAF24064869003D4025 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
50033AC227813F1700253856 /* BundleIDs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleIDs.swift; sourceTree = "<group>"; };
|
50033AC227813F1700253856 /* BundleIDs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleIDs.swift; sourceTree = "<group>"; };
|
||||||
5003EF39278005C800DF2006 /* Packages */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Packages; sourceTree = "<group>"; };
|
5003EF39278005C800DF2006 /* Packages */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Packages; sourceTree = "<group>"; };
|
||||||
500B93C22B478D8400E157DE /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
|
5008C23D2E525D8200507AC2 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = Localizable.xcstrings; path = Packages/Localizable.xcstrings; sourceTree = SOURCE_ROOT; };
|
||||||
50153E1F250AFCB200525160 /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; };
|
50153E1F250AFCB200525160 /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; };
|
||||||
50153E21250DECA300525160 /* SecretListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretListItemView.swift; sourceTree = "<group>"; };
|
50153E21250DECA300525160 /* SecretListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretListItemView.swift; sourceTree = "<group>"; };
|
||||||
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
|
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
|
||||||
@ -210,7 +210,7 @@
|
|||||||
508BF28D25B4F005009EFB7E /* InternetAccessPolicy.plist */,
|
508BF28D25B4F005009EFB7E /* InternetAccessPolicy.plist */,
|
||||||
50617D8F23FCE48E0099B055 /* Secretive.entitlements */,
|
50617D8F23FCE48E0099B055 /* Secretive.entitlements */,
|
||||||
506772C62424784600034DED /* Credits.rtf */,
|
506772C62424784600034DED /* Credits.rtf */,
|
||||||
500B93C22B478D8400E157DE /* Localizable.xcstrings */,
|
5008C23D2E525D8200507AC2 /* Localizable.xcstrings */,
|
||||||
50617D8823FCE48E0099B055 /* Preview Content */,
|
50617D8823FCE48E0099B055 /* Preview Content */,
|
||||||
);
|
);
|
||||||
path = Secretive;
|
path = Secretive;
|
||||||
@ -404,7 +404,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
50617D8A23FCE48E0099B055 /* Preview Assets.xcassets in Resources */,
|
50617D8A23FCE48E0099B055 /* Preview Assets.xcassets in Resources */,
|
||||||
500B93C32B478D8400E157DE /* Localizable.xcstrings in Resources */,
|
5008C23E2E525D8900507AC2 /* Localizable.xcstrings in Resources */,
|
||||||
50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */,
|
50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */,
|
||||||
506772C72424784600034DED /* Credits.rtf in Resources */,
|
506772C72424784600034DED /* Credits.rtf in Resources */,
|
||||||
508BF28E25B4F005009EFB7E /* InternetAccessPolicy.plist in Resources */,
|
508BF28E25B4F005009EFB7E /* InternetAccessPolicy.plist in Resources */,
|
||||||
@ -416,7 +416,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
50A3B79724026B7600D209EA /* Main.storyboard in Resources */,
|
50A3B79724026B7600D209EA /* Main.storyboard in Resources */,
|
||||||
50E9CF422B51D596004AB36D /* Localizable.xcstrings in Resources */,
|
5008C2412E52D18700507AC2 /* Localizable.xcstrings in Resources */,
|
||||||
50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */,
|
50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */,
|
||||||
508BF2AA25B4F1CB009EFB7E /* InternetAccessPolicy.plist in Resources */,
|
508BF2AA25B4F1CB009EFB7E /* InternetAccessPolicy.plist in Resources */,
|
||||||
5008C2402E52792400507AC2 /* Assets.xcassets in Resources */,
|
5008C2402E52792400507AC2 /* Assets.xcassets in Resources */,
|
||||||
|
@ -59,18 +59,18 @@ struct Secretive: App {
|
|||||||
}
|
}
|
||||||
.commands {
|
.commands {
|
||||||
CommandGroup(after: CommandGroupPlacement.newItem) {
|
CommandGroup(after: CommandGroupPlacement.newItem) {
|
||||||
Button("app_menu_new_secret_button") {
|
Button(.appMenuNewSecretButton) {
|
||||||
showingCreation = true
|
showingCreation = true
|
||||||
}
|
}
|
||||||
.keyboardShortcut(KeyboardShortcut(KeyEquivalent("N"), modifiers: [.command, .shift]))
|
.keyboardShortcut(KeyboardShortcut(KeyEquivalent("N"), modifiers: [.command, .shift]))
|
||||||
}
|
}
|
||||||
CommandGroup(replacing: .help) {
|
CommandGroup(replacing: .help) {
|
||||||
Button("app_menu_help_button") {
|
Button(.appMenuHelpButton) {
|
||||||
NSWorkspace.shared.open(Constants.helpURL)
|
NSWorkspace.shared.open(Constants.helpURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CommandGroup(after: .help) {
|
CommandGroup(after: .help) {
|
||||||
Button("app_menu_setup_button") {
|
Button(.appMenuSetupButton) {
|
||||||
showingSetup = true
|
showingSetup = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,15 +70,15 @@ extension ContentView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateNoticeContent: (LocalizedStringKey, Color)? {
|
var updateNoticeContent: (LocalizedStringResource, Color)? {
|
||||||
guard let update = updater.update else { return nil }
|
guard let update = updater.update else { return nil }
|
||||||
if update.critical {
|
if update.critical {
|
||||||
return ("update_critical_notice_title", .red)
|
return (.updateCriticalNoticeTitle, .red)
|
||||||
} else {
|
} else {
|
||||||
if updater.testBuild {
|
if updater.testBuild {
|
||||||
return ("update_test_notice_title", .blue)
|
return (.updateTestNoticeTitle, .blue)
|
||||||
} else {
|
} else {
|
||||||
return ("update_normal_notice_title", .orange)
|
return (.updateNormalNoticeTitle, .orange)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,13 +127,13 @@ extension ContentView {
|
|||||||
}, label: {
|
}, label: {
|
||||||
Group {
|
Group {
|
||||||
if hasRunSetup && !agentStatusChecker.running {
|
if hasRunSetup && !agentStatusChecker.running {
|
||||||
Text("agent_not_running_notice_title")
|
Text(.agentNotRunningNoticeTitle)
|
||||||
} else {
|
} else {
|
||||||
Text("agent_setup_notice_title")
|
Text(.agentSetupNoticeTitle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(.white)
|
|
||||||
})
|
})
|
||||||
.buttonStyle(ToolbarButtonStyle(color: .orange))
|
.buttonStyle(ToolbarButtonStyle(color: .orange))
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ extension ContentView {
|
|||||||
showingAgentInfo = true
|
showingAgentInfo = true
|
||||||
}, label: {
|
}, label: {
|
||||||
HStack {
|
HStack {
|
||||||
Text("agent_running_notice_title")
|
Text(.agentRunningNoticeTitle)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(colorScheme == .light ? Color(white: 0.3) : .white)
|
.foregroundColor(colorScheme == .light ? Color(white: 0.3) : .white)
|
||||||
Circle()
|
Circle()
|
||||||
@ -155,10 +155,10 @@ extension ContentView {
|
|||||||
.buttonStyle(ToolbarButtonStyle(lightColor: .black.opacity(0.05), darkColor: .white.opacity(0.05)))
|
.buttonStyle(ToolbarButtonStyle(lightColor: .black.opacity(0.05), darkColor: .white.opacity(0.05)))
|
||||||
.popover(isPresented: $showingAgentInfo, attachmentAnchor: attachmentAnchor, arrowEdge: .bottom) {
|
.popover(isPresented: $showingAgentInfo, attachmentAnchor: attachmentAnchor, arrowEdge: .bottom) {
|
||||||
VStack {
|
VStack {
|
||||||
Text("agent_running_notice_detail_title")
|
Text(.agentRunningNoticeDetailTitle)
|
||||||
.font(.title)
|
.font(.title)
|
||||||
.padding(5)
|
.padding(5)
|
||||||
Text("agent_running_notice_detail_description")
|
Text(.agentRunningNoticeDetailDescription)
|
||||||
.frame(width: 300)
|
.frame(width: 300)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
@ -172,7 +172,7 @@ extension ContentView {
|
|||||||
showingAppPathNotice = true
|
showingAppPathNotice = true
|
||||||
}, label: {
|
}, label: {
|
||||||
Group {
|
Group {
|
||||||
Text("app_not_in_applications_notice_title")
|
Text(.appNotInApplicationsNoticeTitle)
|
||||||
}
|
}
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
@ -184,7 +184,7 @@ extension ContentView {
|
|||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
.frame(width: 64)
|
.frame(width: 64)
|
||||||
Text("app_not_in_applications_notice_detail_description")
|
Text(.appNotInApplicationsNoticeDetailDescription)
|
||||||
.frame(maxWidth: 300)
|
.frame(maxWidth: 300)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
@ -3,7 +3,7 @@ import UniformTypeIdentifiers
|
|||||||
|
|
||||||
struct CopyableView: View {
|
struct CopyableView: View {
|
||||||
|
|
||||||
var title: LocalizedStringKey
|
var title: LocalizedStringResource
|
||||||
var image: Image
|
var image: Image
|
||||||
var text: String
|
var text: String
|
||||||
|
|
||||||
|
@ -14,30 +14,30 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View {
|
|||||||
HStack {
|
HStack {
|
||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
Text("create_secret_title")
|
Text(.createSecretTitle)
|
||||||
.font(.largeTitle)
|
.font(.largeTitle)
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Text("create_secret_name_label")
|
Text(.createSecretNameLabel)
|
||||||
TextField("create_secret_name_placeholder", text: $name)
|
TextField(String(localized: .createSecretNamePlaceholder), text: $name)
|
||||||
.focusable()
|
.focusable()
|
||||||
}
|
}
|
||||||
ThumbnailPickerView(items: [
|
ThumbnailPickerView(items: [
|
||||||
ThumbnailPickerView.Item(value: true, name: "create_secret_require_authentication_title", description: "create_secret_require_authentication_description", thumbnail: AuthenticationView()),
|
ThumbnailPickerView.Item(value: true, name: .createSecretRequireAuthenticationTitle, description: .createSecretRequireAuthenticationDescription, thumbnail: AuthenticationView()),
|
||||||
ThumbnailPickerView.Item(value: false, name: "create_secret_notify_title",
|
ThumbnailPickerView.Item(value: false, name: .createSecretNotifyTitle,
|
||||||
description: "create_secret_notify_description",
|
description: .createSecretNotifyDescription,
|
||||||
thumbnail: NotificationView())
|
thumbnail: NotificationView())
|
||||||
], selection: $requiresAuthentication)
|
], selection: $requiresAuthentication)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("create_secret_cancel_button") {
|
Button(.createSecretCancelButton) {
|
||||||
showing = false
|
showing = false
|
||||||
}
|
}
|
||||||
.keyboardShortcut(.cancelAction)
|
.keyboardShortcut(.cancelAction)
|
||||||
Button("create_secret_create_button", action: save)
|
Button(.createSecretCreateButton, action: save)
|
||||||
.disabled(name.isEmpty)
|
.disabled(name.isEmpty)
|
||||||
.keyboardShortcut(.defaultAction)
|
.keyboardShortcut(.defaultAction)
|
||||||
}
|
}
|
||||||
@ -98,11 +98,11 @@ extension ThumbnailPickerView {
|
|||||||
struct Item<InnerValueType: Hashable>: Identifiable {
|
struct Item<InnerValueType: Hashable>: Identifiable {
|
||||||
let id = UUID()
|
let id = UUID()
|
||||||
let value: InnerValueType
|
let value: InnerValueType
|
||||||
let name: LocalizedStringKey
|
let name: LocalizedStringResource
|
||||||
let description: LocalizedStringKey
|
let description: LocalizedStringResource
|
||||||
let thumbnail: AnyView
|
let thumbnail: AnyView
|
||||||
|
|
||||||
init<ViewType: View>(value: InnerValueType, name: LocalizedStringKey, description: LocalizedStringKey, thumbnail: ViewType) {
|
init<ViewType: View>(value: InnerValueType, name: LocalizedStringResource, description: LocalizedStringResource, thumbnail: ViewType) {
|
||||||
self.value = value
|
self.value = value
|
||||||
self.name = name
|
self.name = name
|
||||||
self.description = description
|
self.description = description
|
||||||
|
@ -18,24 +18,24 @@ struct DeleteSecretView<StoreType: SecretStoreModifiable>: View {
|
|||||||
.padding()
|
.padding()
|
||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
Text("delete_confirmation_title_\(secret.name)").bold()
|
Text(.deleteConfirmationTitle(secretName: secret.name)).bold()
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Text("delete_confirmation_description_\(secret.name)_\(secret.name)")
|
Text(.deleteConfirmationDescription(secretName: secret.name, confirmSecretName: secret.name))
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Text("delete_confirmation_confirm_name_label")
|
Text(.deleteConfirmationConfirmNameLabel)
|
||||||
TextField(secret.name, text: $confirm)
|
TextField(secret.name, text: $confirm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("delete_confirmation_delete_button", action: delete)
|
Button(.deleteConfirmationDeleteButton, action: delete)
|
||||||
.disabled(confirm != secret.name)
|
.disabled(confirm != secret.name)
|
||||||
Button("delete_confirmation_cancel_button") {
|
Button(.deleteConfirmationCancelButton) {
|
||||||
dismissalBlock(false)
|
dismissalBlock(false)
|
||||||
}
|
}
|
||||||
.keyboardShortcut(.cancelAction)
|
.keyboardShortcut(.cancelAction)
|
||||||
|
@ -18,9 +18,9 @@ struct EmptyStoreImmutableView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Text("empty_store_nonmodifiable_title").bold()
|
Text(.emptyStoreNonmodifiableTitle).bold()
|
||||||
Text("empty_store_nonmodifiable_description")
|
Text(.emptyStoreNonmodifiableDescription)
|
||||||
Text("empty_store_nonmodifiable_supported_key_types")
|
Text(.emptyStoreNonmodifiableSupportedKeyTypes)
|
||||||
}.frame(maxWidth: .infinity, maxHeight: .infinity)
|
}.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +49,8 @@ struct EmptyStoreModifiableView: View {
|
|||||||
path.addLine(to: CGPoint(x: g.size.width - 3, y: 0))
|
path.addLine(to: CGPoint(x: g.size.width - 3, y: 0))
|
||||||
}.fill()
|
}.fill()
|
||||||
}.frame(height: (windowGeometry.size.height/2) - 20).padding()
|
}.frame(height: (windowGeometry.size.height/2) - 20).padding()
|
||||||
Text("empty_store_modifiable_click_here_title").bold()
|
Text(.emptyStoreModifiableClickHereTitle).bold()
|
||||||
Text("empty_store_modifiable_click_here_description")
|
Text(.emptyStoreModifiableClickHereDescription)
|
||||||
Spacer()
|
Spacer()
|
||||||
}.frame(maxWidth: .infinity, maxHeight: .infinity)
|
}.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,10 @@ struct NoStoresView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Text("no_secure_storage_title")
|
Text(.noSecureStorageTitle)
|
||||||
.bold()
|
.bold()
|
||||||
Text("no_secure_storage_description")
|
Text(.noSecureStorageDescription)
|
||||||
Link("no_secure_storage_yubico_link", destination: URL(string: "https://www.yubico.com/products/compare-yubikey-5-series/")!)
|
Link(.noSecureStorageYubicoLink, destination: URL(string: "https://www.yubico.com/products/compare-yubikey-5-series/")!)
|
||||||
}.padding()
|
}.padding()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ struct RenameSecretView<StoreType: SecretStoreModifiable>: View {
|
|||||||
.padding()
|
.padding()
|
||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
Text("rename_title_\(secret.name)")
|
Text(.renameTitle(secretName: secret.name))
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
@ -28,10 +28,10 @@ struct RenameSecretView<StoreType: SecretStoreModifiable>: View {
|
|||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("rename_rename_button", action: rename)
|
Button(.renameRenameButton, action: rename)
|
||||||
.disabled(newName.count == 0)
|
.disabled(newName.count == 0)
|
||||||
.keyboardShortcut(.return)
|
.keyboardShortcut(.return)
|
||||||
Button("rename_cancel_button") {
|
Button(.renameCancelButton) {
|
||||||
dismissalBlock(false)
|
dismissalBlock(false)
|
||||||
}.keyboardShortcut(.cancelAction)
|
}.keyboardShortcut(.cancelAction)
|
||||||
}
|
}
|
||||||
|
@ -12,16 +12,16 @@ struct SecretDetailView<SecretType: Secret>: View {
|
|||||||
ScrollView {
|
ScrollView {
|
||||||
Form {
|
Form {
|
||||||
Section {
|
Section {
|
||||||
CopyableView(title: "secret_detail_sha256_fingerprint_label", image: Image(systemName: "touchid"), text: keyWriter.openSSHSHA256Fingerprint(secret: secret))
|
CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "touchid"), text: keyWriter.openSSHSHA256Fingerprint(secret: secret))
|
||||||
Spacer()
|
Spacer()
|
||||||
.frame(height: 20)
|
.frame(height: 20)
|
||||||
CopyableView(title: "secret_detail_md5_fingerprint_label", image: Image(systemName: "touchid"), text: keyWriter.openSSHMD5Fingerprint(secret: secret))
|
CopyableView(title: .secretDetailMd5FingerprintLabel, image: Image(systemName: "touchid"), text: keyWriter.openSSHMD5Fingerprint(secret: secret))
|
||||||
Spacer()
|
Spacer()
|
||||||
.frame(height: 20)
|
.frame(height: 20)
|
||||||
CopyableView(title: "secret_detail_public_key_label", image: Image(systemName: "key"), text: keyString)
|
CopyableView(title: .secretDetailPublicKeyLabel, image: Image(systemName: "key"), text: keyString)
|
||||||
Spacer()
|
Spacer()
|
||||||
.frame(height: 20)
|
.frame(height: 20)
|
||||||
CopyableView(title: "secret_detail_public_key_path_label", image: Image(systemName: "lock.doc"), text: publicKeyFileStoreController.publicKeyPath(for: secret))
|
CopyableView(title: .secretDetailPublicKeyPathLabel, image: Image(systemName: "lock.doc"), text: publicKeyFileStoreController.publicKeyPath(for: secret))
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,10 @@ struct SecretListItemView: View {
|
|||||||
.contextMenu {
|
.contextMenu {
|
||||||
if store is AnySecretStoreModifiable {
|
if store is AnySecretStoreModifiable {
|
||||||
Button(action: { isRenaming = true }) {
|
Button(action: { isRenaming = true }) {
|
||||||
Text("secret_list_rename_button")
|
Text(.secretListRenameButton)
|
||||||
}
|
}
|
||||||
Button(action: { isDeleting = true }) {
|
Button(action: { isDeleting = true }) {
|
||||||
Text("secret_list_delete_button")
|
Text(.secretListDeleteButton)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ struct StepView: View {
|
|||||||
Circle()
|
Circle()
|
||||||
.foregroundColor(.green)
|
.foregroundColor(.green)
|
||||||
.frame(width: Constants.circleWidth, height: Constants.circleWidth)
|
.frame(width: Constants.circleWidth, height: Constants.circleWidth)
|
||||||
Text("setup_step_complete_symbol")
|
Text(.setupStepCompleteSymbol)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.bold()
|
.bold()
|
||||||
} else {
|
} else {
|
||||||
@ -101,14 +101,14 @@ extension StepView {
|
|||||||
|
|
||||||
struct SetupStepView<Content> : View where Content : View {
|
struct SetupStepView<Content> : View where Content : View {
|
||||||
|
|
||||||
let title: LocalizedStringKey
|
let title: LocalizedStringResource
|
||||||
let image: Image
|
let image: Image
|
||||||
let bodyText: LocalizedStringKey
|
let bodyText: LocalizedStringResource
|
||||||
let buttonTitle: LocalizedStringKey
|
let buttonTitle: LocalizedStringResource
|
||||||
let buttonAction: () -> Void
|
let buttonAction: () -> Void
|
||||||
let content: Content
|
let content: Content
|
||||||
|
|
||||||
init(title: LocalizedStringKey, image: Image, bodyText: LocalizedStringKey, buttonTitle: LocalizedStringKey, buttonAction: @escaping () -> Void = {}, @ViewBuilder content: () -> Content) {
|
init(title: LocalizedStringResource, image: Image, bodyText: LocalizedStringResource, buttonTitle: LocalizedStringResource, buttonAction: @escaping () -> Void = {}, @ViewBuilder content: () -> Content) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.image = image
|
self.image = image
|
||||||
self.bodyText = bodyText
|
self.bodyText = bodyText
|
||||||
@ -145,12 +145,12 @@ struct SecretAgentSetupView: View {
|
|||||||
let buttonAction: () -> Void
|
let buttonAction: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
SetupStepView(title: "setup_agent_title",
|
SetupStepView(title: .setupAgentTitle,
|
||||||
image: Image(nsImage: NSApplication.shared.applicationIconImage),
|
image: Image(nsImage: NSApplication.shared.applicationIconImage),
|
||||||
bodyText: "setup_agent_description",
|
bodyText: .setupAgentDescription,
|
||||||
buttonTitle: "setup_agent_install_button",
|
buttonTitle: .setupAgentInstallButton,
|
||||||
buttonAction: install) {
|
buttonAction: install) {
|
||||||
Text("setup_agent_activity_monitor_description")
|
Text(.setupAgentActivityMonitorDescription)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,12 +172,12 @@ struct SSHAgentSetupView: View {
|
|||||||
@State private var selectedShellInstruction: ShellConfigInstruction = controller.shellInstructions.first!
|
@State private var selectedShellInstruction: ShellConfigInstruction = controller.shellInstructions.first!
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
SetupStepView(title: "setup_ssh_title",
|
SetupStepView(title: .setupSshTitle,
|
||||||
image: Image(systemName: "terminal"),
|
image: Image(systemName: "terminal"),
|
||||||
bodyText: "setup_ssh_description",
|
bodyText: .setupSshDescription,
|
||||||
buttonTitle: "setup_ssh_added_manually_button",
|
buttonTitle: .setupSshAddedManuallyButton,
|
||||||
buttonAction: buttonAction) {
|
buttonAction: buttonAction) {
|
||||||
Link("setup_third_party_faq_link", destination: URL(string: "https://github.com/maxgoedjen/secretive/blob/main/APP_CONFIG.md")!)
|
Link(.setupThirdPartyFaqLink, destination: URL(string: "https://github.com/maxgoedjen/secretive/blob/main/APP_CONFIG.md")!)
|
||||||
Picker(selection: $selectedShellInstruction, label: EmptyView()) {
|
Picker(selection: $selectedShellInstruction, label: EmptyView()) {
|
||||||
ForEach(SSHAgentSetupView.controller.shellInstructions) { instruction in
|
ForEach(SSHAgentSetupView.controller.shellInstructions) { instruction in
|
||||||
Text(instruction.shell)
|
Text(instruction.shell)
|
||||||
@ -185,8 +185,8 @@ struct SSHAgentSetupView: View {
|
|||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
}.pickerStyle(SegmentedPickerStyle())
|
}.pickerStyle(SegmentedPickerStyle())
|
||||||
CopyableView(title: "setup_ssh_add_to_config_button_\(selectedShellInstruction.shellConfigPath)", image: Image(systemName: "greaterthan.square"), text: selectedShellInstruction.text)
|
CopyableView(title: .setupSshAddToConfigButton(configPath: selectedShellInstruction.shellConfigPath), image: Image(systemName: "greaterthan.square"), text: selectedShellInstruction.text)
|
||||||
Button("setup_ssh_add_for_me_button") {
|
Button(.setupSshAddForMeButton) {
|
||||||
let controller = ShellConfigurationController()
|
let controller = ShellConfigurationController()
|
||||||
if controller.addToShell(shellInstructions: selectedShellInstruction) {
|
if controller.addToShell(shellInstructions: selectedShellInstruction) {
|
||||||
buttonAction()
|
buttonAction()
|
||||||
@ -216,12 +216,12 @@ struct UpdaterExplainerView: View {
|
|||||||
let buttonAction: () -> Void
|
let buttonAction: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
SetupStepView(title: "setup_updates_title",
|
SetupStepView(title: .setupUpdatesTitle,
|
||||||
image: Image(systemName: "dot.radiowaves.left.and.right"),
|
image: Image(systemName: "dot.radiowaves.left.and.right"),
|
||||||
bodyText: "setup_updates_description",
|
bodyText: .setupUpdatesDescription,
|
||||||
buttonTitle: "setup_updates_ok",
|
buttonTitle: .setupUpdatesOk,
|
||||||
buttonAction: buttonAction) {
|
buttonAction: buttonAction) {
|
||||||
Link("setup_updates_readmore", destination: SetupView.Constants.updaterFAQURL)
|
Link(.setupUpdatesReadmore, destination: SetupView.Constants.updaterFAQURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,22 +9,22 @@ struct UpdateDetailView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Text("update_version_name_\(update.name)").font(.title)
|
Text(.updateVersionName(updateName: update.name)).font(.title)
|
||||||
GroupBox(label: Text("update_release_notes_title")) {
|
GroupBox(label: Text(.updateReleaseNotesTitle)) {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
attributedBody
|
attributedBody
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
if !update.critical {
|
if !update.critical {
|
||||||
Button("update_ignore_button") {
|
Button(.updateIgnoreButton) {
|
||||||
Task {
|
Task {
|
||||||
await updater.ignore(release: update)
|
await updater.ignore(release: update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
Button("update_update_button") {
|
Button(.updateUpdateButton) {
|
||||||
NSWorkspace.shared.open(update.html_url)
|
NSWorkspace.shared.open(update.html_url)
|
||||||
}
|
}
|
||||||
.keyboardShortcut(.defaultAction)
|
.keyboardShortcut(.defaultAction)
|
||||||
|
Loading…
Reference in New Issue
Block a user