Skip to content

Commit

Permalink
feat: 🎸 [JIRA:HCPSDKFIORIUIKIT-1933]SwiftUI Timeline (#734)
Browse files Browse the repository at this point in the history
* feat: 🎸 [JIRA:HCPSDKFIORIUIKIT-1933]SwiftUI Timeline

* feat: 🎸 Fixed swift scan issues

* feat: 🎸 [JIRA:HCPSDKFIORIUIKIT-1933]SwiftUI Timeline

* feat: 🎸 address review comments

* feat: 🎸 Address comments

* feat: 🎸 address hound comments

* feat: 🎸 addressed new coomments

---------

Co-authored-by: Bill Zhou <bill.zhou01@sap.com>
  • Loading branch information
zzchao-1999 and billzhou0223 authored Jul 18, 2024
1 parent 2c47cd3 commit d457091
Show file tree
Hide file tree
Showing 42 changed files with 3,212 additions and 1 deletion.
25 changes: 25 additions & 0 deletions Apps/Examples/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
691DE21925F2A30B00094D4A /* KPIViewExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691DE21825F2A30B00094D4A /* KPIViewExample.swift */; };
692F338B26556A6A009B98DA /* SideBarExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692F338A26556A6A009B98DA /* SideBarExample.swift */; };
69B2B5D9268A333C009AC6B3 /* KPIProgressViewExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69B2B5D8268A333C009AC6B3 /* KPIProgressViewExample.swift */; };
8732C2C52C350957002110E9 /* TimelineExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8732C2C42C350957002110E9 /* TimelineExample.swift */; };
8732C2C72C3524B6002110E9 /* TimelineItemsExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8732C2C62C3524B6002110E9 /* TimelineItemsExample.swift */; };
8732C2C92C3524C9002110E9 /* SimpleTimelineExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8732C2C82C3524C9002110E9 /* SimpleTimelineExample.swift */; };
8732C2CB2C3524D9002110E9 /* CustomTimelineExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8732C2CA2C3524D9002110E9 /* CustomTimelineExample.swift */; };
878219C42BEE128E002FDFBC /* StepperViewExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 878219C32BEE128E002FDFBC /* StepperViewExample.swift */; };
8A55795724C1286E0098003A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A55795624C1286E0098003A /* AppDelegate.swift */; };
8A55795924C1286E0098003A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A55795824C1286E0098003A /* SceneDelegate.swift */; };
Expand Down Expand Up @@ -212,6 +216,10 @@
691DE21825F2A30B00094D4A /* KPIViewExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KPIViewExample.swift; sourceTree = "<group>"; };
692F338A26556A6A009B98DA /* SideBarExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideBarExample.swift; sourceTree = "<group>"; };
69B2B5D8268A333C009AC6B3 /* KPIProgressViewExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KPIProgressViewExample.swift; sourceTree = "<group>"; };
8732C2C42C350957002110E9 /* TimelineExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineExample.swift; sourceTree = "<group>"; };
8732C2C62C3524B6002110E9 /* TimelineItemsExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemsExample.swift; sourceTree = "<group>"; };
8732C2C82C3524C9002110E9 /* SimpleTimelineExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleTimelineExample.swift; sourceTree = "<group>"; };
8732C2CA2C3524D9002110E9 /* CustomTimelineExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimelineExample.swift; sourceTree = "<group>"; };
878219C32BEE128E002FDFBC /* StepperViewExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepperViewExample.swift; sourceTree = "<group>"; };
8A1E99AD24D59C8000ED8A39 /* cloud-sdk-ios-fiori */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "cloud-sdk-ios-fiori"; path = ../..; sourceTree = "<group>"; };
8A55795324C1286E0098003A /* Examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Examples.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -460,6 +468,17 @@
path = SideBar;
sourceTree = "<group>";
};
8732C2C32C35092D002110E9 /* Timeline */ = {
isa = PBXGroup;
children = (
8732C2C42C350957002110E9 /* TimelineExample.swift */,
8732C2C62C3524B6002110E9 /* TimelineItemsExample.swift */,
8732C2C82C3524C9002110E9 /* SimpleTimelineExample.swift */,
8732C2CA2C3524D9002110E9 /* CustomTimelineExample.swift */,
);
path = Timeline;
sourceTree = "<group>";
};
8A55794A24C1286E0098003A = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -531,6 +550,7 @@
8A5579C824C1293C0098003A /* FioriSwiftUICore */ = {
isa = PBXGroup;
children = (
8732C2C32C35092D002110E9 /* Timeline */,
B19006582C201BAC000C8B10 /* ProfileHeader */,
1F1A1FF82C0BDA42007109D8 /* MenuSelection */,
B1A98FF02C11591B00FC9998 /* BannerMessage */,
Expand Down Expand Up @@ -966,6 +986,7 @@
1FC30414270541BF004BEE00 /* FioriThemeManagerContentView.swift in Sources */,
C106AD422B336EA400FE8B35 /* SearchWithSuggestion.swift in Sources */,
99942D59261698FC001912C5 /* InfoViewSample.swift in Sources */,
8732C2C72C3524B6002110E9 /* TimelineItemsExample.swift in Sources */,
993B55BE29DF7EC70002B065 /* IconLibraryExample.swift in Sources */,
B80DA9BE260C1CC200C0B2E9 /* ListDataProtocol.swift in Sources */,
B1DD86532B0758F000D7EDFD /* NavigationBarPopover.swift in Sources */,
Expand Down Expand Up @@ -993,6 +1014,8 @@
8A5579CC24C1293C0098003A /* SettingsColorForCategory.swift in Sources */,
C18868D12B32535100F865F7 /* SearchFontAndColor.swift in Sources */,
9D0B26092B9BA5C0004278A5 /* KeyValueFormViewExample.swift in Sources */,
8732C2C52C350957002110E9 /* TimelineExample.swift in Sources */,
9D057DAB2C2F260200F5331C /* RatingControlExample.swift in Sources */,
8A557A1A24C12C820098003A /* ChartsContentView.swift in Sources */,
8A5579CE24C1293C0098003A /* SettingColor.swift in Sources */,
1F55FEF32AC941FF00D7A1BE /* View+Extensions.swift in Sources */,
Expand All @@ -1010,6 +1033,7 @@
B8D4376F25F980340024EE7D /* ObjectCell_Spec_Jan2018.swift in Sources */,
8A5579CF24C1293C0098003A /* SettingsAxis.swift in Sources */,
B80DA9BC260BED9400C0B2E9 /* SingleActionCollectionView.swift in Sources */,
8732C2CB2C3524D9002110E9 /* CustomTimelineExample.swift in Sources */,
8A5579D924C1293C0098003A /* SettingsSelection.swift in Sources */,
B1A98FF22C11592B00FC9998 /* BannerMessageExample.swift in Sources */,
B80DA9C62612A54E00C0B2E9 /* ActivationScreenSample.swift in Sources */,
Expand Down Expand Up @@ -1049,6 +1073,7 @@
975CB76B256C5A7400DB7A15 /* SignatureCaptureViewExample.swift in Sources */,
8AD9DFB125D49967007448EC /* ContactItemStateAndDataBindingExample.swift in Sources */,
C150CCCC2B86B78E00118DF7 /* ChromeEffect.swift in Sources */,
8732C2C92C3524C9002110E9 /* SimpleTimelineExample.swift in Sources */,
B190065A2C201BBE000C8B10 /* ProfileHeaderExample.swift in Sources */,
B86F02A82679835F0049DDA7 /* ObjectItemInitExamples.swift in Sources */,
692F338B26556A6A009B98DA /* SideBarExample.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,14 @@ struct CoreContentView: View {
{
Text("Menu Selection")
}


NavigationLink(
destination: TimelineExample(),
label: {
Text("Timeline")
}
)

NavigationLink(
destination: OtherViewExamples())
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import FioriSwiftUICore
import SwiftUI

struct CustomTimelineExample: View {
var body: some View {
List {
Section(header: Text("Custom Timeline Example")) {
TimelineMarker(timestamp: "06/03/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .beforeStart, title: "POC", isPast: true, showUpperVerticalLine: false)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
TimelineMarker(timestamp: "06/05/24", secondaryTimestamp: .text("Sunny"), timelineNode: .start, title: "Project Start", isPast: true)
.modifier(CustomListRowModifier())
.timestampStyle(content: { config in
config.timestamp.foregroundColor(.red)
})
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.red)
})
.timelineNodeStyle(content: { config in
config.timelineNode.foregroundColor(.yellow)
})
.titleStyle(content: { config in
config.title.foregroundColor(.red)
})
Timeline(timestamp: "06/12/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .complete, title: "Project Phase 1", attribute: "xx features implementation done", status: .text("Done"), isPast: true)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
Timeline(timestamp: "06/20/24", timelineNode: .inProgress, title: "Project Phase 2", subtitle: "Integration test", status: .text("ongoing"), isPresent: true)
.modifier(CustomListRowModifier())
TimelineNowIndicator()
.modifier(CustomListRowModifier())
Timeline(timestamp: "06/25/24", timelineNode: .open, title: "Project Phase 3", attribute: "feature list: xx, xx, xx", status: .text("pending"))
.modifier(CustomListRowModifier())
.timestampStyle(content: { config in
config.timestamp.foregroundColor(.red)
})
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.red)
})
.timelineNodeStyle(content: { config in
config.timelineNode.foregroundColor(.yellow)
})
.titleStyle(content: { config in
config.title.foregroundColor(.red)
})
.statusStyle(content: { config in
config.status.foregroundColor(.red)
})
.attributeStyle(content: { config in
config.attribute.foregroundColor(.red)
})
Timeline(timestamp: "06/28/24", timelineNode: .open, icon: Image(systemName: "p.circle"), title: "Project Phase 4", attribute: "feature list: xx, xx, xx", status: .text("pending"))
.modifier(CustomListRowModifier())
.iconStyle(content: { config in
config.icon.foregroundColor(.cyan)
})
TimelineMarker(timestamp: "07/06/24", timelineNode: .open, icon: Image(systemName: "a.circle"), title: "Accept Test")
.modifier(CustomListRowModifier())
.iconStyle(content: { config in
config.icon.foregroundColor(.red)
})
TimelineMarker(timestamp: "07/09/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .end, title: "Project End", showLowerVerticalLine: false)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
}
}
.listStyle(.plain)
.environment(\.defaultMinListRowHeight, 7)
}
}

#Preview {
CustomTimelineExample()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import FioriSwiftUICore
import SwiftUI

struct SimpleTimelineExample: View {
var body: some View {
List {
Section(header: Text("Simple Timeline Example")) {
TimelineMarker(timestamp: "06/03/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .beforeStart, title: "POC", isPast: true, showUpperVerticalLine: false)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
TimelineMarker(timestamp: "06/05/24", secondaryTimestamp: .text("Sunny"), timelineNode: .start, title: "Project Start", isPast: true)
.modifier(CustomListRowModifier())
Timeline(timestamp: "06/12/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .complete, title: "Project Phase 1", attribute: "xx features implementation done", status: .text("Done"), isPast: true)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
Timeline(timestamp: "06/20/24", timelineNode: .inProgress, title: "Project Phase 2", subtitle: "Integration test", status: .text("ongoing"), isPresent: true)
.modifier(CustomListRowModifier())
TimelineNowIndicator()
.modifier(CustomListRowModifier())
Timeline(timestamp: "06/25/24", timelineNode: .open, title: "Project Phase 3", attribute: "feature list: xx, xx, xx", status: .text("pending"))
.modifier(CustomListRowModifier())
Timeline(timestamp: "06/28/24", timelineNode: .open, title: "Project Phase 4", attribute: "feature list: xx, xx, xx", status: .text("pending"))
.modifier(CustomListRowModifier())
TimelineMarker(timestamp: "07/05/24", timelineNode: .beforeEnd, title: "Accept Test")
.modifier(CustomListRowModifier())
TimelineMarker(timestamp: "07/09/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .end, title: "Project End", showLowerVerticalLine: false)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
}
}
.listStyle(.plain)
.environment(\.defaultMinListRowHeight, 7)
}
}

#Preview {
SimpleTimelineExample()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import SwiftUI

struct TimelineExample: View {
var body: some View {
List {
NavigationLink("TimelineItems", destination: TimelineItemsExample())
NavigationLink("SimpleTimelineExample", destination: SimpleTimelineExample())
NavigationLink("CustomTimelineExample", destination: CustomTimelineExample())
}
}
}

#Preview {
TimelineExample()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import FioriSwiftUICore
import SwiftUI

struct TimelineItemsExample: View {
var body: some View {
List {
Section(header: Text("TimelineMarker")) {
TimelineMarker(timestamp: "06/20/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .beforeStart, title: "Before Start", isPast: true, showUpperVerticalLine: false)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
TimelineMarker(timestamp: "06/20/24", secondaryTimestamp: .text("Sunny"), timelineNode: .start, title: "Start", isPresent: true)
.modifier(CustomListRowModifier())
TimelineMarker(timestamp: "06/20/24", secondaryTimestamp: .text("Sunny"), timelineNode: .beforeEnd, title: "Before End", isPresent: true)
.modifier(CustomListRowModifier())
TimelineMarker(timestamp: "06/20/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .end, title: "End", showLowerVerticalLine: true)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
}
Section(header: Text("Timeline")) {
Timeline(timestamp: "06/21/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .complete, title: "Complete", subtitle: "abc", attribute: "attr", status: .text("Info"), substatus: .icon(Image(systemName: "exclamationmark.circle")), subAttribute: "subAttr", isPast: true)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
.substatusStyle(content: { config in
config.substatus.foregroundColor(.yellow)
})
Timeline(timestamp: "06/21/24", secondaryTimestamp: .icon(Image(systemName: "sun.max")), timelineNode: .complete, title: "Complete(Disabled)", subtitle: "abc", attribute: "attr", status: .text("Info"), substatus: .icon(Image(systemName: "exclamationmark.circle")), subAttribute: "subAttr", isPast: true)
.modifier(CustomListRowModifier())
.disabled(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/)
Timeline(timestamp: "06/21/24", secondaryTimestamp: .text("Sunny"), timelineNode: .inProgress, title: "Inprogress", subtitle: "abc", attribute: "attr", status: .text("Info"), substatus: .text("Warning"), subAttribute: "subAttr", isPresent: true)
.modifier(CustomListRowModifier())
.secondaryTimestampStyle(content: { config in
config.secondaryTimestamp.foregroundColor(.yellow)
})
.substatusStyle(content: { config in
config.substatus.foregroundColor(.yellow)
})
Timeline(timestamp: "06/21/24", secondaryTimestamp: .text("Sunny"), timelineNode: .inProgress, title: "Inprogress(Disabled)", subtitle: "abc", attribute: "attr", status: .text("Info"), substatus: .text("Warning"), subAttribute: "subAttr", isPresent: true)
.modifier(CustomListRowModifier())
.disabled(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/)
Timeline(timestamp: "06/21/24", secondaryTimestamp: .text("Sunny"), timelineNode: .open, title: "Open", subtitle: "abc", attribute: "attr", status: .text("Info"), substatus: .text("Warning"), subAttribute: "subAttr")
.modifier(CustomListRowModifier())
Timeline(timestamp: "06/21/24", secondaryTimestamp: .text("Sunny"), timelineNode: .open, title: "Open(Disabled)", subtitle: "abc", attribute: "attr", status: .text("Info"), substatus: .text("Warning"), subAttribute: "subAttr")
.modifier(CustomListRowModifier())
.disabled(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/)
}
Section(header: Text("TimelineNowIndicator")) {
TimelineNowIndicator()
.modifier(CustomListRowModifier())
}
}
.listStyle(.plain)
.environment(\.defaultMinListRowHeight, 7)
}
}

struct CustomListRowModifier: ViewModifier {
func body(content: Content) -> some View {
content
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.listRowSeparator(.hidden)
}
}

#Preview {
TimelineItemsExample()
}
Loading

0 comments on commit d457091

Please sign in to comment.