Use typed Kotlin lambdas for SSD callbacks

ober

d173beaf18aca9dc51dbd0addcafaf4acee1c874

diff --git a/.build.yml b/.build.yml
index 6326009..04981ee 100644
--- a/.build.yml
+++ b/.build.yml
@@ -5,7 +5,7 @@ packages:
   - make=4.4.1-r4
 sources:
   # Build dependency: full immutable commit, mirrored in dependencies.lock.json.
-  - "https://git.sr.ht/~lisp/jerboa#3c4bedd1ae46a385df7ee25f576f55ed448586c1"
+  - "https://git.sr.ht/~lisp/jerboa#2112b909dff4150a763859878d45cc81dcc05037"
   # The second source is the build subject selected by the SourceHut submitter.
   - https://git.sr.ht/~lisp/jerboa-android
 tasks:
@@ -14,6 +14,6 @@ tasks:
       test "$(apk info -v chez-scheme)" = chez-scheme-10.3.0-r2
       test "$(apk info -v git)" = git-2.54.0-r0
       test "$(apk info -v make)" = make-4.4.1-r4
-      test "$(git -C ../jerboa rev-parse HEAD)" = 3c4bedd1ae46a385df7ee25f576f55ed448586c1
-      test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = ed0e590577c49db0c4762f848d6106de36dc6350
+      test "$(git -C ../jerboa rev-parse HEAD)" = 2112b909dff4150a763859878d45cc81dcc05037
+      test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = 91e02e7a6c31ccbb5604c75cc42775a4de22c313
       JERBOA="chez --libdirs .:../jerboa/lib --script" make test
diff --git a/dependencies.lock.json b/dependencies.lock.json
index 038660c..8dc79cd 100644
--- a/dependencies.lock.json
+++ b/dependencies.lock.json
@@ -11,8 +11,8 @@
   "generator_runtime": {
     "name": "jerboa",
     "repository": "https://git.sr.ht/~lisp/jerboa",
-    "commit": "3c4bedd1ae46a385df7ee25f576f55ed448586c1",
-    "tree": "ed0e590577c49db0c4762f848d6106de36dc6350"
+    "commit": "2112b909dff4150a763859878d45cc81dcc05037",
+    "tree": "91e02e7a6c31ccbb5604c75cc42775a4de22c313"
   },
   "assurance_tools": {
     "osv_scanner": {
diff --git a/scripts/verify-supply-chain.sh b/scripts/verify-supply-chain.sh
index fc1ad81..485604f 100755
--- a/scripts/verify-supply-chain.sh
+++ b/scripts/verify-supply-chain.sh
@@ -3,8 +3,8 @@ set -eu
 
 repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P)
 lock="$repo/dependencies.lock.json"
-jerboa_commit=3c4bedd1ae46a385df7ee25f576f55ed448586c1 # gitsafe:ignore
-jerboa_tree=ed0e590577c49db0c4762f848d6106de36dc6350 # gitsafe:ignore
+jerboa_commit=2112b909dff4150a763859878d45cc81dcc05037 # gitsafe:ignore
+jerboa_tree=91e02e7a6c31ccbb5604c75cc42775a4de22c313 # gitsafe:ignore
 gradle_sha=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78
 jdk_macos_sha=8fa1eff40bb637a33613b2ccb8b12c70dc3661cc22cf8e784943715769a05336
 jdk_linux_sha=d8afc263758141a66e0e3aafc321e783f7016696f4eaea067d340a269037d331
diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index cce977e..727fb05 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -4693,6 +4693,7 @@
                 reviewViewSelectMode
                 reviewViewCaptureViewportForSave
                 reviewViewRestoreViewport
+                reviewViewRestoreViewportAfterLayout
                 reviewViewClearInteractionState
                 mainActivitySelectGroupId
                 mainActivitySelectRequestedGroup
@@ -4712,6 +4713,8 @@
                 mainActivitySetLoadedPdfState
                 mainActivityAdvanceLoadGeneration
                 mainActivityRotateReviewPage
+                mainActivitySeedBundledTruthAsync
+                mainActivityHandleAreaSelectionAfterDelay
                 mainActivitySetTruthStore mainActivitySetStatusView
                 mainActivitySetReviewView
                 truthStoreApplyTruthAndPrune
@@ -4846,6 +4849,10 @@
           (kotlin-member-call appendEvent))
         (extern (truthStoreStorageSummaryRaw (store : TruthStore)) : String
           (kotlin-member-call storageSummary))
