generated from StanfordBDHG/SwiftPackageTemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Customizable Area to AccountOverview (#27)
<!-- This source file is part of the Stanford Spezi open-source project SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) SPDX-License-Identifier: MIT --> # Add Customizable Area to AccountOverview ## ♻️ Current situation & Problem Like described in issue #25, some applications like the Spezi Template application could display some additional information such as licensing information or other settings at the bottom of the Account Overview. Furthermore, some developers might want to do it the other way around and link to account information within a settings page. ## 💡 Proposed Solution Add footer components to AccountOverview, as suggested by @PSchmiedmayer Implement an additional "AccountHeader" that looks something like the one in the Apple Settings app, as suggested by @Supereg ## ⚙️ Release Notes This PR adds two major things. 1. A customizable content section ViewBuilder to the `AccountOverview`. Simply pass any view as a trailing closure of AccountOverview and it will be rendered as a Section right between the other AccountOverview information and the log out button. Here is an example: ``` AccountOverview() { NavigationLink { // ... } label: { Text("General Settings") } NavigationLink { // ... } label: { Text("License Information") } } ``` <img width="255" alt="Screenshot 2023-09-27 at 17 30 04" src="https://github.com/StanfordSpezi/SpeziAccount/assets/33159293/6a34258a-0f0d-4c73-85bb-8a6311bc1828"> 2. A `AccountHeader`, similar to the one of the iOS Settings App, that could be used as a button that brings a user to the `AccountOverview`. Here is an example: ``` Section { NavigationLink { AccountOverview() } label: { AccountHeader(details: details) } } ``` <img width="251" alt="Screenshot 2023-09-27 at 17 29 33" src="https://github.com/StanfordSpezi/SpeziAccount/assets/33159293/e9d4f3aa-b5f2-4a62-9843-99e88ae77e1d"> ## 📚 Documentation *in progress* ## ✅ Testing UI tests for the customizable content section have been written. ## 📝 Code of Conduct & Contributing Guidelines By submitting creating this pull request, you agree to follow our [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md): - [x] I agree to follow the [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md). --------- Co-authored-by: Paul Schmiedmayer <[email protected]>
- Loading branch information
1 parent
5937ed6
commit 1eca293
Showing
11 changed files
with
274 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import SpeziViews | ||
import SwiftUI | ||
|
||
|
||
/// A summary view for ``SpeziAccountOverview`` that can be used as a Button to link to ``SpeziAccountOverview``. | ||
/// | ||
/// Below is a short code example on how to use the `AccountHeader` view. | ||
/// | ||
/// ```swift | ||
/// struct MyView: View { | ||
/// var body: some View { | ||
/// NavigationStack { | ||
/// Form { | ||
/// Section { | ||
/// NavigationLink { | ||
/// AccountOverview() | ||
/// } label: { | ||
/// AccountHeader(details: details) | ||
/// } | ||
/// } | ||
/// } | ||
/// } | ||
/// } | ||
/// } | ||
/// ``` | ||
public struct AccountHeader: View { | ||
/// Default values for the ``AccountHeader`` view. | ||
@_documentation(visibility: internal) | ||
public enum Defaults { | ||
/// Default caption. | ||
@_documentation(visibility: internal) | ||
public static let caption = LocalizedStringResource("ACCOUNT_HEADER_CAPTION", bundle: .atURL(from: .module)) // swiftlint:disable:this attributes | ||
} | ||
|
||
@EnvironmentObject private var account: Account | ||
private var caption: LocalizedStringResource | ||
|
||
public var body: some View { | ||
let accountDetails = account.details | ||
|
||
HStack { | ||
UserProfileView(name: accountDetails?.name ?? PersonNameComponents(givenName: "Placeholder", familyName: "Placeholder")) | ||
.frame(height: 60) | ||
.redacted(reason: account.details == nil ? .placeholder : []) | ||
.accessibilityHidden(true) | ||
VStack(alignment: .leading) { | ||
Text(accountDetails?.name?.formatted() ?? "Placeholder") | ||
.font(.title2) | ||
.fontWeight(.semibold) | ||
.redacted(reason: account.details == nil ? .placeholder : []) | ||
Text(caption) | ||
.font(.caption) | ||
} | ||
} | ||
} | ||
|
||
/// Display a new Account Header. | ||
/// - Parameter caption: A descriptive text displayed under the account name giving the user a brief explanation of what to expect when they interact with the header. | ||
public init(caption: LocalizedStringResource = Defaults.caption) { | ||
self.caption = caption | ||
} | ||
} | ||
|
||
|
||
#if DEBUG | ||
#Preview { | ||
let details = AccountDetails.Builder() | ||
.set(\.userId, value: "[email protected]") | ||
.set(\.name, value: PersonNameComponents(givenName: "Andreas", familyName: "Bauer")) | ||
|
||
return AccountHeader() | ||
.environmentObject(Account(building: details, active: MockUserIdPasswordAccountService())) | ||
} | ||
|
||
#Preview { | ||
AccountHeader(caption: "Email, Password, Preferences") | ||
.environmentObject(Account(MockUserIdPasswordAccountService())) | ||
} | ||
|
||
#Preview { | ||
let details = AccountDetails.Builder() | ||
.set(\.userId, value: "[email protected]") | ||
.set(\.name, value: PersonNameComponents(givenName: "Andreas", familyName: "Bauer")) | ||
|
||
return NavigationStack { | ||
Form { | ||
Section { | ||
NavigationLink { | ||
AccountOverview() | ||
} label: { | ||
AccountHeader() | ||
} | ||
} | ||
} | ||
} | ||
.environmentObject(Account(building: details, active: MockUserIdPasswordAccountService())) | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,16 +33,35 @@ import SwiftUI | |
/// AccountOverview() | ||
/// } | ||
/// } | ||
/// ``` | ||
/// | ||
/// Optionally, additional sections can be passed to AccountOverview within the trailing closure, providing the opportunity for customization and extension of the view." | ||
/// Below is a short code example. | ||
/// | ||
/// ```swift | ||
/// struct MyView: View { | ||
/// var body: some View { | ||
/// AccountOverview { | ||
/// NavigationLink { | ||
/// // ... next view | ||
/// } label: { | ||
/// Text("General Settings") | ||
/// } | ||
/// } | ||
/// } | ||
/// } | ||
/// ``` | ||
/// | ||
/// - Note: The ``init(isEditing:)`` initializer allows to pass an optional `Bool` Binding to retrieve the | ||
/// current edit mode of the view. This can be helpful to, e.g., render a custom `Close` Button if the | ||
/// view is not editing when presenting the AccountOverview in a sheet. | ||
/// ``` | ||
public struct AccountOverview: View { | ||
public struct AccountOverview<AdditionalSections: View>: View { | ||
@EnvironmentObject private var account: Account | ||
|
||
@Binding private var isEditing: Bool | ||
|
||
|
||
let additionalSections: AdditionalSections | ||
|
||
public var body: some View { | ||
VStack { | ||
if let details = account.details { | ||
|
@@ -53,7 +72,9 @@ public struct AccountOverview: View { | |
account: account, | ||
details: details, | ||
isEditing: $isEditing | ||
) | ||
) { | ||
additionalSections | ||
} | ||
} | ||
.padding(.top, -20) | ||
} else { | ||
|
@@ -68,12 +89,15 @@ public struct AccountOverview: View { | |
.navigationTitle(Text("ACCOUNT_OVERVIEW", bundle: .module)) | ||
.navigationBarTitleDisplayMode(.inline) | ||
} | ||
|
||
|
||
/// Display a new Account Overview. | ||
/// - Parameter isEditing: A Binding that allows you to read the current editing state of the Account Overview view. | ||
public init(isEditing: Binding<Bool> = .constant(false)) { | ||
/// - Parameters: | ||
/// - isEditing: A Binding that allows you to read the current editing state of the Account Overview view. | ||
/// - additionalSections: Optional additional sections displayed between the other AccountOverview information and the log out button. | ||
public init(isEditing: Binding<Bool> = .constant(false), @ViewBuilder additionalSections: () -> AdditionalSections = { EmptyView() }) { | ||
self._isEditing = isEditing | ||
self.additionalSections = additionalSections() | ||
} | ||
} | ||
|
||
|
@@ -84,13 +108,26 @@ struct AccountOverView_Previews: PreviewProvider { | |
.set(\.userId, value: "[email protected]") | ||
.set(\.name, value: PersonNameComponents(givenName: "Andreas", familyName: "Bauer")) | ||
.set(\.genderIdentity, value: .male) | ||
|
||
static var previews: some View { | ||
NavigationStack { | ||
AccountOverview() | ||
AccountOverview { | ||
NavigationLink { | ||
Text("") | ||
.navigationTitle(Text("Settings")) | ||
} label: { | ||
Text("General Settings") | ||
} | ||
NavigationLink { | ||
Text("") | ||
.navigationTitle(Text("Package Dependencies")) | ||
} label: { | ||
Text("License Information") | ||
} | ||
} | ||
} | ||
.environmentObject(Account(building: details, active: MockUserIdPasswordAccountService())) | ||
|
||
NavigationStack { | ||
AccountOverview() | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.