Move SSD box type item callback to typed Kotlin

ober

179a3dcc8e7826cbee4035a47f71fdd9f0ae860c

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 560a3e8..7565563 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -4621,6 +4621,7 @@
                       (android view View)
                       (android view Window)
                       (android widget AutoCompleteTextView)
+                      (android widget EditText)
                       (android widget Button)
                       (android widget TextView)
                       (androidx documentfile provider DocumentFile)
@@ -4745,6 +4746,7 @@
                 autoCompleteFocusAndShowDropdown
                 autoCompleteUpdateFiringArcVisibility
                 autoCompleteInstallFiringArcVisibilityWatcher
+                autoCompleteInstallBoxTypeDialogBehavior
                 buttonSetOnClickAction
                 permissionResultGranted downloadAccessBeforeRuntimePermissions
                 downloadAccessFromPermission activityResultRejected
@@ -4794,10 +4796,12 @@
         (type Bitmap)
         (type Char)
         (type AlertDialog)
+        (type AdapterView)
         (type AutoCompleteTextView)
         (type Button)
         (type CharSequence)
         (type Editable)
+        (type EditText)
         (type File)
         (type InputStream)
         (type OutputStream)
@@ -4816,6 +4820,8 @@
         (type TextView)
         (type TextWatcher)
         (type ViewportState)
+        (record BoxTypeDialogState
+          ((mut previousBoxType : String)))
         (extern (fileIsFile (file : File)) : Bool
           (kotlin-member-get isFile))
         (extern (fileName (file : File)) : String
@@ -4876,6 +4882,21 @@
                   (view : AutoCompleteTextView)
                   (watcher : TextWatcher)) : Unit
           (kotlin-member-call addTextChangedListener))
+        (extern (autoCompleteSetOnItemClickListenerRaw
+                  (view : AutoCompleteTextView)
+                  (listener : (-> AdapterView View Int32 Int Unit))) : Unit
+          (kotlin-member-call setOnItemClickListener))
+        (extern (editTextRaw
+                  (view : EditText)) : Editable
+          (kotlin-member-get text))
+        (extern (editTextSetTextRaw
+                  (view : EditText)
+                  (text : String)) : Unit
+          (kotlin-member-call setText))
+        (extern (editTextSetSelectionRaw
+                  (view : EditText)
+                  (index : Int32)) : Unit
+          (kotlin-member-call setSelection))
         (extern (buttonSetOnClickListenerRaw
                   (button : Button)
                   (listener : (-> View Unit))) : Unit
@@ -4884,6 +4905,15 @@
                   (activity : MainActivity)
                   (raw : String)) : Bool
           (kotlin-call boxTypeRawIsWeapon))
+        (extern (defaultLabelForBoxTypeFromActivity
+                  (activity : MainActivity)
+                  (boxType : String)) : String
+          (kotlin-call defaultLabelForBoxTypeAndroid))
+        (extern (shouldKeepLabelForBoxTypeFromActivity
+                  (activity : MainActivity)
+                  (label : String)
+                  (previousBoxType : String)) : Bool
+          (kotlin-call shouldKeepLabelForBoxTypeAndroid))
         (extern (stringLines (text : String)) : (List String)
           (kotlin-member-call lines))
         (extern (stringSplitTwoChars (text : String)
@@ -6226,6 +6256,99 @@
               (override (afterTextChanged
                           (s : (Nullable Editable))) : Unit
                 (begin)))))