+        (extern (truthStoreSeedBundledTruthAsyncRaw
+                  (store : TruthStore)
+                  (done : (-> Int32 Unit))) : Unit
+          (kotlin-member-call seedBundledTruthAsync))
         (extern (truthStoreSaveTruthSnapshot
                   (store : TruthStore)
                   (truth : JSONObject)) : File
@@ -4872,6 +4879,15 @@
                   (view : SsdReviewView)
                   (viewport : (Nullable ViewportState))) : Unit
           (kotlin-member-call restoreViewport))
+        (extern (reviewViewPostRaw
+                  (view : SsdReviewView)
+                  (callback : (-> Unit))) : Unit
+          (kotlin-member-call post))
+        (extern (reviewViewPostDelayedRaw
+                  (view : SsdReviewView)
+                  (callback : (-> Unit))
+                  (delayMillis : Int32)) : Unit
+          (kotlin-member-call postDelayed))
         (extern (reviewViewClearInteractionStateRaw (view : SsdReviewView)) : Unit
           (kotlin-member-call clearInteractionState))
         (extern (reviewViewSelectModeRaw (view : SsdReviewView)) : Bool
@@ -4996,6 +5012,32 @@
                   (activity : MainActivity)
                   (store : TruthStore)) : Unit
           (kotlin-member-set truthStore))
+        (extern (mainActivityPdfUriRaw
+                  (activity : MainActivity)) : (Nullable Uri)
+          (kotlin-member-get pdfUri))
+        (extern (mainActivityCurrentSessionRaw
+                  (activity : MainActivity)) : (Nullable SsdSession)
+          (kotlin-member-get currentSession))
+        (extern (mainActivityRunOnUiThreadRaw
+                  (activity : MainActivity)
+                  (callback : (-> Unit))) : Unit
+          (kotlin-member-call runOnUiThread))
+        (extern (mainActivitySetStatusRaw
+                  (activity : MainActivity)
+                  (text : String)) : Unit
+          (kotlin-member-call setStatus))
+        (extern (mainActivityRenderCurrentPageRaw
+                  (activity : MainActivity)) : Unit
+          (kotlin-member-call renderCurrentPage))
+        (extern (mainActivityApplySsdAreaRaw
+                  (activity : MainActivity)
+                  (rect : FloatArray)) : Unit
+          (kotlin-member-call applySsdArea))
+        (extern (mainActivityShowApproveDialogRaw
+                  (activity : MainActivity)
+                  (rect : FloatArray)
+                  (detectedIds : (List String))) : Unit
+          (kotlin-member-call showApproveDialog))
         (extern (mainActivityReviewViewSet
                   (activity : MainActivity)
                   (view : SsdReviewView)) : Unit
@@ -5613,6 +5655,20 @@
                (view : SsdReviewView)
                (viewport : (Nullable ViewportState))) : Unit
           (reviewViewRestoreViewportRaw view viewport))
+        (def (reviewViewRestoreViewportAfterLayout
+               (view : SsdReviewView)
+               (viewport : (Nullable ViewportState))) : Unit
+          (begin
+            (reviewViewRestoreViewport view viewport)
+            (reviewViewPostRaw
+              view
+              (lambda ()
+                (reviewViewRestoreViewport view viewport)))
+            (reviewViewPostDelayedRaw
+              view
+              (lambda ()
+                (reviewViewRestoreViewport view viewport))
+              (int32 180))))
         (def (reviewViewClearInteractionState (view : SsdReviewView)) : Unit
           (reviewViewClearInteractionStateRaw view))
         (def (mainActivitySelectGroupId (activity : MainActivity)
@@ -5792,6 +5848,41 @@
             (mainActivityAdvanceLoadGeneration activity currentGeneration)
             (reviewViewRotateClockwise view)
             (begin)))
+        (def (mainActivitySeedBundledTruthAsync
+               (activity : MainActivity)
+               (store : TruthStore)) : Unit
+          (truthStoreSeedBundledTruthAsyncRaw
+            store
+            (lambda ((imported : Int32))
+              (if (positiveCount imported)
+                (mainActivityRunOnUiThreadRaw
+                  activity
+                  (lambda ()
+                    (begin
+                      (mainActivitySetStatusRaw
+                        activity
+                        (truthSeedMergedStatus
+                          imported
+                          (truthStoreStorageSummary store)))
+                      (if (pdfUriLoaded (mainActivityPdfUriRaw activity))
+                        (mainActivityRenderCurrentPageRaw activity)
+                        (begin)))))
+                (begin)))))
+        (def (mainActivityHandleAreaSelectionAfterDelay
+               (activity : MainActivity)
+               (view : SsdReviewView)
+               (rect : FloatArray)
+               (detectedIds : (List String))
+               (applyAsSsdArea : Bool)) : Unit
+          (reviewViewPostDelayedRaw
+            view
+            (lambda ()
+              (if (sessionMissing (mainActivityCurrentSessionRaw activity))
+                (mainActivitySetStatusRaw activity (selectionIgnoredLoadingStatus))
+                (if applyAsSsdArea
+                  (mainActivityApplySsdAreaRaw activity rect)
+                  (mainActivityShowApproveDialogRaw activity rect detectedIds))))
+            (int32 80)))
         (def (mainActivitySetTruthStore (activity : MainActivity)
                                         (store : TruthStore)) : Unit
           (mainActivityTruthStoreSet activity store))
