@momo-kits/native-kits 0.168.1-beta.6-debug → 0.168.1-beta.7-debug
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +185 -0
- package/CLAUDE.md +1 -1
- package/compose/build.gradle.kts +1 -1
- package/compose/compose.podspec +1 -1
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +4 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +10 -3
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +54 -10
- package/gradle.properties +1 -1
- package/ios/Layout/ScreenLayout.swift +41 -11
- package/ios/Popup/PopupLayout.swift +0 -2
- package/ios/native-kits.podspec +1 -1
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
- package/local.properties +8 -0
- package/package.json +1 -1
|
@@ -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
|
@@ -71,7 +71,7 @@ Publishing is automated (`publish.sh` + GitLab CI on `[ci build]` / `main`). Do
|
|
|
71
71
|
## Screen layout / iPhone Duo (port of RN `useScreenLayout`, momo-kits !664)
|
|
72
72
|
|
|
73
73
|
- `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.
|
|
74
|
-
- 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` (
|
|
74
|
+
- 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` (Apple's foldable check: a `.division` reserved region, queried with include-inactive; Swift also latches on `UIHingeInteraction`) drives popups, modal and bottom sheet.
|
|
75
75
|
- Header height is `headerHeight` (not `AppStatusBar + HEADER_HEIGHT`); the bar row is `headerBarHeight` and starts `headerStatusBarHeight` below the window top. When the status bar is off the top edge (iPhone landscape, iPhone Duo) `headerStatusBarHeight` is 0 so the title stays centered — except on the Duo outer display: in portrait the header is 76pt and the row starts at 14pt so the title centers on the camera punchout; in landscape the row centers on the camera when it sits at the top end of the strip (else on the back button) and the header reaches 8pt below the back button.
|
|
76
76
|
- iPhone Duo inner display in portrait (status bar on top): the header row shares the status bar band — `headerHeight` 94pt (2 × the clock digits' y 47), `headerStatusBarHeight` 0 — and `ScreenLayout.statusBarClearance` keeps it between the clock / battery clusters (from reserved regions, else 128pt on the right). Back and toolkit use the 48pt side bar controls laid out horizontally (`ToolkitLayout.SideBarRow`); the collapsed search and a centered title stay clear of the clusters. Port of momo-kits `90af33ba2`.
|
|
77
77
|
- 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. `sideBar.top` is 170pt in portrait, 120pt on the inner display in landscape (height ≥ 600), 24pt on the outer display in landscape, or below the header when the status bar is on top; UIKit's `statusBarFrame` is useless on Duo. Unlike RN the column is clamped above footer (24pt gap) / rail (12pt gap).
|
package/compose/build.gradle.kts
CHANGED
package/compose/compose.podspec
CHANGED
|
@@ -14,7 +14,6 @@ import androidx.compose.ui.unit.dp
|
|
|
14
14
|
import vn.momo.kits.const.Spacing
|
|
15
15
|
import vn.momo.kits.navigation.component.HEADER_HEIGHT
|
|
16
16
|
import vn.momo.kits.platform.ReservedRegion
|
|
17
|
-
import vn.momo.kits.platform.getScreenDimensions
|
|
18
17
|
import vn.momo.kits.platform.isPhoneIdiom
|
|
19
18
|
import vn.momo.kits.platform.rememberReservedRegions
|
|
20
19
|
import vn.momo.kits.utils.getAppStatusBarHeight
|
|
@@ -52,7 +51,7 @@ data class ScreenLayout(
|
|
|
52
51
|
val headerStatusBarHeight: Dp,
|
|
53
52
|
// iPhone Duo moves back and toolkit into a column in the side safe area; null while they stay in the bar.
|
|
54
53
|
val sideBar: SideBarLayout? = null,
|
|
55
|
-
//
|
|
54
|
+
// The device has a hinge, folded or not, whatever the window size; drives popups, modal and bottom sheet.
|
|
56
55
|
val isIPhoneDuoDevice: Boolean = isIPhoneDuo,
|
|
57
56
|
// Portrait iPhone Duo puts the status bar in the side strip, about twice as tall as the strip is wide.
|
|
58
57
|
// Stored so it survives consumeHorizontalInsets().
|
|
@@ -93,9 +92,6 @@ internal object DuoMetrics {
|
|
|
93
92
|
val floatingTabBarInsetOverlap = 13.dp
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
// Widest short side of any single-display iPhone.
|
|
97
|
-
private val IPHONE_MAX_SHORT_SIDE = 440.dp
|
|
98
|
-
|
|
99
95
|
private val IPHONE_HEADER_MIN_HEIGHT = 72.dp
|
|
100
96
|
|
|
101
97
|
// A smaller top inset means the status bar is not on the top edge.
|
|
@@ -134,10 +130,9 @@ internal fun calculateScreenLayout(topInset: Dp, parent: ScreenLayout? = null):
|
|
|
134
130
|
val leftPx = insets.getLeft(density, layoutDirection)
|
|
135
131
|
val rightPx = insets.getRight(density, layoutDirection)
|
|
136
132
|
val bottomPx = WindowInsets.systemBars.getBottom(density)
|
|
137
|
-
val screen = getScreenDimensions()
|
|
138
133
|
val reservedRegions = rememberReservedRegions()
|
|
139
134
|
|
|
140
|
-
return remember(size, leftPx, rightPx, bottomPx, topInset,
|
|
135
|
+
return remember(size, leftPx, rightPx, bottomPx, topInset, density, reservedRegions) {
|
|
141
136
|
with(density) {
|
|
142
137
|
val width = size.width.toDp()
|
|
143
138
|
val height = size.height.toDp()
|
|
@@ -150,11 +145,8 @@ internal fun calculateScreenLayout(topInset: Dp, parent: ScreenLayout? = null):
|
|
|
150
145
|
bottomInset = bottomPx.toDp(),
|
|
151
146
|
isPhone = isPhone,
|
|
152
147
|
asymmetricInsets = leftPx != rightPx,
|
|
153
|
-
isDuoDevice = isPhone &&
|
|
154
|
-
|
|
155
|
-
minOf(width, height),
|
|
156
|
-
) > IPHONE_MAX_SHORT_SIDE,
|
|
157
|
-
reservedRegions = reservedRegions,
|
|
148
|
+
isDuoDevice = isPhone && reservedRegions.isFoldable,
|
|
149
|
+
reservedRegions = reservedRegions.occlusion,
|
|
158
150
|
)
|
|
159
151
|
}
|
|
160
152
|
}
|
|
@@ -7,7 +7,14 @@ import androidx.compose.ui.unit.Dp
|
|
|
7
7
|
@Immutable
|
|
8
8
|
internal data class ReservedRegion(val x: Dp, val y: Dp, val width: Dp, val height: Dp)
|
|
9
9
|
|
|
10
|
-
//
|
|
11
|
-
// iPhone Duo camera, and the status bar cluster as it grows for a call or a Live Activity.
|
|
10
|
+
// occlusion: regions the system occludes (iOS 27.1+), in the coordinates of the Compose root view:
|
|
11
|
+
// the iPhone Duo camera, and the status bar cluster as it grows for a call or a Live Activity.
|
|
12
|
+
// isFoldable: the device reports a `.division` (hinge) region, Apple's foldable check.
|
|
13
|
+
@Immutable
|
|
14
|
+
internal data class ReservedRegions(
|
|
15
|
+
val occlusion: List<ReservedRegion> = emptyList(),
|
|
16
|
+
val isFoldable: Boolean = false,
|
|
17
|
+
)
|
|
18
|
+
|
|
12
19
|
@Composable
|
|
13
|
-
internal expect fun rememberReservedRegions():
|
|
20
|
+
internal expect fun rememberReservedRegions(): ReservedRegions
|
|
@@ -9,9 +9,15 @@ import androidx.compose.runtime.setValue
|
|
|
9
9
|
import androidx.compose.ui.uikit.LocalUIViewController
|
|
10
10
|
import androidx.compose.ui.unit.dp
|
|
11
11
|
import kotlinx.cinterop.BetaInteropApi
|
|
12
|
+
import kotlinx.cinterop.CFunction
|
|
13
|
+
import kotlinx.cinterop.COpaquePointer
|
|
12
14
|
import kotlinx.cinterop.ExperimentalForeignApi
|
|
15
|
+
import kotlinx.cinterop.interpretCPointer
|
|
13
16
|
import kotlinx.cinterop.interpretObjCPointer
|
|
17
|
+
import kotlinx.cinterop.interpretObjCPointerOrNull
|
|
18
|
+
import kotlinx.cinterop.invoke
|
|
14
19
|
import kotlinx.cinterop.objcPtr
|
|
20
|
+
import kotlinx.cinterop.reinterpret
|
|
15
21
|
import kotlinx.cinterop.readValue
|
|
16
22
|
import kotlinx.cinterop.useContents
|
|
17
23
|
import platform.CoreGraphics.CGRectZero
|
|
@@ -25,18 +31,54 @@ import platform.UIKit.UIViewAutoresizingFlexibleHeight
|
|
|
25
31
|
import platform.UIKit.UIViewAutoresizingFlexibleWidth
|
|
26
32
|
import platform.darwin.NSObject
|
|
27
33
|
import platform.Foundation.NSClassFromString
|
|
34
|
+
import platform.posix.RTLD_DEFAULT
|
|
35
|
+
import platform.posix.dlsym
|
|
28
36
|
|
|
29
37
|
// The API is newer than the SDK Kotlin/Native binds, so it is reached through the runtime.
|
|
30
38
|
@OptIn(ExperimentalForeignApi::class)
|
|
31
39
|
private val regionsOfKind = NSSelectorFromString("reservedRegionsOfKind:")
|
|
32
40
|
|
|
41
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
42
|
+
private val regionsOfKindOptions = NSSelectorFromString("reservedRegionsOfKind:options:")
|
|
43
|
+
|
|
44
|
+
// a hinge never goes away, so a positive answer is kept for every later container
|
|
45
|
+
private var isKnownFoldable = false
|
|
46
|
+
|
|
33
47
|
@OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)
|
|
34
|
-
private fun
|
|
35
|
-
if (window == null || !respondsToSelector(regionsOfKind)) return emptyList()
|
|
48
|
+
private fun regionKind(name: String): Any? {
|
|
36
49
|
// a class object fails `as? NSObjectProtocol` (K/N checks it as an instance), so it is reinterpreted
|
|
37
50
|
val kindClass = NSClassFromString("UIViewReservedRegionKind")
|
|
38
|
-
?.let { interpretObjCPointer<NSObject>(it.objcPtr()) } ?: return
|
|
39
|
-
|
|
51
|
+
?.let { interpretObjCPointer<NSObject>(it.objcPtr()) } ?: return null
|
|
52
|
+
return kindClass.performSelector(NSSelectorFromString(name))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// performSelector cannot pass the NSUInteger options, so objc_msgSend is called with the method's own signature.
|
|
56
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
57
|
+
private val msgSendRegionsOfKindOptions = dlsym(RTLD_DEFAULT, "objc_msgSend")
|
|
58
|
+
?.reinterpret<CFunction<(COpaquePointer?, COpaquePointer?, COpaquePointer?, ULong) -> COpaquePointer?>>()
|
|
59
|
+
|
|
60
|
+
// Apple's foldable check: only a device with a hinge reports a `.division` region, inactive while
|
|
61
|
+
// flat (UIViewReservedRegionQueryOptionsIncludeInactive) but still there. Screen size cannot tell it
|
|
62
|
+
// apart from a large iPhone in landscape or a narrowed window.
|
|
63
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
64
|
+
private fun UIView.hasDivisionRegion(): Boolean {
|
|
65
|
+
if (window == null || !respondsToSelector(regionsOfKindOptions)) return false
|
|
66
|
+
val msgSend = msgSendRegionsOfKindOptions ?: return false
|
|
67
|
+
val kind = regionKind("divisionRegionKind") as? NSObject ?: return false
|
|
68
|
+
val result = msgSend(
|
|
69
|
+
interpretCPointer(objcPtr()),
|
|
70
|
+
regionsOfKindOptions,
|
|
71
|
+
interpretCPointer(kind.objcPtr()),
|
|
72
|
+
1uL,
|
|
73
|
+
)
|
|
74
|
+
val regions = interpretObjCPointerOrNull<NSArray>(result?.rawValue ?: return false)
|
|
75
|
+
return (regions?.count ?: 0uL) > 0uL
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
79
|
+
private fun UIView.occlusionRegions(target: UIView): List<ReservedRegion> {
|
|
80
|
+
if (window == null || !respondsToSelector(regionsOfKind)) return emptyList()
|
|
81
|
+
val kind = regionKind("occlusionRegionKind") ?: return emptyList()
|
|
40
82
|
val regions = when (val result = performSelector(regionsOfKind, withObject = kind)) {
|
|
41
83
|
is List<*> -> result
|
|
42
84
|
is NSArray -> List(result.count.toInt()) { result.objectAtIndex(it.toULong()) }
|
|
@@ -54,9 +96,9 @@ private fun UIView.occlusionRegions(target: UIView): List<ReservedRegion> {
|
|
|
54
96
|
// when they change, so nothing polls.
|
|
55
97
|
@OptIn(ExperimentalForeignApi::class)
|
|
56
98
|
private class ReservedRegionsProbe(
|
|
57
|
-
private val onChange: (
|
|
99
|
+
private val onChange: (ReservedRegions) -> Unit,
|
|
58
100
|
) : UIView(frame = CGRectZero.readValue()) {
|
|
59
|
-
private var last:
|
|
101
|
+
private var last: ReservedRegions? = null
|
|
60
102
|
|
|
61
103
|
init {
|
|
62
104
|
userInteractionEnabled = false
|
|
@@ -65,7 +107,9 @@ private class ReservedRegionsProbe(
|
|
|
65
107
|
|
|
66
108
|
override fun layoutSubviews() {
|
|
67
109
|
super.layoutSubviews()
|
|
68
|
-
|
|
110
|
+
// re-read until found: the window may not report the hinge on the first pass
|
|
111
|
+
if (!isKnownFoldable) isKnownFoldable = hasDivisionRegion()
|
|
112
|
+
val regions = ReservedRegions(superview?.let { occlusionRegions(it) } ?: emptyList(), isKnownFoldable)
|
|
69
113
|
if (regions != last) {
|
|
70
114
|
last = regions
|
|
71
115
|
onChange(regions)
|
|
@@ -80,10 +124,10 @@ private class ReservedRegionsProbe(
|
|
|
80
124
|
|
|
81
125
|
@OptIn(ExperimentalForeignApi::class)
|
|
82
126
|
@Composable
|
|
83
|
-
internal actual fun rememberReservedRegions():
|
|
84
|
-
if (!isPhoneIdiom()) return
|
|
127
|
+
internal actual fun rememberReservedRegions(): ReservedRegions {
|
|
128
|
+
if (!isPhoneIdiom()) return ReservedRegions()
|
|
85
129
|
val host = LocalUIViewController.current.view
|
|
86
|
-
var regions by remember { mutableStateOf(
|
|
130
|
+
var regions by remember { mutableStateOf(ReservedRegions(isFoldable = isKnownFoldable)) }
|
|
87
131
|
DisposableEffect(host) {
|
|
88
132
|
val probe = ReservedRegionsProbe { regions = it }
|
|
89
133
|
probe.setFrame(host.bounds)
|
package/gradle.properties
CHANGED
|
@@ -32,6 +32,8 @@ public struct ScreenLayout: Equatable {
|
|
|
32
32
|
public let width: CGFloat
|
|
33
33
|
public let height: CGFloat
|
|
34
34
|
public let isIPhoneDuo: Bool
|
|
35
|
+
/// The device has a hinge, folded or not, whatever the window size; drives popups, modal and bottom sheet.
|
|
36
|
+
public let isDuoDevice: Bool
|
|
35
37
|
public let insets: EdgeInsets
|
|
36
38
|
public let insetLeft: CGFloat
|
|
37
39
|
public let insetRight: CGFloat
|
|
@@ -73,8 +75,6 @@ enum DuoMetrics {
|
|
|
73
75
|
static let floatingTabBarHeight: CGFloat = 62
|
|
74
76
|
static let floatingTabBarMargin: CGFloat = 20
|
|
75
77
|
static let floatingTabBarInsetOverlap: CGFloat = 13
|
|
76
|
-
// Widest short side of any single-display iPhone.
|
|
77
|
-
static let iPhoneMaxShortSide: CGFloat = 440
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
enum HeaderMetrics {
|
|
@@ -109,15 +109,17 @@ extension ScreenLayout {
|
|
|
109
109
|
size: CGSize,
|
|
110
110
|
insets: EdgeInsets,
|
|
111
111
|
reservedRegions: [CGRect] = ReservedRegions.current,
|
|
112
|
-
isPhone: Bool = isPhoneIdiom
|
|
112
|
+
isPhone: Bool = isPhoneIdiom,
|
|
113
|
+
isFoldable: Bool = FoldableDevice.isFoldable(measuredIn: keyWindow)
|
|
113
114
|
) -> ScreenLayout {
|
|
114
115
|
let width = size.width
|
|
115
116
|
let height = size.height
|
|
117
|
+
let isDuoDevice = isPhone && isFoldable
|
|
116
118
|
var (headerHeight, headerStatusBarHeight) = headerGeometry(topInset: insets.top, isPhone: isPhone)
|
|
117
119
|
let isDuo = isPhone && isIPhoneDuoWindow(width: width, height: height, insets: insets)
|
|
118
120
|
guard isDuo else {
|
|
119
121
|
return ScreenLayout(
|
|
120
|
-
width: width, height: height, isIPhoneDuo: false, insets: insets,
|
|
122
|
+
width: width, height: height, isIPhoneDuo: false, isDuoDevice: isDuoDevice, insets: insets,
|
|
121
123
|
insetLeft: 0, insetRight: 0, contentWidth: width,
|
|
122
124
|
headerHeight: headerHeight, headerStatusBarHeight: headerStatusBarHeight, sideBar: nil,
|
|
123
125
|
statusBarClearance: nil
|
|
@@ -177,7 +179,7 @@ extension ScreenLayout {
|
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
return ScreenLayout(
|
|
180
|
-
width: width, height: height, isIPhoneDuo: true, insets: insets,
|
|
182
|
+
width: width, height: height, isIPhoneDuo: true, isDuoDevice: isDuoDevice, insets: insets,
|
|
181
183
|
insetLeft: insets.leading, insetRight: insets.trailing,
|
|
182
184
|
contentWidth: width - insets.leading - insets.trailing,
|
|
183
185
|
headerHeight: headerHeight, headerStatusBarHeight: headerStatusBarHeight, sideBar: sideBar,
|
|
@@ -256,13 +258,40 @@ extension ScreenLayout {
|
|
|
256
258
|
}
|
|
257
259
|
}
|
|
258
260
|
|
|
259
|
-
///
|
|
260
|
-
///
|
|
261
|
+
/// Snapshot for call sites without `\.screenLayout`; not reactive. `windowSize` is ignored,
|
|
262
|
+
/// kept for host call sites.
|
|
261
263
|
public func isIPhoneDuoDevice(windowSize: CGSize? = nil) -> Bool {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
isPhoneIdiom && FoldableDevice.isFoldable(measuredIn: keyWindow)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/// Apple's foldable check (as the host's `SideTabRailView.isFoldableDevice`): only a device with a
|
|
268
|
+
/// hinge reports a `.division` region, inactive while flat but still there. Screen size cannot tell
|
|
269
|
+
/// it apart from a large iPhone in landscape or a narrowed window.
|
|
270
|
+
enum FoldableDevice {
|
|
271
|
+
// a hinge never goes away, so a positive answer is kept
|
|
272
|
+
private static var isKnownFoldable = false
|
|
273
|
+
|
|
274
|
+
static func isFoldable(measuredIn view: UIView?) -> Bool {
|
|
275
|
+
if isKnownFoldable { return true }
|
|
276
|
+
// compiled out on SDKs older than iOS 27.1 (UIKit 9127.0.85.28)
|
|
277
|
+
#if canImport(UIKit, _version: 9127.0.85.28)
|
|
278
|
+
guard #available(iOS 27.1, *), let view, view.window != nil || view is UIWindow else { return false }
|
|
279
|
+
isKnownFoldable = !view.reservedRegions(kind: .division, options: .includeInactive).isEmpty
|
|
280
|
+
#endif
|
|
281
|
+
return isKnownFoldable
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/// Catches the hinge when the regions were read too early (before the window had them).
|
|
285
|
+
static func observe(in view: UIView) {
|
|
286
|
+
#if canImport(UIKit, _version: 9127.0.85.28)
|
|
287
|
+
guard #available(iOS 27.1, *) else { return }
|
|
288
|
+
view.addInteraction(UIHingeInteraction { _, update in
|
|
289
|
+
guard update.hinge != nil, !isKnownFoldable else { return }
|
|
290
|
+
isKnownFoldable = true
|
|
291
|
+
NotificationCenter.default.post(name: ReservedRegions.didChange, object: nil)
|
|
292
|
+
})
|
|
293
|
+
#endif
|
|
294
|
+
}
|
|
266
295
|
}
|
|
267
296
|
|
|
268
297
|
// MARK: - Reserved regions
|
|
@@ -287,6 +316,7 @@ private final class ReservedRegionsProbe: UIView {
|
|
|
287
316
|
override init(frame: CGRect) {
|
|
288
317
|
super.init(frame: frame)
|
|
289
318
|
isUserInteractionEnabled = false
|
|
319
|
+
FoldableDevice.observe(in: self)
|
|
290
320
|
}
|
|
291
321
|
|
|
292
322
|
required init?(coder: NSCoder) { nil }
|
|
@@ -5,8 +5,6 @@ import SwiftUI
|
|
|
5
5
|
private let duoPopupMaxWidth: CGFloat = 440
|
|
6
6
|
|
|
7
7
|
extension ScreenLayout {
|
|
8
|
-
var isDuoDevice: Bool { isIPhoneDuoDevice(windowSize: CGSize(width: width, height: height)) }
|
|
9
|
-
|
|
10
8
|
/// Card width cap (Compose `popupMaxWidth`); unbounded off iPhone Duo, where the popup's own padding sets the width.
|
|
11
9
|
var popupMaxWidth: CGFloat {
|
|
12
10
|
isDuoDevice ? duoPopupMaxWidth : .infinity
|
package/ios/native-kits.podspec
CHANGED
package/local.properties
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
## This file must *NOT* be checked into Version Control Systems,
|
|
2
|
+
# as it contains information specific to your local configuration.
|
|
3
|
+
#
|
|
4
|
+
# Location of the SDK. This is only used by Gradle.
|
|
5
|
+
# For customization when using a Version Control System, please read the
|
|
6
|
+
# header note.
|
|
7
|
+
#Tue Jun 02 17:05:32 ICT 2026
|
|
8
|
+
sdk.dir=/Users/sophia/Library/Android/sdk
|