Move SSD approved area group creation to typed Kotlin

ober

e483ccd185ddb9050e0edfff6900cc215a27005d

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index d40c247..309f64b 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -570,7 +570,7 @@
                 ssdSessionStoreSsdArea ssdSessionSsdAreaOutsideCount
                 ssdSessionSetSsdArea ssdSessionPruneGroupsOutsideSsdArea
                 createManualCells selectedOrManualCellIds
-                ssdSessionNextCellId ssdSessionNextGroupId
+                copyStringIds ssdSessionNextCellId ssdSessionNextGroupId
                 bboxForMutableCells)
         (type Int32)
         (type FloatArray)
@@ -956,7 +956,7 @@
               (mutable-set-add! ids (SsdCell-id (list-ref (SsdSession-cells session) i)))
               ids)))
         (def (ssdSessionCellsByIds (session : SsdSession)
-                                   (ids : (List String))) : (MutableList SsdCell)
+                                   (ids : (MutableList String))) : (MutableList SsdCell)
           (for/fold ((out (mutable-list-empty SsdCell)))
                     ((i (in-range (int32 0) (list-size ids))))
             (let ((cell (ssdSessionFindCellById session (list-ref ids i))))
@@ -1025,7 +1025,7 @@
                     (let ((bottom (+ (SsdCell-y cell) (SsdCell-h cell))))
                       (if (> bottom y2) bottom y2))))))))
         (def (ssdSessionBBoxForCellIds (session : SsdSession)
-                                       (ids : (List String))) : FloatArray
+                                       (ids : (MutableList String))) : FloatArray
           (bboxForMutableCells (ssdSessionCellsByIds session ids)))
         (def (ssdSessionRecomputeGroup (session : SsdSession) (group : SsdGroup)) : Unit
           (let ((groupCells (ssdSessionGroupCells session group)))
@@ -4613,7 +4613,7 @@
                 openSsdPdfTitle noSsdPdfsDialogMessage
                 noSsdPdfsFoundStatus
                 dialogCountValue editedGroupCountText
-                ssdSessionApplyEditedGroup
+                ssdSessionAddApprovedAreaGroup ssdSessionApplyEditedGroup
                 selectionIgnoredLoadingStatus
                 shouldShowFiringArc shouldFocusFiringArc
                 canvasLabelPresent canvasLabelMissing groupIdSelected
@@ -5133,6 +5133,26 @@
           (parsedCountOrFallback text (int32 1)))
         (def (editedGroupCountText (text : String) (fallback : Int32)) : Int32
           (parsedCountOrFallback text fallback))
+        (def (ssdSessionAddApprovedAreaGroup (session : SsdSession)
+                                             (ids : (List String))
+                                             (label : String)
+                                             (boxTypeId : String)
+                                             (firingArcText : String)) : SsdGroup
+          (let ((groupIds (copyStringIds ids)))
+            (let ((group
+                    (make-SsdGroup
+                      (ssdSessionNextGroupId session)
+                      label
+                      boxTypeId
+                      "reviewed"
+                      (list-size groupIds)
+                      (ssdSessionBBoxForCellIds session groupIds)
+                      groupIds
+                      (normalizeFiringArc firingArcText)
+                      "Approved on Android")))
+              (begin
+                (mutable-list-add! (SsdSession-groups session) group)
+                group))))
         (def (ssdSessionApplyEditedGroup (session : SsdSession)
                                          (group : SsdGroup)
                                          (firingArcText : String)
@@ -7445,18 +7465,7 @@
        "        val resolvedType = BoxTypes.resolve(this, boxType)"
        "        val cleanLabel = manualGroupLabel(resolvedLabelForBoxTypeAndroid(this, label, boxType, \"\"), resolvedBoxTypeNameOr(resolvedType, \"\"), \"\")"
        "        val ids = selectedOrManualCellIds(session, rect, detectedIds, count)"
-       "        val group = SsdGroup("
-       "            id = ssdSessionNextGroupId(session),"
-       "            label = cleanLabel,"
-       "            boxTypeId = resolvedBoxTypeIdOr(resolvedType, boxType),"
-       "            status = \"reviewed\","
-       "            count = ids.size,"
-       "            bbox = ssdSessionBBoxForCellIds(session, ids),"
-       "            cellIds = ids,"
-       "            firingArc = normalizeFiringArc(firingArc),"
-       "            notes = \"Approved on Android\""
-       "        )"
-       "        session.groups.add(group)"
+       "        val group = ssdSessionAddApprovedAreaGroup(session, ids, cleanLabel, resolvedBoxTypeIdOr(resolvedType, boxType), firingArc)"
        "        truthStore.appendEvent(\"group_approved\", session)"
        "        selectedGroupId = group.id"
        "        reviewView.selectedGroupId = group.id"