@momo-kits/native-kits 0.162.18-debug → 0.162.19-debug
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compose/build.gradle.kts +1 -1
- package/compose/compose.podspec +1 -1
- package/gradle.properties +1 -1
- package/ios/Application/ApplicationEnvironment.swift +11 -0
- package/ios/Application/Components.swift +34 -44
- package/ios/Application/FloatingButton.swift +10 -9
- package/ios/Application/HeaderRight.swift +79 -45
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +103 -0
- package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
- package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
- package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
- package/ios/Application/Navigation/HeaderTitle.swift +57 -0
- package/ios/Application/Navigation/HeaderUser.swift +209 -0
- package/ios/Application/Navigation/NavigationContainer.swift +176 -0
- package/ios/Application/Navigation/NavigationOptions.swift +109 -0
- package/ios/Application/Navigation/Navigator.swift +364 -0
- package/ios/Application/Navigation/Overplay/BottomSheet.swift +188 -0
- package/ios/Application/Navigation/Overplay/ModalScreen.swift +68 -0
- package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
- package/ios/Application/Navigation/component/Header.swift +178 -0
- package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
- package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
- package/ios/Application/Screen.swift +2 -1
- package/ios/Application/StackScreen.swift +453 -0
- package/ios/Avatar/Avatar.swift +193 -0
- package/ios/Badge/Badge.swift +11 -14
- package/ios/Badge/BadgeRibbon.swift +12 -21
- package/ios/BaselineView/BaselineView.swift +163 -0
- package/ios/Button/Button.swift +61 -22
- package/ios/Carousel/Carousel.swift +181 -0
- package/ios/Checkbox/Checkbox.swift +14 -13
- package/ios/Chip/Chip.swift +23 -9
- package/ios/Collapse/Collapse.swift +182 -0
- package/ios/Colors+Radius+Spacing/Colors.swift +12 -12
- package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
- package/ios/DateTimePicker/DateTimePicker.swift +210 -0
- package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
- package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
- package/ios/DateTimePicker/WheelPicker.swift +161 -0
- package/ios/Divider/Divider.swift +16 -0
- package/ios/Extensions/Color++.swift +32 -0
- package/ios/Icon/Icon.swift +6 -1
- package/ios/IconButton/IconButton.swift +112 -0
- package/ios/Input/Input.swift +41 -25
- package/ios/Input/InputPhoneNumber.swift +20 -19
- package/ios/Input/InputSearch.swift +100 -47
- package/ios/Input/InputTextArea.swift +66 -40
- package/ios/InputDropDown/InputDropDown.swift +198 -0
- package/ios/InputMoney/InputMoney.swift +335 -0
- package/ios/InputOTP/InputOTP.swift +210 -0
- package/ios/Loader/Loader.swift +113 -0
- package/ios/MoMoUIKits.podspec +5 -0
- package/ios/Pagination/PaginationDot.swift +61 -0
- package/ios/Pagination/PaginationNumber.swift +35 -0
- package/ios/Pagination/PaginationScroll.swift +101 -0
- package/ios/Pagination/PaginationWhiteDot.swift +37 -0
- package/ios/Popup/PopupDisplay.swift +8 -16
- package/ios/Popup/PopupInput.swift +2 -8
- package/ios/Popup/PopupNotify.swift +219 -0
- package/ios/ProgressInfo/ProgressInfo.swift +294 -0
- package/ios/Radio/Radio.swift +70 -0
- package/ios/Rating/Rating.swift +82 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json +11 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Background.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Border.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Card.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Contents.json +6 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Error.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Primary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryDark.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryLight.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Success.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Text.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/TextSecondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Warning.colorset/Contents.json +38 -0
- package/ios/Skeleton/Skeleton.swift +99 -0
- package/ios/Slider/Slider.swift +237 -0
- package/ios/Stepper/Stepper.swift +220 -0
- package/ios/Steps/Steps.swift +451 -0
- package/ios/SuggestAction/SuggestAction.swift +97 -0
- package/ios/Swipeable/SwipeCell.swift +185 -0
- package/ios/Swipeable/SwipeCellModel.swift +21 -0
- package/ios/TabView/TabView.swift +530 -0
- package/ios/Tag/Tag.swift +98 -0
- package/ios/Title/Title.swift +269 -0
- package/ios/Tooltip/Tooltip.swift +482 -0
- package/ios/Typography/Text.swift +76 -5
- package/ios/Uploader/Uploader.swift +183 -0
- package/ios/native-kits.podspec +61 -8
- package/ios-demo/MoMoUIKitsDemo.podspec +20 -0
- package/ios-demo/README.md +120 -0
- package/ios-demo/Resources/dot_loading.json +558 -0
- package/ios-demo/Resources/icon.json +4052 -0
- package/ios-demo/Resources/lottie_circle_loader.json +1 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +24 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +93 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +269 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +100 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +126 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +63 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +20 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +93 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +124 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +14 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +278 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +58 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +78 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +138 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +111 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +136 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +107 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +73 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +100 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +32 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +57 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +70 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +227 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +72 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +121 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +76 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +89 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +32 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +56 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +32 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +150 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +138 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +103 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +94 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +79 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +152 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +33 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +190 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +34 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +182 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +109 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +187 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +131 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +51 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
- package/package.json +1 -1
- package/publish.sh +50 -0
- package/scripts/gen-ios-color.mjs +136 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Theme.swift
|
|
3
|
+
// MoMoUIKits
|
|
4
|
+
//
|
|
5
|
+
// Created by sophia on 25/2/26.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
import SwiftUI
|
|
10
|
+
|
|
11
|
+
// MARK: - Background
|
|
12
|
+
|
|
13
|
+
public struct Background {
|
|
14
|
+
public let `default`: Color
|
|
15
|
+
public let surface: Color
|
|
16
|
+
public let tonal: Color
|
|
17
|
+
public let pressed: Color
|
|
18
|
+
public let selected: Color
|
|
19
|
+
public let disable: Color
|
|
20
|
+
|
|
21
|
+
public init(
|
|
22
|
+
default defaultColor: Color,
|
|
23
|
+
surface: Color,
|
|
24
|
+
tonal: Color,
|
|
25
|
+
pressed: Color,
|
|
26
|
+
selected: Color,
|
|
27
|
+
disable: Color
|
|
28
|
+
) {
|
|
29
|
+
self.default = defaultColor
|
|
30
|
+
self.surface = surface
|
|
31
|
+
self.tonal = tonal
|
|
32
|
+
self.pressed = pressed
|
|
33
|
+
self.selected = selected
|
|
34
|
+
self.disable = disable
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// MARK: - TextColors
|
|
39
|
+
|
|
40
|
+
public struct TextColors {
|
|
41
|
+
public let `default`: Color
|
|
42
|
+
public let secondary: Color
|
|
43
|
+
public let hint: Color
|
|
44
|
+
public let disable: Color
|
|
45
|
+
|
|
46
|
+
public init(
|
|
47
|
+
default defaultColor: Color,
|
|
48
|
+
secondary: Color,
|
|
49
|
+
hint: Color,
|
|
50
|
+
disable: Color
|
|
51
|
+
) {
|
|
52
|
+
self.default = defaultColor
|
|
53
|
+
self.secondary = secondary
|
|
54
|
+
self.hint = hint
|
|
55
|
+
self.disable = disable
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// MARK: - BorderColors
|
|
60
|
+
|
|
61
|
+
public struct BorderColors {
|
|
62
|
+
public let `default`: Color
|
|
63
|
+
public let disable: Color
|
|
64
|
+
|
|
65
|
+
public init(default defaultColor: Color, disable: Color) {
|
|
66
|
+
self.default = defaultColor
|
|
67
|
+
self.disable = disable
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// MARK: - ColorSet
|
|
72
|
+
|
|
73
|
+
public struct ColorSet {
|
|
74
|
+
public let primary: Color
|
|
75
|
+
public let secondary: Color
|
|
76
|
+
public let container: Color
|
|
77
|
+
|
|
78
|
+
public init(primary: Color, secondary: Color, container: Color) {
|
|
79
|
+
self.primary = primary
|
|
80
|
+
self.secondary = secondary
|
|
81
|
+
self.container = container
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// MARK: - ColorScheme
|
|
86
|
+
|
|
87
|
+
public struct ColorScheme {
|
|
88
|
+
public let primary: Color
|
|
89
|
+
public let secondary: Color
|
|
90
|
+
public let gradient: Color
|
|
91
|
+
public let background: Background
|
|
92
|
+
public let text: TextColors
|
|
93
|
+
public let border: BorderColors
|
|
94
|
+
public let success: ColorSet
|
|
95
|
+
public let warning: ColorSet
|
|
96
|
+
public let error: ColorSet
|
|
97
|
+
public let highlight: ColorSet
|
|
98
|
+
public let interactive: ColorSet
|
|
99
|
+
|
|
100
|
+
public init(
|
|
101
|
+
primary: Color,
|
|
102
|
+
secondary: Color,
|
|
103
|
+
gradient: Color,
|
|
104
|
+
background: Background,
|
|
105
|
+
text: TextColors,
|
|
106
|
+
border: BorderColors,
|
|
107
|
+
success: ColorSet,
|
|
108
|
+
warning: ColorSet,
|
|
109
|
+
error: ColorSet,
|
|
110
|
+
highlight: ColorSet,
|
|
111
|
+
interactive: ColorSet
|
|
112
|
+
) {
|
|
113
|
+
self.primary = primary
|
|
114
|
+
self.secondary = secondary
|
|
115
|
+
self.gradient = gradient
|
|
116
|
+
self.background = background
|
|
117
|
+
self.text = text
|
|
118
|
+
self.border = border
|
|
119
|
+
self.success = success
|
|
120
|
+
self.warning = warning
|
|
121
|
+
self.error = error
|
|
122
|
+
self.highlight = highlight
|
|
123
|
+
self.interactive = interactive
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// MARK: - ThemeAssets
|
|
128
|
+
|
|
129
|
+
public struct ThemeAssets {
|
|
130
|
+
public let headerBackground: String?
|
|
131
|
+
|
|
132
|
+
public init(headerBackground: String? = nil) {
|
|
133
|
+
self.headerBackground = headerBackground
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public var isHeaderImage: Bool {
|
|
137
|
+
guard let url = headerBackground else { return false }
|
|
138
|
+
return !url.isEmpty
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// MARK: - Theme
|
|
143
|
+
|
|
144
|
+
public struct Theme {
|
|
145
|
+
public let dark: Bool
|
|
146
|
+
public let colors: ColorScheme
|
|
147
|
+
public let font: String
|
|
148
|
+
public let assets: ThemeAssets
|
|
149
|
+
|
|
150
|
+
public init(dark: Bool, colors: ColorScheme, font: String, assets: ThemeAssets) {
|
|
151
|
+
self.dark = dark
|
|
152
|
+
self.colors = colors
|
|
153
|
+
self.font = font
|
|
154
|
+
self.assets = assets
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public func copy(
|
|
158
|
+
dark: Bool? = nil,
|
|
159
|
+
colors: ColorScheme? = nil,
|
|
160
|
+
font: String? = nil,
|
|
161
|
+
assets: ThemeAssets? = nil
|
|
162
|
+
) -> Theme {
|
|
163
|
+
Theme(
|
|
164
|
+
dark: dark ?? self.dark,
|
|
165
|
+
colors: colors ?? self.colors,
|
|
166
|
+
font: font ?? self.font,
|
|
167
|
+
assets: assets ?? self.assets
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// MARK: - Default Theme (Light)
|
|
173
|
+
|
|
174
|
+
public let defaultTheme = Theme(
|
|
175
|
+
dark: false,
|
|
176
|
+
colors: ColorScheme(
|
|
177
|
+
primary: Color.momoAsset("ThemeColors/primary"),
|
|
178
|
+
secondary: Color.momoAsset("ThemeColors/secondary"),
|
|
179
|
+
gradient: Color.momoAsset("ThemeColors/gradient"),
|
|
180
|
+
background: Background(
|
|
181
|
+
default: Color.momoAsset("ThemeColors/background-default"),
|
|
182
|
+
surface: Color.momoAsset("ThemeColors/background-surface"),
|
|
183
|
+
tonal: Color.momoAsset("ThemeColors/background-tonal"),
|
|
184
|
+
pressed: Color.momoAsset("ThemeColors/background-pressed"),
|
|
185
|
+
selected: Color.momoAsset("ThemeColors/background-selected"),
|
|
186
|
+
disable: Color.momoAsset("ThemeColors/background-disable")
|
|
187
|
+
),
|
|
188
|
+
text: TextColors(
|
|
189
|
+
default: Color.momoAsset("ThemeColors/text-default"),
|
|
190
|
+
secondary: Color.momoAsset("ThemeColors/text-secondary"),
|
|
191
|
+
hint: Color.momoAsset("ThemeColors/text-hint"),
|
|
192
|
+
disable: Color.momoAsset("ThemeColors/text-disable")
|
|
193
|
+
),
|
|
194
|
+
border: BorderColors(
|
|
195
|
+
default: Color.momoAsset("ThemeColors/border-default"),
|
|
196
|
+
disable: Color.momoAsset("ThemeColors/border-disable")
|
|
197
|
+
),
|
|
198
|
+
success: ColorSet(
|
|
199
|
+
primary: Colors.green03,
|
|
200
|
+
secondary: Colors.green07,
|
|
201
|
+
container: Colors.green08
|
|
202
|
+
),
|
|
203
|
+
warning: ColorSet(
|
|
204
|
+
primary: Colors.orange03,
|
|
205
|
+
secondary: Colors.orange07,
|
|
206
|
+
container: Colors.orange08
|
|
207
|
+
),
|
|
208
|
+
error: ColorSet(
|
|
209
|
+
primary: Colors.red03,
|
|
210
|
+
secondary: Colors.red07,
|
|
211
|
+
container: Colors.red08
|
|
212
|
+
),
|
|
213
|
+
highlight: ColorSet(
|
|
214
|
+
primary: Colors.mint03,
|
|
215
|
+
secondary: Colors.mint07,
|
|
216
|
+
container: Colors.mint08
|
|
217
|
+
),
|
|
218
|
+
interactive: ColorSet(
|
|
219
|
+
primary: Colors.blue03,
|
|
220
|
+
secondary: Colors.blue07,
|
|
221
|
+
container: Colors.blue08
|
|
222
|
+
)
|
|
223
|
+
),
|
|
224
|
+
font: "SFProText",
|
|
225
|
+
assets: ThemeAssets(headerBackground: nil)
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
// MARK: - Dark Theme
|
|
229
|
+
|
|
230
|
+
public let darkTheme = Theme(
|
|
231
|
+
dark: true,
|
|
232
|
+
colors: ColorScheme(
|
|
233
|
+
primary: Colors.pink04,
|
|
234
|
+
secondary: Colors.pink08,
|
|
235
|
+
gradient: Color(hex: "FDCADE"),
|
|
236
|
+
background: Background(
|
|
237
|
+
default: Color(hex: "121212"),
|
|
238
|
+
surface: Color(hex: "1E1E1E"),
|
|
239
|
+
tonal: Colors.pink10,
|
|
240
|
+
pressed: Color(hex: "1A1A1A"),
|
|
241
|
+
selected: Colors.pink11,
|
|
242
|
+
disable: Color(hex: "303030")
|
|
243
|
+
),
|
|
244
|
+
text: TextColors(
|
|
245
|
+
default: Color.white,
|
|
246
|
+
secondary: Color(hex: "B0B0B0"),
|
|
247
|
+
hint: Color(hex: "727272"),
|
|
248
|
+
disable: Color(hex: "505050")
|
|
249
|
+
),
|
|
250
|
+
border: BorderColors(
|
|
251
|
+
default: Color(hex: "2A2A2A"),
|
|
252
|
+
disable: Color(hex: "242424")
|
|
253
|
+
),
|
|
254
|
+
success: ColorSet(
|
|
255
|
+
primary: Colors.green03,
|
|
256
|
+
secondary: Colors.green07,
|
|
257
|
+
container: Colors.green08
|
|
258
|
+
),
|
|
259
|
+
warning: ColorSet(
|
|
260
|
+
primary: Colors.orange03,
|
|
261
|
+
secondary: Colors.orange07,
|
|
262
|
+
container: Colors.orange08
|
|
263
|
+
),
|
|
264
|
+
error: ColorSet(
|
|
265
|
+
primary: Colors.red03,
|
|
266
|
+
secondary: Colors.red07,
|
|
267
|
+
container: Colors.red08
|
|
268
|
+
),
|
|
269
|
+
highlight: ColorSet(
|
|
270
|
+
primary: Colors.mint03,
|
|
271
|
+
secondary: Colors.mint07,
|
|
272
|
+
container: Colors.mint08
|
|
273
|
+
),
|
|
274
|
+
interactive: ColorSet(
|
|
275
|
+
primary: Colors.blue03,
|
|
276
|
+
secondary: Colors.blue07,
|
|
277
|
+
container: Colors.blue08
|
|
278
|
+
)
|
|
279
|
+
),
|
|
280
|
+
font: "SFProText",
|
|
281
|
+
assets: ThemeAssets(headerBackground: nil)
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
// MARK: - AppTheme Environment Key
|
|
285
|
+
|
|
286
|
+
private struct AppThemeKey: EnvironmentKey {
|
|
287
|
+
static let defaultValue: Theme = defaultTheme
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public extension EnvironmentValues {
|
|
291
|
+
var appTheme: Theme {
|
|
292
|
+
get { self[AppThemeKey.self] }
|
|
293
|
+
set { self[AppThemeKey.self] = newValue }
|
|
294
|
+
}
|
|
295
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
// MARK: - Constants
|
|
4
|
+
|
|
5
|
+
private let datePickerHeight: CGFloat = 210
|
|
6
|
+
private let datePickerWithLabelsHeight: CGFloat = 238
|
|
7
|
+
|
|
8
|
+
// MARK: - DateTimePicker
|
|
9
|
+
|
|
10
|
+
/// A wheel-style date/time picker matching Compose `DateTimePicker`.
|
|
11
|
+
///
|
|
12
|
+
/// The `format` string drives which columns are shown:
|
|
13
|
+
/// - `DD` day, `MM` month, `YYYY` year, `HH` hour, `mm` minute.
|
|
14
|
+
/// - `"HH:mm"` shows hour + minute; a lone `"HH"` switches the hour wheel to a
|
|
15
|
+
/// 12-hour clock with an AM/PM column.
|
|
16
|
+
public struct DateTimePicker: View {
|
|
17
|
+
// MARK: Lifecycle
|
|
18
|
+
|
|
19
|
+
public init(
|
|
20
|
+
format: String = "DD-MM-YYYY",
|
|
21
|
+
minuteInterval: Int = 1,
|
|
22
|
+
selectedValue: Date? = nil,
|
|
23
|
+
minDate: Date? = nil,
|
|
24
|
+
maxDate: Date? = nil,
|
|
25
|
+
arrayLabelTime: [String] = [],
|
|
26
|
+
onChange: @escaping (Date) -> Void
|
|
27
|
+
) {
|
|
28
|
+
self.format = format
|
|
29
|
+
self.minuteInterval = minuteInterval
|
|
30
|
+
self.selectedValue = selectedValue
|
|
31
|
+
self.minDate = minDate
|
|
32
|
+
self.maxDate = maxDate
|
|
33
|
+
self.arrayLabelTime = arrayLabelTime
|
|
34
|
+
self.onChange = onChange
|
|
35
|
+
|
|
36
|
+
let calendar = Calendar.current
|
|
37
|
+
let effectiveSelected = selectedValue ?? DateTimePickerUtils.getCurrentDateTime()
|
|
38
|
+
let effectiveMin = minDate ?? DateTimePickerUtils.createRelativeDate(years: -10)
|
|
39
|
+
let effectiveMax = maxDate ?? DateTimePickerUtils.createRelativeDate(years: 10)
|
|
40
|
+
|
|
41
|
+
// needCheckRange is true only when the caller supplied no bounds.
|
|
42
|
+
let needCheckRange = (minDate == nil && maxDate == nil)
|
|
43
|
+
|
|
44
|
+
let initialValue: Date
|
|
45
|
+
if !needCheckRange {
|
|
46
|
+
initialValue = effectiveSelected
|
|
47
|
+
} else if effectiveSelected < effectiveMin {
|
|
48
|
+
initialValue = effectiveMin
|
|
49
|
+
} else if effectiveSelected > effectiveMax {
|
|
50
|
+
initialValue = effectiveMax
|
|
51
|
+
} else {
|
|
52
|
+
initialValue = effectiveSelected
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let comps = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: initialValue)
|
|
56
|
+
self._currentData = State(initialValue: DateTimePickerData(
|
|
57
|
+
day: comps.day ?? 1,
|
|
58
|
+
month: comps.month ?? 1,
|
|
59
|
+
year: comps.year ?? 2000,
|
|
60
|
+
hour: comps.hour ?? 0,
|
|
61
|
+
minute: comps.minute ?? 0
|
|
62
|
+
))
|
|
63
|
+
|
|
64
|
+
self.effectiveMinComponents = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: effectiveMin)
|
|
65
|
+
self.effectiveMaxComponents = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: effectiveMax)
|
|
66
|
+
self.needCheckRange = needCheckRange
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// MARK: Public
|
|
70
|
+
|
|
71
|
+
public var body: some View {
|
|
72
|
+
let components = DateTimePickerUtils.getDateComponents(
|
|
73
|
+
format: format,
|
|
74
|
+
currentData: currentData,
|
|
75
|
+
minDate: effectiveMinComponents,
|
|
76
|
+
maxDate: effectiveMaxComponents,
|
|
77
|
+
minuteInterval: minuteInterval
|
|
78
|
+
)
|
|
79
|
+
let pickerHeight = arrayLabelTime.isEmpty ? datePickerHeight : datePickerWithLabelsHeight
|
|
80
|
+
|
|
81
|
+
return HStack(spacing: Spacing.M) {
|
|
82
|
+
ForEach(Array(components.enumerated()), id: \.offset) { index, component in
|
|
83
|
+
let hasLabel = index < arrayLabelTime.count && !arrayLabelTime[index].isEmpty
|
|
84
|
+
|
|
85
|
+
VStack(spacing: 0) {
|
|
86
|
+
if hasLabel {
|
|
87
|
+
MomoText(arrayLabelTime[index], typography: .actionSBold, color: Colors.text)
|
|
88
|
+
.padding(.bottom, Spacing.S)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
WheelPicker(
|
|
92
|
+
name: component.name,
|
|
93
|
+
data: component.data,
|
|
94
|
+
selectedData: selectedDataFor(component.name),
|
|
95
|
+
onChange: onWheelChange
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
.frame(maxWidth: .infinity)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
.frame(maxWidth: .infinity)
|
|
102
|
+
.frame(height: pickerHeight)
|
|
103
|
+
.background(Colors.background)
|
|
104
|
+
.padding(.horizontal, Spacing.M)
|
|
105
|
+
.onAppear { emitIfValid() }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// MARK: Internal
|
|
109
|
+
|
|
110
|
+
let format: String
|
|
111
|
+
let minuteInterval: Int
|
|
112
|
+
let selectedValue: Date?
|
|
113
|
+
let minDate: Date?
|
|
114
|
+
let maxDate: Date?
|
|
115
|
+
let arrayLabelTime: [String]
|
|
116
|
+
let onChange: (Date) -> Void
|
|
117
|
+
|
|
118
|
+
@State private var currentData: DateTimePickerData
|
|
119
|
+
|
|
120
|
+
private let effectiveMinComponents: DateComponents
|
|
121
|
+
private let effectiveMaxComponents: DateComponents
|
|
122
|
+
private let needCheckRange: Bool
|
|
123
|
+
|
|
124
|
+
private func selectedDataFor(_ name: String) -> String {
|
|
125
|
+
switch name {
|
|
126
|
+
case "day": return DateTimePickerUtils.paddingNum(currentData.day)
|
|
127
|
+
case "month": return DateTimePickerUtils.paddingNum(currentData.month)
|
|
128
|
+
case "year": return String(currentData.year)
|
|
129
|
+
case "hour": return DateTimePickerUtils.paddingNum(currentData.hour)
|
|
130
|
+
case "minute": return DateTimePickerUtils.paddingNum(currentData.minute)
|
|
131
|
+
case "timeMode": return currentData.timeMode
|
|
132
|
+
default: return ""
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/// Mirrors Compose `onWheelChangeValue`: applies value and coerces day/month
|
|
137
|
+
/// to stay within the effective min/max bounds.
|
|
138
|
+
private func onWheelChange(_ name: String, _ value: String) {
|
|
139
|
+
var day = name == "day" ? (Int(value) ?? currentData.day) : currentData.day
|
|
140
|
+
var month = name == "month" ? (Int(value) ?? currentData.month) : currentData.month
|
|
141
|
+
let year = name == "year" ? (Int(value) ?? currentData.year) : currentData.year
|
|
142
|
+
let hour = name == "hour" ? (Int(value) ?? currentData.hour) : currentData.hour
|
|
143
|
+
let minute = name == "minute" ? (Int(value) ?? currentData.minute) : currentData.minute
|
|
144
|
+
let timeMode = name == "timeMode" ? value : currentData.timeMode
|
|
145
|
+
|
|
146
|
+
let maxYear = effectiveMaxComponents.year ?? year
|
|
147
|
+
let minYear = effectiveMinComponents.year ?? year
|
|
148
|
+
let maxMonth = effectiveMaxComponents.month ?? 12
|
|
149
|
+
let minMonth = effectiveMinComponents.month ?? 1
|
|
150
|
+
let maxDayBound = effectiveMaxComponents.day ?? 31
|
|
151
|
+
let minDayBound = effectiveMinComponents.day ?? 1
|
|
152
|
+
|
|
153
|
+
if name == "year" {
|
|
154
|
+
if year == maxYear {
|
|
155
|
+
month = min(max(month, 1), maxMonth)
|
|
156
|
+
} else if year == minYear {
|
|
157
|
+
month = min(max(month, minMonth), 12)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if name == "month" || name == "year" {
|
|
162
|
+
let maxDayOfMonth: Int
|
|
163
|
+
switch month {
|
|
164
|
+
case 4, 6, 9, 11: maxDayOfMonth = 30
|
|
165
|
+
case 2: maxDayOfMonth = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 29 : 28
|
|
166
|
+
default: maxDayOfMonth = 31
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if year == maxYear && month == maxMonth {
|
|
170
|
+
day = min(max(day, 1), maxDayBound)
|
|
171
|
+
} else if year == minYear && month == minMonth {
|
|
172
|
+
day = min(max(day, minDayBound), maxDayOfMonth)
|
|
173
|
+
} else if day > maxDayOfMonth {
|
|
174
|
+
day = maxDayOfMonth
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
currentData = DateTimePickerData(
|
|
179
|
+
day: day,
|
|
180
|
+
month: month,
|
|
181
|
+
year: year,
|
|
182
|
+
hour: hour,
|
|
183
|
+
minute: minute,
|
|
184
|
+
timeMode: timeMode
|
|
185
|
+
)
|
|
186
|
+
emitIfValid()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// Emit `onChange` only when the assembled date is valid and (when bounds were
|
|
190
|
+
/// not supplied) within the effective min/max range. Mirrors the Compose
|
|
191
|
+
/// `snapshotFlow.mapNotNull` filter.
|
|
192
|
+
private func emitIfValid() {
|
|
193
|
+
guard let date = currentData.toDate() else { return }
|
|
194
|
+
if !needCheckRange {
|
|
195
|
+
onChange(date)
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
let calendar = Calendar.current
|
|
199
|
+
guard
|
|
200
|
+
let minDate = calendar.date(from: effectiveMinComponents),
|
|
201
|
+
let maxDate = calendar.date(from: effectiveMaxComponents)
|
|
202
|
+
else {
|
|
203
|
+
onChange(date)
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
if date >= minDate && date <= maxDate {
|
|
207
|
+
onChange(date)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
// MARK: - PickerData
|
|
4
|
+
|
|
5
|
+
/// Internal mutable representation of the picker's current selection.
|
|
6
|
+
/// Mirrors Compose `PickerData`.
|
|
7
|
+
public struct DateTimePickerData: Equatable {
|
|
8
|
+
public var day: Int
|
|
9
|
+
public var month: Int
|
|
10
|
+
public var year: Int
|
|
11
|
+
public var hour: Int
|
|
12
|
+
public var minute: Int
|
|
13
|
+
public var timeMode: String
|
|
14
|
+
|
|
15
|
+
public init(
|
|
16
|
+
day: Int,
|
|
17
|
+
month: Int,
|
|
18
|
+
year: Int,
|
|
19
|
+
hour: Int = 0,
|
|
20
|
+
minute: Int = 0,
|
|
21
|
+
timeMode: String = ""
|
|
22
|
+
) {
|
|
23
|
+
self.day = day
|
|
24
|
+
self.month = month
|
|
25
|
+
self.year = year
|
|
26
|
+
self.hour = hour
|
|
27
|
+
self.minute = minute
|
|
28
|
+
self.timeMode = timeMode
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Convert to a `DateComponents` based value. Returns `nil` if the date is invalid.
|
|
32
|
+
public func toDate(calendar: Calendar = Calendar.current) -> Date? {
|
|
33
|
+
var components = DateComponents()
|
|
34
|
+
components.year = year
|
|
35
|
+
components.month = month
|
|
36
|
+
components.day = day
|
|
37
|
+
components.hour = hour
|
|
38
|
+
components.minute = minute
|
|
39
|
+
components.second = 0
|
|
40
|
+
return calendar.date(from: components)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// MARK: - DateComponent
|
|
45
|
+
|
|
46
|
+
/// A single wheel column descriptor. Mirrors Compose `DateComponent`.
|
|
47
|
+
public struct DateTimePickerComponent: Equatable {
|
|
48
|
+
public let name: String
|
|
49
|
+
public let data: [String]
|
|
50
|
+
|
|
51
|
+
public init(name: String, data: [String]) {
|
|
52
|
+
self.name = name
|
|
53
|
+
self.data = data
|
|
54
|
+
}
|
|
55
|
+
}
|