@momo-kits/native-kits 0.164.1-beta.1-debug → 0.164.1-beta.10-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.
Files changed (38) hide show
  1. package/.claude/settings.local.json +185 -0
  2. package/compose/build.gradle.kts +1 -1
  3. package/compose/compose.podspec +1 -1
  4. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +19 -0
  5. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +12 -0
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +27 -5
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +1 -3
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +16 -0
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +28 -41
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +50 -30
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +35 -1
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +24 -1
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +164 -0
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +41 -0
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +15 -0
  16. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +40 -0
  17. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ComposeBackGesture.ios.kt +65 -0
  18. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +35 -0
  19. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +23 -2
  20. package/gradle.properties +1 -1
  21. package/ios/native-kits.podspec +1 -1
  22. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  23. package/local.properties +2 -2
  24. package/package.json +1 -1
  25. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  26. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  27. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  28. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  29. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  30. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  31. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  32. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  33. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  34. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  35. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  36. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  37. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  38. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
@@ -0,0 +1,185 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(curl -s -o /dev/null -w \"%{http_code}\" \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.144.6/skiko-android-0.144.6.pom\")",
5
+ "Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/maven-metadata.xml\")",
6
+ "Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko/maven-metadata.xml\")",
7
+ "Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko/0.144.6/skiko-0.144.6.module\")",
8
+ "Bash(curl -s -o /dev/null -w '%{http_code}' https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.144.6/skiko-android-0.144.6.__TRACKED_VAR__)",
9
+ "Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.144.6/\")",
10
+ "Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/\")",
11
+ "Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.148.1/skiko-android-0.148.1.pom\")",
12
+ "Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.144.5/skiko-android-0.144.5.pom\")",
13
+ "Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" \"https://dl.google.com/dl/android/maven2/org/jetbrains/skiko/skiko-android/0.144.6/skiko-android-0.144.6.pom\")",
14
+ "Bash(curl -s \"https://search.maven.org/solrsearch/select?q=a:skiko-android&rows=5&wt=json\")",
15
+ "Bash(curl -sL -o /dev/null -w \"%{http_code} %{url_effective}\\\\n\" \"https://repo1.maven.org/maven2/org/jetbrains/skiko/skiko-android/0.144.6/skiko-android-0.144.6.pom\")",
16
+ "Bash(curl *)",
17
+ "Bash(./gradlew :sample:androidApp:dependencies --configuration debugRuntimeClasspath)",
18
+ "Bash(./gradlew :sample:shared:compileDebugKotlinAndroid)",
19
+ "Bash(./gradlew :sample:androidApp:compileDebugKotlin)",
20
+ "Bash(ls -d *.xcodeproj)",
21
+ "Bash(grep -c ChipDemo.swift __TRACKED_VAR__/project.pbxproj)",
22
+ "Bash(grep -c PBXFileSystemSynchronizedRootGroup __TRACKED_VAR__/project.pbxproj)",
23
+ "Bash(grep -c InformationDemo.swift __TRACKED_VAR__/project.pbxproj)",
24
+ "Bash(plutil -lint project.pbxproj)",
25
+ "Bash(xcode-select -p)",
26
+ "Bash(/usr/bin/xcrun xcodebuild *)",
27
+ "Bash(echo \"exit: $?\")",
28
+ "Bash(/Applications/Xcode26.app/Contents/Developer/usr/bin/xcodebuild -version)",
29
+ "Bash(./gradlew :compose:tasks --all)",
30
+ "Bash(grep -n \"vanniktech\\\\|mavenPublishing\\\\|^publishing\\\\|version = gitlabVersion\\\\|namespace =\\\\|compileSdk =\\\\|minSdk =\\\\|GitLabPackages\\\\|name = \\\\\"\\\\${gitlabRepo}Packages\\\\\"\")",
31
+ "Bash(git checkout *)",
32
+ "Bash(./gradlew :compose:publishAllPublicationsToGitLabPackagesRepository --dry-run)",
33
+ "Bash(git fetch *)",
34
+ "Bash(git pull *)",
35
+ "Bash(git push *)",
36
+ "Bash(git branch *)",
37
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -list)",
38
+ "Bash(xcrun simctl *)",
39
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14 Pro' -configuration Debug build CODE_SIGNING_ALLOWED=NO)",
40
+ "Bash(pod install *)",
41
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'id=1E6F9A79-5E64-4590-BEA2-828D75D99393' -configuration Debug build CODE_SIGNING_ALLOWED=NO)",
42
+ "Bash(xcrun swiftc *)",
43
+ "Bash(echo \"=== exit: $? \\(1=none found\\) ===\")",
44
+ "Bash(cat Radius.swift)",
45
+ "Bash(cat Spacing.swift)",
46
+ "Bash(echo \"exit=$?\")",
47
+ "Bash(ruby *)",
48
+ "Bash(xcodebuild -list -workspace iosApp.xcworkspace)",
49
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14 Pro' build)",
50
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'platform=iOS Simulator,id=E6A899C0-098E-473A-95B8-A2BBD2D42A92' build)",
51
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'platform=iOS Simulator,id=E6A899C0-098E-473A-95B8-A2BBD2D42A92' build)",
52
+ "Bash(xcodebuild build *)",
53
+ "Bash(git stash *)",
54
+ "Bash(plutil -lint sample/iosApp/iosApp.xcodeproj/project.pbxproj)",
55
+ "Bash(git add *)",
56
+ "Bash(git commit -m 'feat: DS-646 [ci build] *)",
57
+ "Bash(git commit -q -m 'fix: DS-656 [ci build] *)",
58
+ "Bash(xargs git log --oneline -1)",
59
+ "Bash(git rev-list *)",
60
+ "Bash(git status *)",
61
+ "Bash(git rebase *)",
62
+ "Bash(git merge *)",
63
+ "Bash(git reset *)",
64
+ "Bash(awk '/^ *)",
65
+ "Bash(git ls-tree *)",
66
+ "Bash(awk *)",
67
+ "Read(//Users/sophia/Workspace/momo/momo-app/**)",
68
+ "Bash(git log *)",
69
+ "Bash(xcodebuild -version)",
70
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -configuration Debug build CODE_SIGNING_ALLOWED=NO)",
71
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -configuration Debug build CODE_SIGNING_ALLOWED=NO)",
72
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -configuration Debug clean build CODE_SIGNING_ALLOWED=NO)",
73
+ "Bash(git commit *)",
74
+ "Bash(npm view *)",
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=$?\")",
132
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'id=0228A4B2-57E0-4E56-BFAD-DB9E95044AD9' -derivedDataPath build/dd build)",
133
+ "Bash(osascript *)",
134
+ "Bash(screencapture -x -R253,53,452,950 win.png)",
135
+ "Bash(sips -g pixelWidth -g pixelHeight win.png)",
136
+ "Bash(screencapture -x -R\"253,53,452,950\" win.png)",
137
+ "Bash(screencapture -x full.png)",
138
+ "Bash(sips -g pixelWidth -g pixelHeight full.png)",
139
+ "Bash(sips -c 1900 904 --cropOffset 106 506 full.png --out crop.png)",
140
+ "Bash(swiftc -O mouse.swift -o mouse)",
141
+ "Bash(./mouse click *)",
142
+ "Bash(./mouse drag *)",
143
+ "Bash(sips -c 900 924 --cropOffset 0 0 s12.png --out s12crop.png)",
144
+ "Bash(sips -c 300 1170 --cropOffset 300 0 s12.png --out s12top.png)",
145
+ "Bash(sips -c 700 1170 --cropOffset 250 0 t1.png --out t1c.png)",
146
+ "Bash(sips -c 700 1170 --cropOffset 250 0 t2.png --out t2c.png)",
147
+ "Bash(sips -c 700 1170 --cropOffset 150 0 t3.png --out t3c.png)",
148
+ "Bash(sips -c 1200 1170 --cropOffset 600 0 t4.png --out t4c.png)",
149
+ "Bash(sips -c 600 1170 --cropOffset 150 0 t5.png --out t5c.png)",
150
+ "Bash(sips -c 500 1170 --cropOffset 150 0 u1.png --out u1c.png)",
151
+ "Bash(cp /Users/sophia/Workspace/momo/momo-native-kits/ios/Application/Navigation/NavigationContainer.swift /Users/sophia/Workspace/momo/momo-app/node_modules/@momo-kits/native-kits/ios/Application/Navigation/NavigationContainer.swift)",
152
+ "Bash(cp /Users/sophia/Workspace/momo/momo-native-kits/ios/Application/Navigation/Navigator.swift /Users/sophia/Workspace/momo/momo-app/node_modules/@momo-kits/native-kits/ios/Application/Navigation/Navigator.swift)",
153
+ "Bash(cp /Users/sophia/Workspace/momo/momo-native-kits/ios/Application/Navigation/NavigatorManager.swift /Users/sophia/Workspace/momo/momo-app/node_modules/@momo-kits/native-kits/ios/Application/Navigation/NavigatorManager.swift)",
154
+ "Bash(cp /Users/sophia/Workspace/momo/momo-native-kits/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift /Users/sophia/Workspace/momo/momo-app/node_modules/@momo-kits/native-kits/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift)",
155
+ "Bash(xcodebuild -workspace MoMoPlatform.xcworkspace -scheme MoMoPlatform-UAT -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build/DerivedData build)",
156
+ "Bash(cp android/gradle/libs.versions.toml /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/bfb380ee-54cb-4a02-bc5f-d152cce4b727/scratchpad/libs.versions.toml.bak)",
157
+ "Bash(sed -i '' 's/kits = \"0.163.1-sp.8\"/kits = \"0.163.1-sp.7\"/' android/gradle/libs.versions.toml)",
158
+ "Bash(xcrun --sdk iphonesimulator --show-sdk-path)",
159
+ "Bash(chmod +x /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/62b6dcd2-247f-4111-98ef-3847c8914676/scratchpad/tc.sh)",
160
+ "Bash(/private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/62b6dcd2-247f-4111-98ef-3847c8914676/scratchpad/tc.sh)",
161
+ "Bash(perl -0pi -e 's{^ static let \\(\\\\w+\\) = \\(appFont\\\\\\(size: [\\\\d.]+\\\\\\)\\(?:\\\\.weight\\\\\\(\\\\.\\\\w+\\\\\\)\\)?\\)\\(\\\\s*//.*\\)?$}{ static var $1: Font { $2 }$3}mg' ios/Typography/Typography.swift)",
162
+ "Bash(perl -0pi -e 's{\\(\\\\s*\\)// AI-GENERATED START: route Localize injection through the observing modifier\\\\n\\(\\\\s*\\)\\\\.momoLocalize\\\\\\(localize\\\\\\)\\\\n\\(\\\\s*\\)// AI-GENERATED END: route Localize injection through the observing modifier}{$1// AI-GENERATED START: route Localize + font-scale injection through the observing modifiers\\\\n$2.momoLocalize\\(localize\\)\\\\n$2.momoFontScale\\(\\)\\\\n$3// AI-GENERATED END: route Localize + font-scale injection through the observing modifiers}g' ios/Application/Navigation/NavigationContainer.swift)",
163
+ "Bash(perl -pi -e 's/Mirrors Compose.s `fontScale\\\\\\(\\\\.\\\\.\\\\.\\\\\\)`/Mirrors Compose'\"'\"'s `scaleSize\\(...\\)`/' ios/Chip/Chip.swift)",
164
+ "Bash(perl -pi -e 's/fontScale\\\\\\(\\(size == \\\\.small \\\\? 48 : 56\\), 1\\\\.1\\\\\\)/fontScale\\($1\\)/' ios/Input/Input.swift ios/Input/InputPhoneNumber.swift)",
165
+ "Bash(perl -pi -e 's/^\\(\\\\s*\\)\\\\.momoFontScale\\\\\\(\\\\\\)$/$1.momoFontScale\\(context: applicationEnvironment.applicationContext\\)/' ios/Application/Navigation/NavigationContainer.swift)",
166
+ "Bash(chmod +x /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/62b6dcd2-247f-4111-98ef-3847c8914676/scratchpad/tcdemo.sh)",
167
+ "Bash(/private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/62b6dcd2-247f-4111-98ef-3847c8914676/scratchpad/tcdemo.sh)",
168
+ "Bash(\"/Users/sophia/Workspace/momo-glab/momo-agent-flows/momo-agent/scripts/repo.sh\" find *)",
169
+ "Read(//Users/sophia/.momo-agent/**)",
170
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -configuration Debug -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -derivedDataPath /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/62b6dcd2-247f-4111-98ef-3847c8914676/scratchpad/dd build)",
171
+ "Bash(\"/Users/sophia/Workspace/momo-glab/momo-agent-flows/momo-agent/scripts/repo.sh\" prep *)",
172
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -configuration Debug -destination id=1E6F9A79-5E64-4590-BEA2-828D75D99393 -derivedDataPath /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/62b6dcd2-247f-4111-98ef-3847c8914676/scratchpad/dd build)",
173
+ "Bash(find /private/tmp/claude-503/-Users-sophia-Workspace-momo-momo-native-kits/62b6dcd2-247f-4111-98ef-3847c8914676/scratchpad/dd/Build/Products -maxdepth 2 -name *.app)",
174
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -configuration Debug -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build/dd build)",
175
+ "Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -configuration Debug -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build/dd ARCHS=arm64 ONLY_ACTIVE_ARCH=YES build)",
176
+ "Bash(./gradlew :compose:generateDummyFramework)",
177
+ "Bash(break)",
178
+ "Bash(\"/Users/sophia/Workspace/momo-glab/momo-agent-flows/momo-agent/scripts/gitlab.sh\" mr-view *)",
179
+ "Bash(\"/Users/sophia/Workspace/momo-glab/momo-agent-flows/momo-agent/scripts/gitlab.sh\" mr-discussions *)",
180
+ "Bash(command -v glab)",
181
+ "Bash(glab --version)",
182
+ "Bash(/Users/sophia/Workspace/momo-glab/momo-agent-flows/momo-agent/scripts/jira.sh transitions *)"
183
+ ]
184
+ }
185
+ }
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.164.1-beta.1-debug"
43
+ version = "0.164.1-beta.10-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |spec|
2
2
  spec.name = 'compose'
