mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 02:29:55 +02:00
feat(apple): type-safe SF Symbols via SFSafeSymbols
Replaces every stringly-typed SF Symbol name with a compile-time-checked SFSymbol case, mirroring the L10n accessor approach. A mistyped or OS-unavailable symbol is now a build error instead of a silently blank glyph at runtime. Adds the SFSafeSymbols SPM package (project.yml) and migrates all call sites: Image(systemName:)/Label(systemImage:) -> systemSymbol, and the five symbol-carrying view properties (AppDestination.systemSymbol, SettingsRow.icon, AboutPoint.symbol, MethodRow.icon, PolicyOption.icon) flipped from String to SFSymbol end to end.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import SwiftUI
|
||||
import SFSafeSymbols
|
||||
|
||||
/// Settings screen, rebuilt on a native `Form` with `NavigationStack` push
|
||||
/// navigation. The model stays the source of truth via a derived path binding.
|
||||
@@ -25,21 +26,21 @@ struct SettingsScreen: View {
|
||||
Form {
|
||||
Section {
|
||||
NavigationLink(value: SettingsSection.preferences) {
|
||||
SettingsRow(icon: "person.crop.circle", title: String(localized: L10n.Preferences.title), value: model.state.username)
|
||||
SettingsRow(icon: .personCropCircle, title: String(localized: L10n.Preferences.title), value: model.state.username)
|
||||
}
|
||||
NavigationLink(value: SettingsSection.appearance) {
|
||||
SettingsRow(icon: "sun.max", title: String(localized: L10n.Appearance.title), value: themeModeLabel(model.state.themeMode))
|
||||
SettingsRow(icon: .sunMax, title: String(localized: L10n.Appearance.title), value: themeModeLabel(model.state.themeMode))
|
||||
}
|
||||
}
|
||||
Section {
|
||||
NavigationLink(value: SettingsSection.notifications) {
|
||||
SettingsRow(icon: "bell", title: String(localized: L10n.Notifications.title), value: nil)
|
||||
SettingsRow(icon: .bell, title: String(localized: L10n.Notifications.title), value: nil)
|
||||
}
|
||||
NavigationLink(value: SettingsSection.storage) {
|
||||
SettingsRow(icon: "internaldrive", title: String(localized: L10n.Storage.title), value: nil)
|
||||
SettingsRow(icon: .internaldrive, title: String(localized: L10n.Storage.title), value: nil)
|
||||
}
|
||||
NavigationLink(value: SettingsSection.about) {
|
||||
SettingsRow(icon: "info.circle", title: String(localized: L10n.About.title), value: nil)
|
||||
SettingsRow(icon: .infoCircle, title: String(localized: L10n.About.title), value: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +70,7 @@ struct SettingsScreen: View {
|
||||
Button {
|
||||
showBugReport = true
|
||||
} label: {
|
||||
Label(String(localized: L10n.About.bugReport), systemImage: "ladybug")
|
||||
Label(String(localized: L10n.About.bugReport), systemSymbol: .ladybug)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,13 +111,13 @@ private struct SettingsSectionContent: View {
|
||||
}
|
||||
|
||||
struct SettingsRow: View {
|
||||
let icon: String
|
||||
let icon: SFSymbol
|
||||
let title: String
|
||||
let value: String?
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: icon)
|
||||
Image(systemSymbol: icon)
|
||||
.foregroundStyle(.tint)
|
||||
.frame(width: 26)
|
||||
Text(title).foregroundStyle(.primary)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import SwiftUI
|
||||
import SFSafeSymbols
|
||||
|
||||
/// Settings section detail views, rebuilt as native `Form` content. Each view is
|
||||
/// placed inside a parent `Form`, so it returns `Section`s / rows directly.
|
||||
@@ -126,24 +127,24 @@ struct AboutSettings: View {
|
||||
}
|
||||
|
||||
Section(String(localized: L10n.About.isTitle)) {
|
||||
AboutPoint(L10n.About.isDirect, "paperplane")
|
||||
AboutPoint(L10n.About.isNoAccount, "person.crop.circle.badge.xmark")
|
||||
AboutPoint(L10n.About.isInControl, "checkmark.shield")
|
||||
AboutPoint(L10n.About.isEncrypted, "lock")
|
||||
AboutPoint(L10n.About.isOpen, "chevron.left.forwardslash.chevron.right")
|
||||
AboutPoint(L10n.About.isDirect, .paperplane)
|
||||
AboutPoint(L10n.About.isNoAccount, .personCropCircleBadgeXmark)
|
||||
AboutPoint(L10n.About.isInControl, .checkmarkShield)
|
||||
AboutPoint(L10n.About.isEncrypted, .lock)
|
||||
AboutPoint(L10n.About.isOpen, .chevronLeftForwardslashChevronRight)
|
||||
}
|
||||
|
||||
Section(String(localized: L10n.About.isntTitle)) {
|
||||
AboutPoint(L10n.About.isntCloud, "icloud.slash")
|
||||
AboutPoint(L10n.About.isntSync, "arrow.triangle.2.circlepath")
|
||||
AboutPoint(L10n.About.isntPublic, "megaphone")
|
||||
AboutPoint(L10n.About.isntCloud, .icloudSlash)
|
||||
AboutPoint(L10n.About.isntSync, .arrowTriangle2Circlepath)
|
||||
AboutPoint(L10n.About.isntPublic, .megaphone)
|
||||
}
|
||||
|
||||
Section(String(localized: L10n.About.privacyTitle)) {
|
||||
AboutPoint(L10n.About.privacyCapability, "qrcode")
|
||||
AboutPoint(L10n.About.privacyDeny, "hand.raised")
|
||||
AboutPoint(L10n.About.privacyRelay, "antenna.radiowaves.left.and.right")
|
||||
AboutPoint(L10n.About.privacyLocal, "internaldrive")
|
||||
AboutPoint(L10n.About.privacyCapability, .qrcode)
|
||||
AboutPoint(L10n.About.privacyDeny, .handRaised)
|
||||
AboutPoint(L10n.About.privacyRelay, .antennaRadiowavesLeftAndRight)
|
||||
AboutPoint(L10n.About.privacyLocal, .internaldrive)
|
||||
}
|
||||
|
||||
Section(String(localized: L10n.About.title)) {
|
||||
@@ -154,7 +155,7 @@ struct AboutSettings: View {
|
||||
}
|
||||
LabeledContent(String(localized: L10n.About.licenseLabel), value: "Apache 2.0")
|
||||
Link(destination: Self.privacyPolicyURL) {
|
||||
Label(String(localized: L10n.About.privacyPolicyLabel), systemImage: "hand.raised")
|
||||
Label(String(localized: L10n.About.privacyPolicyLabel), systemSymbol: .handRaised)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,9 +206,9 @@ struct BugReportSheet: View {
|
||||
/// A bullet-style informational row with an SF Symbol and wrapping localized text.
|
||||
private struct AboutPoint: View {
|
||||
let key: String.LocalizationValue
|
||||
let symbol: String
|
||||
let symbol: SFSymbol
|
||||
|
||||
init(_ key: String.LocalizationValue, _ symbol: String) {
|
||||
init(_ key: String.LocalizationValue, _ symbol: SFSymbol) {
|
||||
self.key = key
|
||||
self.symbol = symbol
|
||||
}
|
||||
@@ -218,7 +219,7 @@ private struct AboutPoint: View {
|
||||
.font(.subheadline)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
} icon: {
|
||||
Image(systemName: symbol).foregroundStyle(.tint)
|
||||
Image(systemSymbol: symbol).foregroundStyle(.tint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user