Move SSD native detection JSON assembly to typed Kotlin

ober

5656a1a2c3a6c03a15f450873d377542e30f8fd0

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index ed93785..e940910 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -776,8 +776,8 @@
         (type SsdCell)
         (type SsdGroup)
         (record NativeDetection
-          ((cells : (List SsdCell))
-           (groups : (List SsdGroup))))))
+          ((cells : (MutableList SsdCell))
+           (groups : (MutableList SsdGroup))))))
 
     (typed-kotlin-file "com/sfb/ssdreview/ViewportState.kt"
       (typed-library (com sfb ssdreview)
@@ -2524,12 +2524,14 @@
     (typed-kotlin-file "com/sfb/ssdreview/SsdVisionJson.kt"
       (kotlin-imports (org json JSONArray) (org json JSONObject))
       (typed-library (com sfb ssdreview)
-        (export nativeDetectionCellsFromJson nativeDetectionGroupsFromJson)
+        (export nativeDetectionCellsFromJson nativeDetectionGroupsFromJson
+                nativeDetectionFromJsonRoot)
         (type JSONArray)
         (type JSONObject)
         (type Int32)
         (type SsdCell)
         (type SsdGroup)
+        (type NativeDetection)
         (def (nullableJsonArrayOrEmpty (raw : (Nullable JSONArray))) : JSONArray
           (if (nullable-null? raw)
               (json-array-empty)
@@ -2604,7 +2606,16 @@
                                         (json-object-opt-string json "arc"))
                                       (json-object-opt-string json "notes")))
                                   ignored))))))))
-                groups))))))
+                groups))))
+        (def (nativeDetectionFromJsonRoot (root : JSONObject)) : (Nullable NativeDetection)
+          (let ((cells (nativeDetectionCellsFromJson (json-object-opt-json-array root "cells"))))
+            (if (= (list-size cells) (int32 0))
+                (nullable-none NativeDetection)
+                (nullable-some
+                  (make-NativeDetection
+                    cells
+                    (nativeDetectionGroupsFromJson
+                      (json-object-opt-json-array root "groups")))))))))
 
     (typed-kotlin-file "com/sfb/ssdreview/UiTextHelpers.kt"
       (typed-library (com sfb ssdreview)
@@ -4899,10 +4910,7 @@
        "            loadError = IllegalStateException(root.optString(\"error\", \"native detector failed\"))"
        "            return null"
        "        }"
-       "        val cells = nativeDetectionCellsFromJson(root.optJSONArray(\"cells\"))"
-       "        if (cells.isEmpty()) return null"
-       "        val groups = nativeDetectionGroupsFromJson(root.optJSONArray(\"groups\"))"
-       "        return NativeDetection(cells, groups)"
+       "        return nativeDetectionFromJsonRoot(root)"
        "    }"
        ""
        "    private fun bitmapToRgba(bitmap: Bitmap): ByteArray {"