Move SSD guess label helper to typed Kotlin

ober

f8d25078d91bc4ee506bcdc6f75bf60269b0f6c2

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 9346a13..de16a6c 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -458,7 +458,7 @@
     (typed-kotlin-file "com/sfb/ssdreview/UiTextHelpers.kt"
       (typed-library (com sfb ssdreview)
         (export normalizeFiringArc normalizeLabel isGenericGuessLabel isSsdPdfName
-                sourceBaseName canonicalSourceName isErrorStatus)
+                sourceBaseName canonicalSourceName isUsefulGuessLabel isErrorStatus)
         (def (normalizeFiringArc (value : String)) : String
           (string-uppercase (string-trim value)))
         (def (normalizeLabel (value : String)) : String
@@ -489,6 +489,13 @@
             (sourceBaseName value)
             " \\(\\d+\\)(?=\\.pdf$)"
             ""))
+        (def (isUsefulGuessLabel (label : String)) : Bool
+          (let ((text (string-trim label)))
+            (if (string-blank? text)
+              #f
+              (if (string-matches-regex? text "^\\d+\\s+boxes\\??$")
+                #f
+                (string-ends-with? text "?")))))
         (def (isErrorStatus (text : String)) : Bool
           (let ((lower (string-lowercase text)))
             (or (or (string-contains? lower "failed")
@@ -3648,13 +3655,6 @@
        "        }"
        "    }"
        ""
-       "    private fun isUsefulGuessLabel(label: String): Boolean {"
-       "        val text = label.trim()"
-       "        if (text.isBlank()) return false"
-       "        if (Regex(\"\"\"^\\d+\\s+boxes\\??$\"\"\").matches(text)) return false"
-       "        return text.endsWith(\"?\")"
-       "    }"
-       ""
        "    private fun drawDrag(canvas: Canvas) {"
        "        val start = dragStart ?: return"
        "        val end = dragEnd ?: return"