Skip to content

Commit

Permalink
Merge branch 'HCPSDKFIORIUIKIT-2461' of github.com:CharlesXu0488/clou…
Browse files Browse the repository at this point in the history
…d-sdk-ios-fiori into HCPSDKFIORIUIKIT-2461
  • Loading branch information
CharlesXu0488 committed Jan 10, 2024
2 parents a581538 + 6961b63 commit d2312ac
Show file tree
Hide file tree
Showing 19 changed files with 251 additions and 99 deletions.
15 changes: 12 additions & 3 deletions Apps/Examples/Examples.xcodeproj/project.pbxproj
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -892,6 +892,7 @@
/* Begin PBXTargetDependency section */
1F6017A029A8439C00DBDCDE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
platformFilter = ios;
target = 1F60179329A8439A00DBDCDE /* WatchExamples Watch App */;
targetProxy = 1F60179F29A8439C00DBDCDE /* PBXContainerItemProxy */;
};
Expand Down Expand Up @@ -1106,8 +1107,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;
};
Expand All @@ -1128,8 +1133,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;
};
Expand Down
Expand Up @@ -125,7 +125,6 @@ struct CoreContentView: View {
NavigationLink(destination: SearchDemos()) {
Text("Search Demos")
}

}
}.navigationBarTitle("FioriSwiftUICore")
}
Expand Down
Expand Up @@ -106,7 +106,6 @@ struct ColorEntity: Identifiable {
}
}
}

}

struct ColorToken: Identifiable {
Expand Down
Expand Up @@ -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
10 changes: 5 additions & 5 deletions Package.swift
@@ -1,12 +1,12 @@
// 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

let package = Package(
name: "FioriSwiftUI",
defaultLocalization: "en",
platforms: [.iOS(.v16), .watchOS(.v7)],
platforms: [.iOS(.v16), .watchOS(.v7), .visionOS(.v1)],
products: [
.library(
name: "FioriSwiftUI",
Expand All @@ -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",
Expand All @@ -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")]
),
Expand Down
6 changes: 3 additions & 3 deletions README.md
Expand Up @@ -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.

Expand All @@ -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.

Expand Down Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion Sources/FioriCharts/Extensions/String+Extensions.swift
Expand Up @@ -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)
Expand Down
Expand Up @@ -37,7 +37,7 @@ struct CancellableResettableDialogForm<Title: View, CancelAction: View, ResetAct
components
applyAction
}
.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, .bottom], UIDevice.current.userInterfaceIdiom == .pad ? 13 : 16)
}
}
Expand All @@ -49,7 +49,7 @@ struct ApplyButtonStyle: PrimitiveButtonStyle {
if self.isEnabled {
configuration.label
.frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2 :
UIScreen.main.bounds.size.width - 16 * 2)
Screen.bounds.size.width - 16 * 2)
.padding([.top, .bottom], 8)
.font(.body)
.fontWeight(.bold)
Expand All @@ -62,7 +62,7 @@ struct ApplyButtonStyle: PrimitiveButtonStyle {
} else {
configuration.label
.frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375 - 13 * 2 :
UIScreen.main.bounds.size.width - 16 * 2)
Screen.bounds.size.width - 16 * 2)
.padding([.top, .bottom], 8)
.font(.body)
.fontWeight(.bold)
Expand Down
22 changes: 12 additions & 10 deletions Sources/FioriSwiftUICore/DataTable/DataTable.swift
Expand Up @@ -49,7 +49,7 @@ public struct DataTable: View {
self.layoutManager = TableLayoutManager(model: model)
}
}

/// Body of the View
public var body: some View {
GeometryReader { proxy in
Expand All @@ -75,7 +75,7 @@ public struct DataTable: View {
}
}
}

if !self.model.showListView {
ScrollAndZoomView(layoutManager: self.layoutManager, size: rect.size)
}
Expand All @@ -90,14 +90,16 @@ public struct DataTable: View {
self.layoutManager.keyboardFrame = .zero
self.layoutManager.keyboardHeight = 0
}
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
// save text changes
self.layoutManager.saveEditingTextChange()
#if !os(visionOS)
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
// save text changes
self.layoutManager.saveEditingTextChange()

if self.layoutManager.currentCell != nil {
self.layoutManager.currentCell = nil
if self.layoutManager.currentCell != nil {
self.layoutManager.currentCell = nil
}
}
}
#endif
.onChange(of: self.dynamicTypeSize) { newValue in
self.layoutManager.dynamicTypeSize = newValue
self.layoutManager.cacheLayoutDataForMeasurement = nil
Expand Down Expand Up @@ -153,7 +155,7 @@ public extension DataTable {
@available(*, deprecated)
func editingMode(_ value: Bool = false) -> DataTable {
self.model.isEditing = value

return self
}

Expand Down Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion Sources/FioriSwiftUICore/DataTable/InlineEditingView.swift
Expand Up @@ -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]
Expand Down Expand Up @@ -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 {
Expand Down
Expand Up @@ -25,10 +25,12 @@ struct PopoverModifier<PopView: View>: ViewModifier {
popover.dismiss()
}
}
#if !os(visionOS)
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
guard let popover = popover else { return }
popover.dismiss()
}
#endif
}
}
}
22 changes: 22 additions & 0 deletions 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
}
}
18 changes: 12 additions & 6 deletions Sources/FioriSwiftUICore/Views/KPIHeader/KPIHeaderContent.swift
Expand Up @@ -116,12 +116,18 @@ extension KPIHeaderContent {
}

private var resizePublisher: AnyPublisher<Void, Never> {
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 {
Expand Down
Expand Up @@ -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
Expand Down

0 comments on commit d2312ac

Please sign in to comment.