Add support for macOS and backport to older OS versions

This commit is contained in:
2026-09-03 20:06:59 +03:00
parent abf7cf2e83
commit deef01a58a
13 changed files with 123 additions and 39 deletions
+35 -7
View File
@@ -6,7 +6,7 @@ struct ContentView: View {
@State private var showCurrencyPicker = false
var body: some View {
NavigationView {
NavigationStack {
Group {
if let state = viewModel.state {
form(for: state)
@@ -121,13 +121,18 @@ struct ContentView: View {
onChange: { viewModel.onFiatAmountChanged(code: row.code, value: $0) }
)
}
#if os(iOS)
.onDelete { indexSet in
for index in indexSet {
viewModel.onFiatCurrencyToggled(state.fiatRows[index].code)
}
}
#endif
}
}
#if os(macOS)
.formStyle(.grouped)
#endif
.sheet(isPresented: $showCurrencyPicker) {
CurrencyPickerSheet(
currencies: state.availableCurrencies,
@@ -142,7 +147,7 @@ struct ContentView: View {
private func amountRow(
label: String,
value: String,
keyboardType: UIKeyboardType,
keyboardType: NumericFieldKeyboard,
sanitize: @escaping (String) -> String,
onChange: @escaping (String) -> Void
) -> some View {
@@ -150,7 +155,7 @@ struct ContentView: View {
Text(label)
Spacer()
NumericField(
placeholder: label,
placeholder: "",
value: value,
keyboardType: keyboardType,
sanitize: sanitize,
@@ -170,7 +175,7 @@ struct ContentView: View {
private struct NumericField: View {
let placeholder: String
let value: String
let keyboardType: UIKeyboardType
let keyboardType: NumericFieldKeyboard
let sanitize: (String) -> String
let onChange: (String) -> Void
var alignment: TextAlignment = .leading
@@ -179,10 +184,15 @@ private struct NumericField: View {
var body: some View {
TextField(placeholder, text: $text)
.keyboardType(keyboardType)
#if os(iOS)
.keyboardType(keyboardType.uiKeyboardType)
#endif
.multilineTextAlignment(alignment)
#if os(macOS)
.frame(maxWidth: 140)
#endif
.onAppear { text = value }
.onChange(of: text) { _, newValue in
.onChange(of: text) { newValue in
let sanitized = sanitize(newValue)
if sanitized != newValue {
text = sanitized
@@ -191,7 +201,7 @@ private struct NumericField: View {
onChange(sanitized)
}
}
.onChange(of: value) { _, newValue in
.onChange(of: value) { newValue in
if newValue != text {
text = newValue
}
@@ -216,3 +226,21 @@ private func sanitizeDecimalInput(_ raw: String) -> String {
private func sanitizeIntegerInput(_ raw: String) -> String {
raw.filter { $0.isNumber }
}
/// `UIKeyboardType` doesn't exist on macOS (no on-screen keyboard), so this stands in for it
/// across both platforms; only iOS actually applies it, via `uiKeyboardType` below.
private enum NumericFieldKeyboard {
case decimalPad
case numberPad
}
#if os(iOS)
private extension NumericFieldKeyboard {
var uiKeyboardType: UIKeyboardType {
switch self {
case .decimalPad: return .decimalPad
case .numberPad: return .numberPad
}
}
}
#endif
+9 -1
View File
@@ -10,7 +10,7 @@ struct CurrencyPickerSheet: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationView {
NavigationStack {
List(currencies, id: \.code) { info in
Button {
onToggle(info.code)
@@ -27,13 +27,21 @@ struct CurrencyPickerSheet: View {
}
}
.navigationTitle(IosLocalizationKt.localizedString(resource: MR.strings.shared.currencies_section_title))
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button(IosLocalizationKt.localizedString(resource: MR.strings.shared.done)) { dismiss() }
}
}
}
#if os(macOS)
// macOS sizes a .sheet() to its content's ideal size rather than the parent window's
// size (unlike iOS, which presents modally full-size); without an explicit frame here,
// the List has no size to lay out rows in and renders empty.
.frame(minWidth: 420, minHeight: 480)
#endif
}
private func currencyLabel(for info: CurrencyInfo) -> String {
+3
View File
@@ -5,6 +5,9 @@ struct iOSApp: App {
var body: some Scene {
WindowGroup {
ContentView()
#if os(macOS)
.frame(minWidth: 420, minHeight: 500)
#endif
}
}
}
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>