3
- spec.version = '0.164.1-beta.1-debug'
3
+ spec.version = '0.164.1-beta.10-debug'
4
4
  spec.homepage = 'https://momo.vn'
5
5
  spec.source = { :http=> ''}
6
6
  spec.authors = ''
@@ -0,0 +1,19 @@
1
+ package vn.momo.kits.const
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.remember
5
+ import androidx.compose.ui.platform.LocalContext
6
+ import androidx.compose.ui.text.font.Font
7
+ import androidx.compose.ui.text.font.FontFamily
8
+
9
+ @Composable
10
+ internal actual fun hostFontFamily(fileName: String): FontFamily? {
11
+ val assets = LocalContext.current.applicationContext.assets
12
+ return remember(fileName) {
13
+ val path = "fonts/$fileName"
14
+ // AssetManager.open ném IOException nếu thiếu file; Font(path, assetManager) thì lỗi
15
+ // muộn lúc render nên phải kiểm tra tồn tại trước.
16
+ val exists = runCatching { assets.open(path).close() }.isSuccess
17
+ if (exists) FontFamily(Font(path = path, assetManager = assets)) else null
18
+ }
19
+ }
@@ -0,0 +1,12 @@
1
+ package vn.momo.kits.platform
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.State
5
+ import androidx.compose.runtime.mutableStateOf
6
+ import androidx.compose.runtime.remember
7
+
8
+ // No passive observer exists at androidx.activity 1.10.x — a second enabled callback would steal
9
+ // the gesture from NavHost. Android's system back gesture emits its own platform haptic on commit.
10
+ // Revisit if androidx.activity >= 1.12 is adopted; this then becomes a copy of the iOS actual.
11
+ @Composable
12
+ actual fun rememberBackGestureProgress(): State<Float?> = remember { mutableStateOf(null) }
@@ -6,6 +6,7 @@ import androidx.compose.foundation.clickable
6
6
  import androidx.compose.foundation.layout.*
