Move SSD UI readiness checks to typed Kotlin

ober

0f49f14092f22829b13965a3ba75a7e09cf8f6e2

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index ea4debc..36064b9 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -1178,6 +1178,7 @@
                 rotationIs90 rotationIs180 rotationIs270
                 touchMoveExceeded shouldCollectSelectionMatches
                 selectionUsesRawRect selectionHasMatches
+                selectionDragReady
                 viewDimensionsReady previousViewSizeMissing
                 motionActionIsDown motionActionIsMove
                 motionActionIsUp motionActionIsUpOrCancel)
@@ -1211,6 +1212,10 @@
           (not snapSelectionToCells))
         (def (selectionHasMatches (matchingCount : Int32)) : Bool
           (> matchingCount (int32 0)))
+        (def (selectionDragReady (selectMode : Bool)
+                                 (hasStart : Bool)
+                                 (hasEnd : Bool)) : Bool
+          (and selectMode (and hasStart hasEnd)))
         (def (viewDimensionsReady (width : Int32) (height : Int32)) : Bool
           (and (> width (int32 0)) (> height (int32 0))))
         (def (previousViewSizeMissing (oldWidth : Int32) (oldHeight : Int32)) : Bool
@@ -4535,6 +4540,10 @@
           (not (string-blank? label)))
         (def (shouldCaptureViewport (includeViewport : Bool)) : Bool
           includeViewport)
+        (def (pdfLoaded (hasPdf : Bool)) : Bool
+          hasPdf)
+        (def (pageNavigationReady (hasPdf : Bool) (pageCount : Int32)) : Bool
+          (and (pdfLoaded hasPdf) (positiveCount pageCount)))
         (def (hasReplacementLabel (replacement : String)) : Bool
           (not (string-blank? replacement)))
         (def (hasResolvedLabel (resolved : String)) : Bool
@@ -5764,7 +5773,7 @@
        "            if (positiveCount(imported)) {"
        "                runOnUiThread {"
        "                    setStatus(truthSeedMergedStatus(imported, truthStore.storageSummary()))"
-       "                    if (pdfUri != null) renderCurrentPage()"
+       "                    if (pdfLoaded(pdfUri != null)) renderCurrentPage()"
        "                }"
        "            }"
        "        }"
@@ -6042,7 +6051,7 @@
        "    }"
        ""
        "    private fun changePage(delta: Int) {"
-       "        if (pdfUri == null || pageCount <= 0) return"
+       "        if (!pageNavigationReady(pdfUri != null, pageCount)) return"
        "        pageIndex = shiftPageIndex(pageIndex, pageCount, delta)"
        "        persistCurrentPdfState(includeViewport = false)"
        "        renderCurrentPage()"
@@ -6113,7 +6122,7 @@
        "    }"
        ""
        "    private fun showPageDialog() {"
-       "        if (pdfUri == null || pageCount <= 0) return"
+       "        if (!pageNavigationReady(pdfUri != null, pageCount)) return"
        "        val input = EditText(this).apply {"
        "            inputType = InputType.TYPE_CLASS_NUMBER"
        "            setText(pageNumberText(pageIndex))"
@@ -6727,7 +6736,7 @@
        "                runOnUiThread {"
        "                    Toast.makeText(this, \"Truth pull complete\", Toast.LENGTH_SHORT).show()"
        "                    setStatus(pulledTruthStatus(imported, truthStore.storageSummary()))"
-       "                    if (pdfUri != null) renderCurrentPage()"
+       "                    if (pdfLoaded(pdfUri != null)) renderCurrentPage()"
        "                }"
        "            } catch (error: Exception) {"
        "                runOnUiThread {"
@@ -7667,7 +7676,7 @@
        "                lastY = event.y"
        "                invalidate()"
        "        } else if (motionActionIsUpOrCancel(event.actionMasked, MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL)) {"
-       "                if (selectMode && dragStart != null && dragEnd != null) {"
+       "                if (selectionDragReady(selectMode, dragStart != null, dragEnd != null)) {"
        "                    finishSelection()"
        "                } else if (!selectMode && !moved && motionActionIsUp(event.actionMasked, MotionEvent.ACTION_UP)) {"
        "                    val point = viewToImage(event.x, event.y)"