From d7f39780ef821f48f61265e5afb94c52e6aba352 Mon Sep 17 00:00:00 2001 From: dyongxu <61523257+dyongxu@users.noreply.github.com> Date: Wed, 20 Dec 2023 18:52:35 -0800 Subject: [PATCH 1/3] feat: merge visionOS branch into main (#622) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 merge visionOS branch into main * feat: 🎸 merge visionOS branch into main update Package.swift to support visonOS, and remove Package@5.9.swift --------- Co-authored-by: David Xu --- .../Examples.xcodeproj/project.pbxproj | 15 +- .../SignatureCaptureViewExample.swift | 39 ++-- Package.swift | 10 +- README.md | 6 +- .../Extensions/String+Extensions.swift | 2 +- .../CancellableResettableForm.swift | 6 +- .../DataTable/DataTable.swift | 22 ++- .../DataTable/InlineEditingView.swift | 10 +- .../Popover/PopoverModifier.swift | 2 + Sources/FioriSwiftUICore/Utils/Screen.swift | 22 +++ .../Views/KPIHeader/KPIHeaderContent.swift | 18 +- .../FilterFeedbackBarItem+View.swift | 4 +- .../_SortFilterCFGItemContainer.swift | 12 +- .../Colors/Color+Extension.swift | 2 +- Sources/FioriThemeManager/ThemeManager.swift | 2 +- .../FioriSwiftUICore/UIFontTests.swift | 172 ++++++++++++++---- .../StyleSheetSettingsIntegrationTests.swift | 4 +- 17 files changed, 251 insertions(+), 97 deletions(-) create mode 100644 Sources/FioriSwiftUICore/Utils/Screen.swift diff --git a/Apps/Examples/Examples.xcodeproj/project.pbxproj b/Apps/Examples/Examples.xcodeproj/project.pbxproj index e1b19b7c5..402e15933 100644 --- a/Apps/Examples/Examples.xcodeproj/project.pbxproj +++ b/Apps/Examples/Examples.xcodeproj/project.pbxproj @@ -15,7 +15,7 @@ 1F60179929A8439A00DBDCDE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F60179829A8439A00DBDCDE /* ContentView.swift */; }; 1F60179B29A8439C00DBDCDE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1F60179A29A8439C00DBDCDE /* Assets.xcassets */; }; 1F60179E29A8439C00DBDCDE /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1F60179D29A8439C00DBDCDE /* Preview Assets.xcassets */; }; - 1F6017A129A8439C00DBDCDE /* WatchExamples Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 1F60179429A8439A00DBDCDE /* WatchExamples Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 1F6017A129A8439C00DBDCDE /* WatchExamples Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 1F60179429A8439A00DBDCDE /* WatchExamples Watch App.app */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 1F6017A729A8450E00DBDCDE /* FioriThemeManager in Frameworks */ = {isa = PBXBuildFile; productRef = 1F6017A629A8450E00DBDCDE /* FioriThemeManager */; }; 1F6017A829A8450E00DBDCDE /* FioriThemeManager in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 1F6017A629A8450E00DBDCDE /* FioriThemeManager */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 1F6017AD29A8481A00DBDCDE /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A6DE30A28DD27F9003222E3 /* Colors.swift */; }; @@ -852,6 +852,7 @@ /* Begin PBXTargetDependency section */ 1F6017A029A8439C00DBDCDE /* PBXTargetDependency */ = { isa = PBXTargetDependency; + platformFilter = ios; target = 1F60179329A8439A00DBDCDE /* WatchExamples Watch App */; targetProxy = 1F60179F29A8439C00DBDCDE /* PBXContainerItemProxy */; }; @@ -1066,8 +1067,12 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "com.sap.cloud-sdk-ios-fiori.Examples"; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,7"; }; name = Debug; }; @@ -1088,8 +1093,12 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "com.sap.cloud-sdk-ios-fiori.Examples"; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,7"; }; name = Release; }; diff --git a/Apps/Examples/Examples/FioriSwiftUICore/SignatureView/SignatureCaptureViewExample.swift b/Apps/Examples/Examples/FioriSwiftUICore/SignatureView/SignatureCaptureViewExample.swift index feb4de2be..7df08fd59 100644 --- a/Apps/Examples/Examples/FioriSwiftUICore/SignatureView/SignatureCaptureViewExample.swift +++ b/Apps/Examples/Examples/FioriSwiftUICore/SignatureView/SignatureCaptureViewExample.swift @@ -72,28 +72,29 @@ class ImageSaver: NSObject { @objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {} } -public extension View { - func asUIImage() -> UIImage { - let hostingController = UIHostingController(rootView: self) +#if !os(visionOS) + public extension View { + func asUIImage() -> UIImage { + let hostingController = UIHostingController(rootView: self) - hostingController.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1) - UIApplication.shared.windows.first!.rootViewController?.view.addSubview(hostingController.view) - - let size = hostingController.sizeThatFits(in: UIScreen.main.bounds.size) - hostingController.view.bounds = CGRect(origin: .zero, size: size) - hostingController.view.sizeToFit() + hostingController.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1) + UIApplication.shared.windows.first!.rootViewController?.view.addSubview(hostingController.view) + let size = hostingController.sizeThatFits(in: UIScreen.main.bounds.size) + hostingController.view.bounds = CGRect(origin: .zero, size: size) + hostingController.view.sizeToFit() - let resultingImage = hostingController.view.asUIImage() - hostingController.view.removeFromSuperview() - return resultingImage + let resultingImage = hostingController.view.asUIImage() + hostingController.view.removeFromSuperview() + return resultingImage + } } -} -public extension UIView { - func asUIImage() -> UIImage { - let renderer = UIGraphicsImageRenderer(bounds: bounds) - return renderer.image { rendererContext in - layer.render(in: rendererContext.cgContext) + public extension UIView { + func asUIImage() -> UIImage { + let renderer = UIGraphicsImageRenderer(bounds: bounds) + return renderer.image { rendererContext in + layer.render(in: rendererContext.cgContext) + } } } -} +#endif diff --git a/Package.swift b/Package.swift index 48162e04b..d8d66005b 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.7 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -6,7 +6,7 @@ import PackageDescription let package = Package( name: "FioriSwiftUI", defaultLocalization: "en", - platforms: [.iOS(.v16), .watchOS(.v7)], + platforms: [.iOS(.v16), .watchOS(.v7), .visionOS(.v1)], products: [ .library( name: "FioriSwiftUI", @@ -30,7 +30,7 @@ let package = Package( targets: [ .target( name: "FioriSwiftUI", - dependencies: [.target(name: "FioriSwiftUICore", condition: .when(platforms: [.iOS]))] + dependencies: [.target(name: "FioriSwiftUICore", condition: .when(platforms: [.iOS, .visionOS]))] ), .target( name: "FioriCharts", @@ -40,8 +40,8 @@ let package = Package( .target( name: "FioriSwiftUICore", dependencies: [ - .target(name: "FioriThemeManager", condition: .when(platforms: [.iOS])), - .target(name: "FioriCharts", condition: .when(platforms: [.iOS])) + .target(name: "FioriThemeManager", condition: .when(platforms: [.iOS, .visionOS])), + .target(name: "FioriCharts", condition: .when(platforms: [.iOS, .visionOS])) ], resources: [.process("FioriSwiftUICore.strings")] ), diff --git a/README.md b/README.md index 9871ac841..c52bdf685 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This project is the SwiftUI implementation of the [SAP Fiori for iOS Design Lang This project currently contains three modules: `FioriThemeManager`, `FioriSwiftUICore`, and `FioriCharts`. ## FioriThemeManager -![FioriThemeManager platform support: iOS and watchOS](https://img.shields.io/badge/platform-ios%20%7C%20watchos-lightgray) +![FioriThemeManager platform support: iOS, visionOS, watchOS](https://img.shields.io/badge/platform-ios%20%7C%20visionos%20%7C%20watchos-lightgray) This module provides a [color palette](https://experience.sap.com/fiori-design-ios/article/colors/) and a new font family [SAP 72](https://experience.sap.com/72/) that conform to [Fiori Design Language](https://experience.sap.com/fiori-design-ios/). It is adopted by all the Fiori components in both this package and SAPFiori. @@ -43,7 +43,7 @@ All Fiori Colors are dynamic colors, which means they will adjust based on iOS A > Custom fonts need to be loaded and registered during App's runtime. Make sure you call `Font.registerFioriFonts()` inside `application(_:didFinishLaunchingWithOptions:)` of your `AppDelegate`. ## FioriSwiftUICore -![FioriSwiftUICore platform support: iOS only](https://img.shields.io/badge/platform-ios-lightgray) +![FioriSwiftUICore platform support: iOS and visionOS](https://img.shields.io/badge/platform-ios%20%7C%20visionos-lightgray) This module contains SwiftUI implementation for those UIKit-based components existing in [SAPFiori](https://help.sap.com/doc/978e4f6c968c4cc5a30f9d324aa4b1d7/Latest/en-US/Documents/Frameworks/SAPFiori/index.html). It provides you with an easy way to migrate your UIKit project to SwiftUI while delivering the same experience as before. @@ -84,7 +84,7 @@ We plan to progressively bring more Fiori UI components into this module in the | TouchIDErrorView | :x: | ## FioriCharts -![FioriCharts platform support: iOS only](https://img.shields.io/badge/platform-ios-lightgray) +![FioriCharts platform support: iOS and visionOS](https://img.shields.io/badge/platform-ios%20%7C%20visionos-lightgray) The FioriCharts module replaces the *RoambiChartKit* charting library which was already embedded in SAPFiori. Migrating to SwiftUI gives the ability to easily add new chart components (donut, bullet, stocks, etc.) while modernizing the existing supported charts with pinch-to-zoom, pan, and new design features. diff --git a/Sources/FioriCharts/Extensions/String+Extensions.swift b/Sources/FioriCharts/Extensions/String+Extensions.swift index 16452f252..669dc21ee 100644 --- a/Sources/FioriCharts/Extensions/String+Extensions.swift +++ b/Sources/FioriCharts/Extensions/String+Extensions.swift @@ -3,7 +3,7 @@ import SwiftUI extension String { func boundingBoxSize(with fontSize: CGFloat) -> CGSize { - #if os(iOS) || os(tvOS) || os(watchOS) + #if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) let font = UIFont.systemFont(ofSize: fontSize) #elseif os(macOS) let font = NSFont.systemFont(ofSize: fontSize) diff --git a/Sources/FioriSwiftUICore/Components/CancellableResettableForm.swift b/Sources/FioriSwiftUICore/Components/CancellableResettableForm.swift index 4d6b3ab28..91129c27c 100644 --- a/Sources/FioriSwiftUICore/Components/CancellableResettableForm.swift +++ b/Sources/FioriSwiftUICore/Components/CancellableResettableForm.swift @@ -37,7 +37,7 @@ struct CancellableResettableDialogForm DataTable { self.model.isEditing = value - + return self } @@ -236,7 +238,7 @@ public extension DataTable { func sizeThatFits(_ size: CGSize) -> CGSize { self.layoutManager.sizeThatFits(size) } - + /// Returns the rect for the specified cell with rowIndex and columnIndex /// - Parameter rowIndex: the row index; rowIndex starts from header if it exists /// - Parameter columnIndex: the column index diff --git a/Sources/FioriSwiftUICore/DataTable/InlineEditingView.swift b/Sources/FioriSwiftUICore/DataTable/InlineEditingView.swift index bfc32c3a8..c5a42546d 100644 --- a/Sources/FioriSwiftUICore/DataTable/InlineEditingView.swift +++ b/Sources/FioriSwiftUICore/DataTable/InlineEditingView.swift @@ -28,6 +28,14 @@ struct InlineEditingView: View { self._editingText = State(initialValue: dataItem?.text ?? "") self._isValid = State(initialValue: (dataItem?.isValid ?? true, "")) } + + var toolbarItemPlacement: ToolbarItemPlacement { + #if os(visionOS) + return .automatic + #else + return .keyboard + #endif + } var body: some View { let dataItem = self.layoutData.allDataItems[self.rowIndex][self.columnIndex] @@ -109,7 +117,7 @@ struct InlineEditingView: View { .frame(width: cellWidth, height: cellHeight) .border(isValid.0 ? Color.preferredColor(.tintColor) : Color.preferredColor(.negativeLabel), width: 2) .toolbar { - ToolbarItemGroup(placement: .keyboard) { + ToolbarItemGroup(placement: toolbarItemPlacement) { Spacer() Button { diff --git a/Sources/FioriSwiftUICore/Experimental/Popover/PopoverModifier.swift b/Sources/FioriSwiftUICore/Experimental/Popover/PopoverModifier.swift index f790e3b97..d61600c72 100644 --- a/Sources/FioriSwiftUICore/Experimental/Popover/PopoverModifier.swift +++ b/Sources/FioriSwiftUICore/Experimental/Popover/PopoverModifier.swift @@ -25,10 +25,12 @@ struct PopoverModifier: ViewModifier { popover.dismiss() } } + #if !os(visionOS) .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in guard let popover = popover else { return } popover.dismiss() } + #endif } } } diff --git a/Sources/FioriSwiftUICore/Utils/Screen.swift b/Sources/FioriSwiftUICore/Utils/Screen.swift new file mode 100644 index 000000000..8f8949c58 --- /dev/null +++ b/Sources/FioriSwiftUICore/Utils/Screen.swift @@ -0,0 +1,22 @@ +import Foundation +import UIKit + +struct Screen { + private init() {} + + static var scale: CGFloat { + #if os(visionOS) + 1.0 + #else + UIScreen.main.scale + #endif + } + + static var bounds: CGRect { + #if os(visionOS) + CGRect(x: 0, y: 0, width: 1280, height: 720) // default window size for visionOS + #else + UIScreen.main.bounds + #endif + } +} diff --git a/Sources/FioriSwiftUICore/Views/KPIHeader/KPIHeaderContent.swift b/Sources/FioriSwiftUICore/Views/KPIHeader/KPIHeaderContent.swift index b35845776..67c31b3cc 100644 --- a/Sources/FioriSwiftUICore/Views/KPIHeader/KPIHeaderContent.swift +++ b/Sources/FioriSwiftUICore/Views/KPIHeader/KPIHeaderContent.swift @@ -116,12 +116,18 @@ extension KPIHeaderContent { } private var resizePublisher: AnyPublisher { - let orientationPublisher = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification) - .compactMap { _ in () } - let sizeCategoryPublisher = NotificationCenter.default.publisher(for: UIContentSizeCategory.didChangeNotification) - .compactMap { _ in () } - return Publishers.Merge(orientationPublisher, sizeCategoryPublisher) - .eraseToAnyPublisher() + #if os(visionOS) + let sizeCategoryPublisher = NotificationCenter.default.publisher(for: UIContentSizeCategory.didChangeNotification) + .compactMap { _ in () } + return sizeCategoryPublisher.eraseToAnyPublisher() + #else + let orientationPublisher = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification) + .compactMap { _ in () } + let sizeCategoryPublisher = NotificationCenter.default.publisher(for: UIContentSizeCategory.didChangeNotification) + .compactMap { _ in () } + return Publishers.Merge(orientationPublisher, sizeCategoryPublisher) + .eraseToAnyPublisher() + #endif } private var minItemSpacing: CGFloat { diff --git a/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItem+View.swift b/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItem+View.swift index e81934969..bd329c8ad 100644 --- a/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItem+View.swift +++ b/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItem+View.swift @@ -299,10 +299,10 @@ struct DateTimeMenuItem: View { ) .datePickerStyle(.graphical) .labelsHidden() - .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 : UIScreen.main.bounds.size.width - 16) + .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 : Screen.bounds.size.width - 16) .clipped() } - .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 : UIScreen.main.bounds.size.width) + .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 : Screen.bounds.size.width) } .readHeight() .onPreferenceChange(HeightPreferenceKey.self) { height in diff --git a/Sources/FioriSwiftUICore/Views/SortFilter/_SortFilterCFGItemContainer.swift b/Sources/FioriSwiftUICore/Views/SortFilter/_SortFilterCFGItemContainer.swift index 3bb033548..7bbae1f84 100644 --- a/Sources/FioriSwiftUICore/Views/SortFilter/_SortFilterCFGItemContainer.swift +++ b/Sources/FioriSwiftUICore/Views/SortFilter/_SortFilterCFGItemContainer.swift @@ -36,13 +36,13 @@ extension _SortFilterCFGItemContainer: View { slider(row: r, column: c) case .datetime: datetimePicker(row: r, column: c) - .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 : UIScreen.main.bounds.size.width) + .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 : Screen.bounds.size.width) } } } .padding([.top], 12) - .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2 : UIScreen.main.bounds.size.width - 16 * 2) - .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 : UIScreen.main.bounds.size.width) + .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2 : Screen.bounds.size.width - 16 * 2) + .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 : Screen.bounds.size.width) .background(Color.preferredColor(.secondaryGroupedBackground)) } } @@ -164,7 +164,7 @@ extension _SortFilterCFGItemContainer: View { .foregroundColor(Color.preferredColor(.primaryLabel)) Spacer() } - .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2 : UIScreen.main.bounds.size.width - 16 * 2) + .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2 : Screen.bounds.size.width - 16 * 2) HStack { Text(NSLocalizedString("Time", tableName: "FioriSwiftUICore", bundle: Bundle.accessor, comment: "")) @@ -178,7 +178,7 @@ extension _SortFilterCFGItemContainer: View { ) .labelsHidden() } - .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2 : UIScreen.main.bounds.size.width - 16 * 2) + .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2 : Screen.bounds.size.width - 16 * 2) DatePicker( "", @@ -187,7 +187,7 @@ extension _SortFilterCFGItemContainer: View { ) .datePickerStyle(.graphical) .labelsHidden() - .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 : UIScreen.main.bounds.size.width - 16) + .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 : Screen.bounds.size.width - 16) // .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 : UIScreen.main.bounds.size.width) .clipped() // .frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2: UIScreen.main.bounds.size.width) diff --git a/Sources/FioriThemeManager/Colors/Color+Extension.swift b/Sources/FioriThemeManager/Colors/Color+Extension.swift index 397c9dac6..7d714f1d6 100644 --- a/Sources/FioriThemeManager/Colors/Color+Extension.swift +++ b/Sources/FioriThemeManager/Colors/Color+Extension.swift @@ -14,7 +14,7 @@ public extension Color { ThemeManager.shared.color(for: style, background: scheme, interface: level, display: mode) } - #if os(iOS) + #if os(iOS) || os(visionOS) /// Extension to `Color`, to resolve a static form of `Color` from the wrapped dynamic color provider. /// /// - parameters: diff --git a/Sources/FioriThemeManager/ThemeManager.swift b/Sources/FioriThemeManager/ThemeManager.swift index bfdaa62ab..0e810e7cf 100644 --- a/Sources/FioriThemeManager/ThemeManager.swift +++ b/Sources/FioriThemeManager/ThemeManager.swift @@ -171,7 +171,7 @@ public class ThemeManager { func uiColor(for style: ColorStyle, background scheme: BackgroundColorScheme?, interface level: InterfaceLevel?, display mode: ColorDisplayMode?) -> UIColor { guard let hc = self.hexColor(for: style) else { return .clear } - #if os(iOS) + #if os(iOS) || os(visionOS) let uc = UIColor { [weak self] traitCollection in guard let self = self else { return .clear } guard let hexColor = self.hexColor(for: style) else { return .clear } diff --git a/Tests/FioriSwiftUITests/FioriSwiftUICore/UIFontTests.swift b/Tests/FioriSwiftUITests/FioriSwiftUICore/UIFontTests.swift index 8d510d632..5609e1e8f 100644 --- a/Tests/FioriSwiftUITests/FioriSwiftUICore/UIFontTests.swift +++ b/Tests/FioriSwiftUITests/FioriSwiftUICore/UIFontTests.swift @@ -2,6 +2,25 @@ import SwiftUI import XCTest +enum AppleSystemUIFont { + static var familyName: String { ".AppleSystemUIFont" } + static var fontName: String { + #if os(visionOS) + return ".SFUI-Bold" + #else + return ".SFUI-Semibold" + #endif + } + + static var pointSize: CGFloat { + #if os(visionOS) + return 12.0 + #else + return 17.0 + #endif + } +} + final class UIFontTests: XCTestCase { override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. @@ -22,20 +41,37 @@ final class UIFontTests: XCTestCase { - weight: nil provider = TextStyleProvider */ + @available(visionOS, unavailable) func testSystemStyleFont() throws { - let font = Font.headline - let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) - let fd = resolvedFont.fontDescriptor + #if os(visionOS) + let font = Font.headline + let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) + let fd = resolvedFont.fontDescriptor - XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") - XCTAssertEqual(resolvedFont.fontName, ".SFUI-Semibold") - XCTAssertEqual(resolvedFont.pointSize, 17.0) - if let style = fd.fontAttributes[.textStyle] as? NSString { - XCTAssertEqual(style, "UICTFontTextStyleHeadline") - } - if let fontSize = fd.fontAttributes[.size] as? NSNumber { - XCTAssertEqual(fontSize, 17) - } + XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") + XCTAssertEqual(resolvedFont.fontName, ".SFUI-Bold") + XCTAssertEqual(resolvedFont.pointSize, 12.0) + if let style = fd.fontAttributes[.textStyle] as? NSString { + XCTAssertEqual(style, "UICTFontTextStyleHeadline") + } + if let fontSize = fd.fontAttributes[.size] as? NSNumber { + XCTAssertEqual(fontSize, 12) + } + #else + let font = Font.headline + let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) + let fd = resolvedFont.fontDescriptor + + XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") + XCTAssertEqual(resolvedFont.fontName, ".SFUI-Semibold") + XCTAssertEqual(resolvedFont.pointSize, 17.0) + if let style = fd.fontAttributes[.textStyle] as? NSString { + XCTAssertEqual(style, "UICTFontTextStyleHeadline") + } + if let fontSize = fd.fontAttributes[.size] as? NSNumber { + XCTAssertEqual(fontSize, 17) + } + #endif } /** @@ -54,31 +90,91 @@ final class UIFontTests: XCTestCase { provider = TextStyleProvider */ func testSystemStyleItalicFont() throws { - let font = Font.headline.italic() - let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) - let fd = resolvedFont.fontDescriptor + #if os(visionOS) + let font = Font.headline.italic() + let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) + let fd = resolvedFont.fontDescriptor - XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") - XCTAssertEqual(resolvedFont.fontName, ".SFUI-SemiboldItalic") - XCTAssertEqual(resolvedFont.pointSize, 17.0) - if let style = fd.fontAttributes[.textStyle] as? NSString { - XCTAssertEqual(style, "UICTFontTextStyleItalicHeadline") - } - if let fontSize = fd.fontAttributes[.size] as? NSNumber { - XCTAssertEqual(fontSize, 17) - } + XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") + XCTAssertEqual(resolvedFont.fontName, ".SFUI-BoldItalic") + XCTAssertEqual(resolvedFont.pointSize, 12.0) + if let style = fd.fontAttributes[.textStyle] as? NSString { + XCTAssertEqual(style, "UICTFontTextStyleItalicHeadline") + } + if let fontSize = fd.fontAttributes[.size] as? NSNumber { + XCTAssertEqual(fontSize, 12) + } + #else + let font = Font.headline.italic() + let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) + let fd = resolvedFont.fontDescriptor + + XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") + XCTAssertEqual(resolvedFont.fontName, ".SFUI-SemiboldItalic") + XCTAssertEqual(resolvedFont.pointSize, 17.0) + if let style = fd.fontAttributes[.textStyle] as? NSString { + XCTAssertEqual(style, "UICTFontTextStyleItalicHeadline") + } + if let fontSize = fd.fontAttributes[.size] as? NSNumber { + XCTAssertEqual(fontSize, 17) + } + #endif + } + + func testSystemStyleItalicFontOnVisionOS() throws { + #if os(visionOS) + let font = Font.headline.italic() + let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) + let fd = resolvedFont.fontDescriptor + + XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") + XCTAssertEqual(resolvedFont.fontName, ".SFUI-BoldItalic") + XCTAssertEqual(resolvedFont.pointSize, 12.0) + if let style = fd.fontAttributes[.textStyle] as? NSString { + XCTAssertEqual(style, "UICTFontTextStyleItalicHeadline") + } + if let fontSize = fd.fontAttributes[.size] as? NSNumber { + XCTAssertEqual(fontSize, 12) + } + #else + let font = Font.headline.italic() + let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) + let fd = resolvedFont.fontDescriptor + + XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") + XCTAssertEqual(resolvedFont.fontName, ".SFUI-SemiboldItalic") + XCTAssertEqual(resolvedFont.pointSize, 17.0) + if let style = fd.fontAttributes[.textStyle] as? NSString { + XCTAssertEqual(style, "UICTFontTextStyleItalicHeadline") + } + if let fontSize = fd.fontAttributes[.size] as? NSNumber { + XCTAssertEqual(fontSize, 17) + } + #endif } func testSystemStyleItalicBoldFont() throws { - let font = Font.headline.italic().bold() - let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) - let fd = resolvedFont.fontDescriptor + #if os(visionOS) + let font = Font.headline.italic().bold() + let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) + let fd = resolvedFont.fontDescriptor - XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") - XCTAssertEqual(resolvedFont.fontName, ".SFUI-Semibold") - if let fontSize = fd.fontAttributes[.size] as? NSNumber { - XCTAssertEqual(fontSize, 17) - } + XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") + XCTAssertEqual(resolvedFont.fontName, ".SFUI-Black") + if let fontSize = fd.fontAttributes[.size] as? NSNumber { + XCTAssertEqual(fontSize, 12) + } + #else + let font = Font.headline.italic().bold() + let resolvedFont = UIFont.resolveFont(font)?.font(with: nil) ?? UIFont.preferredFont(forTextStyle: .footnote) + let fd = resolvedFont.fontDescriptor + + XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") + XCTAssertEqual(resolvedFont.fontName, ".SFUI-Semibold") + if let fontSize = fd.fontAttributes[.size] as? NSNumber { + XCTAssertEqual(fontSize, 17) + } + #endif } /** @@ -112,12 +208,20 @@ final class UIFontTests: XCTestCase { XCTAssertEqual(resolvedFont.familyName, ".AppleSystemUIFont") XCTAssertEqual(resolvedFont.fontName, ".SFUI-BlackItalic") - XCTAssertEqual(resolvedFont.pointSize, 20.0) + #if os(visionOS) + XCTAssertEqual(resolvedFont.pointSize, 14.0) + #else + XCTAssertEqual(resolvedFont.pointSize, 20.0) + #endif if let style = fd.fontAttributes[.textStyle] as? NSString { XCTAssertEqual(style, "UICTFontTextStyleItalicTitle3") } if let fontSize = fd.fontAttributes[.size] as? NSNumber { - XCTAssertEqual(fontSize, 20) + #if os(visionOS) + XCTAssertEqual(fontSize, 14) + #else + XCTAssertEqual(fontSize, 20) + #endif } } diff --git a/Tests/FioriSwiftUITests/FioriThemeManager/StyleSheetSettingsIntegrationTests.swift b/Tests/FioriSwiftUITests/FioriThemeManager/StyleSheetSettingsIntegrationTests.swift index 7b52ff8c8..b5c3d310c 100644 --- a/Tests/FioriSwiftUITests/FioriThemeManager/StyleSheetSettingsIntegrationTests.swift +++ b/Tests/FioriSwiftUITests/FioriThemeManager/StyleSheetSettingsIntegrationTests.swift @@ -54,7 +54,7 @@ class StyleSheetSettingsIntegrationTests: XCTestCase { XCTAssertNoThrow(try? StyleSheetSettings.loadStylesheetByString(content: sampleStyleSheetContent)) - #if os(iOS) + #if os(iOS) || os(visionOS) XCTAssertNotEqual(originalColor.resolvedColor(with: .light).uiColor(), Color.preferredColor(.primaryLabel).uiColor(), "Color.preferredColor should return the color specified in the styleSheet") #else XCTAssertNotEqual(originalColor.uiColor(), Color.preferredColor(.primaryLabel).uiColor(), "Color.preferredColor should return the color specified in the styleSheet") @@ -68,7 +68,7 @@ class StyleSheetSettingsIntegrationTests: XCTestCase { XCTAssertNoThrow(try? StyleSheetSettings.loadStylesheetByURL(url: Bundle.module.url(forResource: "styleSheet", withExtension: "nss")!)) - #if os(iOS) + #if os(iOS) || os(visionOS) XCTAssertNotEqual(originalColor.resolvedColor(with: .light).uiColor(), Color.preferredColor(.primaryLabel).uiColor(), "Color.preferredColor should return the color specified in the styleSheet") #else XCTAssertNotEqual(originalColor.uiColor(), Color.preferredColor(.primaryLabel).uiColor(), "Color.preferredColor should return the color specified in the styleSheet") From 3aef5b3d5efd73fce14d54d4d766f2153130bfe5 Mon Sep 17 00:00:00 2001 From: CharlesXu0488 <104950838+CharlesXu0488@users.noreply.github.com> Date: Tue, 9 Jan 2024 19:12:13 -0800 Subject: [PATCH 2/3] fix: format update CoreContentView.swift --- Apps/Examples/Examples/FioriSwiftUICore/CoreContentView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Apps/Examples/Examples/FioriSwiftUICore/CoreContentView.swift b/Apps/Examples/Examples/FioriSwiftUICore/CoreContentView.swift index 5d805916f..fc5e78084 100644 --- a/Apps/Examples/Examples/FioriSwiftUICore/CoreContentView.swift +++ b/Apps/Examples/Examples/FioriSwiftUICore/CoreContentView.swift @@ -125,7 +125,6 @@ struct CoreContentView: View { NavigationLink(destination: SearchDemos()) { Text("Search Demos") } - } }.navigationBarTitle("FioriSwiftUICore") } From 6961b6308b5215a9486498580d1c4a44a21a4f5c Mon Sep 17 00:00:00 2001 From: CharlesXu0488 <104950838+CharlesXu0488@users.noreply.github.com> Date: Tue, 9 Jan 2024 19:13:31 -0800 Subject: [PATCH 3/3] fix: format ColorEntity.swift --- .../Examples/FioriSwiftUICore/SearchBar/ColorEntity.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Apps/Examples/Examples/FioriSwiftUICore/SearchBar/ColorEntity.swift b/Apps/Examples/Examples/FioriSwiftUICore/SearchBar/ColorEntity.swift index b26719881..d21aa564f 100644 --- a/Apps/Examples/Examples/FioriSwiftUICore/SearchBar/ColorEntity.swift +++ b/Apps/Examples/Examples/FioriSwiftUICore/SearchBar/ColorEntity.swift @@ -106,7 +106,6 @@ struct ColorEntity: Identifiable { } } } - } struct ColorToken: Identifiable {