Move SSD load and HTTP status checks to typed Kotlin

ober

026a204292d611caa788ad5a7d630eb64b7e6fe0

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index fc5f788..50d7df0 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -1412,7 +1412,7 @@
                 learnedExamplesFileName
                 inputLimitExceededMessage outputLimitExceededMessage
                 clientLogHttpStatusMessage bearerAuthorizationHeader
-                zipEntryCountLimitExceededMessage httpStatusMessage
+                zipEntryCountLimitExceededMessage httpStatusSuccessful httpStatusMessage
                 unableToCreateSyncFolderMessage unableToCreateFileMessage)
         (type Int32)
         (record ImportBudget
@@ -1477,6 +1477,8 @@
             (string-append
               (int32->string entries)
               (string-append "/" (int32->string limit)))))
+        (def (httpStatusSuccessful (code : Int32)) : Bool
+          (and (>= code (int32 200)) (<= code (int32 299))))
         (def (httpStatusMessage (code : Int32)) : String
           (string-append "HTTP " (int32->string code)))
         (def (unableToCreateSyncFolderMessage (name : String)) : String
@@ -4125,6 +4127,7 @@
 
     (typed-kotlin-file "com/sfb/ssdreview/UiTextHelpers.kt"
       (kotlin-imports (java io File)
+                      (android net Uri)
                       (androidx documentfile provider DocumentFile))
       (typed-library (com sfb ssdreview)
         (export normalizeFiringArc normalizeLabel shouldReplaceGuessLabel
@@ -4176,6 +4179,7 @@
                 permissionResultGranted downloadAccessBeforeRuntimePermissions
                 downloadAccessFromPermission viewportScalePreferencePresent
                 displayNameColumnPresent displayNameCursorHasFirstRow
+                currentLoadMatches
                 packageUriText mediaStorePdfSelection
                 mediaStoreDisplayNameSort
                 requestIsOpenPdf requestIsOpenSsdPdfTree
@@ -4203,6 +4207,7 @@
         (type Float32)
         (type Char)
         (type File)
+        (type Uri)
         (type DocumentFile)
         (extern (fileIsFile (file : File)) : Bool
           (kotlin-member-get isFile))
@@ -4666,6 +4671,16 @@
           (>= columnIndex (int32 0)))
         (def (displayNameCursorHasFirstRow (hasFirstRow : Bool)) : Bool
           hasFirstRow)
+        (def (currentLoadMatches (expectedGeneration : Int32)
+                                 (loadGeneration : Int32)
+                                 (currentUri : (Nullable Uri))
+                                 (expectedUri : Uri)
+                                 (currentPage : Int32)
+                                 (expectedPage : Int32)) : Bool
+          (and (= expectedGeneration loadGeneration)
+               (and (not (nullable-null? currentUri))
+                    (and (equal? (nullable-get currentUri) expectedUri)
+                         (= currentPage expectedPage)))))
         (def (packageUriText (packageName : String)) : String
           (string-append "package:" packageName))
         (def (mediaStorePdfSelection (mimeTypeColumn : String)
@@ -6524,7 +6539,7 @@
        "    }"
        ""
 	       "    private fun isCurrentLoad(generation: Int, uri: Uri, page: Int): Boolean ="
-	       "        generation == loadGeneration && pdfUri == uri && pageIndex == page"
+	       "        currentLoadMatches(generation, loadGeneration, pdfUri, uri, pageIndex, page)"
 	       ""
 	       "    private fun handleAreaSelected(rect: FloatArray, detectedIds: List<String>) {"
 	       "        if (currentSession == null) {"
@@ -7302,7 +7317,7 @@
        "        try {"
        "            connection.outputStream.use { it.write(bytes) }"
        "            val code = connection.responseCode"
-       "            if (code !in 200..299) throw IllegalStateException(clientLogHttpStatusMessage(code))"
+       "            if (!httpStatusSuccessful(code)) throw IllegalStateException(clientLogHttpStatusMessage(code))"
        "            connection.inputStream.close()"
        "        } finally {"
        "            connection.disconnect()"
@@ -8471,7 +8486,7 @@
        "            val connection = openPinnedConnection(relative, \"GET\", acceptGzip = true)"
        "            try {"
        "            val code = connection.responseCode"
-       "            if (code !in 200..299) {"
+       "            if (!httpStatusSuccessful(code)) {"
        "                connection.errorStream?.close()"
        "                return 0"
        "            }"
@@ -8694,7 +8709,7 @@
        "        val connection = openPinnedConnection(\"dump.zip?scope=app\", \"GET\")"
        "        try {"
        "            val code = connection.responseCode"
-       "            if (code !in 200..299) {"
+       "            if (!httpStatusSuccessful(code)) {"
        "                connection.errorStream?.close()"
        "                throw IllegalStateException(httpStatusMessage(code))"
        "            }"
@@ -8723,7 +8738,7 @@
        "                    archive.inputStream().use { input -> input.copyTo(output, 32 * 1024) }"
        "                }"
        "            val code = connection.responseCode"
-       "            if (code !in 200..299) {"
+       "            if (!httpStatusSuccessful(code)) {"
        "                connection.errorStream?.close()"
        "                throw IllegalStateException(httpStatusMessage(code))"
        "            }"
@@ -8940,7 +8955,7 @@
        "                try {"
        "                    connection.outputStream.use { it.write(bytes) }"
        "                    val code = connection.responseCode"
-       "                    if (code !in 200..299) {"
+       "                    if (!httpStatusSuccessful(code)) {"
        "                        connection.errorStream?.close()"
        "                    } else {"
        "                        connection.inputStream?.close()"