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

Customize Security Overview #70

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
10 changes: 10 additions & 0 deletions Sources/SpeziAccount/AccountValue/AccountKey+Views.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,17 @@
return AnyView(DataDisplay(value))
}

static func securityViewWithCurrentStoredValueIfPresent(from details: AccountDetails) -> AnyView? {
let value = details[Self.self]

if let securityView = DataDisplay as? any SecurityView.Type {
return AnyView(securityView.init()) // TODO: pass the current value!

Check failure on line 46 in Sources/SpeziAccount/AccountValue/AccountKey+Views.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Todo Violation: TODOs should be resolved (pass the current value!) (todo)
}
return nil
}

static func singleEditView(model: AccountOverviewFormViewModel, details accountDetails: AccountDetails) -> AnyView {
// TODO: pass as environment object

Check failure on line 52 in Sources/SpeziAccount/AccountValue/AccountKey+Views.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Todo Violation: TODOs should be resolved (pass as environment object) (todo)
AnyView(SingleEditView<Self>(model: model, details: accountDetails))
}
}
29 changes: 29 additions & 0 deletions Sources/SpeziAccount/AccountValue/Keys/ConfiguredCredentials.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SpeziFoundation


extension AccountDetails {
fileprivate struct ConfiguredCredentials: DefaultProvidingKnowledgeSource {
typealias Anchor = AccountAnchor
typealias Value = [any AccountKey.Type]

static let defaultValue: Value = []
}

/// The list of credentials that are configured for the user account.
public var configuredCredentials: [any AccountKey.Type] {
get {
self[ConfiguredCredentials.self]
}
set {
self[ConfiguredCredentials.self] = newValue
}
}
}
34 changes: 34 additions & 0 deletions Sources/SpeziAccount/AccountValue/Keys/PasswordKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,39 @@
import SwiftUI


private struct ConfigureView: SecurityView {
typealias Value = String

@Environment(Account.self)
private var account

@State private var presentingPasswordSheet = false

private var label: Text {
if account.details?.configuredCredentials.contains(where: { $0 == AccountKeys.password }) == true {

Check failure on line 23 in Sources/SpeziAccount/AccountValue/Keys/PasswordKey.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package / Test using xcodebuild or run fastlane

main actor-isolated property 'details' can not be referenced from a non-isolated context

Check failure on line 23 in Sources/SpeziAccount/AccountValue/Keys/PasswordKey.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package macOS / Test using xcodebuild or run fastlane

main actor-isolated property 'details' can not be referenced from a non-isolated context

Check failure on line 23 in Sources/SpeziAccount/AccountValue/Keys/PasswordKey.swift

View workflow job for this annotation

GitHub Actions / Build and Test UI Tests / Test using xcodebuild or run fastlane

main actor-isolated property 'details' can not be referenced from a non-isolated context

Check failure on line 23 in Sources/SpeziAccount/AccountValue/Keys/PasswordKey.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package visionOS / Test using xcodebuild or run fastlane

main actor-isolated property 'details' can not be referenced from a non-isolated context

Check failure on line 23 in Sources/SpeziAccount/AccountValue/Keys/PasswordKey.swift

View workflow job for this annotation

GitHub Actions / Build and Test UI Tests visionOS / Test using xcodebuild or run fastlane

main actor-isolated property 'details' can not be referenced from a non-isolated context
Text("CHANGE_PASSWORD", bundle: .module)
} else {
Text("Setup Password", bundle: .module)
}
}

var body: some View {
Button(action: {
presentingPasswordSheet = true
}) {
label
}
.sheet(isPresented: $presentingPasswordSheet) {
PasswordChangeSheet()
}
}

init() { // TODO: does that make sense?

Check failure on line 41 in Sources/SpeziAccount/AccountValue/Keys/PasswordKey.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Todo Violation: TODOs should be resolved (does that make sense?) (todo)
// password will be never present, configuring/changing password is done via other mechanisms
}
}


private struct EntryView: DataEntryView {
@Environment(\.accountViewType)
private var accountViewType
Expand Down Expand Up @@ -69,6 +102,7 @@
name: LocalizedStringResource("UP_PASSWORD", bundle: .atURL(from: .module)),
category: .credentials,
as: String.self,
displayView: ConfigureView.self,
entryView: EntryView.self
)
public var password: String?
Expand Down
5 changes: 4 additions & 1 deletion Sources/SpeziAccount/Mock/InMemoryAccountService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,12 @@
details.userId = userId
}

