ReviewOS

also looking at this

craft-native/craft

fix(mobile): preserve native editing, navigation, and durable media requests

#369
Merged chris wants to merge codex/native-vertical-scroll-tab-swipes into main
36 files +864 -185

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/android/fixtures/native-navigation/NativeFlatListTest.ktmodified+13-6
Changes to packages/android/fixtures/native-navigation/NativeFlatListTest.kt
@@ -12,10 +12,13 @@ import android.widget.LinearLayout
1212import android.widget.TextView
1313import androidx.recyclerview.widget.GridLayoutManager
1414import androidx.recyclerview.widget.LinearLayoutManager
15import androidx.recyclerview.widget.RecyclerView
1516import androidx.test.ext.junit.runners.AndroidJUnit4
1617import androidx.test.core.app.ActivityScenario
1718import androidx.test.platform.app.InstrumentationRegistry
1819import java.util.concurrent.atomic.AtomicInteger
20import java.util.concurrent.CountDownLatch
21import java.util.concurrent.TimeUnit
1922import org.json.JSONArray
2023import org.json.JSONObject
2124import org.junit.Assert.assertEquals
@@ -180,26 +183,30 @@ class NativeFlatListTest {
180183 val scrollCount = AtomicInteger()
181184 val momentumBeginCount = AtomicInteger()
182185 val momentumEndCount = AtomicInteger()
186 val momentumEnded = CountDownLatch(1)
183187 val rows = (0 until 100).map(::row)
184188 try {
185189 instrumentation.runOnMainSync {
186190 list.onScrollEvent = { scrollCount.incrementAndGet() }
187191 list.onMomentumScrollBegin = { momentumBeginCount.incrementAndGet() }
188 list.onMomentumScrollEnd = { momentumEndCount.incrementAndGet() }
192 list.onMomentumScrollEnd = {
193 momentumEndCount.incrementAndGet()
194 momentumEnded.countDown()
195 }
189196 list.apply(rows, false, 1, false, 0.1, renderer(context, AtomicInteger()), { _ -> }, { _ -> }, null)
190197 }
191198 awaitCount(list, 100)
192199 instrumentation.runOnMainSync {
193200 attach(list)
194 list.smoothScrollToPosition(99)
195 }
196 repeat(50) {
197 if (momentumEndCount.get() > 0) return@repeat
198 SystemClock.sleep(50)
201 // Exercise a real viewport-sized animation, rather than
202 // coupling callback delivery to a 99-row traversal's duration.
203 list.smoothScrollBy(0, list.height)
199204 }
205 assertTrue("RecyclerView did not finish its native momentum animation", momentumEnded.await(2500, TimeUnit.MILLISECONDS))
200206 assertTrue("RecyclerView did not emit scroll callbacks", scrollCount.get() > 0)
201207 assertEquals(1, momentumBeginCount.get())
202208 assertEquals(1, momentumEndCount.get())
209 instrumentation.runOnMainSync { assertEquals(RecyclerView.SCROLL_STATE_IDLE, list.scrollState) }
203210 } finally {
204211 scenario.close()
205212 }
scripts/native-renderer-contract.test.tsmodified+3-1
Changes to scripts/native-renderer-contract.test.ts
@@ -3522,7 +3522,9 @@ describe('native renderer component contract', () => {
35223522 })
35233523
35243524 it('waits for asynchronous Android native fixture updates before asserting', () => {
3525 expect(androidFlatListTest).toContain('list.smoothScrollToPosition(99)')
3525 expect(androidFlatListTest).toContain('list.smoothScrollBy(0, list.height)')
3526 expect(androidFlatListTest).toContain('momentumEnded.await(2500, TimeUnit.MILLISECONDS)')
3527 expect(androidFlatListTest).toContain('assertEquals(RecyclerView.SCROLL_STATE_IDLE, list.scrollState)')
35263528 expect(androidFlatListTest).toContain('ActivityScenario.launch(MainActivity::class.java)')
35273529 expect(androidNavigationTest).toContain('awaitText(activity, "input-style-status", "input colors on")')
35283530 expect(androidNavigationTest).toContain('awaitText(activity, "native-link-status", "link pressed")')