Skip to content

Commit 75b24eb

Browse files
authored
feat: 🎸 [JIRA:HCPSDKFIORIUIKIT-2806] Processing Indicator (SAP#906)
* feat: 🎸 [JIRA:HCPSDKFIORIUIKIT-2806] Processing Indicator * test: 💍 change optional title value
1 parent c537d85 commit 75b24eb

File tree

14 files changed

+361
-1
lines changed

14 files changed

+361
-1
lines changed

Apps/Examples/Examples.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
3CDD6ECD2CE4277300DDAE7D /* CheckoutIndicatorModalExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDD6ECC2CE4277300DDAE7D /* CheckoutIndicatorModalExample.swift */; };
3232
55598FAD2CDDB4F6007CFFBB /* ValuePickerExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55598FAC2CDDB4F6007CFFBB /* ValuePickerExample.swift */; };
3333
6432FFA02C5164F8008ECE89 /* SegmentedControlExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432FF9F2C5164F8008ECE89 /* SegmentedControlExample.swift */; };
34+
6439F5142CEE892200EF1B42 /* ProcessingIndicatorExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439F5132CEE892200EF1B42 /* ProcessingIndicatorExample.swift */; };
3435
64905D072C6D13E20062AAD4 /* SwitchExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64905D062C6D13E20062AAD4 /* SwitchExample.swift */; };
3536
64905D092C7693970062AAD4 /* DateTimePickerExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64905D082C7693970062AAD4 /* DateTimePickerExample.swift */; };
3637
649C7F482CE531C8007B78A7 /* ProgressIndicatorExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649C7F472CE531C5007B78A7 /* ProgressIndicatorExample.swift */; };
@@ -251,6 +252,7 @@
251252
3CDD6ECC2CE4277300DDAE7D /* CheckoutIndicatorModalExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckoutIndicatorModalExample.swift; sourceTree = "<group>"; };
252253
55598FAC2CDDB4F6007CFFBB /* ValuePickerExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValuePickerExample.swift; sourceTree = "<group>"; };
253254
6432FF9F2C5164F8008ECE89 /* SegmentedControlExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedControlExample.swift; sourceTree = "<group>"; };
255+
6439F5132CEE892200EF1B42 /* ProcessingIndicatorExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessingIndicatorExample.swift; sourceTree = "<group>"; };
254256
64905D062C6D13E20062AAD4 /* SwitchExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchExample.swift; sourceTree = "<group>"; };
255257
64905D082C7693970062AAD4 /* DateTimePickerExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimePickerExample.swift; sourceTree = "<group>"; };
256258
649C7F472CE531C5007B78A7 /* ProgressIndicatorExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressIndicatorExample.swift; sourceTree = "<group>"; };
@@ -752,6 +754,7 @@
752754
649C7F472CE531C5007B78A7 /* ProgressIndicatorExample.swift */,
753755
99658F872B7C359D0026A743 /* LinearProgressIndicatorExample.swift */,
754756
A65036932CC6365C0093086A /* LoadingIndicatorExample.swift */,
757+
6439F5132CEE892200EF1B42 /* ProcessingIndicatorExample.swift */,
755758
);
756759
path = Indicator;
757760
sourceTree = "<group>";
@@ -1250,6 +1253,7 @@
12501253
6D6E866F2C539CDE00EDB6F4 /* InPlaceLoadingFlexibleButtonExample.swift in Sources */,
12511254
B1F384322C815A540090A858 /* AvatarStackExample.swift in Sources */,
12521255
B1BCB6E12C2EB362008AC070 /* ProfileHeaderStaticExample.swift in Sources */,
1256+
6439F5142CEE892200EF1B42 /* ProcessingIndicatorExample.swift in Sources */,
12531257
C1C764882A818BEC00BCB0F7 /* SortFilterExample.swift in Sources */,
12541258
64905D072C6D13E20062AAD4 /* SwitchExample.swift in Sources */,
12551259
B1F6FC302B22BDDA005190F9 /* ToolbarView.swift in Sources */,

Apps/Examples/Examples/FioriSwiftUICore/CoreContentView.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ struct CoreContentView: View {
277277
{
278278
Text("Progress Indicator")
279279
}
280+
281+
NavigationLink(
282+
destination: ProcessingIndicatorExample())
283+
{
284+
Text("Processing Indicator")
285+
}
280286
}
281287