@@ -7357,14 +7448,7 @@
        "        setContentView(buildUi())"
        "        setStatus(startupStatus(truthStoreStorageSummary(truthStore)))"
        "        restoreLastPdf()"
-       "        truthStore.seedBundledTruthAsync { imported ->"
-       "            if (positiveCount(imported)) {"
-       "                runOnUiThread {"
-       "                    setStatus(truthSeedMergedStatus(imported, truthStoreStorageSummary(truthStore)))"
-       "                    if (pdfUriLoaded(pdfUri)) renderCurrentPage()"
-       "                }"
-       "            }"
-       "        }"
+       "        mainActivitySeedBundledTruthAsync(this, truthStore)"
        "    }"
        ""
        "    override fun onResume() {"
@@ -7664,9 +7748,7 @@
 	       "    }"
        ""
        "    private fun restoreViewportAfterLayout(viewport: ViewportState?) {"
-       "        reviewViewRestoreViewport(reviewView, viewport)"
-       "        reviewView.post { reviewViewRestoreViewport(reviewView, viewport) }"
-       "        reviewView.postDelayed({ reviewViewRestoreViewport(reviewView, viewport) }, 180)"
+       "        reviewViewRestoreViewportAfterLayout(reviewView, viewport)"
        "    }"
        ""
        "    private fun startAppendMode() {"
@@ -7715,7 +7797,7 @@
 	       "            .show()"
 	       "    }"
 	       ""
-	       "    private fun applySsdArea(rect: FloatArray) {"
+       "    internal fun applySsdArea(rect: FloatArray) {"
 	       "        if (sessionMissing(currentSession)) return"
 	       "        val session = ssdSessionOrEmpty(currentSession)"
        "        val area = ssdSessionBoundedSsdArea(session, rect)"
@@ -7782,7 +7864,7 @@
        "        )"
        "    }"
        ""
-       "    private fun renderCurrentPage() {"
+       "    internal fun renderCurrentPage() {"
        "        if (!pdfUriLoaded(pdfUri)) return"
        "        val uri = uriOrEmpty(pdfUri)"
        "        val renderPageIndex = pageIndex"
@@ -7960,20 +8042,10 @@
 	       "        val applyAsSsdArea = ssdAreaMode"
 	       "        val statusText = areaSelectionStatus(applyAsSsdArea, detectedIds.size)"
 	       "        setStatus(statusText)"
-	       "        reviewView.postDelayed({"
-	       "            if (sessionMissing(currentSession)) {"
-       "                setStatus(selectionIgnoredLoadingStatus())"
-	       "                return@postDelayed"
-	       "            }"
-	       "            if (applyAsSsdArea) {"
-	       "                applySsdArea(rect)"
-	       "            } else {"
-	       "                showApproveDialog(rect, detectedIds)"
-	       "            }"
-	       "        }, 80)"
+       "        mainActivityHandleAreaSelectionAfterDelay(this, reviewView, rect, detectedIds, applyAsSsdArea)"
 	       "    }"
 	       ""
-	       "    private fun showApproveDialog(rect: FloatArray, detectedIds: List<String>) {"
+       "    internal fun showApproveDialog(rect: FloatArray, detectedIds: List<String>) {"
 	       "        val session = currentSession"
 	       "        if (sessionMissing(session)) {"
        "            setStatus(selectionIgnoredLoadingStatus())"
@@ -8772,7 +8844,7 @@
        "        return throwableLogJson(error.javaClass.name, nullableTextOrEmpty(error.message), stackText)"
        "    }"
        ""
-       "    private fun setStatus(text: String) {"
+       "    internal fun setStatus(text: String) {"
        "        status.text = text"
        "        if (isErrorStatus(text)) {"
        "            logClientEvent(\"ssd-status-error\", statusLogFields(text))"