mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +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
|
||||
|
||||
/// Send screen, rebuilt on native SwiftUI. A grouped `List` of outgoing transfers,
|
||||
/// with the composer and detail panels as native sheets and delete as an alert.
|
||||
@@ -31,7 +32,7 @@ struct SendScreen: View {
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: model.openComposer) {
|
||||
Label(String(localized: L10n.Button.createNewTransfer), systemImage: "plus")
|
||||
Label(String(localized: L10n.Button.createNewTransfer), systemSymbol: .plus)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,12 +102,12 @@ struct SendScreen: View {
|
||||
|
||||
private var emptyState: some View {
|
||||
ContentUnavailableView {
|
||||
Label(String(localized: L10n.Send.emptyTitle), systemImage: "paperplane")
|
||||
Label(String(localized: L10n.Send.emptyTitle), systemSymbol: .paperplane)
|
||||
} description: {
|
||||
Text(String(localized: L10n.Send.emptyBody))
|
||||
} actions: {
|
||||
Button(action: model.openComposer) {
|
||||
Label(String(localized: L10n.Button.createNewTransfer), systemImage: "plus")
|
||||
Label(String(localized: L10n.Button.createNewTransfer), systemSymbol: .plus)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.controlSize(.large)
|
||||
@@ -166,7 +167,7 @@ private struct TransferListItem: View {
|
||||
.padding(.top, 2)
|
||||
}
|
||||
}
|
||||
Image(systemName: "chevron.forward")
|
||||
Image(systemSymbol: .chevronForward)
|
||||
.font(.footnote.weight(.semibold)).foregroundStyle(.tertiary)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
@@ -181,7 +182,7 @@ struct FileArtwork: View {
|
||||
image.resizable().aspectRatio(contentMode: .fill)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
} else {
|
||||
Image(systemName: "doc")
|
||||
Image(systemSymbol: .doc)
|
||||
.font(.system(size: 18))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import SwiftUI
|
||||
import SFSafeSymbols
|
||||
|
||||
/// Transfer composer drawer, ported from `feature/send/TransferComposer.kt`.
|
||||
/// Two steps: choose files/folder, then review + name + access policy + share.
|
||||
@@ -27,7 +28,7 @@ struct TransferComposer: View {
|
||||
Text(String(localized: L10n.Send.chooseFileBody))
|
||||
.font(.subheadline).foregroundStyle(.secondary)
|
||||
VStack(spacing: 14) {
|
||||
Image(systemName: "doc").font(.system(size: 30)).foregroundStyle(.tint)
|
||||
Image(systemSymbol: .doc).font(.system(size: 30)).foregroundStyle(.tint)
|
||||
PrimaryButton(title: String(localized: L10n.Button.chooseFiles), action: model.selectFile).fixedSize()
|
||||
QuietButton(title: String(localized: L10n.Button.chooseFolder), action: model.selectFolder)
|
||||
}
|
||||
@@ -57,17 +58,17 @@ struct TransferComposer: View {
|
||||
value: Binding(get: { state.senderName }, set: { model.setSenderName($0) }))
|
||||
Text(String(localized: L10n.Send.accessTitle)).font(.headline)
|
||||
PolicyOption(
|
||||
icon: "checkmark.shield", titleKey: L10n.Send.accessApproval, descKey: L10n.Send.accessApprovalDescription,
|
||||
icon: .checkmarkShield, titleKey: L10n.Send.accessApproval, descKey: L10n.Send.accessApprovalDescription,
|
||||
selected: state.accessPolicy == .requireApproval,
|
||||
onTap: { model.setAccessPolicy(.requireApproval) }
|
||||
)
|
||||
PolicyOption(
|
||||
icon: "globe", titleKey: L10n.Send.accessAnyone, descKey: L10n.Send.accessAnyoneDescription,
|
||||
icon: .globe, titleKey: L10n.Send.accessAnyone, descKey: L10n.Send.accessAnyoneDescription,
|
||||
selected: state.accessPolicy == .anyoneWithTransfer,
|
||||
onTap: { model.setAccessPolicy(.anyoneWithTransfer) }
|
||||
)
|
||||
if state.accessPolicy == .anyoneWithTransfer {
|
||||
Label(String(localized: L10n.Send.accessAnyoneWarning), systemImage: "exclamationmark.triangle.fill")
|
||||
Label(String(localized: L10n.Send.accessAnyoneWarning), systemSymbol: .exclamationmarkTriangleFill)
|
||||
.font(.caption).foregroundStyle(.orange)
|
||||
}
|
||||
actions
|
||||
@@ -116,7 +117,7 @@ private struct SelectedFileCard: View {
|
||||
Spacer()
|
||||
if canRemove {
|
||||
Button(role: .destructive, action: onRemove) {
|
||||
Image(systemName: "trash")
|
||||
Image(systemSymbol: .trash)
|
||||
}
|
||||
.buttonStyle(.borderless)
|
||||
.tint(.red)
|
||||
@@ -135,7 +136,7 @@ private struct SelectedFileCard: View {
|
||||
}
|
||||
|
||||
private struct PolicyOption: View {
|
||||
let icon: String
|
||||
let icon: SFSymbol
|
||||
let titleKey: String.LocalizationValue
|
||||
let descKey: String.LocalizationValue
|
||||
let selected: Bool
|
||||
@@ -144,7 +145,7 @@ private struct PolicyOption: View {
|
||||
var body: some View {
|
||||
Button(action: onTap) {
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: icon)
|
||||
Image(systemSymbol: icon)
|
||||
.font(.system(size: 20))
|
||||
.foregroundStyle(selected ? AnyShapeStyle(.tint) : AnyShapeStyle(.secondary))
|
||||
.frame(width: 22)
|
||||
@@ -153,7 +154,7 @@ private struct PolicyOption: View {
|
||||
Text(String(localized: descKey)).font(.caption).foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: selected ? "checkmark.circle.fill" : "circle")
|
||||
Image(systemSymbol: selected ? .checkmarkCircleFill : .circle)
|
||||
.foregroundStyle(selected ? AnyShapeStyle(.tint) : AnyShapeStyle(.tertiary))
|
||||
}
|
||||
.padding(14)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import SwiftUI
|
||||
import SFSafeSymbols
|
||||
import CoreImage.CIFilterBuiltins
|
||||
|
||||
/// Transfer details + drawer panels, ported from `feature/send/TransferDetails.kt`.
|
||||
@@ -56,7 +57,7 @@ struct TransferDetailsView: View {
|
||||
Button(role: .destructive) {
|
||||
showStopConfirmation = true
|
||||
} label: {
|
||||
Label(String(localized: L10n.Send.stopSharing), systemImage: "stop.circle")
|
||||
Label(String(localized: L10n.Send.stopSharing), systemSymbol: .stopCircle)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +70,7 @@ struct TransferDetailsView: View {
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(role: .destructive, action: model.requestDeleteTransfer) {
|
||||
Image(systemName: "trash")
|
||||
Image(systemSymbol: .trash)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +116,7 @@ private struct DetailDestination: View {
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
Image(systemName: "chevron.forward")
|
||||
Image(systemSymbol: .chevronForward)
|
||||
.font(.footnote.weight(.semibold)).foregroundStyle(.tertiary)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
|
||||
Reference in New Issue
Block a user