diff --git a/Sources/Bedrock/Views/Settings/LicensesView.swift b/Sources/Bedrock/Views/Settings/LicensesView.swift new file mode 100644 index 0000000..ed6faab --- /dev/null +++ b/Sources/Bedrock/Views/Settings/LicensesView.swift @@ -0,0 +1,105 @@ +// +// LicensesView.swift +// Bedrock +// +// Created by Matt Bruce on 1/4/26. +// + +import SwiftUI + +// MARK: - License Model + +/// Represents an open source license for a third-party library +public struct License: Identifiable, Sendable { + public let id: String + public let name: String + public let url: String + public let licenseType: String + public let description: String + + public init( + name: String, + url: String, + licenseType: String, + description: String + ) { + self.id = name + self.name = name + self.url = url + self.licenseType = licenseType + self.description = description + } +} + +// MARK: - Licenses View + +/// A reusable view for displaying open source licenses +public struct LicensesView: View { + public let licenses: [License] + public let backgroundColor: Color + public let cardBackgroundColor: Color + public let cardBorderColor: Color + public let accentColor: Color + public let navigationTitle: String + + public init( + licenses: [License], + backgroundColor: Color = .Surface.overlay, + cardBackgroundColor: Color = .Surface.card, + cardBorderColor: Color = .Border.subtle, + accentColor: Color = .Accent.primary, + navigationTitle: String = String(localized: "Open Source Licenses") + ) { + self.licenses = licenses + self.backgroundColor = backgroundColor + self.cardBackgroundColor = cardBackgroundColor + self.cardBorderColor = cardBorderColor + self.accentColor = accentColor + self.navigationTitle = navigationTitle + } + + public var body: some View { + ScrollView { + VStack(alignment: .leading, spacing: Design.Spacing.large) { + ForEach(licenses) { license in + licenseCard(license) + } + } + .padding(Design.Spacing.large) + } + .background(backgroundColor) + .navigationTitle(navigationTitle) + .navigationBarTitleDisplayMode(.inline) + } + + private func licenseCard(_ license: License) -> some View { + SettingsCard(backgroundColor: cardBackgroundColor, borderColor: cardBorderColor) { + VStack(alignment: .leading, spacing: Design.Spacing.small) { + Text(license.name) + .font(.system(size: Design.BaseFontSize.medium, weight: .bold)) + .foregroundStyle(.white) + + Text(license.description) + .font(.system(size: Design.BaseFontSize.caption)) + .foregroundStyle(.white.opacity(Design.Opacity.strong)) + + HStack { + Label(license.licenseType, systemImage: "doc.text") + .font(.system(size: Design.BaseFontSize.xSmall)) + .foregroundStyle(accentColor) + + Spacer() + + if let linkURL = URL(string: license.url) { + Link(destination: linkURL) { + Label(String(localized: "View on GitHub"), systemImage: "arrow.up.right.square") + .font(.system(size: Design.BaseFontSize.xSmall)) + .foregroundStyle(accentColor) + } + } + } + .padding(.top, Design.Spacing.xSmall) + } + } + } +} diff --git a/Sources/Bedrock/Views/Settings/SETTINGS_GUIDE.md b/Sources/Bedrock/Views/Settings/SETTINGS_GUIDE.md index 83106f3..68e401f 100644 --- a/Sources/Bedrock/Views/Settings/SETTINGS_GUIDE.md +++ b/Sources/Bedrock/Views/Settings/SETTINGS_GUIDE.md @@ -489,6 +489,63 @@ SettingsNavigationRow( --- +### LicensesView + +A reusable view for displaying open source licenses used in your app. + +**Step 1: Define licenses in your app** + +```swift +import Bedrock + +extension License { + static let appLicenses: [License] = [ + License( + name: "MijickCamera", + url: "https://github.com/Mijick/Camera", + licenseType: "Apache 2.0 License", + description: "Camera framework for SwiftUI." + ), + License( + name: "RevenueCat", + url: "https://github.com/RevenueCat/purchases-ios", + licenseType: "MIT License", + description: "In-app subscriptions made easy." + ) + ] +} +``` + +**Step 2: Create app-specific wrapper view** + +```swift +struct AppLicensesView: View { + var body: some View { + LicensesView( + licenses: License.appLicenses, + backgroundColor: AppSurface.overlay, + cardBackgroundColor: AppSurface.card, + cardBorderColor: AppBorder.subtle, + accentColor: AppAccent.primary + ) + } +} +``` + +**Step 3: Navigate to it from settings** + +```swift +SettingsNavigationRow( + title: "Open Source Licenses", + subtitle: "Third-party libraries used in this app", + backgroundColor: .clear +) { + AppLicensesView() +} +``` + +--- + ### SettingsSegmentedPicker A segmented picker with title, subtitle, and optional accessory (follows the same pattern as `SettingsToggle` and `SettingsSlider`). @@ -825,6 +882,7 @@ SettingsCard(backgroundColor: AppSurface.card, borderColor: AppBorder.subtle) { | `SelectableRow` | Card selection | `title`, `isSelected`, `badge` | | `BadgePill` | Price/tag badges | `text`, `isSelected` | | `iCloudSyncSettingsView` | iCloud sync controls | `viewModel: CloudSyncable`, colors | +| `LicensesView` | Open source licenses | `licenses: [License]`, colors | ---