if storage.password == nil {
if let password = storage.password {

Check warning on line 390 in Sources/SpeziAccount/Mock/InMemoryAccountService.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package macOS / Test using xcodebuild or run fastlane

value 'password' was defined but never used; consider replacing with boolean test

Check warning on line 390 in Sources/SpeziAccount/Mock/InMemoryAccountService.swift

View workflow job for this annotation

GitHub Actions / Build and Test UI Tests visionOS / Test using xcodebuild or run fastlane

value 'password' was defined but never used; consider replacing with boolean test
details.configuredCredentials = [AccountKeys.password]
} else {
details.isAnonymous = true
}

return details
}
}
Expand Down
9 changes: 9 additions & 0 deletions Sources/SpeziAccount/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@
}
}
}
},
"Changing the password requires a signed in user account." : {

},
"CLOSE" : {
"localizations" : {
Expand Down Expand Up @@ -1016,6 +1019,9 @@
}
}
}
},
"No Account" : {

},
"Numeric Key" : {
"localizations" : {
Expand Down Expand Up @@ -1174,6 +1180,9 @@
}
}
}
},
"Setup Password" : {

},
"SIGN_IN_AND_SECURITY" : {
"localizations" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import SwiftUI
struct AccountKeyOverviewRow: View {
private let accountDetails: AccountDetails
private let accountKey: any AccountKey.Type
private let model: AccountOverviewFormViewModel

@Environment(Account.self)
private var account
@Environment(AccountOverviewFormViewModel.self)
private var model
@Environment(\.editMode)
private var editMode

Expand Down Expand Up @@ -58,15 +59,17 @@ struct AccountKeyOverviewRow: View {
if let view = accountKey.dataDisplayViewWithCurrentStoredValue(from: accountDetails) {
view
.environment(\.accountViewType, .overview(mode: .display))
} else if let view = accountKey.securityViewWithCurrentStoredValueIfPresent(from: accountDetails) {
view
.environment(\.accountViewType, .overview(mode: .display))
}
}
}


init(details accountDetails: AccountDetails, for accountKey: any AccountKey.Type, model: AccountOverviewFormViewModel) {
init(details accountDetails: AccountDetails, for accountKey: any AccountKey.Type) {
self.accountDetails = accountDetails
self.accountKey = accountKey
self.model = model
}


Expand All @@ -92,7 +95,8 @@ private let key = AccountKeys.genderIdentity
return AccountDetailsReader { account, details in
let model = AccountOverviewFormViewModel(account: account, details: details)

AccountKeyOverviewRow(details: details, for: key, model: model)
AccountKeyOverviewRow(details: details, for: key)
.environment(model)
.injectEnvironmentObjects(configuration: details.accountServiceConfiguration, model: model)
}
.previewWith {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ struct AccountOverviewSections<AdditionalSections: View>: View {
defaultSections

sectionsView
.environment(model)
.injectEnvironmentObjects(configuration: accountDetails.accountServiceConfiguration, model: model)
.receiveValidation(in: $validation)
.focused($isFocused)
Expand Down Expand Up @@ -194,7 +195,8 @@ struct AccountOverviewSections<AdditionalSections: View>: View {
Section {
if displayName {
NavigationLink {
NameOverview(model: model, details: accountDetails)
NameOverview(details: accountDetails)
.environment(model)
} label: {
Label {
model.accountIdentifierLabel(configuration: account.configuration, accountDetails)
Expand All @@ -206,7 +208,8 @@ struct AccountOverviewSections<AdditionalSections: View>: View {

if displaySecurity {
NavigationLink {
SecurityOverview(model: model, details: accountDetails)
SecurityOverview(details: accountDetails)
.environment(model)
} label: {
Label {
Text("SIGN_IN_AND_SECURITY", bundle: .module)
Expand All @@ -229,7 +232,7 @@ struct AccountOverviewSections<AdditionalSections: View>: View {
}

ForEach(forEachWrappers) { wrapper in
AccountKeyOverviewRow(details: accountDetails, for: wrapper.accountKey, model: model)
AccountKeyOverviewRow(details: accountDetails, for: wrapper.accountKey)
}
.onDelete { indexSet in
model.deleteAccountKeys(at: indexSet, in: accountKeys)
Expand Down
12 changes: 7 additions & 5 deletions Sources/SpeziAccount/Views/AccountOverview/NameOverview.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import SwiftUI


struct NameOverview: View {
private let model: AccountOverviewFormViewModel
private let accountDetails: AccountDetails

@Environment(Account.self)
private var account
@Environment(AccountOverviewFormViewModel.self)
private var model


var body: some View {
Expand Down Expand Up @@ -63,8 +64,7 @@ struct NameOverview: View {
}


init(model: AccountOverviewFormViewModel, details accountDetails: AccountDetails) {
self.model = model
init(details accountDetails: AccountDetails) {
self.accountDetails = accountDetails
}
}
Expand All @@ -78,7 +78,8 @@ struct NameOverview: View {

return NavigationStack {
AccountDetailsReader { account, details in
NameOverview(model: AccountOverviewFormViewModel(account: account, details: details), details: details)
NameOverview(details: details)
.environment(AccountOverviewFormViewModel(account: account, details: details))
}
}
.previewWith {
Expand All @@ -92,7 +93,8 @@ struct NameOverview: View {

return NavigationStack {
AccountDetailsReader { account, details in
NameOverview(model: AccountOverviewFormViewModel(account: account, details: details), details: details)
NameOverview(details: details)
.environment(AccountOverviewFormViewModel(account: account, details: details))
}
}
.previewWith {
Expand Down
Loading
Loading