Skip to content

Commit f635983

Browse files
committed
Address some PR comments
Update some doc comments
1 parent abac684 commit f635983

File tree

11 files changed

+87
-68
lines changed

11 files changed

+87
-68
lines changed

Examples/Sources/DatePickerExample/DatePickerApp.swift

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,40 +12,25 @@ struct DatePickerApp: App {
1212
@State var date = Date()
1313
@State var style: DatePickerStyle? = .automatic
1414

15-
var allStyles: [DatePickerStyle]
16-
17-
init() {
18-
allStyles = [.automatic]
19-
20-
if #available(iOS 14, macCatalyst 14, *) {
21-
allStyles.append(.graphical)
22-
}
23-
24-
#if !canImport(GtkBackend)
25-
if #available(iOS 13.4, macCatalyst 13.4, *) {
26-
allStyles.append(.compact)
27-
#if os(iOS) || os(visionOS) || canImport(WinUIBackend)
28-
allStyles.append(.wheel)
29-
#endif
30-
}
31-
#endif
32-
}
15+
@Environment(\.supportedDatePickerStyles) var allStyles: [DatePickerStyle]
3316

3417
var body: some Scene {
3518
WindowGroup("Date Picker") {
36-
VStack {
37-
Text("Selected date: \(date)")
19+
#hotReloadable {
20+
VStack {
21+
Text("Selected date: \(date)")
3822

39-
Picker(of: allStyles, selection: $style)
23+
Picker(of: allStyles, selection: $style)
4024

41-
DatePicker(
42-
"Test Picker",
43-
selection: $date
44-
)
45-
.datePickerStyle(style ?? .automatic)
25+
DatePicker(
26+
"Test Picker",
27+
selection: $date
28+
)
29+
.datePickerStyle(style ?? .automatic)
4630

47-
Button("Reset date") {
48-
date = Date()
31+
Button("Reset date to now") {
32+
date = Date()
33+
}
4934
}
5035
}
5136
}

Sources/AppKitBackend/AppKitBackend.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public final class AppKitBackend: AppBackend {
2626
public let menuImplementationStyle = MenuImplementationStyle.dynamicPopover
2727
public let canRevealFiles = true
2828
public let deviceClass = DeviceClass.desktop
29+
public let supportedDatePickerStyles: [DatePickerStyle] = [.automatic, .graphical, .compact]
2930

3031
public var scrollBarWidth: Int {
3132
// We assume that all scrollers have their controlSize set to `.regular` by default.
@@ -1822,7 +1823,7 @@ public final class NSCustomSheet: NSCustomWindow, NSWindowDelegate {
18221823
// choice for the current calendar means the cursor position is reset after every keystroke. I
18231824
// know of no simple way to tell whether NSDatePicker requires or forbids eras for a given
18241825
// calendar, so in lieu of that I have hardcoded the calendar identifiers.
1825-
private let calendarsWithEras: Set<Calendar.Identifier> = [
1826+
private let calendarsRequiringEra: Set<Calendar.Identifier> = [
18261827
.buddhist, .coptic, .ethiopicAmeteAlem, .ethiopicAmeteMihret, .indian, .islamic,
18271828
.islamicCivil, .islamicTabular, .islamicUmmAlQura, .japanese, .persian, .republicOfChina,
18281829
]
@@ -1858,7 +1859,7 @@ public final class NSCustomSheet: NSCustomWindow, NSWindowDelegate {
18581859
var elementFlags: NSDatePicker.ElementFlags = []
18591860
if components.contains(.date) {
18601861
elementFlags.insert(.yearMonthDay)
1861-
if calendarsWithEras.contains(environment.calendar.identifier) {
1862+
if calendarsRequiringEra.contains(environment.calendar.identifier) {
18621863
elementFlags.insert(.era)
18631864
}
18641865
}

Sources/Gtk/Utility/GDateTime.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class GDateTime {
1313
self.pointer = pointer
1414
}
1515

16-
public convenience init?(unixEpoch: TimeInterval) {
16+
public convenience init?(unixEpoch: Int) {
1717
// g_date_time_new_from_unix_utc_usec appears to be too new
1818
self.init(g_date_time_new_from_unix_utc(gint64(unixEpoch)))
1919
}
@@ -41,7 +41,7 @@ public class GDateTime {
4141
}
4242

4343
public convenience init!(_ date: Date) {
44-
self.init(unixEpoch: date.timeIntervalSince1970)
44+
self.init(unixEpoch: Int(date.timeIntervalSince1970))
4545
}
4646

4747
deinit {

Sources/Gtk3Backend/Gtk3Backend.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public final class Gtk3Backend: AppBackend {
3838
public let menuImplementationStyle = MenuImplementationStyle.dynamicPopover
3939
public let canRevealFiles = true
4040
public let deviceClass = DeviceClass.desktop
41+
public let supportedDatePickerStyles: [DatePickerStyle] = []
4142

4243
var gtkApp: Application
4344

Sources/GtkBackend/GtkBackend.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public final class GtkBackend: AppBackend {
4343
public let canRevealFiles = true
4444
public let deviceClass = DeviceClass.desktop
4545
public let defaultSheetCornerRadius = 10
46+
public let supportedDatePickerStyles: [DatePickerStyle] = [.automatic, .graphical]
4647

4748
var gtkApp: Application
4849

@@ -1524,9 +1525,6 @@ public final class GtkBackend: AppBackend {
15241525
if components.contains(.hourAndMinute) {
15251526
print("Warning: time picker is unimplemented on GtkBackend")
15261527
}
1527-
if environment.datePickerStyle != .automatic && environment.datePickerStyle != .graphical {
1528-
print("Warning: only DatePickerStyle.graphical is implemented in GtkBackend")
1529-
}
15301528

15311529
let calendarWidget = datePicker as! Gtk.Calendar
15321530
calendarWidget.date = date
@@ -1772,7 +1770,7 @@ final class TimePicker: Box {
17721770
case .zeroToEleven, .zeroToTwentyThree: 0
17731771
case .oneToTwelve, .oneToTwentyFour: 1
17741772
#if os(macOS)
1775-
@unknown default: fatalError()
1773+
@unknown default: fatalError("Unrecognized hourCycle \(hourCycle)")
17761774
#endif
17771775
}
17781776
}
@@ -1784,7 +1782,7 @@ final class TimePicker: Box {
17841782
case .zeroToTwentyThree: 23
17851783
case .oneToTwentyFour: 24
17861784
#if os(macOS)
1787-
@unknown default: fatalError()
1785+
@unknown default: fatalError("Unrecognized hourCycle \(hourCycle)")
17881786
#endif
17891787
}
17901788
}
@@ -1884,7 +1882,7 @@ final class TimePicker: Box {
18841882
case .zeroToTwentyThree: value % 24
18851883
case .oneToTwentyFour: (value + 23) % 24 + 1
18861884
#if os(macOS)
1887-
@unknown default: fatalError()
1885+
@unknown default: fatalError("Unrecognized hourCycle \(hourCycle)")
18881886
#endif
18891887
}
18901888
}

Sources/SwiftCrossUI/Backend/AppBackend.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ public protocol AppBackend: Sendable {
9898
/// Mobile backends generally can't.
9999
var canRevealFiles: Bool { get }
100100

101+
/// The supported date picker styles. Must include ``DatePickerStyle/automatic`` if date pickers
102+
/// are supported at all.
103+
nonisolated var supportedDatePickerStyles: [DatePickerStyle] { get }
104+
101105
/// Often in UI frameworks (such as Gtk), code is run in a callback
102106
/// after starting the app, and hence this generic root window creation
103107
/// API must reflect that. This is always the first method to be called

Sources/SwiftCrossUI/Environment/EnvironmentValues.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,11 @@ public struct EnvironmentValues {
201201
/// The current time zone that views should use when handling dates.
202202
public var timeZone: TimeZone
203203

204-
#if !os(tvOS)
205-
public var datePickerStyle: DatePickerStyle
206-
#endif
204+
/// The display style used by ``DatePicker``.
205+
public var datePickerStyle: DatePickerStyle
206+
207+
/// The display styles supported by ``DatePicker``. ``datePickerStyle`` must be one of these.
208+
public let supportedDatePickerStyles: [DatePickerStyle]
207209

208210
/// Creates the default environment.
209211
init<Backend: AppBackend>(backend: Backend) {
@@ -229,9 +231,8 @@ public struct EnvironmentValues {
229231
isTextSelectionEnabled = false
230232
calendar = .autoupdatingCurrent
231233
timeZone = .autoupdatingCurrent
232-
#if !os(tvOS)
233-
datePickerStyle = .automatic
234-
#endif
234+
datePickerStyle = .automatic
235+
supportedDatePickerStyles = backend.supportedDatePickerStyles
235236
}
236237

237238
/// Returns a copy of the environment with the specified property set to the

Sources/SwiftCrossUI/Views/DatePicker.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ public struct DatePickerComponents: OptionSet, Sendable {
1212
self.rawValue = 0
1313
}
1414

15+
/*
16+
* These magic numbers are the same as SwiftUI. It's actually a bitfield:
17+
*
18+
* smhdMy--
19+
* date 00011100
20+
* hourAndMinute 01100000
21+
* hourMinuteAndSecond 11100000
22+
*
23+
* Like SwiftUI, not all combinations are valid (SwiftUI fatalErrors if you try to get creative
24+
* with your choice of flags), and hourMinuteAndSecond intentionally includes hourAndMinute.
25+
*/
26+
1527
public static let date = DatePickerComponents(rawValue: 0x1C)
1628
public static let hourAndMinute = DatePickerComponents(rawValue: 0x60)
1729

@@ -21,9 +33,8 @@ public struct DatePickerComponents: OptionSet, Sendable {
2133
public static let hourMinuteAndSecond = DatePickerComponents(rawValue: 0xE0)
2234
}
2335

24-
@available(tvOS, unavailable)
2536
public enum DatePickerStyle: Sendable, Hashable {
26-
/// A date input chosen by the backend.
37+
/// A date input that adapts to the current platform and context.
2738
case automatic
2839

2940
/// A date input that shows a calendar grid.
@@ -54,11 +65,11 @@ public struct DatePicker<Label: View> {
5465
/// - range: The range of dates to display. The backend takes this as a hint but it is not
5566
/// necessarily enforced. As such this parameter should be treated as an aid to validation
5667
/// rather than a replacement for it.
57-
/// - displayedComponents: What parts of the date/time to display in the input.
68+
/// - displayedComponents: Which parts of the date/time to display in the input.
5869
/// - label: The view to be shown next to the date input.
5970
public nonisolated init(
6071
selection: Binding<Date>,
61-
range: ClosedRange<Date> = Date.distantPast...Date.distantFuture,
72+
in range: ClosedRange<Date> = Date.distantPast...Date.distantFuture,
6273
displayedComponents: DatePickerComponents = [.hourAndMinute, .date],
6374
@ViewBuilder label: () -> Label
6475
) {
@@ -75,11 +86,11 @@ public struct DatePicker<Label: View> {
7586
/// - range: The range of dates to display. The backend takes this as a hint but it is not
7687
/// necessarily enforced. As such this parameter should be treated as an aid to validation
7788
/// rather than a replacement for it.
78-
/// - displayedComponents: What parts of the date/time to display in the input.
89+
/// - displayedComponents: Which parts of the date/time to display in the input.
7990
public nonisolated init(
8091
_ label: String,
8192
selection: Binding<Date>,
82-
range: ClosedRange<Date> = Date.distantPast...Date.distantFuture,
93+
in range: ClosedRange<Date> = Date.distantPast...Date.distantFuture,
8394
displayedComponents: DatePickerComponents = [.hourAndMinute, .date]
8495
) where Label == Text {
8596
self.label = Text(label)
Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
extension View {
2-
@available(tvOS, unavailable)
32
public func datePickerStyle(_ style: DatePickerStyle) -> some View {
4-
#if os(tvOS)
5-
assertionFailure()
6-
return EmptyView()
7-
#else
8-
EnvironmentModifier(self) { environment in
9-
environment.with(\.datePickerStyle, style)
3+
EnvironmentModifier(self) { environment in
4+
var style = style
5+
if !environment.supportedDatePickerStyles.contains(style) {
6+
assertionFailure("Unsupported date picker style: \(style)")
7+
style = .automatic
108
}
11-
#endif
9+
return environment.with(\.datePickerStyle, style)
10+
}
1211
}
1312
}

Sources/UIKitBackend/UIKitBackend.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ public final class UIKitBackend: AppBackend {
4444
}
4545
}
4646

47+
public nonisolated var supportedDatePickerStyles: [DatePickerStyle] {
48+
#if os(tvOS)
49+
[]
50+
#else
51+
if #available(iOS 14, macCatalyst 14, *) {
52+
[.automatic, .graphical, .compact, .wheel]
53+
} else if #available(iOS 13.4, macCatalyst 13.4, *) {
54+
[.automatic, .compact, .wheel]
55+
} else {
56+
[.automatic]
57+
}
58+
#endif
59+
}
60+
4761
var onTraitCollectionChange: (() -> Void)?
4862

4963
private let appDelegateClass: ApplicationDelegate.Type

0 commit comments

Comments
 (0)