@momo-kits/native-kits 0.167.1-duo.2-debug → 0.167.1-duo.3-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/scheduled_tasks.lock +1 -0
- package/.claude/settings.local.json +185 -0
- package/CLAUDE.md +8 -3
- package/compose/build.gradle.kts +15 -1
- package/compose/build.gradle.kts.backup +14 -0
- package/compose/compose.podspec +1 -1
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +52 -25
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +12 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +45 -15
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +43 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +8 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +34 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +81 -62
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +281 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +31 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +27 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +17 -10
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +3 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +4 -0
- package/gradle.properties +1 -1
- package/ios/Application/HeaderRight.swift +25 -12
- package/ios/Application/Layout/ScreenLayout.swift +196 -0
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +30 -9
- package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +5 -2
- package/ios/Application/Navigation/BottomTab/DuoTabBar.swift +275 -0
- package/ios/Application/Navigation/HeaderUser.swift +4 -1
- package/ios/Application/Navigation/NavigationContainer.swift +3 -0
- package/ios/Application/Navigation/Overplay/BottomSheet.swift +41 -4
- package/ios/Application/Navigation/Overplay/ModalScreen.swift +5 -1
- package/ios/Application/Navigation/component/DuoScrollGradient.swift +55 -0
- package/ios/Application/Navigation/component/Header.swift +9 -3
- package/ios/Application/Navigation/component/HeaderBackground.swift +3 -2
- package/ios/Application/Navigation/component/NavigationFooter.swift +1 -1
- package/ios/Application/Navigation/component/NavigationHeaderRight.swift +61 -9
- package/ios/Application/Navigation/component/SideBar.swift +155 -0
- package/ios/Application/StackScreen.swift +135 -18
- package/ios/Popup/PopupDisplay.swift +84 -68
- package/ios/Popup/PopupLayout.swift +45 -0
- package/ios/Popup/PopupNotify.swift +43 -32
- package/ios/Popup/PopupPromotion.swift +17 -5
- package/ios/native-kits.podspec +1 -1
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +76 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +1 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +170 -0
- package/local.properties +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"sessionId":"611d4121-c353-42bf-a58b-2fe5f02b02bb","pid":99784,"procStart":"Sun Oct 4 12:12:05 2026","acquiredAt":1791116444172}
|
|
@@ -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
|
+
}
|
package/CLAUDE.md
CHANGED
|
@@ -47,11 +47,16 @@ Publishing is automated (`publish.sh` + GitLab CI on `[ci build]` / `main`). Do
|
|
|
47
47
|
- Navigation uses a runtime `DynamicScreenRegistry`; overlays (modal/bottom-sheet/snackbar) go through `Navigator` + `OverplayComponentRegistry`.
|
|
48
48
|
- **iOS swipe-back:** the host owns the only edge-pan recogniser and replays it through `HostBackGestureBridge` (`navigation/HostBackGestureBridge.kt`; the kit framework is never exported, so the host reaches it through its own Koin-provided facade): `checkCanPop` / `canPopInner` / `pop` route the back into the kit stack, `started` / `progressed` / `completed` / `cancelled` seek the NavHost transition, `shouldUseFloatingArrowBack` is set by bottom tabs. `NavigationContainer` attaches itself automatically (`AttachHostBackGesture`, iOS only, detached by identity on dispose) — hosts need no wrapper and no `setNavigator`. `maxApi` is a required parameter of `NavigationContainer` — every container, nested or root, is handed its host bridge explicitly.
|
|
49
49
|
|
|
50
|
-
## Screen layout / iPhone Duo (port of RN `useScreenLayout
|
|
50
|
+
## Screen layout / iPhone Duo (port of RN `useScreenLayout`, momo-kits !664)
|
|
51
51
|
|
|
52
|
-
- `layout/ScreenLayout.kt`: `getScreenLayout()` returns window size, side
|
|
52
|
+
- `layout/ScreenLayout.kt`: `getScreenLayout()` returns window size, raw top/bottom + side insets, `contentWidth`, header geometry, the iPhone Duo `sideBar` and `duoTopInset`. `NavigationContainer` computes it once and provides `LocalScreenLayout`; reactive to fold/unfold and rotation (window size + `WindowInsets`). Metrics (`DuoMetrics`, 72pt iPhone header floor, 20pt status-bar threshold) mirror RN `Layout/utils.ts` — change both together.
|
|
53
|
+
- iPhone-only: everything gates on `isPhoneIdiom()` (`platform/`), never on "iOS", so iPad windows keep the regular layout. Two detectors, as in RN: `isIPhoneDuo` (window aspect < 1.6 or asymmetric side insets) drives layout; `isIPhoneDuoDevice` (short side of screen or window > 440, RN `device.ts`) drives popups, modal and bottom sheet.
|
|
53
54
|
- Header height is `headerHeight` (not `AppStatusBar + HEADER_HEIGHT`); the bar row is `headerBarHeight`. When the status bar is off the top edge (iPhone landscape, iPhone Duo) `headerStatusBarHeight` is 0 so the title stays centered.
|
|
54
|
-
- iPhone Duo with a side strip ≥ 60pt: back + toolkit leave the bar for `HeaderSideBar` (`navigation/component/SideBar.kt`, 48pt glass controls); custom header-right stays in the bar. The column starts
|
|
55
|
+
- iPhone Duo with a side strip ≥ 60pt: back + toolkit leave the bar for `HeaderSideBar` (`navigation/component/SideBar.kt`, 48pt glass controls); custom header-right stays in the bar. The column starts at 120pt when the inner display is landscape (height ≥ 600), else 170pt, or below the header when the status bar is on top; UIKit's `statusBarFrame` is useless on Duo. Unlike RN it is clamped 24pt above footer / tab bar / rail.
|
|
56
|
+
- Tab bar on Duo is `bottomtab/DuoTabBar.kt`: a rail in the side strip (anchored 24pt from the bottom, QR below it) or, without a side bar, a floating bar spanning 6/8 grid columns. Both overlay the content; `duoFloatingTabBarInset` pads tab content, footer and FAB.
|
|
57
|
+
- Glass header: on Duo with a side bar, Default/Extended headers without search and with a `ScrollState` let content scroll under the bar (`usesDuoGlassHeader`); the bar fades in a translucent surface + hairline over 16pt (Compose has no backdrop blur — RN's fallback look), the gradient scrolls away / collapses.
|
|
58
|
+
- Overlays on Duo: popups cap at 440pt wide and the room between `duoTopInset` and the bottom inset (body scrolls, actions stay); modal centers inside that room; bottom sheet uses the window height, centers at width ≥ 600 and pads by side insets in landscape.
|
|
59
|
+
- Font scale deliberately uses the short side (`min(w, h)`), unlike RN which reads the window width — landscape must not inflate every font.
|
|
55
60
|
- `StackScreen` pads content/footer/search/FAB by the side insets and provides an inset-consumed layout to its content; a bottom-tab root stays full width (tab bar + each tab's StackScreen handle insets). Grid columns use `contentWidth`.
|
|
56
61
|
|
|
57
62
|
## i18n / Localize (port of RN `Localize`)
|
package/compose/build.gradle.kts
CHANGED
|
@@ -40,7 +40,7 @@ kotlin {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
cocoapods {
|
|
43
|
-
version = "0.167.1-duo.
|
|
43
|
+
version = "0.167.1-duo.3-debug"
|
|
44
44
|
summary = "IOS Shared module"
|
|
45
45
|
homepage = "https://momo.vn"
|
|
46
46
|
ios.deploymentTarget = "15.0"
|
|
@@ -188,3 +188,17 @@ compose {
|
|
|
188
188
|
// }
|
|
189
189
|
// }
|
|
190
190
|
// }
|
|
191
|
+
|
|
192
|
+
// Xcode 27 rejects pods below iOS 15 (lottie-ios 4.4.3 declares 13.0), and the synthetic Podfile has no post_install hook.
|
|
193
|
+
val syntheticPodsProject = layout.buildDirectory.file("cocoapods/synthetic/ios/Pods/Pods.xcodeproj/project.pbxproj")
|
|
194
|
+
tasks.matching { it.name.startsWith("podInstallSynthetic") }.configureEach {
|
|
195
|
+
doLast {
|
|
196
|
+
val pbxproj = syntheticPodsProject.get().asFile
|
|
197
|
+
if (!pbxproj.exists()) return@doLast
|
|
198
|
+
val target = Regex("IPHONEOS_DEPLOYMENT_TARGET = ([0-9.]+);")
|
|
199
|
+
pbxproj.writeText(pbxproj.readText().replace(target) { match ->
|
|
200
|
+
val major = match.groupValues[1].substringBefore('.').toIntOrNull() ?: 0
|
|
201
|
+
if (major < 15) "IPHONEOS_DEPLOYMENT_TARGET = 15.0;" else match.value
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -188,3 +188,17 @@ mavenPublishing {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
|
+
|
|
192
|
+
// Xcode 27 rejects pods below iOS 15 (lottie-ios 4.4.3 declares 13.0), and the synthetic Podfile has no post_install hook.
|
|
193
|
+
val syntheticPodsProject = layout.buildDirectory.file("cocoapods/synthetic/ios/Pods/Pods.xcodeproj/project.pbxproj")
|
|
194
|
+
tasks.matching { it.name.startsWith("podInstallSynthetic") }.configureEach {
|
|
195
|
+
doLast {
|
|
196
|
+
val pbxproj = syntheticPodsProject.get().asFile
|
|
197
|
+
if (!pbxproj.exists()) return@doLast
|
|
198
|
+
val target = Regex("IPHONEOS_DEPLOYMENT_TARGET = ([0-9.]+);")
|
|
199
|
+
pbxproj.writeText(pbxproj.readText().replace(target) { match ->
|
|
200
|
+
val major = match.groupValues[1].substringBefore('.').toIntOrNull() ?: 0
|
|
201
|
+
if (major < 15) "IPHONEOS_DEPLOYMENT_TARGET = 15.0;" else match.value
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
}
|
package/compose/compose.podspec
CHANGED
|
@@ -36,6 +36,8 @@ import androidx.activity.compose.BackHandler as AndroidBackHandler
|
|
|
36
36
|
|
|
37
37
|
actual fun getPlatformName(): String = "Android"
|
|
38
38
|
|
|
39
|
+
actual fun isPhoneIdiom(): Boolean = false
|
|
40
|
+
|
|
39
41
|
@Composable
|
|
40
42
|
actual fun getScreenDimensions(): ScreenDimension {
|
|
41
43
|
val config = LocalConfiguration.current
|
|
@@ -4,6 +4,8 @@ import androidx.compose.foundation.background
|
|
|
4
4
|
import androidx.compose.foundation.border
|
|
5
5
|
import androidx.compose.foundation.clickable
|
|
6
6
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
7
|
+
import androidx.compose.foundation.rememberScrollState
|
|
8
|
+
import androidx.compose.foundation.verticalScroll
|
|
7
9
|
import androidx.compose.foundation.layout.*
|
|
8
10
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
9
11
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
@@ -20,7 +22,7 @@ import vn.momo.kits.application.LocalLocalize
|
|
|
20
22
|
import vn.momo.kits.const.*
|
|
21
23
|
import vn.momo.kits.modifier.conditional
|
|
22
24
|
import vn.momo.kits.modifier.setAutomationId
|
|
23
|
-
import vn.momo.kits.
|
|
25
|
+
import vn.momo.kits.layout.getScreenLayout
|
|
24
26
|
import kotlin.math.min
|
|
25
27
|
|
|
26
28
|
data class PopupAction(
|
|
@@ -34,9 +36,21 @@ enum class PopupActionDirection {
|
|
|
34
36
|
AUTO
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
//
|
|
39
|
+
// Width of a system alert on the iPhone Duo inner display, in both orientations (RN Popup/utils.ts).
|
|
40
|
+
private val DUO_POPUP_MAX_WIDTH = 440.dp
|
|
41
|
+
|
|
42
|
+
// Card width cap plus the popup's own side padding; unbounded off iPhone Duo.
|
|
43
|
+
@Composable
|
|
44
|
+
internal fun popupMaxWidth(horizontalPadding: Dp): Dp =
|
|
45
|
+
if (getScreenLayout().isIPhoneDuoDevice) DUO_POPUP_MAX_WIDTH + horizontalPadding * 2 else Dp.Unspecified
|
|
46
|
+
|
|
47
|
+
// Room left for a popup on iPhone Duo, where landscape is too short for it; null elsewhere.
|
|
38
48
|
@Composable
|
|
39
|
-
internal fun
|
|
49
|
+
internal fun popupMaxHeight(): Dp? {
|
|
50
|
+
val layout = getScreenLayout()
|
|
51
|
+
if (!layout.isIPhoneDuoDevice) return null
|
|
52
|
+
return layout.height - layout.duoTopInset - layout.insetBottom - Spacing.XL * 2
|
|
53
|
+
}
|
|
40
54
|
|
|
41
55
|
private fun heightForLines(
|
|
42
56
|
layout: TextLayoutResult,
|
|
@@ -129,12 +143,15 @@ fun PopupNotify(
|
|
|
129
143
|
callback?.invoke()
|
|
130
144
|
}
|
|
131
145
|
|
|
146
|
+
val maxHeight = popupMaxHeight()
|
|
147
|
+
val bodyScrollState = rememberScrollState()
|
|
148
|
+
|
|
132
149
|
Box(
|
|
133
150
|
Modifier.setAutomationId("popup_notify"), contentAlignment = Alignment.TopEnd
|
|
134
151
|
) {
|
|
135
152
|
Column(
|
|
136
153
|
modifier = Modifier
|
|
137
|
-
.widthIn(max = popupMaxWidth())
|
|
154
|
+
.widthIn(max = popupMaxWidth(horizontalPadding = 12.dp))
|
|
138
155
|
.fillMaxWidth()
|
|
139
156
|
.padding(horizontal = 12.dp)
|
|
140
157
|
.clip(RoundedCornerShape(Radius.L))
|
|
@@ -145,31 +162,41 @@ fun PopupNotify(
|
|
|
145
162
|
.conditional(IsShowBaseLineDebug) {
|
|
146
163
|
border(1.dp, Colors.blue_03)
|
|
147
164
|
}
|
|
165
|
+
.conditional(maxHeight != null) {
|
|
166
|
+
heightIn(max = maxHeight ?: Dp.Unspecified)
|
|
167
|
+
}
|
|
148
168
|
) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
169
|
+
// scrolls when iPhone Duo landscape is too short; actions stay visible
|
|
170
|
+
Column(
|
|
171
|
+
Modifier.conditional(maxHeight != null) {
|
|
172
|
+
weight(1f, fill = false).verticalScroll(bodyScrollState)
|
|
173
|
+
}
|
|
174
|
+
) {
|
|
175
|
+
if(props.image.isNotEmpty()) {
|
|
176
|
+
Image(
|
|
177
|
+
source = props.image,
|
|
178
|
+
modifier = Modifier.fillMaxWidth().aspectRatio(1.777f),
|
|
179
|
+
options = Options(alignment = Alignment.Center)
|
|
180
|
+
)
|
|
181
|
+
}
|
|
156
182
|
|
|
157
|
-
|
|
158
|
-
Text(
|
|
159
|
-
style = Typography.headerDefaultBold,
|
|
160
|
-
maxLines = 2,
|
|
161
|
-
text = props.title,
|
|
162
|
-
modifier = Modifier.setAutomationId("title_popup_permission")
|
|
163
|
-
)
|
|
164
|
-
content(Modifier.padding(top = Spacing.S))
|
|
165
|
-
if (props.error.isNotEmpty()) {
|
|
183
|
+
Column(modifier = Modifier.padding(Spacing.XL)) {
|
|
166
184
|
Text(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
modifier = Modifier.padding(top = Spacing.S)
|
|
185
|
+
style = Typography.headerDefaultBold,
|
|
186
|
+
maxLines = 2,
|
|
187
|
+
text = props.title,
|
|
188
|
+
modifier = Modifier.setAutomationId("title_popup_permission")
|
|
172
189
|
)
|
|
190
|
+
content(Modifier.padding(top = Spacing.S))
|
|
191
|
+
if (props.error.isNotEmpty()) {
|
|
192
|
+
Text(
|
|
193
|
+
text = LocalLocalize.current.translate("errorCode") + props.error,
|
|
194
|
+
style = Typography.descriptionXsRegular,
|
|
195
|
+
color = AppTheme.current.colors.text.hint,
|
|
196
|
+
maxLines = 1,
|
|
197
|
+
modifier = Modifier.padding(top = Spacing.S)
|
|
198
|
+
)
|
|
199
|
+
}
|
|
173
200
|
}
|
|
174
201
|
}
|
|
175
202
|
|
|
@@ -22,14 +22,24 @@ import vn.momo.kits.modifier.conditional
|
|
|
22
22
|
import vn.momo.kits.modifier.setAutomationId
|
|
23
23
|
import vn.momo.kits.utils.ifNotNull
|
|
24
24
|
|
|
25
|
+
private const val ASPECT_RATIO = 0.72f
|
|
26
|
+
private val CLOSE_ROW_HEIGHT = Spacing.S + 40.dp
|
|
27
|
+
|
|
25
28
|
@Composable
|
|
26
29
|
fun PopupPromotion(
|
|
27
30
|
source: String = "",
|
|
28
31
|
onPress: (() -> Unit) = {},
|
|
29
32
|
onClose: (() -> Unit) = {},
|
|
30
33
|
) {
|
|
34
|
+
val maxHeight = popupMaxHeight()
|
|
35
|
+
var maxWidth = popupMaxWidth(horizontalPadding = Spacing.M)
|
|
36
|
+
if (maxHeight != null) {
|
|
37
|
+
// fit the portrait image by height when iPhone Duo leaves too little room
|
|
38
|
+
maxWidth = minOf(maxWidth, (maxHeight - CLOSE_ROW_HEIGHT) * ASPECT_RATIO + Spacing.M * 2)
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
Column(Modifier
|
|
32
|
-
.widthIn(max =
|
|
42
|
+
.widthIn(max = maxWidth)
|
|
33
43
|
.padding(horizontal = Spacing.M)
|
|
34
44
|
.conditional(IsShowBaseLineDebug) {
|
|
35
45
|
border(1.dp, Colors.blue_03)
|
|
@@ -39,7 +49,7 @@ fun PopupPromotion(
|
|
|
39
49
|
Image(
|
|
40
50
|
source = source,
|
|
41
51
|
modifier = Modifier.fillMaxWidth()
|
|
42
|
-
.aspectRatio(
|
|
52
|
+
.aspectRatio(ASPECT_RATIO)
|
|
43
53
|
.clickable(
|
|
44
54
|
interactionSource = remember { MutableInteractionSource() },
|
|
45
55
|
indication = null,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package vn.momo.kits.layout
|
|
2
2
|
|
|
3
|
+
import androidx.compose.foundation.layout.WindowInsets
|
|
4
|
+
import androidx.compose.foundation.layout.systemBars
|
|
3
5
|
import androidx.compose.runtime.Composable
|
|
4
6
|
import androidx.compose.runtime.Immutable
|
|
5
7
|
import androidx.compose.runtime.compositionLocalOf
|
|
@@ -11,7 +13,8 @@ import androidx.compose.ui.unit.Dp
|
|
|
11
13
|
import androidx.compose.ui.unit.dp
|
|
12
14
|
import vn.momo.kits.const.Spacing
|
|
13
15
|
import vn.momo.kits.navigation.component.HEADER_HEIGHT
|
|
14
|
-
import vn.momo.kits.platform.
|
|
16
|
+
import vn.momo.kits.platform.getScreenDimensions
|
|
17
|
+
import vn.momo.kits.platform.isPhoneIdiom
|
|
15
18
|
import vn.momo.kits.utils.getAppStatusBarHeight
|
|
16
19
|
import vn.momo.kits.utils.horizontalSafeAreaInsets
|
|
17
20
|
|
|
@@ -30,6 +33,9 @@ data class ScreenLayout(
|
|
|
30
33
|
val width: Dp,
|
|
31
34
|
val height: Dp,
|
|
32
35
|
val isIPhoneDuo: Boolean,
|
|
36
|
+
// Raw top / bottom safe area; overlays and the Duo floating tab bar keep clear of them.
|
|
37
|
+
val insetTop: Dp,
|
|
38
|
+
val insetBottom: Dp,
|
|
33
39
|
val insetLeft: Dp,
|
|
34
40
|
val insetRight: Dp,
|
|
35
41
|
val contentWidth: Dp,
|
|
@@ -38,6 +44,11 @@ data class ScreenLayout(
|
|
|
38
44
|
val headerStatusBarHeight: Dp,
|
|
39
45
|
// iPhone Duo moves back and toolkit into a column in the side safe area; null while they stay in the bar.
|
|
40
46
|
val sideBar: SideBarLayout? = null,
|
|
47
|
+
// Port of RN `device.ts` isIPhoneDuo: the screen stays on the outer display, so Split View still matches.
|
|
48
|
+
val isIPhoneDuoDevice: Boolean = isIPhoneDuo,
|
|
49
|
+
// Portrait iPhone Duo puts the status bar in the side strip, about twice as tall as the strip is wide.
|
|
50
|
+
// Stored so it survives consumeHorizontalInsets().
|
|
51
|
+
val duoTopInset: Dp = insetTop,
|
|
41
52
|
) {
|
|
42
53
|
val headerBarHeight: Dp get() = headerHeight - headerStatusBarHeight
|
|
43
54
|
}
|
|
@@ -50,11 +61,15 @@ internal object DuoMetrics {
|
|
|
50
61
|
val itemPitch = 50.dp
|
|
51
62
|
// Portrait: below the camera/clock cluster in the strip (ends near y 151).
|
|
52
63
|
val firstItemTop = 170.dp
|
|
53
|
-
//
|
|
54
|
-
// (ends near y 60) and leaves the longest toolkit ~36pt above the footer.
|
|
64
|
+
// Inner display in landscape: below its status cluster (ends near y 98).
|
|
55
65
|
val firstItemTopLandscape = 120.dp
|
|
66
|
+
// Window height from which the inner display is in use (outer is 466pt tall in landscape, inner 669pt).
|
|
67
|
+
val innerMinHeight = 600.dp
|
|
56
68
|
}
|
|
57
69
|
|
|
70
|
+
// Widest short side of any single-display iPhone.
|
|
71
|
+
private val IPHONE_MAX_SHORT_SIDE = 440.dp
|
|
72
|
+
|
|
58
73
|
private val IPHONE_HEADER_MIN_HEIGHT = 72.dp
|
|
59
74
|
|
|
60
75
|
// A smaller top inset means the status bar is not on the top edge.
|
|
@@ -69,9 +84,9 @@ fun getScreenLayout(): ScreenLayout =
|
|
|
69
84
|
|
|
70
85
|
@Composable
|
|
71
86
|
internal fun calculateScreenLayout(topInset: Dp, parent: ScreenLayout? = null): ScreenLayout {
|
|
72
|
-
val
|
|
87
|
+
val isPhone = isPhoneIdiom()
|
|
73
88
|
if (parent != null) {
|
|
74
|
-
val (headerHeight, headerStatusBarHeight) = headerGeometry(topInset,
|
|
89
|
+
val (headerHeight, headerStatusBarHeight) = headerGeometry(topInset, isPhone)
|
|
75
90
|
return parent.copy(headerHeight = headerHeight, headerStatusBarHeight = headerStatusBarHeight)
|
|
76
91
|
}
|
|
77
92
|
|
|
@@ -81,17 +96,26 @@ internal fun calculateScreenLayout(topInset: Dp, parent: ScreenLayout? = null):
|
|
|
81
96
|
val insets = horizontalSafeAreaInsets
|
|
82
97
|
val leftPx = insets.getLeft(density, layoutDirection)
|
|
83
98
|
val rightPx = insets.getRight(density, layoutDirection)
|
|
99
|
+
val bottomPx = WindowInsets.systemBars.getBottom(density)
|
|
100
|
+
val screen = getScreenDimensions()
|
|
84
101
|
|
|
85
|
-
return remember(size, leftPx, rightPx, topInset, density) {
|
|
102
|
+
return remember(size, leftPx, rightPx, bottomPx, topInset, screen, density) {
|
|
86
103
|
with(density) {
|
|
104
|
+
val width = size.width.toDp()
|
|
105
|
+
val height = size.height.toDp()
|
|
87
106
|
screenLayoutOf(
|
|
88
|
-
width =
|
|
89
|
-
height =
|
|
107
|
+
width = width,
|
|
108
|
+
height = height,
|
|
90
109
|
insetLeft = leftPx.toDp(),
|
|
91
110
|
insetRight = rightPx.toDp(),
|
|
92
111
|
topInset = topInset,
|
|
93
|
-
|
|
112
|
+
bottomInset = bottomPx.toDp(),
|
|
113
|
+
isPhone = isPhone,
|
|
94
114
|
asymmetricInsets = leftPx != rightPx,
|
|
115
|
+
isDuoDevice = isPhone && maxOf(
|
|
116
|
+
minOf(screen.width, screen.height).dp,
|
|
117
|
+
minOf(width, height),
|
|
118
|
+
) > IPHONE_MAX_SHORT_SIDE,
|
|
95
119
|
)
|
|
96
120
|
}
|
|
97
121
|
}
|
|
@@ -101,9 +125,9 @@ internal fun calculateScreenLayout(topInset: Dp, parent: ScreenLayout? = null):
|
|
|
101
125
|
internal fun ScreenLayout.consumeHorizontalInsets(): ScreenLayout =
|
|
102
126
|
copy(width = contentWidth, insetLeft = 0.dp, insetRight = 0.dp, sideBar = null)
|
|
103
127
|
|
|
104
|
-
private fun headerGeometry(topInset: Dp,
|
|
128
|
+
private fun headerGeometry(topInset: Dp, isPhone: Boolean): Pair<Dp, Dp> {
|
|
105
129
|
val height = topInset + HEADER_HEIGHT.dp
|
|
106
|
-
if (!
|
|
130
|
+
if (!isPhone) return height to topInset
|
|
107
131
|
return maxOf(height, IPHONE_HEADER_MIN_HEIGHT) to if (topInset < STATUS_BAR_MIN_INSET) 0.dp else topInset
|
|
108
132
|
}
|
|
109
133
|
|
|
@@ -120,11 +144,13 @@ private fun screenLayoutOf(
|
|
|
120
144
|
insetLeft: Dp,
|
|
121
145
|
insetRight: Dp,
|
|
122
146
|
topInset: Dp,
|
|
123
|
-
|
|
147
|
+
bottomInset: Dp,
|
|
148
|
+
isPhone: Boolean,
|
|
124
149
|
asymmetricInsets: Boolean,
|
|
150
|
+
isDuoDevice: Boolean,
|
|
125
151
|
): ScreenLayout {
|
|
126
|
-
val (headerHeight, headerStatusBarHeight) = headerGeometry(topInset,
|
|
127
|
-
val isIPhoneDuo =
|
|
152
|
+
val (headerHeight, headerStatusBarHeight) = headerGeometry(topInset, isPhone)
|
|
153
|
+
val isIPhoneDuo = isPhone && isIPhoneDuoWindow(width, height, asymmetricInsets)
|
|
128
154
|
|
|
129
155
|
var sideBar: SideBarLayout? = null
|
|
130
156
|
val sideInset = maxOf(insetLeft, insetRight)
|
|
@@ -133,7 +159,7 @@ private fun screenLayoutOf(
|
|
|
133
159
|
// UIKit reports no usable status bar frame here (a 2pt top strip), so the spot is inferred like RN
|
|
134
160
|
val top = when {
|
|
135
161
|
topInset >= STATUS_BAR_MIN_INSET -> topInset + HEADER_HEIGHT.dp + Spacing.M
|
|
136
|
-
width > height -> DuoMetrics.firstItemTopLandscape
|
|
162
|
+
width > height && height >= DuoMetrics.innerMinHeight -> DuoMetrics.firstItemTopLandscape
|
|
137
163
|
else -> DuoMetrics.firstItemTop
|
|
138
164
|
}
|
|
139
165
|
sideBar = SideBarLayout(
|
|
@@ -147,11 +173,15 @@ private fun screenLayoutOf(
|
|
|
147
173
|
width = width,
|
|
148
174
|
height = height,
|
|
149
175
|
isIPhoneDuo = isIPhoneDuo,
|
|
176
|
+
insetTop = topInset,
|
|
177
|
+
insetBottom = bottomInset,
|
|
150
178
|
insetLeft = insetLeft,
|
|
151
179
|
insetRight = insetRight,
|
|
152
180
|
contentWidth = width - insetLeft - insetRight,
|
|
153
181
|
headerHeight = headerHeight,
|
|
154
182
|
headerStatusBarHeight = headerStatusBarHeight,
|
|
155
183
|
sideBar = sideBar,
|
|
184
|
+
isIPhoneDuoDevice = isDuoDevice,
|
|
185
|
+
duoTopInset = maxOf(topInset, if (height > width) sideInset * 2 else 0.dp),
|
|
156
186
|
)
|
|
157
187
|
}
|