Move SSD PDF sort key to typed Kotlin

ober

a3f34deb659e0e8232d4cc0e436e34bea61d41a7

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 0f791e0..7cef390 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -3682,12 +3682,16 @@
                 selectedGroupStatus sessionCountsStatus rotatedPageStatus
                 manualGroupLabel manualCellCount editedGroupCount
                 clampPageIndex shiftPageIndex displayGroupCanvasLabel
-                dropdownHeight dialogPageNumber)
+                dropdownHeight dialogPageNumber nullableLowercaseOrEmpty)
         (type Int32)
         (def (normalizeFiringArc (value : String)) : String
           (string-uppercase (string-trim value)))
         (def (normalizeLabel (value : String)) : String
           (string-filter-letter-or-digit (string-lowercase value)))
+        (def (nullableLowercaseOrEmpty (value : (Nullable String))) : String
+          (if (nullable-null? value)
+            ""
+            (string-lowercase (nullable-get value))))
         (def (isGenericGuessLabel (label : String)) : Bool
           (let ((normalized
                   (string-trim
@@ -5966,7 +5970,7 @@
        "    ) {"
        "        if (depth > MAX_SSD_PDF_SCAN_DEPTH || choices.size >= MAX_SSD_PDF_CHOICES) return"
        "        dir.listFiles()"
-       "            .sortedWith(compareBy<DocumentFile>({ !it.isDirectory }, { it.name?.lowercase() ?: \"\" }))"
+       "            .sortedWith(compareBy<DocumentFile>({ !it.isDirectory }, { nullableLowercaseOrEmpty(it.name) }))"
        "            .forEach { child ->"
        "                if (choices.size >= MAX_SSD_PDF_CHOICES) return"
        "                val name = child.name ?: return@forEach"