Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 🎸 [JIRA:HCPSDKFIORIUIKIT-2880] ActivityItemModel Refactor #928

Merged
merged 8 commits into from
Dec 13, 2024
12 changes: 12 additions & 0 deletions Apps/Examples/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
6D10F8A02C7DB3F50071DD3E /* BannerMultiMessageExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D10F89F2C7DB3F50071DD3E /* BannerMultiMessageExample.swift */; };
6D14F05E2C9290F20053BA98 /* BannerMultiMessageCustomInitExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D14F05D2C9290F20053BA98 /* BannerMultiMessageCustomInitExample.swift */; };
6D3A3DE92CDB5F1E004D4597 /* ObjectCellEnhancementExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D3A3DE82CDB5F1E004D4597 /* ObjectCellEnhancementExample.swift */; };
6D66D7F12D02FC7B00F7A97D /* ActivityItemExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D66D7EF2D02FC7B00F7A97D /* ActivityItemExample.swift */; };
6D6E86252C50D42000EDB6F4 /* FioriButtonInListExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6E86242C50D42000EDB6F4 /* FioriButtonInListExample.swift */; };
6D6E86292C50E5F900EDB6F4 /* FioriButtonInListMultipleLineExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6E86282C50E5F900EDB6F4 /* FioriButtonInListMultipleLineExample.swift */; };
6D6E86672C50FDBE00EDB6F4 /* FioriButtonInCollectionExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6E86662C50FDBE00EDB6F4 /* FioriButtonInCollectionExample.swift */; };
Expand Down Expand Up @@ -262,6 +263,7 @@
6D10F89F2C7DB3F50071DD3E /* BannerMultiMessageExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerMultiMessageExample.swift; sourceTree = "<group>"; };
6D14F05D2C9290F20053BA98 /* BannerMultiMessageCustomInitExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BannerMultiMessageCustomInitExample.swift; sourceTree = "<group>"; };
6D3A3DE82CDB5F1E004D4597 /* ObjectCellEnhancementExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectCellEnhancementExample.swift; sourceTree = "<group>"; };
6D66D7EF2D02FC7B00F7A97D /* ActivityItemExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityItemExample.swift; sourceTree = "<group>"; };
6D6E86242C50D42000EDB6F4 /* FioriButtonInListExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FioriButtonInListExample.swift; sourceTree = "<group>"; };
6D6E86282C50E5F900EDB6F4 /* FioriButtonInListMultipleLineExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FioriButtonInListMultipleLineExample.swift; sourceTree = "<group>"; };
6D6E86662C50FDBE00EDB6F4 /* FioriButtonInCollectionExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FioriButtonInCollectionExample.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -569,6 +571,14 @@
path = SideBar;
sourceTree = "<group>";
};
6D66D7F02D02FC7B00F7A97D /* ActivityItem */ = {
isa = PBXGroup;
children = (
6D66D7EF2D02FC7B00F7A97D /* ActivityItemExample.swift */,
);
path = ActivityItem;
sourceTree = "<group>";
};
8732C2C32C35092D002110E9 /* Timeline */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -662,6 +672,7 @@
8A5579C824C1293C0098003A /* FioriSwiftUICore */ = {
isa = PBXGroup;
children = (
6D66D7F02D02FC7B00F7A97D /* ActivityItem */,
87F14B192CD86F65004A69A0 /* DocumentScannerView */,
3CD71F272CDB625000B037EB /* CheckoutIndicator */,
3CC870942CB6F4E20081909C /* ToastMessage */,
Expand Down Expand Up @@ -1197,6 +1208,7 @@
B846F94A26815DF30085044B /* ContactItemCompactExamples.swift in Sources */,
C106AD442B33710800FE8B35 /* SearchWithScope.swift in Sources */,
6D14F05E2C9290F20053BA98 /* BannerMultiMessageCustomInitExample.swift in Sources */,
6D66D7F12D02FC7B00F7A97D /* ActivityItemExample.swift in Sources */,
6DEC32042C4E49C70084DD20 /* CardFixedWidthButtonsExample.swift in Sources */,
B1C7DC8129FBB13F00DC5EEB /* SPIModelExample.swift in Sources */,
C106AD462B338D1300FE8B35 /* SearchWithToken.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import FioriSwiftUICore
import SwiftUI

struct ActivityItemExample: View {
var body: some View {
List {
Section {
ActivityItem(icon: Image(systemName: "phone"), subtitle: AttributedString("phone"))
ActivityItem(icon: Image(systemName: "envelope"), subtitle: AttributedString("envelope"))
ActivityItem(icon: Image(systemName: "message"), subtitle: AttributedString("message"))
ActivityItem(icon: Image(systemName: "video"), subtitle: AttributedString("video"))
} header: {
Text("Normal-Vertical")
}

Section {
ActivityItem(icon: Image(systemName: "phone"), subtitle: AttributedString("phone"), layout: .horizontal)
ActivityItem(icon: Image(systemName: "envelope"), subtitle: AttributedString("envelope"), layout: .horizontal)
ActivityItem(icon: Image(systemName: "message"), subtitle: AttributedString("message"), layout: .horizontal)
ActivityItem(icon: Image(systemName: "video"), subtitle: AttributedString("video"), layout: .horizontal)
} header: {
Text("Normal-Horizontal")
}

Section {
ActivityItem(icon: Image(systemName: "phone"))
ActivityItem(icon: Image(systemName: "envelope"))
ActivityItem(icon: Image(systemName: "message"))
ActivityItem(icon: Image(systemName: "video"))
} header: {
Text("Only Icon")
}

Section {
ActivityItem(subtitle: AttributedString("phone"))
ActivityItem(subtitle: AttributedString("envelope"))
ActivityItem(subtitle: AttributedString("message"))
ActivityItem(subtitle: AttributedString("video"))
} header: {
Text("Only Subtitle")
}
}
.navigationTitle(Text("ActivityItemExample"))
}
}

#Preview {
ActivityItemExample()
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ struct CoreContentView: View {
var body: some View {
List {
Section(header: Text("Views")) {
NavigationLink {
ActivityItemExample()
} label: {
Text("ActivityItem")
}

NavigationLink(
destination: AvatarStackExample(),
label: {
Expand Down
6 changes: 5 additions & 1 deletion Sources/FioriSwiftUICore/Models/ModelDefinitions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ public protocol ActionModel: ActionComponent {}
public protocol TextInputModel: TextInputComponent {}

// sourcery: generated_component
public protocol ActivityItemModel: IconComponent, SubtitleComponent {}
public protocol _ActivityItemModel: IconComponent, SubtitleComponent {}

/// Deprecated ActivityItemModel
@available(*, unavailable, renamed: "_ActivityItemModel", message: "Will be removed in the future release. Please create ActivityItemModel with other initializers instead.")
hengyi-zhang marked this conversation as resolved.
Show resolved Hide resolved
public protocol ActivityItemModel {}

// sourcery: generated_component_not_configurable
public protocol ActivityItemsModel: ActionItemsComponent {}
Expand Down
4 changes: 2 additions & 2 deletions Sources/FioriSwiftUICore/Views/ActivityItem+View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import SwiftUI
// FIXME: - Implement Fiori style definitions

extension Fiori {
enum ActivityItem {
enum _ActivityItem {
typealias Icon = EmptyModifier
typealias Subtitle = EmptyModifier
typealias IconCumulative = EmptyModifier
Expand All @@ -30,7 +30,7 @@ extension Fiori {

// FIXME: - Implement ActivityItem View body

extension ActivityItem: View {
extension _ActivityItem: View {
public var body: some View {
VStack {
icon
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Foundation
import SwiftUI

// swiftlint:disable file_length

/// A view that displays information of an object.
// sourcery: CompositeComponent
protocol _ObjectItemComponent: _TitleComponent, _SubtitleComponent, _FootnoteComponent, _DescriptionComponent, _StatusComponent, _SubstatusComponent, _DetailImageComponent, _IconsComponent, _AvatarsComponent, _FootnoteIconsComponent, _FootnoteIconsTextComponent, _TagsComponent, _ActionComponent {
Expand Down Expand Up @@ -726,3 +728,16 @@ protocol _ProgressIndicatorComponent: _ProgressIndicatorProtocol {}
/// ```
// sourcery: CompositeComponent
protocol _ProcessingIndicatorComponent: _OptionalTitleComponent {}

hengyi-zhang marked this conversation as resolved.
Show resolved Hide resolved
/// `ActivityItem` is a View that provides a customizable activity item with icon and subtitle.
///
/// ## Usage
/// ```swift
/// ActivityItem(icon: Image(systemName: "phone"), subtitle: AttributedString("phone"))
/// ```
// sourcery: CompositeComponent
protocol _ActivityItemComponent: _IconComponent, _SubtitleComponent {
/// Activity item layout. The default is .vertical
// sourcery: defaultValue = .vertical
var layout: ActivityItemLayout { get }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import FioriThemeManager
import Foundation
import SwiftUI

/// Activity item layout
public enum ActivityItemLayout {
/// Vertical layout for ActivityItem.
case vertical
/// Horizontal layout for ActivityItem.
case horizontal
}

// Base Layout style
public struct ActivityItemBaseStyle: ActivityItemStyle {
public func makeBody(_ configuration: ActivityItemConfiguration) -> some View {
// Add default layout here
switch configuration.layout {
case .vertical:
VStack {
configuration.icon
configuration.subtitle
}
.typeErased
case .horizontal:
HStack {
configuration.icon
configuration.subtitle
}
.typeErased
}
}
}

// Default fiori styles
extension ActivityItemFioriStyle {
struct ContentFioriStyle: ActivityItemStyle {
func makeBody(_ configuration: ActivityItemConfiguration) -> some View {
ActivityItem(configuration)
}
}

struct IconFioriStyle: IconStyle {
let activityItemConfiguration: ActivityItemConfiguration

func makeBody(_ configuration: IconConfiguration) -> some View {
Icon(configuration)
}
}

struct SubtitleFioriStyle: SubtitleStyle {
let activityItemConfiguration: ActivityItemConfiguration

func makeBody(_ configuration: SubtitleConfiguration) -> some View {
Subtitle(configuration)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
import Foundation
import SwiftUI

public struct ActivityItem {
let icon: any View
let subtitle: any View
/// Activity item layout. The default is .vertical
let layout: ActivityItemLayout

@Environment(\.activityItemStyle) var style

fileprivate var _shouldApplyDefaultStyle = true

public init(@ViewBuilder icon: () -> any View = { EmptyView() },
@ViewBuilder subtitle: () -> any View = { EmptyView() },
layout: ActivityItemLayout = .vertical)
{
self.icon = Icon(icon: icon)
self.subtitle = Subtitle(subtitle: subtitle)
self.layout = layout
}
}

public extension ActivityItem {
init(icon: Image? = nil,
subtitle: AttributedString? = nil,
layout: ActivityItemLayout = .vertical)
{
self.init(icon: { icon }, subtitle: { OptionalText(subtitle) }, layout: layout)
}
}

public extension ActivityItem {
init(_ configuration: ActivityItemConfiguration) {
self.init(configuration, shouldApplyDefaultStyle: false)
}

internal init(_ configuration: ActivityItemConfiguration, shouldApplyDefaultStyle: Bool) {
self.icon = configuration.icon
self.subtitle = configuration.subtitle
self.layout = configuration.layout
self._shouldApplyDefaultStyle = shouldApplyDefaultStyle
}
}

extension ActivityItem: View {
public var body: some View {
if self._shouldApplyDefaultStyle {
self.defaultStyle()
} else {
self.style.resolve(configuration: .init(icon: .init(self.icon), subtitle: .init(self.subtitle), layout: self.layout)).typeErased
.transformEnvironment(\.activityItemStyleStack) { stack in
if !stack.isEmpty {
stack.removeLast()
}
}
}
}
}

private extension ActivityItem {
func shouldApplyDefaultStyle(_ bool: Bool) -> some View {
var s = self
s._shouldApplyDefaultStyle = bool
return s
}

func defaultStyle() -> some View {
ActivityItem(.init(icon: .init(self.icon), subtitle: .init(self.subtitle), layout: self.layout))
.shouldApplyDefaultStyle(false)
.activityItemStyle(ActivityItemFioriStyle.ContentFioriStyle())
.typeErased
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
import Foundation
import SwiftUI

public protocol ActivityItemStyle: DynamicProperty {
associatedtype Body: View

func makeBody(_ configuration: ActivityItemConfiguration) -> Body
}

struct AnyActivityItemStyle: ActivityItemStyle {
let content: (ActivityItemConfiguration) -> any View

init(@ViewBuilder _ content: @escaping (ActivityItemConfiguration) -> any View) {
self.content = content
}

public func makeBody(_ configuration: ActivityItemConfiguration) -> some View {
self.content(configuration).typeErased
}
}

public struct ActivityItemConfiguration {
public let icon: Icon
public let subtitle: Subtitle
public let layout: ActivityItemLayout

public typealias Icon = ConfigurationViewWrapper
public typealias Subtitle = ConfigurationViewWrapper
}

public struct ActivityItemFioriStyle: ActivityItemStyle {
public func makeBody(_ configuration: ActivityItemConfiguration) -> some View {
ActivityItem(configuration)
.iconStyle(IconFioriStyle(activityItemConfiguration: configuration))
.subtitleStyle(SubtitleFioriStyle(activityItemConfiguration: configuration))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public struct ObjectItem {
let footnoteIconsText: any View
let tags: any View
let action: any View
/// For accessory enhancement
let objectItemButton: any View

@Environment(\.objectItemStyle) var style
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import Foundation
import SwiftUI

/// `ValuePicker` provides a title and value label with Fiori styling and a wheel-style`Picker`.
///
/// `ValuePicker` provides a title and value label with Fiori styling and a wheel-style `Picker`.
/// ## Usage
/// ```swift
/// let valueOptions :[AttributedString] = ["1", "20", "300"]
Expand All @@ -13,24 +12,20 @@ import SwiftUI
/// @State var stateIndex: Int = 0
/// @State var isTrackingLiveChanges = true
/// @State var showsErrorMessage = false
///
/// ValuePicker(title: "Picker Title(Default Style)", isRequired: self.isRequired, options: self.valueOptions, selectedIndex: self.$selectedIndex, isTrackingLiveChanges: self.isTrackingLiveChanges)
/// .informationView(isPresented: self.$showsErrorMessage, description: AttributedString("Please choose one available data"))
/// .informationViewStyle(.informational)
/// ```
public struct ValuePicker {
let title: any View
let valueLabel: any View
let mandatoryFieldIndicator: any View
let isRequired: Bool
let options: [AttributedString]
/// The selected value index of the Value Picker
/// The index for the selected value in the valueOptions.
@Binding var selectedIndex: Int
/// When `isTrackingLiveChanges` is true, the value will be shown every time a selection is made. If it is set to false, the value will only be displayed when the value picker is collapsed. The default setting is true.
var isTrackingLiveChanges: Bool
/// This property indicates whether the picker is to always be displayed. The default is false.
var alwaysShowPicker: Bool
/// The `ControlState` of the view. The default is `normal`
/// The `ControlState` of the view. Currently, `.disabled`, `.normal` and `.readOnly` are supported. The default is `normal`.
let controlState: ControlState

@Environment(\.valuePickerStyle) var style
Expand Down
Loading
Loading