@momo-kits/native-kits 0.163.1-sp.3-debug → 0.163.1-sp.4-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/.claude/settings.local.json +57 -1
- package/compose/build.gradle.kts +1 -1
- package/compose/compose.podspec +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +5 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +4 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +66 -19
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +15 -3
- package/gradle.properties +1 -1
- package/ios/Application/Components.swift +14 -14
- package/ios/Application/HeaderRight.swift +45 -79
- package/ios/Application/Navigation/component/Header.swift +1 -1
- package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +11 -0
- package/ios/Application/Navigation/component/NavigationFooter.swift +90 -0
- package/ios/Application/Navigation/component/NavigationHeaderRight.swift +196 -0
- package/ios/Application/StackScreen.swift +18 -21
- package/ios/Badge/BadgeRibbon.swift +4 -1
- package/ios/Button/Button.swift +54 -80
- package/ios/Icon/Icon.swift +13 -4
- package/ios/Layout/GridContext.swift +30 -0
- package/ios/Layout/Item.swift +42 -0
- package/ios/Layout/Section.swift +134 -0
- package/ios/native-kits.podspec +2 -1
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +8 -8
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +3 -2
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +5 -12
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconDemo.swift +104 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SectionDemo.swift +100 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +3 -1
- package/package.json +1 -1
|
@@ -72,7 +72,63 @@
|
|
|
72
72
|
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -configuration Debug clean build CODE_SIGNING_ALLOWED=NO)",
|
|
73
73
|
"Bash(git commit *)",
|
|
74
74
|
"Bash(npm view *)",
|
|
75
|
-
"Bash(echo \"EXIT=$? -> not resolvable\")"
|
|
75
|
+
"Bash(echo \"EXIT=$? -> not resolvable\")",
|
|
76
|
+
"Bash(yarn install *)",
|
|
77
|
+
"Bash(RCT_NEW_ARCH_ENABLED=1 pod install)",
|
|
78
|
+
"Bash(xcodebuild -workspace MoMoPlatform.xcworkspace -list)",
|
|
79
|
+
"Bash(git --no-pager diff --stat ios/Application/Localize.swift ios/Application/Navigation/NavigationContainer.swift ios/Popup/PopupDisplay.swift ios/Popup/PopupNotify.swift ios/Template/TrustBanner/TrustBanner.swift)",
|
|
80
|
+
"Bash(git rm *)",
|
|
81
|
+
"Bash(echo \"EXIT=$?\")",
|
|
82
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits diff sample/iosApp/iosApp/Demo/ButtonDemo.swift)",
|
|
83
|
+
"Bash(python3 *)",
|
|
84
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits status --short)",
|
|
85
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits log --oneline -3)",
|
|
86
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits log --oneline -5 -- ios/Button/Button.swift)",
|
|
87
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits diff ios/native-kits.podspec compose/compose.podspec gradle.properties package.json)",
|
|
88
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits show HEAD:ios/Button/Button.swift)",
|
|
89
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits diff package.json ios/native-kits.podspec)",
|
|
90
|
+
"Bash(grep -n \"must be a \\\\`.background\\\\` of the label\" /Users/sophia/Workspace/momo/momo-app/node_modules/@momo-kits/native-kits/ios/Button/Button.swift)",
|
|
91
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits show -s --format=\"%h %ci %s\" 953b234d)",
|
|
92
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-app show -s --format=\"%h %ci %s\" f8757a14437)",
|
|
93
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-app log -S '\"@momo-kits/native-kits\": \"0.163.1-beta.18\"' --format=\"%h %ci %s\" -- package.json)",
|
|
94
|
+
"Bash(swiftc -O repro_isfull.swift -o repro_isfull)",
|
|
95
|
+
"Bash(./repro_isfull)",
|
|
96
|
+
"Bash(grep -n '^\\\\[32;1m$\\\\|section_start\\\\|xcodebuild.*-workspace\\\\|xcodebuild.*archive\\\\|Prebuilt\\\\|prebuilt\\\\|framework.*download\\\\|rugby\\\\|Rugby' /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/7e2b5bd7-f8b3-42f7-b242-127fa8eabd12/scratchpad/job_trace.log)",
|
|
97
|
+
"Bash(grep -n '\\\\[32;1m\\\\$' /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/7e2b5bd7-f8b3-42f7-b242-127fa8eabd12/scratchpad/job_trace.log)",
|
|
98
|
+
"Bash(npm pack *)",
|
|
99
|
+
"Bash(mkdir -p b13 b18)",
|
|
100
|
+
"Bash(tar xzf *)",
|
|
101
|
+
"Bash(git *)",
|
|
102
|
+
"Bash(tar -tzf momo-kits-native-kits-0.163.1-beta.18.tgz)",
|
|
103
|
+
"Bash(tar -xzf momo-kits-native-kits-0.163.1-beta.18.tgz package/ios/Button/Button.swift)",
|
|
104
|
+
"Bash(tar -xzf momo-kits-native-kits-0.162.28.tgz package/ios/Button/Button.swift -C .)",
|
|
105
|
+
"Bash(mkdir -p old)",
|
|
106
|
+
"Bash(tar -xzf momo-kits-native-kits-0.162.28.tgz -C old package/ios/Button/Button.swift)",
|
|
107
|
+
"Bash(nm '/private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/7e2b5bd7-f8b3-42f7-b242-127fa8eabd12/scratchpad/ipa_extract/Payload/MoMoPlatform UAT.app/MoMoPlatform UAT')",
|
|
108
|
+
"Bash(xcodebuild -workspace /Users/sophia/Workspace/momo/momo-native-kits/sample/iosApp/iosApp.xcworkspace -list)",
|
|
109
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' build)",
|
|
110
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build-verify build)",
|
|
111
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build-verify build)",
|
|
112
|
+
"Bash(./gradlew :sample:shared:syncComposeResourcesForIos)",
|
|
113
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'platform=iOS Simulator,id=E6A899C0-098E-473A-95B8-A2BBD2D42A92' -derivedDataPath build-verify build)",
|
|
114
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -quiet build)",
|
|
115
|
+
"Bash(xcodebuild -workspace sample/iosApp/iosApp.xcworkspace -list)",
|
|
116
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -destination 'id=0228A4B2-57E0-4E56-BFAD-DB9E95044AD9' -derivedDataPath /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/6986983a-795d-419d-9d78-fcc100e87876/scratchpad/dd build)",
|
|
117
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -destination 'id=1E6F9A79-5E64-4590-BEA2-828D75D99393' -derivedDataPath /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/6986983a-795d-419d-9d78-fcc100e87876/scratchpad/dd build)",
|
|
118
|
+
"Bash([ -s $S/kb.png ])",
|
|
119
|
+
"Bash(sips -g pixelWidth -g pixelHeight /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/6986983a-795d-419d-9d78-fcc100e87876/scratchpad/kb.png)",
|
|
120
|
+
"Bash(defaults read *)",
|
|
121
|
+
"Bash(defaults write *)",
|
|
122
|
+
"Bash(xcrun xcodebuild *)",
|
|
123
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -quiet build)",
|
|
124
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'platform=iOS Simulator,id=E6A899C0-098E-473A-95B8-A2BBD2D42A92' -quiet build)",
|
|
125
|
+
"Read(//tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/3e8adc08-a7e7-4169-aee6-8b22a6996f38/scratchpad/**)",
|
|
126
|
+
"Bash(echo \"parse-exit=$?\")",
|
|
127
|
+
"Bash(echo \"=== exit $?\")",
|
|
128
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -configuration Debug build)",
|
|
129
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'platform=iOS Simulator,id=E6A899C0-098E-473A-95B8-A2BBD2D42A92' -configuration Debug build)",
|
|
130
|
+
"Bash(./gradlew :sample:shared:compileCommonMainKotlinMetadata -q)",
|
|
131
|
+
"Bash(echo \"gradle=$?\")"
|
|
76
132
|
]
|
|
77
133
|
}
|
|
78
134
|
}
|
package/compose/build.gradle.kts
CHANGED
package/compose/compose.podspec
CHANGED
|
@@ -29,6 +29,7 @@ import androidx.compose.ui.Alignment
|
|
|
29
29
|
import androidx.compose.ui.Modifier
|
|
30
30
|
import androidx.compose.ui.focus.onFocusChanged
|
|
31
31
|
import androidx.compose.ui.graphics.Color
|
|
32
|
+
import androidx.compose.ui.graphics.takeOrElse
|
|
32
33
|
import androidx.compose.ui.text.TextStyle
|
|
33
34
|
import androidx.compose.ui.text.input.KeyboardType
|
|
34
35
|
import androidx.compose.ui.text.style.TextOverflow
|
|
@@ -49,7 +50,7 @@ import vn.momo.kits.utils.ifTrue
|
|
|
49
50
|
internal fun RenderRightIconSearch(
|
|
50
51
|
loading: Boolean,
|
|
51
52
|
icon: String,
|
|
52
|
-
color: Color
|
|
53
|
+
color: Color?,
|
|
53
54
|
onClick: () -> Unit,
|
|
54
55
|
iconModifier: Modifier = Modifier
|
|
55
56
|
) {
|
|
@@ -57,7 +58,7 @@ internal fun RenderRightIconSearch(
|
|
|
57
58
|
Box(Modifier.padding(horizontal = Spacing.S)) {
|
|
58
59
|
CircularProgressIndicator(
|
|
59
60
|
modifier = Modifier.size(16.dp),
|
|
60
|
-
color = color,
|
|
61
|
+
color = color ?: AppTheme.current.colors.text.default,
|
|
61
62
|
trackColor = Color.Transparent,
|
|
62
63
|
strokeWidth = 2.dp
|
|
63
64
|
)
|
|
@@ -90,7 +91,7 @@ data class InputSearchProps(
|
|
|
90
91
|
val onPressButtonText: () -> Unit = {},
|
|
91
92
|
val disabled: Boolean = false,
|
|
92
93
|
val icon: String = "",
|
|
93
|
-
val iconColor: Color = Color
|
|
94
|
+
val iconColor: Color? = Color.Unspecified,
|
|
94
95
|
val onRightIconPressed: () -> Unit = {},
|
|
95
96
|
val onFocus: () -> Unit = {},
|
|
96
97
|
val onBlur: () -> Unit = {},
|
|
@@ -113,7 +114,6 @@ data class InputSearchProps(
|
|
|
113
114
|
fun InputSearch(
|
|
114
115
|
inputSearchProps: InputSearchProps = InputSearchProps(
|
|
115
116
|
text = remember { mutableStateOf("") },
|
|
116
|
-
iconColor = AppTheme.current.colors.text.default
|
|
117
117
|
),
|
|
118
118
|
) {
|
|
119
119
|
var isFocused by remember { mutableStateOf(false) }
|
|
@@ -121,7 +121,7 @@ fun InputSearch(
|
|
|
121
121
|
val disabledColor = AppTheme.current.colors.text.disable
|
|
122
122
|
var textColor = AppTheme.current.colors.text.default
|
|
123
123
|
var placeholderColor = AppTheme.current.colors.text.hint
|
|
124
|
-
var iconTintColor = inputSearchProps.iconColor
|
|
124
|
+
var iconTintColor = inputSearchProps.iconColor?.takeOrElse { AppTheme.current.colors.text.default }
|
|
125
125
|
|
|
126
126
|
if (inputSearchProps.disabled) {
|
|
127
127
|
textColor = disabledColor
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
package vn.momo.kits.layout
|
|
2
2
|
|
|
3
|
-
import androidx.compose.foundation.layout.
|
|
3
|
+
import androidx.compose.foundation.layout.Column
|
|
4
4
|
import androidx.compose.foundation.layout.height
|
|
5
5
|
import androidx.compose.foundation.layout.width
|
|
6
6
|
import androidx.compose.runtime.Composable
|
|
@@ -32,5 +32,7 @@ internal fun Item(
|
|
|
32
32
|
m = m.width(grid.sizeForSpan(widthSpan))
|
|
33
33
|
if (heightSpan > 0) m = m.height(grid.sizeForSpan(heightSpan))
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
// A Column (not a Box) so multiple children flow VERTICALLY instead of stacking
|
|
36
|
+
// on top of each other — matches the React Item's flex-column content.
|
|
37
|
+
Column(modifier = m) { content() }
|
|
36
38
|
}
|
|
@@ -28,6 +28,7 @@ import androidx.compose.runtime.remember
|
|
|
28
28
|
import androidx.compose.runtime.rememberCoroutineScope
|
|
29
29
|
import androidx.compose.ui.Alignment
|
|
30
30
|
import androidx.compose.ui.Modifier
|
|
31
|
+
import androidx.compose.ui.graphics.Brush
|
|
31
32
|
import androidx.compose.ui.graphics.Color
|
|
32
33
|
import androidx.compose.ui.input.pointer.pointerInput
|
|
33
34
|
import androidx.compose.ui.platform.LocalDensity
|
|
@@ -57,6 +58,9 @@ internal fun BottomSheet(
|
|
|
57
58
|
header: BottomHeader,
|
|
58
59
|
isSurface: Boolean = false,
|
|
59
60
|
barrierDismissible: Boolean = true,
|
|
61
|
+
draggable: Boolean = true,
|
|
62
|
+
useBottomInset: Boolean = true,
|
|
63
|
+
footerComponent: (@Composable () -> Unit)? = null,
|
|
60
64
|
onDismiss: (() -> Unit)?
|
|
61
65
|
) {
|
|
62
66
|
val screenHeightDp = getScreenHeight()
|
|
@@ -161,30 +165,35 @@ internal fun BottomSheet(
|
|
|
161
165
|
.noFeedbackClickable { },
|
|
162
166
|
contentAlignment = Alignment.BottomCenter
|
|
163
167
|
) {
|
|
164
|
-
|
|
168
|
+
val bottomInset = if (useBottomInset) {
|
|
169
|
+
(AppNavigationBar.current - keyboardSizeState().value).coerceAtLeast(0.dp)
|
|
170
|
+
} else 0.dp
|
|
171
|
+
Column(Modifier.padding(bottom = bottomInset)) {
|
|
165
172
|
Box(
|
|
166
173
|
modifier = Modifier
|
|
167
174
|
.height(72.dp)
|
|
168
175
|
.fillMaxWidth()
|
|
169
|
-
.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
change
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
176
|
+
.conditional(draggable) {
|
|
177
|
+
pointerInput(Unit) {
|
|
178
|
+
detectDragGestures(
|
|
179
|
+
onDrag = { change, dragAmount ->
|
|
180
|
+
change.consume()
|
|
181
|
+
coroutineScope.launch {
|
|
182
|
+
val newOffset = (sheetOffset.value + dragAmount.y).coerceAtLeast(0f)
|
|
183
|
+
sheetOffset.snapTo(newOffset)
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
onDragEnd = {
|
|
187
|
+
coroutineScope.launch {
|
|
188
|
+
if (sheetOffset.value > sheetCloseOffset) {
|
|
189
|
+
closeEvent()
|
|
190
|
+
} else {
|
|
191
|
+
sheetOffset.animateTo(0f)
|
|
192
|
+
}
|
|
184
193
|
}
|
|
185
194
|
}
|
|
186
|
-
|
|
187
|
-
|
|
195
|
+
)
|
|
196
|
+
}
|
|
188
197
|
}
|
|
189
198
|
) {
|
|
190
199
|
Column(
|
|
@@ -235,12 +244,50 @@ internal fun BottomSheet(
|
|
|
235
244
|
}
|
|
236
245
|
}
|
|
237
246
|
Divider()
|
|
238
|
-
|
|
247
|
+
if (footerComponent != null) {
|
|
248
|
+
Box(Modifier.weight(1f, fill = false)) {
|
|
249
|
+
content()
|
|
250
|
+
}
|
|
251
|
+
BottomSheetFooter(footerComponent)
|
|
252
|
+
} else {
|
|
253
|
+
content()
|
|
254
|
+
}
|
|
239
255
|
}
|
|
240
256
|
}
|
|
241
257
|
}
|
|
242
258
|
}
|
|
243
259
|
|
|
260
|
+
@Composable
|
|
261
|
+
private fun BottomSheetFooter(footerComponent: @Composable () -> Unit) {
|
|
262
|
+
val shadowBrush = remember {
|
|
263
|
+
Brush.verticalGradient(
|
|
264
|
+
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.05f))
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
Box {
|
|
269
|
+
Box(
|
|
270
|
+
Modifier
|
|
271
|
+
.fillMaxWidth()
|
|
272
|
+
.background(AppTheme.current.colors.background.surface)
|
|
273
|
+
.conditional(IsShowBaseLineDebug) {
|
|
274
|
+
border(1.dp, Colors.blue_03)
|
|
275
|
+
}
|
|
276
|
+
.padding(vertical = Spacing.S)
|
|
277
|
+
) {
|
|
278
|
+
footerComponent()
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
Box(
|
|
282
|
+
modifier = Modifier
|
|
283
|
+
.fillMaxWidth()
|
|
284
|
+
.height(6.dp)
|
|
285
|
+
.offset(x = 0.dp, y = (-6).dp)
|
|
286
|
+
.background(shadowBrush)
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
244
291
|
sealed class BottomHeader {
|
|
245
292
|
data class Title(
|
|
246
293
|
val data: String = "Bottom Sheet Title",
|
|
@@ -139,10 +139,13 @@ class Navigator(
|
|
|
139
139
|
isSurface: Boolean = false,
|
|
140
140
|
barrierDismissible: Boolean = true,
|
|
141
141
|
onDismiss: (() -> Unit)? = null,
|
|
142
|
-
bottomSheetHeader: BottomHeader? = null
|
|
142
|
+
bottomSheetHeader: BottomHeader? = null,
|
|
143
|
+
draggable: Boolean = true,
|
|
144
|
+
useBottomInset: Boolean = true,
|
|
145
|
+
footerComponent: (@Composable () -> Unit)? = null
|
|
143
146
|
){
|
|
144
147
|
val id = currentScreen()?.id ?: -1
|
|
145
|
-
OverplayComponentRegistry.registerOverplay(id, content, OverplayComponentType.BOTTOM_SHEET, isSurface, barrierDismissible, onDismiss, bottomSheetHeader)
|
|
148
|
+
OverplayComponentRegistry.registerOverplay(id, content, OverplayComponentType.BOTTOM_SHEET, isSurface, barrierDismissible, onDismiss, bottomSheetHeader, draggable, useBottomInset, footerComponent)
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
fun showSnackBar(snackBar: SnackBar, onDismiss: (() -> Unit)? = null) {
|
|
@@ -257,6 +260,9 @@ sealed class OverplayComponentParams {
|
|
|
257
260
|
val onDismiss: (() -> Unit)? = null,
|
|
258
261
|
val barrierDismissible: Boolean = true,
|
|
259
262
|
val bottomSheetHeader: BottomHeader? = null,
|
|
263
|
+
val draggable: Boolean = true,
|
|
264
|
+
val useBottomInset: Boolean = true,
|
|
265
|
+
val footerComponent: (@Composable () -> Unit)? = null,
|
|
260
266
|
) : OverplayComponentParams()
|
|
261
267
|
|
|
262
268
|
class SnackBar : OverplayComponentParams()
|
|
@@ -288,10 +294,13 @@ object OverplayComponentRegistry {
|
|
|
288
294
|
barrierDismissible: Boolean = true,
|
|
289
295
|
onDismiss: (() -> Unit)?,
|
|
290
296
|
bottomSheetHeader: BottomHeader? = null,
|
|
297
|
+
draggable: Boolean = true,
|
|
298
|
+
useBottomInset: Boolean = true,
|
|
299
|
+
footerComponent: (@Composable () -> Unit)? = null,
|
|
291
300
|
){
|
|
292
301
|
val params = when(type){
|
|
293
302
|
OverplayComponentType.MODAL -> OverplayComponentParams.Modal(onDismiss, barrierDismissible)
|
|
294
|
-
OverplayComponentType.BOTTOM_SHEET -> OverplayComponentParams.BottomSheet(isSurface, onDismiss, barrierDismissible, bottomSheetHeader)
|
|
303
|
+
OverplayComponentType.BOTTOM_SHEET -> OverplayComponentParams.BottomSheet(isSurface, onDismiss, barrierDismissible, bottomSheetHeader, draggable, useBottomInset, footerComponent)
|
|
295
304
|
OverplayComponentType.SNACK_BAR -> OverplayComponentParams.SnackBar()
|
|
296
305
|
}
|
|
297
306
|
|
|
@@ -333,6 +342,9 @@ object OverplayComponentRegistry {
|
|
|
333
342
|
header = params.bottomSheetHeader ?: Title(),
|
|
334
343
|
isSurface = params.isSurface,
|
|
335
344
|
barrierDismissible = params.barrierDismissible,
|
|
345
|
+
draggable = params.draggable,
|
|
346
|
+
useBottomInset = params.useBottomInset,
|
|
347
|
+
footerComponent = params.footerComponent,
|
|
336
348
|
onDismiss = params.onDismiss
|
|
337
349
|
)
|
|
338
350
|
}
|
package/gradle.properties
CHANGED
|
@@ -100,6 +100,20 @@ public struct HeaderBackground: View {
|
|
|
100
100
|
.frame(height: height)
|
|
101
101
|
.shadow(color: Colors.black20.opacity(0.2), radius: 10, x: 0, y: -2)
|
|
102
102
|
.background(backgroundColor)
|
|
103
|
+
.overlay(
|
|
104
|
+
headerTransparent ? AnyView(EmptyView()) :
|
|
105
|
+
AnyView(
|
|
106
|
+
Rectangle()
|
|
107
|
+
.fill(LinearGradient(
|
|
108
|
+
gradient: Gradient(colors: [
|
|
109
|
+
Color(red: 1, green: 0.8, blue: 0.87),
|
|
110
|
+
Color(red: 1, green: 0.8, blue: 0.87).opacity(0.5)
|
|
111
|
+
]),
|
|
112
|
+
startPoint: .top,
|
|
113
|
+
endPoint: .bottom))
|
|
114
|
+
.opacity(opacity)
|
|
115
|
+
.frame(height: height))
|
|
116
|
+
)
|
|
103
117
|
if !headerTransparent {
|
|
104
118
|
Rectangle()
|
|
105
119
|
.fill(Color.black.opacity(0.1))
|
|
@@ -132,17 +146,6 @@ public struct HeaderBackground: View {
|
|
|
132
146
|
}
|
|
133
147
|
}
|
|
134
148
|
|
|
135
|
-
// MARK: - Header right width preference
|
|
136
|
-
|
|
137
|
-
/// Reports the measured width of the header-right area so the animated search
|
|
138
|
-
/// header can compute its trailing inset (mirrors Compose's headerRightWidthPx).
|
|
139
|
-
public struct HeaderRightWidthKey: PreferenceKey {
|
|
140
|
-
public static var defaultValue: CGFloat = 0
|
|
141
|
-
public static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
|
142
|
-
value = max(value, nextValue())
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
149
|
// MARK: - Bottom-tab root preference
|
|
147
150
|
|
|
148
151
|
/// Set by `BottomTab` on appear so its enclosing `StackScreen` can detect that
|
|
@@ -232,9 +235,6 @@ public struct Header: View {
|
|
|
232
235
|
|
|
233
236
|
if let headerRight = headerRight {
|
|
234
237
|
AnyView(headerRight())
|
|
235
|
-
.background(GeometryReader { geo in
|
|
236
|
-
Color.clear.preference(key: HeaderRightWidthKey.self, value: geo.size.width)
|
|
237
|
-
})
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
.padding(.horizontal, 12)
|
|
@@ -101,98 +101,69 @@ struct ToolkitHeaderRight: View {
|
|
|
101
101
|
var tintColor: Color?
|
|
102
102
|
@State private var isFavorite: Bool = false
|
|
103
103
|
@State private var isLoading: Bool = false
|
|
104
|
-
@
|
|
105
|
-
|
|
106
|
-
private func apiValue(_ value: Any?) -> Any {
|
|
107
|
-
value ?? NSNull()
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private var contextMap: [String: Any] {
|
|
111
|
-
let context = environment.applicationContext
|
|
112
|
-
return [
|
|
113
|
-
"appId": apiValue(context?.appId),
|
|
114
|
-
"code": apiValue(context?.appCode),
|
|
115
|
-
"name": apiValue(context?.appName),
|
|
116
|
-
"icon": apiValue(context?.appIcon),
|
|
117
|
-
"description": apiValue(context?.description),
|
|
118
|
-
"support": apiValue(context?.support),
|
|
119
|
-
"toolkitConfig": apiValue(context?.toolkitConfig),
|
|
120
|
-
"providerId": apiValue(context?.providerId),
|
|
121
|
-
"permissions": apiValue(context?.permissions)
|
|
122
|
-
]
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private var shouldShowShortcut: Bool {
|
|
126
|
-
headerRight?.useShortcut == true && !(headerRight?.useMore == true && environment.applicationContext == nil)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private func parseResponse(_ response: String) -> Any? {
|
|
130
|
-
guard let jsonData = response.data(using: .utf8),
|
|
131
|
-
let json = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any] else {
|
|
132
|
-
return nil
|
|
133
|
-
}
|
|
134
|
-
return json["response"]
|
|
135
|
-
}
|
|
104
|
+
@EnvironmentObject private var environment: ApplicationEnvironment
|
|
136
105
|
|
|
137
106
|
// MARK: - Actions
|
|
138
|
-
private func loadFavoriteState() {
|
|
139
|
-
environment.composeApi?.request(
|
|
140
|
-
funcName: "isFavoriteApp",
|
|
141
|
-
params: ["code": apiValue(environment.applicationContext?.appCode)]
|
|
142
|
-
) { response in
|
|
143
|
-
if let isFavorite = parseResponse(response) as? Bool {
|
|
144
|
-
self.isFavorite = isFavorite
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
107
|
private func onPressShortcut() {
|
|
150
108
|
environment.composeApi?.request(
|
|
151
109
|
funcName: "onToolAction",
|
|
152
|
-
params: [
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
]
|
|
156
|
-
) { response in
|
|
157
|
-
if let result = parseResponse(response) as? [String: Any],
|
|
158
|
-
result["success"] as? Bool == true {
|
|
159
|
-
isFavorite.toggle()
|
|
160
|
-
}
|
|
110
|
+
params: ["item": ["key": "onFavorite"]]
|
|
111
|
+
) { _ in
|
|
112
|
+
isFavorite.toggle()
|
|
161
113
|
}
|
|
162
114
|
}
|
|
163
115
|
|
|
164
116
|
private func onPressHelpCenter() {
|
|
117
|
+
let context = environment.applicationContext
|
|
118
|
+
let paramMap: [String: Any] = [
|
|
119
|
+
"appId": context?.appId,
|
|
120
|
+
"code": context?.appCode,
|
|
121
|
+
"name": context?.appName,
|
|
122
|
+
"icon": context?.appIcon,
|
|
123
|
+
"description": context?.description
|
|
124
|
+
]
|
|
165
125
|
environment.composeApi?.request(
|
|
166
126
|
funcName: "showHelpCenter",
|
|
167
|
-
params:
|
|
168
|
-
"appId": apiValue(environment.applicationContext?.appId),
|
|
169
|
-
"code": apiValue(environment.applicationContext?.appCode),
|
|
170
|
-
"name": apiValue(environment.applicationContext?.appName),
|
|
171
|
-
"icon": apiValue(environment.applicationContext?.appIcon),
|
|
172
|
-
"description": apiValue(environment.applicationContext?.description)
|
|
173
|
-
]
|
|
127
|
+
params: paramMap
|
|
174
128
|
) { _ in }
|
|
175
129
|
}
|
|
176
130
|
|
|
177
131
|
private func onPressClose() {
|
|
178
132
|
environment.composeApi?.request(
|
|
179
133
|
funcName: "dismissAll",
|
|
180
|
-
params:
|
|
134
|
+
params: ""
|
|
181
135
|
) { _ in }
|
|
182
136
|
}
|
|
183
137
|
|
|
184
138
|
private func onPressMore() {
|
|
139
|
+
let context = environment.applicationContext
|
|
185
140
|
let params: [String: Any] = [
|
|
186
|
-
"useSystemTools": headerRight?.useSystemTools
|
|
141
|
+
"useSystemTools": headerRight?.useSystemTools,
|
|
187
142
|
"tools": headerRight?.tools.map { $0.toMap() } ?? [],
|
|
188
|
-
"context":
|
|
143
|
+
"context": [
|
|
144
|
+
"appId": context?.appId,
|
|
145
|
+
"code": context?.appCode,
|
|
146
|
+
"name": context?.appName,
|
|
147
|
+
"icon": context?.appIcon,
|
|
148
|
+
"description": context?.description,
|
|
149
|
+
"support": context?.support,
|
|
150
|
+
"toolkitConfig": context?.toolkitConfig,
|
|
151
|
+
"providerId": context?.providerId,
|
|
152
|
+
"permissions": context?.permissions
|
|
153
|
+
]
|
|
189
154
|
]
|
|
190
155
|
environment.composeApi?.request(
|
|
191
156
|
funcName: "showTools",
|
|
192
157
|
params: params
|
|
193
158
|
) { response in
|
|
194
|
-
|
|
195
|
-
|
|
159
|
+
do {
|
|
160
|
+
if let jsonData = response.data(using: .utf8),
|
|
161
|
+
let json = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any],
|
|
162
|
+
let toolResponse = json["response"] as? String {
|
|
163
|
+
headerRight?.toolCallback?(toolResponse)
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
print("Error parsing response:", error)
|
|
196
167
|
}
|
|
197
168
|
}
|
|
198
169
|
}
|
|
@@ -224,7 +195,7 @@ struct ToolkitHeaderRight: View {
|
|
|
224
195
|
} ?? false
|
|
225
196
|
|
|
226
197
|
HStack(alignment: .center, spacing: 0) {
|
|
227
|
-
if
|
|
198
|
+
if headerRight?.useShortcut == true {
|
|
228
199
|
NavigationButton(
|
|
229
200
|
disabled: isLoading,
|
|
230
201
|
icon: navButtonConfig.icon,
|
|
@@ -235,17 +206,15 @@ struct ToolkitHeaderRight: View {
|
|
|
235
206
|
}
|
|
236
207
|
|
|
237
208
|
HStack(alignment: .center, spacing: 0) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
.frame(width: 0.5, height: 12)
|
|
248
|
-
}
|
|
209
|
+
Icon(source: "help_center", size: 20, color: tintColor ?? Colors.black17)
|
|
210
|
+
.padding(4)
|
|
211
|
+
.onTapGesture {
|
|
212
|
+
onPressHelpCenter()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
Rectangle()
|
|
216
|
+
.fill(tintColor ?? Colors.black20)
|
|
217
|
+
.frame(width: 0.5, height: 12)
|
|
249
218
|
|
|
250
219
|
Icon(source: "16_basic_home", size: 20, color: tintColor ?? Colors.black17)
|
|
251
220
|
.padding(4)
|
|
@@ -262,9 +231,6 @@ struct ToolkitHeaderRight: View {
|
|
|
262
231
|
)
|
|
263
232
|
.padding(.leading, Spacing.S)
|
|
264
233
|
}
|
|
265
|
-
.onAppear {
|
|
266
|
-
loadFavoriteState()
|
|
267
|
-
}
|
|
268
234
|
}
|
|
269
235
|
}
|
|
270
236
|
|
|
@@ -22,7 +22,7 @@ public struct NavigationHeader: View {
|
|
|
22
22
|
/// Optional rich title (mirrors Compose's `HeaderTitle`); `.user` renders an
|
|
23
23
|
/// avatar group, `.default`/nil renders plain `title`.
|
|
24
24
|
var headerTitle: HeaderTitle?
|
|
25
|
-
var headerRight: (() -> any View)? = {
|
|
25
|
+
var headerRight: (() -> any View)? = { NavigationHeaderRight() }
|
|
26
26
|
var goBack: (() -> Void)?
|
|
27
27
|
var opacity: CGFloat = 1
|
|
28
28
|
var animatedHeader: AnimatedHeader?
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
/// Reports the measured width of the header-right area so the animated search
|
|
4
|
+
/// header can compute its trailing inset (mirrors Compose's headerRightWidthPx).
|
|
5
|
+
/// Written by the header views (`NavigationHeader`) and read by `StackScreen`.
|
|
6
|
+
public struct HeaderRightWidthKey: PreferenceKey {
|
|
7
|
+
public static var defaultValue: CGFloat = 0
|
|
8
|
+
public static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
|
9
|
+
value = max(value, nextValue())
|
|
10
|
+
}
|
|
11
|
+
}
|