From 489318b2201274f6ad7c2ab2b338b57a1bebd38f Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 2 Jan 2026 16:18:07 -0600 Subject: [PATCH] Add Open Source Licenses section in Settings Apache 2.0 license requires attribution for MijickCamera. Added: - 'About' section in Settings with 'Open Source Licenses' link - LicensesView showing all third-party libraries: - MijickCamera (Apache 2.0) - RevenueCat (MIT) - Links to GitHub repositories - License type badges This fulfills the attribution requirement for Apache 2.0 licensed libraries used in the app. --- .../Features/Settings/SettingsView.swift | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/SelfieRingLight/Features/Settings/SettingsView.swift b/SelfieRingLight/Features/Settings/SettingsView.swift index 0dc2c3a..5124a3a 100644 --- a/SelfieRingLight/Features/Settings/SettingsView.swift +++ b/SelfieRingLight/Features/Settings/SettingsView.swift @@ -85,6 +85,12 @@ struct SettingsView: View { iCloudSyncSection + // MARK: - About Section + + SettingsSectionHeader(title: "About", systemImage: "info.circle") + + acknowledgmentsSection + Spacer(minLength: Design.Spacing.xxxLarge) } .padding(.horizontal, Design.Spacing.large) @@ -323,6 +329,98 @@ struct SettingsView: View { ? String(localized: "Synced") : viewModel.syncStatus } + + // MARK: - Acknowledgments Section + + private var acknowledgmentsSection: some View { + VStack(alignment: .leading, spacing: Design.Spacing.small) { + NavigationLink { + LicensesView() + } label: { + HStack { + VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) { + Text(String(localized: "Open Source Licenses")) + .font(.system(size: Design.BaseFontSize.body, weight: .medium)) + .foregroundStyle(.white) + + Text(String(localized: "Third-party libraries used in this app")) + .font(.system(size: Design.BaseFontSize.caption)) + .foregroundStyle(.white.opacity(Design.Opacity.medium)) + } + + Spacer() + + Image(systemName: "chevron.right") + .font(.system(size: Design.BaseFontSize.caption)) + .foregroundStyle(.white.opacity(Design.Opacity.medium)) + } + .padding(Design.Spacing.medium) + .background(Color.Surface.primary, in: RoundedRectangle(cornerRadius: Design.CornerRadius.medium)) + } + .buttonStyle(.plain) + } + } +} + +// MARK: - Licenses View + +struct LicensesView: View { + var body: some View { + ScrollView { + VStack(alignment: .leading, spacing: Design.Spacing.large) { + // MijickCamera + licenseCard( + name: "MijickCamera", + url: "https://github.com/Mijick/Camera", + license: "Apache License 2.0", + description: "Camera made simple. The ultimate camera library that significantly reduces implementation time and effort." + ) + + // RevenueCat + licenseCard( + name: "RevenueCat", + url: "https://github.com/RevenueCat/purchases-ios", + license: "MIT License", + description: "In-app subscriptions made easy." + ) + } + .padding(Design.Spacing.large) + } + .background(Color.Surface.overlay) + .navigationTitle(String(localized: "Open Source Licenses")) + .navigationBarTitleDisplayMode(.inline) + } + + private func licenseCard(name: String, url: String, license: String, description: String) -> some View { + VStack(alignment: .leading, spacing: Design.Spacing.small) { + Text(name) + .font(.system(size: Design.BaseFontSize.medium, weight: .bold)) + .foregroundStyle(.white) + + Text(description) + .font(.system(size: Design.BaseFontSize.caption)) + .foregroundStyle(.white.opacity(Design.Opacity.strong)) + + HStack { + Label(license, systemImage: "doc.text") + .font(.system(size: Design.BaseFontSize.xSmall)) + .foregroundStyle(Color.Accent.primary) + + Spacer() + + if let linkURL = URL(string: url) { + Link(destination: linkURL) { + Label(String(localized: "View on GitHub"), systemImage: "arrow.up.right.square") + .font(.system(size: Design.BaseFontSize.xSmall)) + .foregroundStyle(Color.Accent.primary) + } + } + } + .padding(.top, Design.Spacing.xSmall) + } + .padding(Design.Spacing.medium) + .background(Color.Surface.primary, in: RoundedRectangle(cornerRadius: Design.CornerRadius.medium)) + } } // MARK: - Color Preset Button