+        (def (editTextText (view : EditText)) : String
+          (editableToString (editTextRaw view)))
+        (def (editTextSetSelectionToEnd (view : EditText) (text : String)) : Unit
+          (editTextSetSelectionRaw view (int32 (string-length text))))
+        (def (editTextReplaceAutoLabelForBoxType
+               (activity : MainActivity)
+               (label : EditText)
+               (boxType : String)
+               (previousBoxType : String)) : Unit
+          (if (shouldKeepLabelForBoxTypeFromActivity
+                activity
+                (editTextText label)
+                previousBoxType)
+            (begin)
+            (let ([replacement
+                   (defaultLabelForBoxTypeFromActivity activity boxType)])
+              (if (missingReplacementLabel replacement)
+                (begin)
+                (begin
+                  (editTextSetTextRaw label replacement)
+                  (editTextSetSelectionToEnd label replacement))))))
+        (def (autoCompleteFocusFiringArcIfNeeded
+               (activity : MainActivity)
+               (boxType : AutoCompleteTextView)
+               (firingArc : AutoCompleteTextView)
+               (rawBoxType : String)) : Unit
+          (if (shouldFocusFiringArc
+                (autoCompleteText firingArc)
+                (boxTypeRawIsWeaponFromActivity activity rawBoxType))
+            (begin
+              (autoCompleteRequestFocusRaw firingArc)
+              (autoCompleteShowDropDownRaw firingArc))
+            (begin)))
+        (def (autoCompleteHandleBoxTypeItemClick
+               (activity : MainActivity)
+               (label : EditText)
+               (boxType : AutoCompleteTextView)
+               (firingArc : AutoCompleteTextView)
+               (state : BoxTypeDialogState)) : Unit
+          (let ([rawBoxType (autoCompleteText boxType)])
+            (begin
+              (editTextReplaceAutoLabelForBoxType
+                activity
+                label
+                rawBoxType
+                (BoxTypeDialogState-previousBoxType state))
+              (BoxTypeDialogState-previousBoxType-set! state rawBoxType)
+              (autoCompleteUpdateFiringArcVisibility activity boxType firingArc)
+              (autoCompleteFocusFiringArcIfNeeded
+                activity
+                boxType
+                firingArc
+                rawBoxType))))
+        (def (autoCompleteInstallBoxTypeItemSelection
+               (activity : MainActivity)
+               (label : EditText)
+               (boxType : AutoCompleteTextView)
+               (firingArc : AutoCompleteTextView)
+               (initialBoxType : String)) : Unit
+          (let ([state (make-BoxTypeDialogState initialBoxType)])
+            (autoCompleteSetOnItemClickListenerRaw
+              boxType
+              (lambda ((unusedParent : AdapterView)
+                       (unusedView : View)
+                       (unusedPosition : Int32)
+                       (unusedId : Int))
+                (autoCompleteHandleBoxTypeItemClick
+                  activity
+                  label
+                  boxType
+                  firingArc
+                  state)))))
+        (def (autoCompleteInstallBoxTypeDialogBehavior
+               (activity : MainActivity)
+               (label : EditText)
+               (boxType : AutoCompleteTextView)
+               (firingArc : AutoCompleteTextView)
+               (initialBoxType : String)) : Unit
+          (begin
+            (autoCompleteInstallFiringArcVisibilityWatcher
+              activity
+              boxType
+              firingArc)
+            (autoCompleteInstallBoxTypeItemSelection
+              activity
+              label
+              boxType
+              firingArc
+              initialBoxType)
+            (autoCompleteUpdateFiringArcVisibility
+              activity
+              boxType
+              firingArc)))
         (def (buttonSetOnClickAction
                (button : Button)
                (action : (-> Unit))) : Unit
@@ -7795,26 +7918,7 @@
        "        firingArc: AutoCompleteTextView,"
        "        initialBoxType: String = \"\""
        "    ) {"
-       "        var previousBoxType = initialBoxType"
-       "        autoCompleteInstallFiringArcVisibilityWatcher(this, boxType, firingArc)"
-       "        boxType.setOnItemClickListener { _, _, _, _ ->"
-       "            replaceAutoLabelForBoxType(label, boxType.text.toString(), previousBoxType)"
-       "            previousBoxType = boxType.text.toString()"
-       "            autoCompleteUpdateFiringArcVisibility(this, boxType, firingArc)"
-       "            if (shouldFocusFiringArc(firingArc.text.toString(), boxTypeRawIsWeapon(this, boxType.text.toString()))) {"
-       "                firingArc.requestFocus()"
-       "                firingArc.showDropDown()"
-       "            }"
-       "        }"
-       "        autoCompleteUpdateFiringArcVisibility(this, boxType, firingArc)"
-       "    }"
-       ""
-       "    private fun replaceAutoLabelForBoxType(label: EditText, boxType: String, previousBoxType: String) {"
-       "        if (shouldKeepLabelForBoxTypeAndroid(this, label.text.toString(), previousBoxType)) return"
-       "        val replacement = defaultLabelForBoxTypeAndroid(this, boxType)"
-       "        if (missingReplacementLabel(replacement)) return"
-       "        label.setText(replacement)"
-       "        label.setSelection(label.text.length)"
+       "        autoCompleteInstallBoxTypeDialogBehavior(this, label, boxType, firingArc, initialBoxType)"
        "    }"
        ""
        "    private fun finalizeGroupLabel(group: SsdGroup) {"