7
7
  import androidx.compose.foundation.shape.RoundedCornerShape
8
8
  import androidx.compose.runtime.Composable
9
+ import androidx.compose.runtime.remember
9
10
  import androidx.compose.ui.Modifier
10
11
  import androidx.compose.ui.draw.clip
11
12
  import androidx.compose.ui.text.style.TextAlign
@@ -16,6 +17,7 @@ import vn.momo.kits.const.Radius
16
17
  import vn.momo.kits.const.Spacing
17
18
  import vn.momo.kits.const.Typography
18
19
  import vn.momo.kits.modifier.conditional
20
+ import vn.momo.kits.modifier.setAutomationId
19
21
 
20
22
  enum class InformationState {
21
23
  DEFAULT,
@@ -34,7 +36,12 @@ fun Information(
34
36
  action: String? = null,
35
37
  showIconClose: Boolean = true,
36
38
  onPressClose: (() -> Unit)? = null,
39
+ accessibilityLabel: String? = null,
37
40
  ) {
41
+ val automationId = remember(accessibilityLabel, title) {
42
+ accessibilityLabel ?: "Information${if (title != null) "/$title" else ""}"
43
+ }
44
+
38
45
  var borderColor = Colors.blue_07
39
46
  var backgroundColor = Colors.blue_10
40
47
  var color = Colors.blue_03
@@ -64,6 +71,7 @@ fun Information(
64
71
  border(1.dp, Colors.blue_03)
65
72
  }
66
73
  .padding(Spacing.M)
74
+ .setAutomationId(automationId)
67
75
  ) {
68
76
  Row {
69
77
  if (image != null) {
@@ -71,7 +79,7 @@ fun Information(
71
79
  source = image,
72
80
  modifier = Modifier.padding(end = Spacing.S).width(40.dp).height(40.dp).clip(
73
81
  RoundedCornerShape(Radius.S)
74
- )
82
+ ).setAutomationId("$automationId|img")
75
83
  )
76
84
  }
77
85
  if (image == null && showIcon) {
@@ -80,30 +88,44 @@ fun Information(
80
88
  size = 16.dp,
81
89
  color = color,
82
90
  modifier = Modifier.padding(end = Spacing.S)
91
+ .setAutomationId("$automationId|icon")
83
92
  )
84
93
  }
85
94
  Column(modifier = Modifier.weight(1f)) {
86
95
  if (title != null) {
87
- Text(title, style = Typography.labelDefaultMedium)
96
+ Text(
97
+ title,
98
+ style = Typography.labelDefaultMedium,
99
+ accessibilityId = "$automationId|title-text"
100
+ )
88
101
  }
89
- Text(description, style = Typography.descriptionDefaultRegular)
102
+ Text(
103
+ description,
104
+ style = Typography.descriptionDefaultRegular,
105
+ accessibilityId = "$automationId|description-text"
106
+ )
90
107
  }
91
108
  if (onPressClose != null && showIconClose) {
92
109
  Icon(
93
110
  source = "navigation_close",
94
111
  size = 16.dp,
95
112
  modifier = Modifier.clickable(onClick = onPressClose)
113
+ .setAutomationId("$automationId|close-icon-touch")
96
114
  )
97
115
  }
98
116
  }
99
117
  if (action != null && onPressAction != null) {
100
- Row(modifier = Modifier.padding(top = Spacing.S)) {
118
+ Row(
119
+ modifier = Modifier.padding(top = Spacing.S)
120
+ .setAutomationId("$automationId|cta-touch")
121
+ ) {
101
122
  Text(
102
123
  action,
103
124
  modifier = Modifier.weight(1f).clickable(onClick = onPressAction),
104
125
  textAlign = TextAlign.End,
105
126
  style = Typography.actionXsBold,
106
- color = color
127
+ color = color,
128
+ accessibilityId = "$automationId|cta-text"
107
129
  )
108
130
  }
109
131
  }
@@ -35,8 +35,6 @@ import vn.momo.kits.application.IsShowBaseLineDebug
35
35
  import vn.momo.kits.const.*
36
36
  import vn.momo.kits.modifier.conditional
37
37
  import vn.momo.kits.modifier.setAutomationId
38
- import vn.momo.uikits.resources.Res
39
- import vn.momo.uikits.resources.sfprotext_regular
40
38
 
41
39
  data class InputSizeDetail(
42
40
  val borderWidth: Dp,
@@ -268,7 +266,7 @@ fun Input(
268
266
  )
269
267
  }
270
268
 
271
- val passwordFontFamily = getFont(Res.font.sfprotext_regular)
269
+ val passwordFontFamily = getFontFamily("SFProText", FontWeight.Normal)
272
270
  val passwordFontSize = scaleSize(24.sp)
273
271
  val visualTransformation = remember(secureTextEntry, inputState.passHidden, passwordFontFamily) {
274
272
  if (secureTextEntry && !inputState.passHidden)
@@ -0,0 +1,16 @@
1
+ package vn.momo.kits.const
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.ui.text.font.FontFamily
5
+
6
+ /**
7
+ * Nạp font từ tài nguyên native của app host thay vì đóng gói bản copy riêng trong SDK.
8
+ *
9
+ * App host (MoMo Platform) đã bundle sẵn toàn bộ font từ `font-source`:
10
+ * - Android: `assets/fonts/<fileName>` (gradle task `syncMomoFonts`)
11
+ * - iOS: file rời ở bundle root (pbxproj fileRef được `post_install.rb` trỏ về font-source)
12
+ *
13
+ * Trả về `null` nếu host không có font đó — caller tự fallback [FontFamily.Default].
14
+ */
15
+ @Composable
16
+ internal expect fun hostFontFamily(fileName: String): FontFamily?
@@ -8,12 +8,8 @@ import androidx.compose.ui.text.font.FontFamily
8
8
  import androidx.compose.ui.text.font.FontWeight
9
9
  import androidx.compose.ui.text.style.TextDecoration
10
10
  import androidx.compose.ui.unit.*
11
- import org.jetbrains.compose.resources.Font
12
- import org.jetbrains.compose.resources.FontResource
13
- import org.jetbrains.compose.resources.InternalResourceApi
14
11
  import vn.momo.kits.application.LocalContext
15
12
  import vn.momo.kits.platform.getScreenDimensions
16
- import vn.momo.uikits.resources.*
17
13
  import kotlin.math.max
18
14
  import kotlin.math.min
19
15
 
@@ -87,48 +83,39 @@ fun scaleSize(textStyle: TextStyle): TextStyle {
87
83
  }
88
84
 
89
85
 
90
- @OptIn(InternalResourceApi::class)
91
- @Composable
92
- internal fun getFont(font: FontResource): FontFamily {
93
- return FontFamily(Font(font))
86
+ /**
87
+ * Tên file font trong tài nguyên native của app host (xem [hostFontFamily]).
88
+ *
89
+ * SDK không đóng gói font riêng nữa: app host đã bundle sẵn toàn bộ font từ `font-source`
90
+ * cho cả React Native lẫn native, nên bản copy trong `composeResources` chỉ làm phình app.
91
+ */
92
+ private const val DEFAULT_FONT_FILE = "SFProText-Regular.ttf"
93
+
94
+ private val hostFontFiles: Map<String, String> = mapOf(
95
+ "SFProText-100" to "SFProText-Thin.ttf",
96
+ "SFProText-200" to "SFProText-Ultralight.ttf",
97
+ "SFProText-300" to "SFProText-Light.ttf",
98
+ "SFProText-400" to DEFAULT_FONT_FILE,
99
+ "SFProText-500" to "SFProText-Medium.ttf",
100
+ "SFProText-600" to "SFProText-Semibold.ttf",
101
+ "SFProText-700" to "SFProText-Bold.ttf",
102
+ "SFProText-800" to "SFProText-Heavy.ttf",
103
+ "SFProText-900" to "SFProText-Black.ttf",
104
+ ) + (1..9).flatMap { step ->
105
+ val weight = step * 100
106
+ listOf(
107
+ "MoMoSignature-$weight" to "MoMoSignature.otf",
108
+ "MoMoTrustDisplay-$weight" to "MoMoTrustDisplay.otf",
109
+ )
94
110
  }
95
111
 
96
112
  @Composable
97
113
  fun getFontFamily(fontFamily: String, fontWeight: FontWeight? = FontWeight.Normal): FontFamily {
98
114
  val key = "$fontFamily-${fontWeight?.weight}"
99
- val fontMap = mapOf(
100
- "SFProText-100" to Res.font.sfprotext_thin,
101
- "SFProText-200" to Res.font.sfprotext_ultralight,
102
- "SFProText-300" to Res.font.sfprotext_light,
103
- "SFProText-400" to Res.font.sfprotext_regular,
104
- "SFProText-500" to Res.font.sfprotext_medium,
105
- "SFProText-600" to Res.font.sfprotext_semibold,
106
- "SFProText-700" to Res.font.sfprotext_bold,
107
- "SFProText-800" to Res.font.sfprotext_heavy,
108
- "SFProText-900" to Res.font.sfprotext_black,
109
-
110
- "MoMoSignature-100" to Res.font.momosignature,
111
- "MoMoSignature-200" to Res.font.momosignature,
112
- "MoMoSignature-300" to Res.font.momosignature,
113
- "MoMoSignature-400" to Res.font.momosignature,
114
- "MoMoSignature-500" to Res.font.momosignature,
115
- "MoMoSignature-600" to Res.font.momosignature,
116
- "MoMoSignature-700" to Res.font.momosignature,
117
- "MoMoSignature-800" to Res.font.momosignature,
118
- "MoMoSignature-900" to Res.font.momosignature,
119
-
120
- "MoMoTrustDisplay-100" to Res.font.momotrustdisplay,
121
- "MoMoTrustDisplay-200" to Res.font.momotrustdisplay,
122
- "MoMoTrustDisplay-300" to Res.font.momotrustdisplay,
123
- "MoMoTrustDisplay-400" to Res.font.momotrustdisplay,
124
- "MoMoTrustDisplay-500" to Res.font.momotrustdisplay,
125
- "MoMoTrustDisplay-600" to Res.font.momotrustdisplay,
126
- "MoMoTrustDisplay-700" to Res.font.momotrustdisplay,
127
- "MoMoTrustDisplay-800" to Res.font.momotrustdisplay,
128
- "MoMoTrustDisplay-900" to Res.font.momotrustdisplay,
129
- )
130
- val font = fontMap[key] ?: Res.font.sfprotext_regular
131
- return getFont(font)
115
+ val fileName = hostFontFiles[key] ?: DEFAULT_FONT_FILE
116
+ return hostFontFamily(fileName)
117
+ ?: hostFontFamily(DEFAULT_FONT_FILE)
118
+ ?: FontFamily.Default
132
119
  }
133
120
 
134
121
  @Immutable
@@ -2,9 +2,7 @@ package vn.momo.kits.navigation
2
2
 
3
3
  import androidx.compose.animation.core.tween
4
4
  import androidx.compose.animation.fadeIn
5
- import androidx.compose.animation.slideInHorizontally
6
5
  import androidx.compose.animation.slideInVertically
7
- import androidx.compose.animation.slideOutHorizontally
8
6
  import androidx.compose.animation.slideOutVertically
9
7
  import androidx.compose.runtime.Composable
10
8
  import androidx.compose.runtime.CompositionLocalProvider
@@ -19,6 +17,8 @@ import androidx.navigation.compose.NavHost
19
17
  import androidx.navigation.compose.composable
20
18
  import androidx.navigation.compose.rememberNavController
21
19
  import androidx.navigation.toRoute
20
+ import kotlinx.coroutines.delay
21
+ import kotlinx.coroutines.flow.collectLatest
22
22
  import vn.momo.kits.application.LocalContext
23
23
  import vn.momo.kits.application.LocalLocalize
24
24
  import vn.momo.kits.application.Localize
@@ -33,6 +33,7 @@ import vn.momo.kits.platform.ProvideOsFontScale
33
33
  import vn.momo.kits.utils.getAppStatusBarHeight
34
34
  import vn.momo.kits.utils.getNavigationBarHeight
35
35
  import vn.momo.maxapi.IMaxApi
36
+ import kotlin.time.Duration.Companion.milliseconds
36
37
 
37
38
  @Composable
38
39
  fun NavigationContainer(
@@ -55,6 +56,7 @@ fun NavigationContainer(
55
56
  val parentContext = LocalContext.current
56
57
  val mergedContext = MiniAppContext.merge(parentContext, miniAppContext)
57
58
 
59
+ val stackTransition = remember { StackTransitionCoordinator() }
58
60
  val theme = remember { mutableStateOf(initialTheme) }
59
61
  val fallbackLocalize = remember { Localize() }
60
62
 
@@ -86,38 +88,53 @@ fun NavigationContainer(
86
88
  AppNavigationBar provides navigationBarHeight,
87
89
  LocalContext provides mergedContext,
88
90
  LocalLocalize provides resolvedLocalize,
91
+ LocalStackTransition provides stackTransition,
89
92
  ) {
90
93
  LaunchedEffect(Unit) {
91
94
  setNavigator?.invoke(navigator)
92
95
  }
93
96
 
94
- NavHost(navController, startDestination = startDestination) {
95
- composable<DynamicScreenRoute>(
96
- enterTransition = {
97
- slideInHorizontally(
98
- animationSpec = tween(300),
99
- initialOffsetX = { it }
100
- )
101
- },
102
- exitTransition = null,
103
- popEnterTransition = { fadeIn(animationSpec = tween(0)) },
104
- popExitTransition = {
105
- slideOutHorizontally(
106
- animationSpec = tween(300),
107
- targetOffsetX = { it }
108
- )
97
+ SwipeBackHaptic(maxApi)
98
+
99
+ // Gesture pops never reach Navigator.dismissScreen(), so prune the registry from
100
+ // the back stack itself. collectLatest lets a rapid re-push cancel a pending prune.
101
+ LaunchedEffect(navController, registry) {
102
+ navController.currentBackStack.collectLatest { entries ->
103
+ delay(STACK_TRANSITION_DURATION.milliseconds)
104
+ val aliveIds = entries.mapNotNullTo(mutableSetOf()) { entry ->
105
+ runCatching { entry.toRoute<DynamicScreenRoute>().id }.getOrNull()
106
+ ?: runCatching { entry.toRoute<DynamicDialogRoute>().id }.getOrNull()
109
107
  }
110
- ) { backStackEntry ->
108
+ aliveIds.add(screenId)
109
+ registry.retainOnly(aliveIds)
110
+ }
111
+ }
112
+
113
+ // The transitions must live on the NavHost call site, not on the destinations:
114
+ // NavHost.uikit computes isDefaultTransition from these arguments alone, and while
115
+ // it is true the library paints its own hard-coded black iOS blackout that would
116
+ // sit over the pink scrim.
117
+ NavHost(
118
+ navController,
119
+ startDestination = startDestination,
120
+ enterTransition = { stackEnter() },
121
+ exitTransition = { stackExit() },
122
+ popEnterTransition = { stackPopEnter() },
123
+ popExitTransition = { stackPopExit() },
124
+ ) {
125
+ composable<DynamicScreenRoute> { backStackEntry ->
111
126
  val route = backStackEntry.toRoute<DynamicScreenRoute>()
112
127
  val screen = registry.getScreen(route.id)
113
128
 
114
129
  if (screen != null) {
115
- StackScreen(
116
- id = route.id,
117
- name = screen.name,
118
- content = screen.content,
119
- navigationOptions = screen.options
120
- )
130
+ StackTransitionDecor(id = route.id, isStackRoute = true) {
131
+ StackScreen(
132
+ id = route.id,
133
+ name = screen.name,
134
+ content = screen.content,
135
+ navigationOptions = screen.options
136
+ )
137
+ }
121
138
  }
122
139
  }
123
140
 
@@ -141,12 +158,15 @@ fun NavigationContainer(
141
158
  val screen = registry.getScreen(route.id)
142
159
 
143
160
  if (screen != null) {
144
- StackScreen(
145
- id = route.id,
146
- name = screen.name,
147
- content = screen.content,
148
- navigationOptions = screen.options
149
- )
161
+ StackTransitionDecor(id = route.id, isStackRoute = false) {
162
+ StackScreen(
163
+ id = route.id,
164
+ name = screen.name,
165
+ content = screen.content,
166
+ navigationOptions = screen.options,
167
+ isDialogRoute = true
168
+ )
169
+ }
150
170
  }
151
171
  }
152
172
  }
@@ -4,11 +4,15 @@ import androidx.compose.foundation.layout.Box
4
4
  import androidx.compose.foundation.layout.fillMaxSize
5
5
  import androidx.compose.runtime.Composable
6
6
  import androidx.compose.runtime.MutableState
7
+ import androidx.compose.runtime.collectAsState
8
+ import androidx.compose.runtime.getValue
7
9
  import androidx.compose.runtime.mutableStateOf
8
10
  import androidx.compose.runtime.staticCompositionLocalOf
9
11
  import androidx.compose.ui.Alignment
10
12
  import androidx.compose.ui.Modifier
13
+ import androidx.navigation.NavBackStackEntry
11
14
  import androidx.navigation.NavController
15
+ import androidx.navigation.NavGraph
12
16
  import androidx.navigation.toRoute
13
17
  import kotlinx.coroutines.CoroutineScope
14
18
  import kotlinx.coroutines.Dispatchers
@@ -78,6 +82,23 @@ class Navigator(
78
82
  }
79
83
  }
80
84
 
85
+ // The swipe-back opt-out predicate in StackScreen needs this: the root screen must keep custom
86
+ // back handling so it still reaches maxApi.dismiss. It has to read currentBackStack rather than
87
+ // previousBackStackEntry — the latter walks a plain ArrayDeque, so a composable reading it never
88
+ // recomposes and the predicate would freeze at the value it had on first composition.
89
+ @Composable
90
+ internal fun rememberCanPop(): Boolean {
91
+ val backStack by navController.currentBackStack.collectAsState()
92
+ return backStack.hasPoppableEntry()
93
+ }
94
+
95
+ /**
96
+ * Non-composable twin of [rememberCanPop] for the iOS host: its own back check is mount-based
97
+ * and so answers `true` even on the mini-app root, where a swipe must dismiss rather than pop.
98
+ * Reads the StateFlow value directly — correct here precisely because nothing recomposes on it.
99
+ */
100
+ fun canPop(): Boolean = navController.currentBackStack.value.hasPoppableEntry()
101
+
81
102
  fun pop(count: Int = 1, callBack: (() -> Unit)? = null) {
82
103
  scope.launch {
83
104
  repeat(count) {
@@ -104,7 +125,7 @@ class Navigator(
104
125
  if (navController.previousBackStackEntry != null){
105
126
  val dismissing = currentScreen()
106
127
  navController.popBackStack()
107
- delay(300L.milliseconds)
128
+ delay(STACK_TRANSITION_DURATION.milliseconds)
108
129
  dismissing?.let { registry.unregisterScreen(it.id) }
109
130
  } else {
110
131
  maxApi?.dismiss { }
@@ -175,6 +196,10 @@ class Navigator(
175
196
  }
176
197
  }
177
198
 
199
+ // The NavGraph itself sits in the back stack as an entry; only real destinations can be popped.
200
+ private fun List<NavBackStackEntry>.hasPoppableEntry(): Boolean =
201
+ count { it.destination !is NavGraph } > 1
202
+
178
203
  val LocalNavigator = staticCompositionLocalOf<Navigator> {
179
204
  error("No NavigationStack provided")
180
205
  }
@@ -222,6 +247,15 @@ class DynamicScreenRegistry {
222
247
  screens.remove(id)
223
248
  }
224
249
 
250
+ // Gesture pops go through composeNavigator.popBackStack() inside NavHost and never reach
251
+ // Navigator.dismissScreen(), so screens would leak without a stack-driven prune.
252
+ fun retainOnly(ids: Set<Int>) {
253
+ val stale = screens.keys.filter { it !in ids }
254
+ for (id in stale) {
255
+ screens.remove(id)
256
+ }
257
+ }
258
+
225
259
  fun unregisterAll(){
226
260
  val ids = screens.keys.toList()
227
261
  for (id in ids) {
@@ -93,6 +93,7 @@ internal fun StackScreen(
93
93
  id: Int = -1,
94
94
  name: String = "",
95
95
  bottomTabIndex: Int = -1,
96
+ isDialogRoute: Boolean = false,
96
97
  onBackHandler: (() -> Unit)? = null,
97
98
  ) {
98
99
  val navigator = LocalNavigator.current
@@ -169,7 +170,29 @@ internal fun StackScreen(
169
170
  RegisterScrollToTop(navigation.options.scrollData.scrollToTopCallback)
170
171
  }
171
172
 
172
- BackHandler(true) { navigator.onBackSafe() }
173
+ // Hoisted out of the `||` chain below: short-circuiting would drop the back-stack subscription
174
+ // whenever an earlier term is true.
175
+ val canPop = navigator.rememberCanPop()
176
+
177
+ // Port of RN's `hasCustomBackHandling`: this handler is registered inside the NavHost
178
+ // destination, so while it is enabled it beats NavHost's own predictive-back handler and
179
+ // swallows the swipe. Enable it only when a plain pop is the wrong answer.
180
+ //
181
+ // A presented route is one of those cases: NavHost arms predictive back on back-stack size
182
+ // alone, so a horizontal edge drag over a dialog would seek its *vertical* slide.
183
+ val hasCustomBackHandling = !SwipeBackConfig.enabled ||
184
+ isBottomTabChild ||
185
+ isDialogRoute ||
186
+ options.onBackHandler != null ||
187
+ options.headerBackProps.preventBack != null ||
188
+ OverplayComponentRegistry.isOverplayShowing() ||
189
+ !canPop
190
+
191
+ // BottomTab supplies a tab-aware handler; falling through to onBackSafe() there would dismiss
192
+ // the whole mini-app instead of returning to tab 0.
193
+ val onBack = onBackHandler ?: { navigator.onBackSafe() }
194
+
195
+ BackHandler(hasCustomBackHandling, onBack)
173
196
 
174
197
  CompositionLocalProvider(
175
198
  StackScreenScrollableState provides options.scrollData.scrollState,
@@ -0,0 +1,164 @@
1
+ package vn.momo.kits.navigation
2
+
3
+ import androidx.compose.animation.AnimatedContentTransitionScope
4
+ import androidx.compose.animation.AnimatedVisibilityScope
5
+ import androidx.compose.animation.EnterExitState
6
+ import androidx.compose.animation.EnterTransition
7
+ import androidx.compose.animation.ExitTransition
8
+ import androidx.compose.animation.core.LinearEasing
9
+ import androidx.compose.animation.core.animateFloat
10
+ import androidx.compose.animation.core.tween
11
+ import androidx.compose.animation.slideInHorizontally
12
+ import androidx.compose.animation.slideOutHorizontally
13
+ import androidx.compose.foundation.layout.Box
14
+ import androidx.compose.foundation.layout.fillMaxSize
15
+ import androidx.compose.runtime.Composable
16
+ import androidx.compose.runtime.DisposableEffect
17
+ import androidx.compose.runtime.Stable
18
+ import androidx.compose.runtime.derivedStateOf
19
+ import androidx.compose.runtime.getValue
20
+ import androidx.compose.runtime.mutableStateMapOf
21
+ import androidx.compose.runtime.mutableStateOf
22
+ import androidx.compose.runtime.remember
23
+ import androidx.compose.runtime.setValue
24
+ import androidx.compose.runtime.staticCompositionLocalOf
25
+ import androidx.compose.ui.Modifier
26
+ import androidx.compose.ui.draw.drawBehind
27
+ import androidx.compose.ui.geometry.Offset
28
+ import androidx.compose.ui.geometry.Size
29
+ import androidx.compose.ui.graphics.Brush
30
+ import androidx.compose.ui.graphics.Color
31
+ import androidx.compose.ui.platform.LocalDensity
32
+ import androidx.compose.ui.unit.IntOffset
33
+ import androidx.compose.ui.unit.dp
34
+ import androidx.navigation.NavBackStackEntry
35
+ import androidx.navigation.NavDestination.Companion.hasRoute
36
+ import vn.momo.kits.const.Colors
37
+ import kotlin.math.roundToInt
38
+
39
+ internal const val STACK_TRANSITION_DURATION = 300
40
+
41
+ // Ported 1:1 from the RN kit's `forStackTransitionWithOverlay` so both kits look identical.
42
+ private const val PARALLAX_RATIO = 0.3f
43
+ private const val SCRIM_MAX_ALPHA = 0.6f
44
+ private const val EDGE_SHADOW_MAX_ALPHA = 0.3f
45
+ private val EDGE_SHADOW_WIDTH = 8.dp
46
+
47
+ /**
48
+ * Kill switch for the swipe-back gesture. Set to `false` to make kit back handling always win,
49
+ * which disables the predictive-back drag on both platforms — the gesture then pops without
50
+ * following the finger, and fires no haptic. Screen transitions stay on the parallax curve either
51
+ * way.
52
+ */
53
+ object SwipeBackConfig {
54
+ // Snapshot-backed so a host toggle takes effect on the next frame instead of waiting for an
55
+ // unrelated recomposition of StackScreen.
56
+ var enabled: Boolean by mutableStateOf(true)
57
+ }
58
+
59
+ // LinearEasing is mandatory, not a style choice: SeekableTransitionState.seekTo() maps the drag
60
+ // fraction straight onto the animation timeline, so any curve would decouple the card from the
61
+ // finger mid-gesture.
62
+ private val stackSpec = tween<IntOffset>(STACK_TRANSITION_DURATION, easing = LinearEasing)
63
+
64
+ internal fun AnimatedContentTransitionScope<NavBackStackEntry>.stackEnter(): EnterTransition =
65
+ slideInHorizontally(stackSpec) { it }
66
+
67
+ internal fun AnimatedContentTransitionScope<NavBackStackEntry>.stackExit(): ExitTransition =
68
+ if (targetState.destination.hasRoute<DynamicDialogRoute>()) ExitTransition.None
69
+ else slideOutHorizontally(stackSpec) { -(it * PARALLAX_RATIO).roundToInt() }
70
+
71
+ internal fun AnimatedContentTransitionScope<NavBackStackEntry>.stackPopEnter(): EnterTransition =
72
+ if (initialState.destination.hasRoute<DynamicDialogRoute>()) EnterTransition.None
73
+ else slideInHorizontally(stackSpec) { -(it * PARALLAX_RATIO).roundToInt() }
74
+
75
+ internal fun AnimatedContentTransitionScope<NavBackStackEntry>.stackPopExit(): ExitTransition =
76
+ slideOutHorizontally(stackSpec) { it }
77
+
78
+ /**
79
+ * Tracks which screen ids are currently composed so a screen can tell whether it is the top card
80
+ * or the one underneath.
81
+ *
82
+ * Screen ids come from a single monotonic process-wide counter and NavHost keeps both entries
83
+ * composed for the whole transition segment, so "highest composed stack id" is stable in both
84
+ * directions. `currentBackStackEntry` is not usable here: it flips at frame 0 of a pop, which
85
+ * would make the scrim vanish instantly instead of fading.
86
+ */
87
+ @Stable
88
+ internal class StackTransitionCoordinator {
89
+ private val composedRoutes = mutableStateMapOf<Int, Boolean>()
90
+
91
+ val topStackId: Int by derivedStateOf {
92
+ composedRoutes.entries.filter { it.value }.maxOfOrNull { it.key } ?: -1
93
+ }
94
+
95
+ fun attach(id: Int, isStackRoute: Boolean) {
96
+ composedRoutes[id] = isStackRoute
97
+ }
98
+
99
+ fun detach(id: Int) {
100
+ composedRoutes.remove(id)
101
+ }
102
+ }
103
+
104
+ internal val LocalStackTransition = staticCompositionLocalOf { StackTransitionCoordinator() }
105
+
106
+ /** Draws the covered-screen scrim and the top card's left-edge shadow around a stack destination. */
107
+ @Composable
108
+ internal fun AnimatedVisibilityScope.StackTransitionDecor(
109
+ id: Int,
110
+ isStackRoute: Boolean,
111
+ content: @Composable () -> Unit,
112
+ ) {
113
+ val coordinator = LocalStackTransition.current
114
+ // attach() writes state that derivedStateOf { topStackId } reads in the same pass, so it has to
115
+ // stay out of the composable body.
116
+ DisposableEffect(coordinator, id, isStackRoute) {
117
+ coordinator.attach(id, isStackRoute)
118
+ onDispose { coordinator.detach(id) }
119
+ }
120
+
121
+ val isTopCard = isStackRoute && id == coordinator.topStackId
122
+ val isCovered = isStackRoute && !isTopCard
123
+
124
+ val scrimAlpha = transition.animateFloat(
125
+ transitionSpec = { tween(STACK_TRANSITION_DURATION, easing = LinearEasing) },
126
+ label = "stackScrimAlpha",
127
+ ) { state -> if (isCovered && state != EnterExitState.Visible) SCRIM_MAX_ALPHA else 0f }
128
+
129
+ val shadowAlpha = transition.animateFloat(
130
+ transitionSpec = { tween(STACK_TRANSITION_DURATION, easing = LinearEasing) },
131
+ label = "stackEdgeShadowAlpha",
132
+ ) { state -> if (isTopCard && state == EnterExitState.Visible) EDGE_SHADOW_MAX_ALPHA else 0f }
133
+
134
+ val shadowWidthPx = with(LocalDensity.current) { EDGE_SHADOW_WIDTH.toPx() }
135
+ val shadowBrush = remember(shadowWidthPx) {
136
+ Brush.horizontalGradient(
137
+ colors = listOf(Color.Transparent, Colors.black_20),
138
+ startX = -shadowWidthPx,
139
+ endX = 0f,
140
+ )
141
+ }
142
+
143
+ Box(Modifier.fillMaxSize()) {
144
+ content()
145
+
146
+ if (isStackRoute) {
147
+ Box(
148
+ Modifier
149
+ .matchParentSize()
150
+ // Both alphas are read inside drawBehind so a drag only re-draws; reading them
151
+ // in the composable body would recompose the whole screen every gesture frame.
152
+ .drawBehind {
153
+ drawRect(
154
+ brush = shadowBrush,
155
+ topLeft = Offset(-shadowWidthPx, 0f),
156
+ size = Size(shadowWidthPx, size.height),
157
+ alpha = shadowAlpha.value,
158
+ )
159
+ drawRect(Colors.pink_09, alpha = scrimAlpha.value)
160
+ }
161
+ )
162
+ }
163
+ }
164
+ }
@@ -0,0 +1,41 @@
1
+ package vn.momo.kits.navigation
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.LaunchedEffect
5
+ import androidx.compose.runtime.snapshotFlow
6
+ import vn.momo.kits.platform.getScreenDimensions
7
+ import vn.momo.kits.platform.rememberBackGestureProgress
8
+ import vn.momo.maxapi.IMaxApi
9
+
10
+ // RN fires the tick at a flat 100 px of thumb travel; keep it unscaled so the physical distance is
11
+ // the same on every device.
12
+ private const val SWIPE_BACK_HAPTIC_THRESHOLD_DP = 50f
13
+
14
+ /**
15
+ * Fires one light tick once the back gesture has travelled ~100dp, re-arming when the finger drops
16
+ * back below the threshold. iOS only — [rememberBackGestureProgress] is always `null` on Android.
17
+ */
18
+ @Composable
19
+ internal fun SwipeBackHaptic(maxApi: IMaxApi?) {
20
+ // With the kill switch off the kit's own BackHandler swallows the gesture, so the card never
21
+ // moves — a tick there would be a phantom.
22
+ if (maxApi == null || !SwipeBackConfig.enabled) return
23
+
24
+ val progress = rememberBackGestureProgress()
25
+ val screenWidth = getScreenDimensions().width.toFloat()
26
+
27
+ LaunchedEffect(maxApi, screenWidth) {
28
+ if (screenWidth <= 0f) return@LaunchedEffect
29
+ val threshold = SWIPE_BACK_HAPTIC_THRESHOLD_DP / screenWidth
30
+ var isSendHaptic = false
31
+ snapshotFlow { progress.value }.collect { fraction ->
32
+ val travelled = fraction ?: 0f
33
+ if (travelled >= threshold && !isSendHaptic) {
34
+ runCatching { maxApi.triggerEventVibration("light", callback = null) }
35
+ isSendHaptic = true
36
+ } else if (travelled < threshold && isSendHaptic) {
37
+ isSendHaptic = false
38
+ }
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,15 @@
1
+ package vn.momo.kits.platform
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.State
5
+
6
+ /**
7
+ * Progress of an in-flight back gesture as a fraction of the container width, or `null` while no
8
+ * gesture is running. Observing only — it must never consume the gesture, otherwise it would steal
9
+ * it from NavHost.
10
+ *
11
+ * Android always returns `null`: its NavHost runs on `androidx.activity`'s OnBackPressedDispatcher,
12
+ * which exposes progress only to the top-most enabled callback, and that has to stay NavHost's.
13
+ */
14
+ @Composable
15
+ expect fun rememberBackGestureProgress(): State<Float?>
@@ -0,0 +1,40 @@
1
+ @file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
2
+
3
+ package vn.momo.kits.const
4
+
5
+ import androidx.compose.runtime.Composable
6
+ import androidx.compose.runtime.remember
7
+ import androidx.compose.ui.text.font.FontFamily
8
+ import androidx.compose.ui.text.platform.Font
9
+ import kotlinx.cinterop.ExperimentalForeignApi
10
+ import kotlinx.cinterop.addressOf
11
+ import kotlinx.cinterop.usePinned
12
+ import platform.Foundation.NSBundle
13
+ import platform.Foundation.NSData
14
+ import platform.Foundation.dataWithContentsOfFile
15
+ import platform.posix.memcpy
16
+
17
+ @Composable
18
+ internal actual fun hostFontFamily(fileName: String): FontFamily? = remember(fileName) {
19
+ val name = fileName.substringBeforeLast('.')
20
+ val ext = fileName.substringAfterLast('.', "")
21
+ // Font từ font-source nằm rời ở bundle root, không nằm trong compose-resources.
22
+ val path = NSBundle.mainBundle.pathForResource(name, ext) ?: return@remember null
23
+ FontFamily(
24
+ Font(
25
+ identity = fileName,
26
+ getData = {
27
+ NSData.dataWithContentsOfFile(path)?.toByteArray() ?: ByteArray(0)
28
+ },
29
+ ),
30
+ )
31
+ }
32
+
33
+ @OptIn(ExperimentalForeignApi::class)
34
+ private fun NSData.toByteArray(): ByteArray {
35
+ val size = length.toInt()
36
+ if (size == 0) return ByteArray(0)
37
+ return ByteArray(size).apply {
38
+ usePinned { pinned -> memcpy(pinned.addressOf(0), bytes, length) }
39
+ }
40
+ }
@@ -0,0 +1,65 @@
1
+ package vn.momo.kits.navigation
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.DisposableEffect
5
+ import androidx.compose.runtime.remember
6
+ import androidx.navigationevent.NavigationEventDispatcher
7
+ import androidx.navigationevent.NavigationEventInput
8
+
9
+ /**
10
+ * Read-only answer to "will Compose consume this back?", for the iOS host.
11
+ *
12
+ * Compose owns the edge-pan gesture through its own `UIKitBackGestureRecognizer`; the host reads
13
+ * this to decide whether to stand down or keep driving its own recogniser, instead of guessing.
14
+ * Nothing here dispatches — [ObserveBackGestureOwnership] only listens.
15
+ *
16
+ * Pair it with [Navigator.canPop]: the mini-app root reports an enabled handler too (it swallows
17
+ * back to reach `maxApi.dismiss`), yet there the host still owns the gesture.
18
+ */
19
+ object ComposeBackGesture {
20
+ private val observers = mutableListOf<BackHandlerObserver>()
21
+
22
+ /** State of the top-most mounted container; `false` when none is mounted. */
23
+ val hasEnabledHandlers: Boolean
24
+ get() = observers.lastOrNull()?.hasEnabledHandlers == true
25
+
26
+ internal fun attach(observer: BackHandlerObserver) {
27
+ observers += observer
28
+ }
29
+
30
+ internal fun detach(observer: BackHandlerObserver) {
31
+ observers -= observer
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Publishes one [NavigationContainer]'s back-handling state to [ComposeBackGesture] while composed.
37
+ *
38
+ * Only called for a container whose dispatcher is the scene's — a bare-`UIView` host gets the
39
+ * detached fallback dispatcher, which can never receive an edge pan, so reporting its handlers
40
+ * would tell the host to stand down in favour of a gesture that does not exist.
41
+ */
42
+ @Composable
43
+ internal fun ObserveBackGestureOwnership(dispatcher: NavigationEventDispatcher) {
44
+ val observer = remember(dispatcher) { BackHandlerObserver() }
45
+
46
+ DisposableEffect(dispatcher, observer) {
47
+ dispatcher.addInput(observer)
48
+ ComposeBackGesture.attach(observer)
49
+ onDispose {
50
+ ComposeBackGesture.detach(observer)
51
+ dispatcher.removeInput(observer)
52
+ }
53
+ }
54
+ }
55
+
56
+ // A NavigationEventInput that never dispatches: adding an input is the only way to observe the
57
+ // dispatcher's enabled-handler state without registering a handler, which would consume the gesture.
58
+ internal class BackHandlerObserver : NavigationEventInput() {
59
+ var hasEnabledHandlers: Boolean = false
60
+ private set
61
+
62
+ override fun onHasEnabledHandlersChanged(hasEnabledHandlers: Boolean) {
63
+ this.hasEnabledHandlers = hasEnabledHandlers
64
+ }
65
+ }
@@ -0,0 +1,35 @@
1
+ package vn.momo.kits.platform
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.LaunchedEffect
5
+ import androidx.compose.runtime.State
6
+ import androidx.compose.runtime.mutableStateOf
7
+ import androidx.compose.runtime.remember
8
+ import androidx.compose.ui.InternalComposeUiApi
9
+ import androidx.compose.ui.backhandler.LocalCompatNavigationEventDispatcherOwner
10
+ import androidx.navigationevent.NavigationEventTransitionState
11
+
12
+ // NavigationEventDispatcher.transitionState is a passive observer: UIKitNavigationEventInput
13
+ // publishes every edge-pan event to it without any handler consuming the gesture. Its `progress`
14
+ // is touch.x / view width, i.e. a plain fraction of the screen width.
15
+ @OptIn(InternalComposeUiApi::class)
16
+ @Composable
17
+ actual fun rememberBackGestureProgress(): State<Float?> {
18
+ val dispatcher = LocalCompatNavigationEventDispatcherOwner.current?.navigationEventDispatcher
19
+ val progress = remember { mutableStateOf<Float?>(null) }
20
+
21
+ LaunchedEffect(dispatcher) {
22
+ if (dispatcher == null) {
23
+ progress.value = null
24
+ return@LaunchedEffect
25
+ }
26
+ dispatcher.transitionState.collect { state ->
27
+ progress.value = (state as? NavigationEventTransitionState.InProgress)
28
+ ?.takeIf { it.direction == NavigationEventTransitionState.TRANSITIONING_BACK }
29
+ ?.latestEvent
30
+ ?.progress
31
+ }
32
+ }
33
+
34
+ return progress
35
+ }
@@ -17,6 +17,7 @@ import androidx.compose.ui.ExperimentalComposeUiApi
17
17
  import androidx.compose.ui.InternalComposeUiApi
18
18
  import androidx.compose.ui.Modifier
19
19
  import androidx.compose.ui.backhandler.LocalCompatNavigationEventDispatcherOwner
20
+ import androidx.compose.ui.backhandler.BackHandler as ComposeBackHandler
20
21
  import androidx.compose.ui.graphics.Color
21
22
  import androidx.compose.ui.graphics.NativePaint
22
23
  import androidx.compose.ui.graphics.toArgb
@@ -38,6 +39,7 @@ import platform.Foundation.NSBundle
38
39
  import platform.UIKit.UIColor
39
40
  import platform.UIKit.UIDevice
40
41
  import platform.UIKit.UIScreen
42
+ import vn.momo.kits.navigation.ObserveBackGestureOwnership
41
43
 
42
44
  actual fun getPlatformName(): String = "iOS"
43
45
 
@@ -60,14 +62,33 @@ actual fun getStatusBarHeight(): Dp {
60
62
  return WindowInsets.systemBars.asPaddingValues().calculateTopPadding()
61
63
  }
62
64
 
65
+ // An enabled kit BackHandler is registered inside the NavHost destination, so it out-ranks
66
+ // NavHost's own predictive-back handler and swallows the gesture — that is how a screen opts out
67
+ // of swipe-back (the port of RN's `hasCustomBackHandling`).
68
+ @Suppress("DEPRECATION")
69
+ @OptIn(ExperimentalComposeUiApi::class)
63
70
  @Composable
64
71
  actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {
72
+ ComposeBackHandler(enabled = enabled, onBack = onBack)
65
73
  }
66
74
 
67
75
  @OptIn(InternalComposeUiApi::class)
68
76
  @Composable
69
77
  actual fun ProvideNavigationEventDispatcherOwner(content: @Composable () -> Unit) {
70
- val navigationEventDispatcherOwner = remember {
78
+ val platformOwner = LocalCompatNavigationEventDispatcherOwner.current
79
+ if (platformOwner != null) {
80
+ // UIKitNavigationEventInput is registered on the scene's dispatcher, and that dispatcher
81
+ // having enabled handlers is what arms Compose's UIKitBackGestureRecognizer. Providing a
82
+ // fresh NavigationEventDispatcher() here would shadow it with an input-less one that never
83
+ // sees a single edge-pan event — no recogniser, and no finger-following seek.
84
+ ObserveBackGestureOwnership(platformOwner.navigationEventDispatcher)
85
+ content()
86
+ return
87
+ }
88
+
89
+ // Bare UIView hosts have no scene dispatcher, and BackHandler/PredictiveBackHandler error() on
90
+ // a null owner. Disabled: nothing can feed it, so it exists only to keep those from throwing.
91
+ val fallbackOwner = remember {
71
92
  object : NavigationEventDispatcherOwner {
72
93
  override val navigationEventDispatcher = NavigationEventDispatcher().apply {
73
94
  isEnabled = false
@@ -76,7 +97,7 @@ actual fun ProvideNavigationEventDispatcherOwner(content: @Composable () -> Unit
76
97
  }
77
98
 
78
99
  CompositionLocalProvider(
79
- LocalCompatNavigationEventDispatcherOwner provides navigationEventDispatcherOwner,
100
+ LocalCompatNavigationEventDispatcherOwner provides fallbackOwner,
80
101
  content = content
81
102
  )
82
103
  }
package/gradle.properties CHANGED
@@ -18,7 +18,7 @@ kotlin.apple.xcodeCompatibility.nowarn=true
18
18
  name="ComposeKits"
19
19
  group=vn.momo.kits
20
20
  artifact.id=kits
21
- version=0.164.1-beta.1
21
+ version=0.164.1-beta.10
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'MoMoUIKits'
3
- s.version = '0.164.1-beta.1'
3
+ s.version = '0.164.1-beta.10'
4
4
  s.summary = 'MoMoUIKits for iOS'
5
5
  s.homepage = 'https://momo.vn'
6
6
  s.license = { :type => 'MIT' }
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'MoMoUIKitsDemo'
3
- s.version = '0.164.1-beta.1'
3
+ s.version = '0.164.1-beta.10'
4
4
  s.summary = 'Demo browser for MoMoUIKits SwiftUI components'
5
5
  s.homepage = 'https://momo.vn'
6
6
  s.license = { :type => 'MIT' }
package/local.properties CHANGED
@@ -4,5 +4,5 @@
4
4
  # Location of the SDK. This is only used by Gradle.
5
5
  # For customization when using a Version Control System, please read the
6
6
  # header note.
7
- #Wed Aug 21 14:20:12 ICT 2024
8
- sdk.dir=/Users/huynhdung/Library/Android/sdk
7
+ #Tue Jun 02 17:05:32 ICT 2026
8
+ sdk.dir=/Users/sophia/Library/Android/sdk
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.164.1-beta.1-debug",
3
+ "version": "0.164.1-beta.10-debug",
4
4
  "private": false,
5
5
  "dependeNavigationncies": {},
6
6
  "devDependencies": {},