Skip to content

Commit 9e4459b

Browse files
authored
Make the package build for watchOS (#8)
* Make the package build for watchOS watchOS is a declared platform, but the package failed to compile for it with 52 distinct errors. UIKit on watchOS has no semantic colors, no UIApplication, UIScreen or UIGraphicsImageRenderer, and SwiftUI there has no GroupBox, DisclosureGroup or rounded text field style. The label and standard colors now map to SwiftUI's own colors on watchOS, which follow the watch's system palette. Helpers without a sensible watchOS counterpart are compiled out: the background, fill, separator, link, tertiary/quaternary label and gray 2-6 colors, UIImage.resized, onAppBecomeActive/onAppResignActive and SideTabView. HPicker and VPicker need the materials of watchOS 10 and are marked accordingly. Previews that use unavailable views skip watchOS, and importing ImageIO makes heicData(compressionQuality:) work there. * Build every platform in CI watchOS was a declared platform that did not compile, and nothing noticed because CI only built for macOS. A matrix job now builds the package for iOS, tvOS, visionOS and watchOS with generic destinations, which need the SDKs but no simulator runtimes. The macOS job uses the swiftbuild build system like on the other open branches, so the workflow changes merge cleanly. * List the platform build job first in the workflow With the new job appended right after the swift test line, git could not merge this workflow with the swiftbuild change of the other open branches. Placed before test-macos, both changes merge cleanly.
1 parent 35edb69 commit 9e4459b

11 files changed

Lines changed: 198 additions & 136 deletions

File tree

‎.github/workflows/main.yml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ on:
55
branches: [main]
66

77
jobs:
8+
build-platforms:
9+
runs-on: macos-26
10+
strategy:
11+
fail-fast: false
12+
matrix:
13+
platform: [iOS, tvOS, visionOS, watchOS]
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Build for ${{ matrix.platform }}
19+
run: xcodebuild -scheme HandySwiftUI -destination 'generic/platform=${{ matrix.platform }}' CODE_SIGNING_ALLOWED=NO build
20+
821
test-macos:
922
runs-on: macos-26
1023

‎Sources/HandySwiftUI/Extensions/ColorExt.swift‎

Lines changed: 74 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ import SwiftUI
77
#endif
88

99
// MARK: - Apple-provided colors
10+
// UIKit on watchOS has no semantic colors. There, the label and standard colors map to SwiftUI's own colors, which use the watchOS
11+
// system palette, and the colors without a watchOS counterpart (backgrounds, fills, separators, …) are not available.
1012
extension Color {
1113
// MARK: - UI Element Colors (https://developer.apple.com/documentation/uikit/uicolor/ui_element_colors)
1214
// MARK: Label Colors
1315
/// The color for text labels that contain primary content.
1416
public static var label: Color {
1517
#if os(macOS)
1618
return Color(NSColor.labelColor)
19+
#elseif os(watchOS)
20+
return .primary
1721
#else
1822
return Color(UIColor.label)
1923
#endif
@@ -23,31 +27,35 @@ extension Color {
2327
public static var secondaryLabel: Color {
2428
#if os(macOS)
2529
return Color(NSColor.secondaryLabelColor)
30+
#elseif os(watchOS)
31+
return .secondary
2632
#else
2733
return Color(UIColor.secondaryLabel)
2834
#endif
2935
}
3036

31-
/// The color for text labels that contain tertiary content.
32-
public static var tertiaryLabel: Color {
33-
#if os(macOS)
34-
return Color(NSColor.tertiaryLabelColor)
35-
#else
36-
return Color(UIColor.tertiaryLabel)
37-
#endif
38-
}
37+
#if !os(watchOS)
38+
/// The color for text labels that contain tertiary content.
39+
public static var tertiaryLabel: Color {
40+
#if os(macOS)
41+
return Color(NSColor.tertiaryLabelColor)
42+
#else
43+
return Color(UIColor.tertiaryLabel)
44+
#endif
45+
}
3946

40-
/// The color for text labels that contain quaternary content.
41-
public static var quaternaryLabel: Color {
42-
#if os(macOS)
43-
return Color(NSColor.quaternaryLabelColor)
44-
#else
45-
return Color(UIColor.quaternaryLabel)
46-
#endif
47-
}
47+
/// The color for text labels that contain quaternary content.
48+
public static var quaternaryLabel: Color {
49+
#if os(macOS)
50+
return Color(NSColor.quaternaryLabelColor)
51+
#else
52+
return Color(UIColor.quaternaryLabel)
53+
#endif
54+
}
55+
#endif
4856

4957
// MARK: Fill Colors
50-
#if !os(tvOS)
58+
#if !os(tvOS) && !os(watchOS)
5159
/// An overlay fill color for thin and small shapes.
5260
public static var systemFill: Color {
5361
#if os(macOS)
@@ -152,39 +160,45 @@ extension Color {
152160
#endif
153161

154162
// MARK: Separator Colors
155-
/// The color for thin borders or divider lines that allows some underlying content to be visible.
156-
public static var separator: Color {
157-
#if os(macOS)
158-
return Color(NSColor.separatorColor)
159-
#else
160-
return Color(UIColor.separator)
161-
#endif
162-
}
163+
#if !os(watchOS)
164+
/// The color for thin borders or divider lines that allows some underlying content to be visible.
165+
public static var separator: Color {
166+
#if os(macOS)
167+
return Color(NSColor.separatorColor)
168+
#else
169+
return Color(UIColor.separator)
170+
#endif
171+
}
163172

164-
/// The color for borders or divider lines that hides any underlying content.
165-
public static var opaqueSeparator: Color {
166-
#if os(macOS)
167-
return Color(NSColor.separatorColor).opacity(1)
168-
#else
169-
return Color(UIColor.opaqueSeparator)
170-
#endif
171-
}
173+
/// The color for borders or divider lines that hides any underlying content.
174+
public static var opaqueSeparator: Color {
175+
#if os(macOS)
176+
return Color(NSColor.separatorColor).opacity(1)
177+
#else
178+
return Color(UIColor.opaqueSeparator)
179+
#endif
180+
}
181+
#endif
172182

173183
// MARK: Link Color
174-
/// The color for links.
175-
public static var link: Color {
176-
#if os(macOS)
177-
return Color(NSColor.linkColor)
178-
#else
179-
return Color(UIColor.link)
180-
#endif
181-
}
184+
#if !os(watchOS)
185+
/// The color for links.
186+
public static var link: Color {
187+
#if os(macOS)
188+
return Color(NSColor.linkColor)
189+
#else
190+
return Color(UIColor.link)
191+
#endif
192+
}
193+
#endif
182194

183195
// MARK: - Standard Colors (https://developer.apple.com/documentation/uikit/uicolor/standard_colors)
184196
// MARK: Adaptable Colors
185197
public static var systemBlue: Color {
186198
#if os(macOS)
187199
return Color(NSColor.systemBlue)
200+
#elseif os(watchOS)
201+
return .blue
188202
#else
189203
return Color(UIColor.systemBlue)
190204
#endif
@@ -193,6 +207,8 @@ extension Color {
193207
public static var systemGreen: Color {
194208
#if os(macOS)
195209
return Color(NSColor.systemGreen)
210+
#elseif os(watchOS)
211+
return .green
196212
#else
197213
return Color(UIColor.systemGreen)
198214
#endif
@@ -201,6 +217,8 @@ extension Color {
201217
public static var systemIndigo: Color {
202218
#if os(macOS)
203219
return Color(NSColor.systemIndigo)
220+
#elseif os(watchOS)
221+
return .indigo
204222
#else
205223
return Color(UIColor.systemIndigo)
206224
#endif
@@ -209,6 +227,8 @@ extension Color {
209227
public static var systemOrange: Color {
210228
#if os(macOS)
211229
return Color(NSColor.systemOrange)
230+
#elseif os(watchOS)
231+
return .orange
212232
#else
213233
return Color(UIColor.systemOrange)
214234
#endif
@@ -217,6 +237,8 @@ extension Color {
217237
public static var systemPink: Color {
218238
#if os(macOS)
219239
return Color(NSColor.systemPink)
240+
#elseif os(watchOS)
241+
return .pink
220242
#else
221243
return Color(UIColor.systemPink)
222244
#endif
@@ -225,6 +247,8 @@ extension Color {
225247
public static var systemPurple: Color {
226248
#if os(macOS)
227249
return Color(NSColor.systemPurple)
250+
#elseif os(watchOS)
251+
return .purple
228252
#else
229253
return Color(UIColor.systemPurple)
230254
#endif
@@ -233,6 +257,8 @@ extension Color {
233257
public static var systemRed: Color {
234258
#if os(macOS)
235259
return Color(NSColor.systemRed)
260+
#elseif os(watchOS)
261+
return .red
236262
#else
237263
return Color(UIColor.systemRed)
238264
#endif
@@ -241,6 +267,8 @@ extension Color {
241267
public static var systemTeal: Color {
242268
#if os(macOS)
243269
return Color(NSColor.systemTeal)
270+
#elseif os(watchOS)
271+
return .teal
244272
#else
245273
return Color(UIColor.systemTeal)
246274
#endif
@@ -249,6 +277,8 @@ extension Color {
249277
public static var systemYellow: Color {
250278
#if os(macOS)
251279
return Color(NSColor.systemYellow)
280+
#elseif os(watchOS)
281+
return .yellow
252282
#else
253283
return Color(UIColor.systemYellow)
254284
#endif
@@ -258,12 +288,14 @@ extension Color {
258288
public static var systemGray: Color {
259289
#if os(macOS)
260290
return Color(NSColor.systemGray)
291+
#elseif os(watchOS)
292+
return .gray
261293
#else
262294
return Color(UIColor.systemGray)
263295
#endif
264296
}
265297

266-
#if !os(tvOS)
298+
#if !os(tvOS) && !os(watchOS)
267299
public static var systemGray2: Color {
268300
#if os(macOS)
269301
return Color(NSColor.systemGray)

‎Sources/HandySwiftUI/Extensions/ImageExt.swift‎

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import ImageIO
12
import SwiftUI
23
import UniformTypeIdentifiers
34

@@ -106,35 +107,38 @@ extension Image {
106107
import UIKit
107108

108109
extension UIImage {
109-
/// Resizes the image to fit within the specified maximum width and height.
110-
///
111-
/// - Parameters:
112-
/// - maxWidth: The maximum width for the resized image.
113-
/// - maxHeight: The maximum height for the resized image.
114-
/// - Returns: A new `UIImage` instance with the resized dimensions, or `nil` if resizing fails.
115-
@MainActor
116-
public func resized(maxWidth: CGFloat, maxHeight: CGFloat) -> UIImage? {
117-
let size = self.size
118-
if size.width <= maxWidth && size.height <= maxHeight { return self }
119-
120-
#if os(visionOS)
121-
let screenScale = 1.0
122-
#else
123-
let screenScale = UIScreen.main.scale
124-
#endif
125-
let widthRatio = (maxWidth / screenScale) / size.width
126-
let heightRatio = (maxHeight / screenScale) / size.height
127-
let scaleFactor = min(widthRatio, heightRatio)
128-
129-
let newSize = CGSize(width: size.width * scaleFactor, height: size.height * scaleFactor)
110+
// watchOS has neither UIGraphicsImageRenderer nor UIScreen
111+
#if !os(watchOS)
112+
/// Resizes the image to fit within the specified maximum width and height.
113+
///
114+
/// - Parameters:
115+
/// - maxWidth: The maximum width for the resized image.
116+
/// - maxHeight: The maximum height for the resized image.
117+
/// - Returns: A new `UIImage` instance with the resized dimensions, or `nil` if resizing fails.
118+
@MainActor
119+
public func resized(maxWidth: CGFloat, maxHeight: CGFloat) -> UIImage? {
120+
let size = self.size
121+
if size.width <= maxWidth && size.height <= maxHeight { return self }
122+
123+
#if os(visionOS)
124+
let screenScale = 1.0
125+
#else
126+
let screenScale = UIScreen.main.scale
127+
#endif
128+
let widthRatio = (maxWidth / screenScale) / size.width
129+
let heightRatio = (maxHeight / screenScale) / size.height
130+
let scaleFactor = min(widthRatio, heightRatio)
131+
132+
let newSize = CGSize(width: size.width * scaleFactor, height: size.height * scaleFactor)
133+
134+
let renderer = UIGraphicsImageRenderer(size: newSize)
135+
let image = renderer.image { _ in
136+
self.draw(in: CGRect(origin: .zero, size: newSize))
137+
}
130138

131-
let renderer = UIGraphicsImageRenderer(size: newSize)
132-
let image = renderer.image { _ in
133-
self.draw(in: CGRect(origin: .zero, size: newSize))
139+
return image.withRenderingMode(self.renderingMode)
134140
}
135-
136-
return image.withRenderingMode(self.renderingMode)
137-
}
141+
#endif
138142

139143
/// Converts the image to HEIC data with specified compression quality.
140144
///

0 commit comments

Comments
 (0)