282288
Section(header: Text("Navigation Bar")) {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import FioriSwiftUICore
2+
import FioriThemeManager
3+
import SwiftUI
4+
5+
struct Blur: UIViewRepresentable {
6+
var style: UIBlurEffect.Style = .extraLight
7+
func makeUIView(context: Context) -> UIVisualEffectView {
8+
let view = UIVisualEffectView(effect: UIBlurEffect(style: .extraLight))
9+
DispatchQueue.main.async {
10+
view.superview?.superview?.backgroundColor = .clear
11+
}
12+
return view
13+
}
14+
15+
func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
16+
uiView.effect = UIBlurEffect(style: self.style)
17+
}
18+
}
19+
20+
struct ProcessingIndicatorExample: View {
21+
@State var labelText: String = "Processing"
22+
@State var showModalIndicator: Bool = false
23+
@State var showInContainer: Bool = false
24+
25+
var body: some View {
26+
VStack {
27+
Spacer()
28+
Button("Show modal indicator", action: {
29+
self.showModalIndicator.toggle()
30+
})
31+
Button("Show/hide in container", action: {
32+
self.showInContainer.toggle()
33+
})
34+
TextFieldFormView(title: "Set label", text: self.$labelText).padding()
35+
ProcessingIndicator(optionalTitle: AttributedString(self.labelText))
36+
Spacer()
37+
if self.showInContainer {
38+
Image("rw")
39+
.overlay(ProcessingIndicator()
40+
.frame(maxWidth: 130, maxHeight: 130)
41+
.background(Color.white.opacity(0.7))
42+
)
43+
} else {
44+
Image("rw")
45+
}
46+
Spacer()
47+
}
48+
.padding()
49+
.fullScreenCover(isPresented: self.$showModalIndicator, content: {
50+
VStack {
51+
ProcessingIndicator(optionalTitle: AttributedString(self.labelText))
52+
.frame(maxWidth: .infinity, maxHeight: .infinity)
53+
.background(Color.clear)
54+
Button("Dismiss", action: {
55+
self.showModalIndicator.toggle()
56+
})
57+
}
58+
.background(Blur())
59+
})
60+
}
61+
}
62+
63+
struct ProcessingIndicatorExample_Previews: PreviewProvider {
64+
static var previews: some View {
65+
ProcessingIndicatorExample()
66+
}
67+
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ We plan to progressively bring more Fiori UI components into this module in the
115115
| Calendar | :x: |
116116
| Search To Select | :x: |
117117
| Progress Indicator | :white_check_mark: |
118-
| Processing Indicator | :x: |
118+
| Processing Indicator | :white_check_mark: |
119119
| Checkout Indicator | :white_check_mark: |
120120
| Loading Indicator | :white_check_mark: |
121121
| Feedback Screen | :x: |

Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,3 +717,12 @@ protocol _ValuePickerComponent: _TitleComponent, _ValueLabelComponent, _Mandator
717717
/// ```
718718
// sourcery: CompositeComponent
719719
protocol _ProgressIndicatorComponent: _ProgressIndicatorProtocol {}
720+
721+
/// `ProcessingIndicator` provides a circular indeterminate indicator with an optional title below the indicator.
722+
///
723+
/// ## Usage
724+
/// ```swift
725+
/// ProcessingIndicator(optionalTitle: "Processing")
726+
/// ```
727+
// sourcery: CompositeComponent
728+
protocol _ProcessingIndicatorComponent: _OptionalTitleComponent {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import FioriThemeManager
2+
3+
// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery
4+
// DO NOT EDIT
5+
import Foundation
6+
import SwiftUI
7+
8+
// Base Layout style
9+
public struct ProcessingIndicatorBaseStyle: ProcessingIndicatorStyle {
10+
struct ProcessingIndicatorStyle: ProgressIndicatorStyle {
11+
func makeBody(_ configuration: ProgressIndicatorConfiguration) -> some View {
12+
ProgressIndicator(configuration)
13+
.frame(width: 56, height: 56)
14+
}
15+
}
16+
17+
public func makeBody(_ configuration: ProcessingIndicatorConfiguration) -> some View {
18+
VStack {
19+
ProgressIndicator(progress: Binding<Double>.constant(0.0))
20+
.progressIndicatorStyle(ProcessingIndicatorStyle())
21+
.progressIndicatorStyle(.processing)
22+
if !configuration.optionalTitle.isEmpty {
23+
configuration.optionalTitle
24+
.offset(y: 15)
25+
}
26+
}.padding()
27+
}
28+
}
29+
30+
// Default fiori styles
31+
extension ProcessingIndicatorFioriStyle {
32+
struct ContentFioriStyle: ProcessingIndicatorStyle {
33+
func makeBody(_ configuration: ProcessingIndicatorConfiguration) -> some View {
34+
ProcessingIndicator(configuration)
35+
}
36+
}
37+
38+
struct OptionalTitleFioriStyle: OptionalTitleStyle {
39+
let processingIndicatorConfiguration: ProcessingIndicatorConfiguration
40+
41+
func makeBody(_ configuration: OptionalTitleConfiguration) -> some View {
42+
OptionalTitle(configuration)
43+
.foregroundStyle(Color.preferredColor(.primaryLabel))
44+
.font(.fiori(fixedSize: 12))
45+
}
46+
}
47+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery
2+
// DO NOT EDIT
3+
import Foundation
4+
import SwiftUI
5+
6+
/// `ProcessingIndicator` provides a circular indeterminate indicator with an optional title below the indicator.
7+
///
8+
/// ## Usage
9+
/// ```swift
10+
/// ProcessingIndicator(optionalTitle: "Processing")
11+
/// ```
12+
public struct ProcessingIndicator {
13+
let optionalTitle: any View
14+
15+
@Environment(\.processingIndicatorStyle) var style
16+
17+
fileprivate var _shouldApplyDefaultStyle = true
18+
19+
public init(@ViewBuilder optionalTitle: () -> any View = { EmptyView() }) {
20+
self.optionalTitle = OptionalTitle(optionalTitle: optionalTitle)
21+
}
22+
}
23+
24+
public extension ProcessingIndicator {
25+
init(optionalTitle: AttributedString?) {
26+
self.init(optionalTitle: { OptionalText(optionalTitle) })
27+
}
28+
}
29+
30+
public extension ProcessingIndicator {
31+
init(_ configuration: ProcessingIndicatorConfiguration) {
32+
self.init(configuration, shouldApplyDefaultStyle: false)
33+
}
34+
35+
internal init(_ configuration: ProcessingIndicatorConfiguration, shouldApplyDefaultStyle: Bool) {
36+
self.optionalTitle = configuration.optionalTitle
37+
self._shouldApplyDefaultStyle = shouldApplyDefaultStyle
38+
}
39+
}
40+
41+
extension ProcessingIndicator: View {
42+
public var body: some View {
43+
if self._shouldApplyDefaultStyle {
44+
self.defaultStyle()
45+
} else {
46+
self.style.resolve(configuration: .init(optionalTitle: .init(self.optionalTitle))).typeErased
47+
.transformEnvironment(\.processingIndicatorStyleStack) { stack in
48+
if !stack.isEmpty {
49+
stack.removeLast()
50+
}
51+
}
52+
}
53+
}
54+
}
55+
56+
private extension ProcessingIndicator {
57+
func shouldApplyDefaultStyle(_ bool: Bool) -> some View {
58+
var s = self
59+
s._shouldApplyDefaultStyle = bool
60+
return s
61+
}
62+
63+
func defaultStyle() -> some View {
64+
ProcessingIndicator(.init(optionalTitle: .init(self.optionalTitle)))
65+
.shouldApplyDefaultStyle(false)
66+
.processingIndicatorStyle(ProcessingIndicatorFioriStyle.ContentFioriStyle())
67+
.typeErased
68+
}
69+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery
2+
// DO NOT EDIT
3+
import Foundation
4+
import SwiftUI
5+
6+
public protocol ProcessingIndicatorStyle: DynamicProperty {
7+
associatedtype Body: View
8+
9+
func makeBody(_ configuration: ProcessingIndicatorConfiguration) -> Body
10+
}
11+
12+
struct AnyProcessingIndicatorStyle: ProcessingIndicatorStyle {
13+
let content: (ProcessingIndicatorConfiguration) -> any View
14+
15+
init(@ViewBuilder _ content: @escaping (ProcessingIndicatorConfiguration) -> any View) {
16+
self.content = content
17+
}
18+
19+
public func makeBody(_ configuration: ProcessingIndicatorConfiguration) -> some View {
20+
self.content(configuration).typeErased
21+
}
22+
}
23+
24+
public struct ProcessingIndicatorConfiguration {
25+
public let optionalTitle: OptionalTitle
26+
27+
public typealias OptionalTitle = ConfigurationViewWrapper
28+
}
29+
30+
public struct ProcessingIndicatorFioriStyle: ProcessingIndicatorStyle {
31+
public func makeBody(_ configuration: ProcessingIndicatorConfiguration) -> some View {
32+
ProcessingIndicator(configuration)
33+
.optionalTitleStyle(OptionalTitleFioriStyle(processingIndicatorConfiguration: configuration))
34+
}
35+
}

Sources/FioriSwiftUICore/_generated/SupportingFiles/ComponentStyleProtocol+Extension.generated.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3657,6 +3657,41 @@ public extension PlaceholderTextFieldStyle where Self == PlaceholderTextFieldPla
36573657
}
36583658
}
36593659

3660+
// MARK: ProcessingIndicatorStyle
3661+
3662+
public extension ProcessingIndicatorStyle where Self == ProcessingIndicatorBaseStyle {
3663+
static var base: ProcessingIndicatorBaseStyle {
3664+
ProcessingIndicatorBaseStyle()
3665+
}
3666+
}
3667+
3668+
public extension ProcessingIndicatorStyle where Self == ProcessingIndicatorFioriStyle {
3669+
static var fiori: ProcessingIndicatorFioriStyle {
3670+
ProcessingIndicatorFioriStyle()
3671+
}
3672+
}
3673+
3674+
public struct ProcessingIndicatorOptionalTitleStyle: ProcessingIndicatorStyle {
3675+
let style: any OptionalTitleStyle
3676+
3677+
public func makeBody(_ configuration: ProcessingIndicatorConfiguration) -> some View {
3678+
ProcessingIndicator(configuration)
3679+
.optionalTitleStyle(self.style)
3680+
.typeErased
3681+
}
3682+
}
3683+
3684+
public extension ProcessingIndicatorStyle where Self == ProcessingIndicatorOptionalTitleStyle {
3685+
static func optionalTitleStyle(_ style: some OptionalTitleStyle) -> ProcessingIndicatorOptionalTitleStyle {
3686+
ProcessingIndicatorOptionalTitleStyle(style: style)
3687+
}
3688+
3689+
static func optionalTitleStyle(@ViewBuilder content: @escaping (OptionalTitleConfiguration) -> some View) -> ProcessingIndicatorOptionalTitleStyle {
3690+
let style = AnyOptionalTitleStyle(content)
3691+
return ProcessingIndicatorOptionalTitleStyle(style: style)
3692+
}
3693+
}
3694+
36603695
// MARK: ProfileHeaderStyle
36613696

36623697
public extension ProfileHeaderStyle where Self == ProfileHeaderBaseStyle {

Sources/FioriSwiftUICore/_generated/SupportingFiles/EnvironmentVariables.generated.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,27 @@ extension EnvironmentValues {
14521452
}
14531453
}
14541454

1455+
// MARK: ProcessingIndicatorStyle
1456+
1457+
struct ProcessingIndicatorStyleStackKey: EnvironmentKey {
1458+
static let defaultValue: [any ProcessingIndicatorStyle] = []
1459+
}
1460+
1461+
extension EnvironmentValues {
1462+
var processingIndicatorStyle: any ProcessingIndicatorStyle {
1463+
self.processingIndicatorStyleStack.last ?? .base.concat(.fiori)
1464+
}
1465+
1466+
var processingIndicatorStyleStack: [any ProcessingIndicatorStyle] {
1467+
get {
1468+
self[ProcessingIndicatorStyleStackKey.self]
1469+
}
1470+
set {
1471+
self[ProcessingIndicatorStyleStackKey.self] = newValue
1472+
}
1473+
}
1474+
}
1475+
14551476
// MARK: ProfileHeaderStyle
14561477

14571478
struct ProfileHeaderStyleStackKey: EnvironmentKey {

0 commit comments

Comments
 (0)