Generate SSD main UI from typed Jerboa

ober

0ef69beb5887e5520abb1673a19f4aae95a04951

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 0028aca..6c544c8 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -12572,6 +12572,578 @@
             (mainActivityClearInteractionModes activity view)
             (reviewViewClearInteractionState view)))))
 
+    (typed-kotlin-file "com/sfb/ssdreview/MainActivityUi.kt"
+      (kotlin-imports (android Manifest)
+                      (android content pm PackageManager)
+                      (android os Build)
+                      (android provider Settings)
+                      (android view Gravity)
+                      (android view HapticFeedbackConstants)
+                      (android widget Button)
+                      (android widget LinearLayout)
+                      (android widget LinearLayout LayoutParams)
+                      (android widget ScrollView)
+                      (android widget TextView))
+      (typed-library (com sfb ssdreview)
+        (export mainActivityBuildUi)
+        (type Button)
+        (type ButtonKind)
+        (type LinearLayout)
+        (type LayoutParams)
+        (type MainActivity)
+        (type ScrollView)
+        (type SsdReviewView)
+        (type SsdSession)
+        (type TextView)
+        (type TruthStore)
+        (type Uri)
+        (type Float32)
+        (type Int32)
+        (extern (mainUiLinearLayout
+                  (activity : MainActivity)) : LinearLayout
+          (kotlin-call LinearLayout))
+        (extern (mainUiTextView
+                  (activity : MainActivity)) : TextView
+          (kotlin-call TextView))
+        (extern (mainUiReviewView
+                  (activity : MainActivity)) : SsdReviewView
+          (kotlin-call SsdReviewView))
+        (extern (mainUiScrollView
+                  (activity : MainActivity)) : ScrollView
+          (kotlin-call ScrollView))
+        (extern (mainUiLinearLayoutOrientationSet
+                  (layout : LinearLayout)
+                  (orientation : Int32)) : Unit
+          (kotlin-member-set orientation))
+        (extern (mainUiLinearLayoutGravitySet
+                  (layout : LinearLayout)
+                  (gravity : Int32)) : Unit
+          (kotlin-member-set gravity))
+        (extern (mainUiLinearLayoutSetPadding
+                  (layout : LinearLayout)
+                  (left : Int32)
+                  (top : Int32)
+                  (right : Int32)
+                  (bottom : Int32)) : Unit
+          (kotlin-member-call setPadding))
+        (extern (mainUiLinearLayoutAddTextView
+                  (layout : LinearLayout)
+                  (view : TextView)) : Unit
+          (kotlin-member-call addView))
+        (extern (mainUiLinearLayoutAddLinearLayout
+                  (layout : LinearLayout)
+                  (view : LinearLayout)) : Unit
+          (kotlin-member-call addView))
+        (extern (mainUiLinearLayoutAddReviewView
+                  (layout : LinearLayout)
+                  (view : SsdReviewView)
+                  (params : LayoutParams)) : Unit
+          (kotlin-member-call addView))
+        (extern (mainUiLinearLayoutAddScrollView
+                  (layout : LinearLayout)
+                  (view : ScrollView)
+                  (params : LayoutParams)) : Unit
+          (kotlin-member-call addView))
+        (extern (mainUiTextViewTextSizeSet
+                  (view : TextView)
+                  (size : Float32)) : Unit
+          (kotlin-member-set textSize))
+        (extern (mainUiTextViewSetPadding
+                  (view : TextView)
+                  (left : Int32)
+                  (top : Int32)
+                  (right : Int32)
+                  (bottom : Int32)) : Unit
+          (kotlin-member-call setPadding))
+        (extern (mainUiLinearLayoutParams
+                  (width : Int32)
+                  (height : Int32)
+                  (weight : Float32)) : LayoutParams
+          (kotlin-call LinearLayout LayoutParams))
+        (extern (mainUiLinearLayoutParamsNoWeight
+                  (width : Int32)
+                  (height : Int32)) : LayoutParams
+          (kotlin-call LinearLayout LayoutParams))
+        (extern (mainUiScrollViewFillViewportSet
+                  (view : ScrollView)
+                  (enabled : Bool)) : Unit
+          (kotlin-member-set isFillViewport))
+        (extern (mainUiScrollViewAddLinearLayout
+                  (view : ScrollView)
+                  (layout : LinearLayout)) : Unit
+          (kotlin-member-call addView))
+        (extern (mainUiButtonKindPrimary) : ButtonKind
+          (kotlin-value ButtonKind PRIMARY))
+        (extern (mainUiButtonKindAccent) : ButtonKind
+          (kotlin-value ButtonKind ACCENT))
+        (extern (mainUiButtonKindMode) : ButtonKind
+          (kotlin-value ButtonKind MODE))
+        (extern (mainUiButtonKindNav) : ButtonKind
+          (kotlin-value ButtonKind NAV))
+        (extern (mainUiButtonKindNeutral) : ButtonKind
+          (kotlin-value ButtonKind NEUTRAL))
+        (extern (mainUiButtonKindDanger) : ButtonKind
+          (kotlin-value ButtonKind DANGER))
+        (extern (mainUiOrientationVertical) : Int32
+          (kotlin-value LinearLayout VERTICAL))
+        (extern (mainUiOrientationHorizontal) : Int32
+          (kotlin-value LinearLayout HORIZONTAL))
+        (extern (mainUiGravityCenterVertical) : Int32
+          (kotlin-value Gravity CENTER_VERTICAL))
+        (extern (mainUiHapticClockTick) : Int32
+          (kotlin-value HapticFeedbackConstants CLOCK_TICK))
+        (extern (mainUiHapticConfirm) : Int32
+          (kotlin-value HapticFeedbackConstants CONFIRM))
+        (extern (mainUiHapticReject) : Int32
+          (kotlin-value HapticFeedbackConstants REJECT))
+        (extern (mainUiDpiValue) : Int32
+          (kotlin-value DPI))
+        (extern (mainUiFastTruthGroupThresholdValue) : Int32
+          (kotlin-value FAST_TRUTH_GROUP_THRESHOLD))
+        (extern (mainUiClientLogReadTimeoutMillisValue) : Int32
+          (kotlin-value CLIENT_LOG_READ_TIMEOUT_MS))
+        (extern (mainUiReqOpenPdfValue) : Int32
+          (kotlin-value REQ_OPEN_PDF))
+        (extern (mainUiReqOpenSsdPdfTreeValue) : Int32
+          (kotlin-value REQ_OPEN_SSD_PDF_TREE))
+        (extern (mainUiReqReadStorageValue) : Int32
+          (kotlin-value REQ_READ_STORAGE))
+        (extern (mainUiReqSyncTreeValue) : Int32
+          (kotlin-value REQ_SYNC_TREE))
+        (extern (mainUiPrefSsdPdfTreeUriValue) : String
+          (kotlin-value PREF_SSD_PDF_TREE_URI))
+        (extern (mainUiPrefLastPdfUriValue) : String
+          (kotlin-value PREF_LAST_PDF_URI))
+        (extern (mainUiBuildSdkIntValue) : Int32
+          (kotlin-value Build VERSION SDK_INT))
+        (extern (mainUiBuildVersionCodesRValue) : Int32
+          (kotlin-value Build VERSION_CODES R))
+        (extern (mainUiBuildVersionCodesMValue) : Int32
+          (kotlin-value Build VERSION_CODES M))
+        (extern (mainUiReadExternalStoragePermissionValue) : String
+          (kotlin-value Manifest permission READ_EXTERNAL_STORAGE))
+        (extern (mainUiPackageManagerPermissionGrantedValue) : Int32
+          (kotlin-value PackageManager PERMISSION_GRANTED))
+        (extern (mainUiManageAppAllFilesAccessActionValue) : String
+          (kotlin-value Settings ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION))
+        (extern (mainUiManageAllFilesAccessActionValue) : String
+          (kotlin-value Settings ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION))
+        (extern (mainUiDetectCurrentForceWithState
+                  (activity : MainActivity)
+                  (dpi : Int32)
+                  (fastTruthGroupThreshold : Int32)
+                  (targetCellCount : Int32)
+                  (clientLogReadTimeoutMillis : Int32)) : Unit
+          (kotlin-call mainActivityDetectCurrentForceWithState))
+        (extern (mainUiDp
+                  (activity : MainActivity)
+                  (value : Int32)) : Int32
+          (kotlin-call mainActivityDp))
+        (extern (mainUiReviewViewRaw
+                  (activity : MainActivity)) : SsdReviewView
+          (kotlin-member-get reviewView))
+        (extern (mainUiTruthStoreRaw
+                  (activity : MainActivity)) : TruthStore
+          (kotlin-member-get truthStore))
+        (extern (mainUiPdfUriRaw
+                  (activity : MainActivity)) : (Nullable Uri)
+          (kotlin-member-get pdfUri))
+        (extern (mainUiPageCountRaw
+                  (activity : MainActivity)) : Int32
+          (kotlin-member-get pageCount))
+        (extern (mainUiPageIndexRaw
+                  (activity : MainActivity)) : Int32
+          (kotlin-member-get pageIndex))
+        (extern (mainUiLoadGenerationRaw
+                  (activity : MainActivity)) : Int32
+          (kotlin-member-get loadGeneration))
+        (extern (mainUiCurrentSessionRaw
+                  (activity : MainActivity)) : (Nullable SsdSession)
+          (kotlin-member-get currentSession))
+        (extern (mainUiSelectedGroupIdRaw
+                  (activity : MainActivity)) : (Nullable String)
+          (kotlin-member-get selectedGroupId))
+        (extern (mainUiAppendModeRaw
+                  (activity : MainActivity)) : Bool
+          (kotlin-member-get appendMode))
+        (extern (mainUiSsdAreaModeRaw
+                  (activity : MainActivity)) : Bool
+          (kotlin-member-get ssdAreaMode))
+        (extern (mainUiBoxTypeDisplaysRaw
+                  (activity : MainActivity)) : (List String)
+          (kotlin-member-get boxTypeDisplays))
+        (def (mainUiMatchParent) : Int32 (int32 -1))
+        (def (mainUiWrapContent) : Int32 (int32 -2))
+        (def (mainUiAddActionRow3
+               (controls : LinearLayout)
+               (activity : MainActivity)
+               (button1 : Button)
+               (button2 : Button)
+               (button3 : Button)) : Unit
+          (let ((row (mainUiLinearLayout activity)))
+            (begin
+              (mainUiLinearLayoutOrientationSet
+                row
+                (mainUiOrientationHorizontal))
+              (mainUiLinearLayoutGravitySet row (mainUiGravityCenterVertical))
+              (mainActivityAddActionRowButtons
+                row
+                (list-of Button button1 button2 button3)
+                (mainUiDp activity (int32 3)))
+              (mainUiLinearLayoutAddLinearLayout controls row))))
+        (def (mainUiOpenPdfAction (activity : MainActivity)) : Unit
+          (mainActivityOpenPdf
+            activity
+            (mainUiReqOpenPdfValue)
+            (mainUiReqOpenSsdPdfTreeValue)
+            (mainUiReqReadStorageValue)
+            (mainUiPrefSsdPdfTreeUriValue)
+            (mainUiPrefLastPdfUriValue)
+            (mainUiBuildSdkIntValue)
+            (mainUiBuildVersionCodesRValue)
+            (mainUiBuildVersionCodesMValue)
+            (mainUiReadExternalStoragePermissionValue)
+            (mainUiPackageManagerPermissionGrantedValue)
+            (mainUiManageAppAllFilesAccessActionValue)
+            (mainUiManageAllFilesAccessActionValue)))
+        (def (mainUiOpenAnyPdfAction (activity : MainActivity)) : Unit
+          (mainActivityOpenAnyPdf
+            activity
+            (mainUiReqOpenPdfValue)
+            (mainUiPrefSsdPdfTreeUriValue)
+            (mainUiPrefLastPdfUriValue)))
+        (def (mainUiInstallReviewView
+               (activity : MainActivity)
+               (root : LinearLayout)) : SsdReviewView
+          (let ((view (mainUiReviewView activity)))
+            (begin
+              (mainActivityInstallReviewViewCallbacks
+                activity
+                view
+                (mainUiTruthStoreRaw activity)
+                (mainUiHapticClockTick)
+                (mainUiHapticConfirm))
+              (mainActivitySetReviewView activity view)
+              (mainUiLinearLayoutAddReviewView
+                root
+                view
+                (mainUiLinearLayoutParams
+                  (mainUiMatchParent)
+                  (int32 0)
+                  (float32 1.0)))
+              view)))
+        (def (mainUiInstallStatusView
+               (activity : MainActivity)
+               (root : LinearLayout)) : Unit
+          (let ((statusView (mainUiTextView activity)))
+            (begin
+              (mainUiTextViewTextSizeSet statusView (float32 14.0))
+              (mainUiTextViewSetPadding
+                statusView
+                (int32 8)
+                (int32 8)
+                (int32 8)
+                (int32 10))
+              (mainActivitySetStatusView activity statusView)
+              (mainUiLinearLayoutAddTextView root statusView))))
+        (def (mainUiAddFirstRow
+               (controls : LinearLayout)
+               (activity : MainActivity)) : Unit
+          (mainUiAddActionRow3
+            controls
+            activity
+            (mainActivityButton
+              activity
+              "Open SSDs"
+              (mainUiButtonKindPrimary)
+              (lambda () (mainUiOpenPdfAction activity)))
+            (mainActivityButton
+              activity
+              "Detect"
+              (mainUiButtonKindAccent)
+              (lambda ()
+                (mainUiDetectCurrentForceWithState
+                  activity
+                  (mainUiDpiValue)
+                  (mainUiFastTruthGroupThresholdValue)
+                  (int32 120)
+                  (mainUiClientLogReadTimeoutMillisValue))))
+            (mainActivityButton
+              activity
+              "Set SSD Area"
+              (mainUiButtonKindMode)
+              (lambda ()
+                (mainActivityStartSsdAreaMode
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiCurrentSessionRaw activity)
+                  (mainUiSelectedGroupIdRaw activity)
+                  (mainUiHapticClockTick))))))
+        (def (mainUiAddSecondRow
+               (controls : LinearLayout)
+               (activity : MainActivity)) : Unit
+          (mainUiAddActionRow3
+            controls
+            activity
+            (mainActivityButton
+              activity
+              "Open Any"
+              (mainUiButtonKindNeutral)
+              (lambda () (mainUiOpenAnyPdfAction activity)))
+            (mainActivityButton
+              activity
+              "Rotate"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivityRotatePage
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiLoadGenerationRaw activity)
+                  (mainUiCurrentSessionRaw activity))))
+            (mainActivityButton
+              activity
+              "Fit"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (reviewViewFitImage (mainUiReviewViewRaw activity))))))
+        (def (mainUiAddPageRow
+               (controls : LinearLayout)
+               (activity : MainActivity)) : Unit
+          (mainUiAddActionRow3
+            controls
+            activity
+            (mainActivityButton
+              activity
+              "Prev Page"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivityChangePage
+                  activity
+                  (mainUiPdfUriRaw activity)
+                  (mainUiPageCountRaw activity)
+                  (mainUiPageIndexRaw activity)
+                  (int32 -1))))
+            (mainActivityButton
+              activity
+              "Page #"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivityShowPageDialog
+                  activity
+                  (mainUiPdfUriRaw activity)
+                  (mainUiPageCountRaw activity)
+                  (mainUiPageIndexRaw activity))))
+            (mainActivityButton
+              activity
+              "Next Page"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivityChangePage
+                  activity
+                  (mainUiPdfUriRaw activity)
+                  (mainUiPageCountRaw activity)
+                  (mainUiPageIndexRaw activity)
+                  (int32 1))))))
+        (def (mainUiAddModeRow
+               (controls : LinearLayout)
+               (activity : MainActivity)) : Unit
+          (mainUiAddActionRow3
+            controls
+            activity
+            (mainActivityButton
+              activity
+              "Pan"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivityApplySelectMode
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiSsdAreaModeRaw activity)
+                  (mainUiAppendModeRaw activity)
+                  #f)))
+            (mainActivityButton
+              activity
+              "Select Area"
+              (mainUiButtonKindPrimary)
+              (lambda ()
+                (mainActivityApplySelectMode
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiSsdAreaModeRaw activity)
+                  (mainUiAppendModeRaw activity)
+                  #t)))
+            (mainActivityButton
+              activity
+              "Add"
+              (mainUiButtonKindAccent)
+              (lambda ()
+                (mainActivityStartAppendMode
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiCurrentSessionRaw activity)
+                  (mainUiSelectedGroupIdRaw activity))))))
+        (def (mainUiAddNavigationRow
+               (controls : LinearLayout)
+               (activity : MainActivity)) : Unit
+          (mainUiAddActionRow3
+            controls
+            activity
+            (mainActivityButton
+              activity
+              "Prev"
+              (mainUiButtonKindNav)
+              (lambda ()
+                (mainActivitySelectRelativeGroup
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiCurrentSessionRaw activity)
+                  (mainUiSelectedGroupIdRaw activity)
+                  (int32 -1)
+                  (mainUiHapticClockTick))))
+            (mainActivityButton
+              activity
+              "Next"
+              (mainUiButtonKindPrimary)
+              (lambda ()
+                (mainActivitySelectRelativeGroup
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiCurrentSessionRaw activity)
+                  (mainUiSelectedGroupIdRaw activity)
+                  (int32 1)
+                  (mainUiHapticClockTick))))
+            (mainActivityButton
+              activity
+              "Edit"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivityEditSelectedGroup
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiTruthStoreRaw activity)
+                  (mainUiCurrentSessionRaw activity)
+                  (mainUiSelectedGroupIdRaw activity)
+                  (mainUiBoxTypeDisplaysRaw activity)
+                  (mainUiHapticConfirm)
+                  (mainUiHapticReject))))))
+        (def (mainUiAddSaveRow
+               (controls : LinearLayout)
+               (activity : MainActivity)) : Unit
+          (mainUiAddActionRow3
+            controls
+            activity
+            (mainActivityButton
+              activity
+              "Approve"
+              (mainUiButtonKindAccent)
+              (lambda ()
+                (mainActivityApproveSelectedGroup
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiTruthStoreRaw activity)
+                  (mainUiCurrentSessionRaw activity)
+                  (mainUiSelectedGroupIdRaw activity)
+                  (mainUiHapticConfirm))))
+            (mainActivityButton
+              activity
+              "Delete"
+              (mainUiButtonKindDanger)
+              (lambda ()
+                (mainActivityDeleteSelectedGroup
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiTruthStoreRaw activity)
+                  (mainUiCurrentSessionRaw activity)
+                  (mainUiSelectedGroupIdRaw activity)
+                  (mainUiHapticReject))))
+            (mainActivityButton
+              activity
+              "Save"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivitySaveTruth
+                  activity
+                  (mainUiReviewViewRaw activity)
+                  (mainUiTruthStoreRaw activity)
+                  (mainUiCurrentSessionRaw activity))))))
+        (def (mainUiAddSyncRow
+               (controls : LinearLayout)
+               (activity : MainActivity)) : Unit
+          (mainUiAddActionRow3
+            controls
+            activity
+            (mainActivityButton
+              activity
+              "Pull Truth"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivityPullTruthDumpAsync
+                  activity
+                  (mainUiTruthStoreRaw activity))))
+            (mainActivityButton
+              activity
+              "Push Truth"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivityPushTruthDumpAsync
+                  activity
+                  (mainUiTruthStoreRaw activity))))
+            (mainActivityButton
+              activity
+              "Sync Folder"
+              (mainUiButtonKindNeutral)
+              (lambda ()
+                (mainActivitySyncTruthFolder
+                  activity
+                  (mainUiReqSyncTreeValue))))))
+        (def (mainUiControls
+               (activity : MainActivity)) : LinearLayout
+          (let ((controls (mainUiLinearLayout activity)))
+            (begin
+              (mainUiLinearLayoutOrientationSet
+                controls
+                (mainUiOrientationVertical))
+              (mainUiAddFirstRow controls activity)
+              (mainUiAddSecondRow controls activity)
+              (mainUiAddPageRow controls activity)
+              (mainUiAddModeRow controls activity)
+              (mainUiAddNavigationRow controls activity)
+              (mainUiAddSaveRow controls activity)
+              (mainUiAddSyncRow controls activity)
+              controls)))
+        (def (mainUiAddControlsScroll
+               (root : LinearLayout)
+               (activity : MainActivity)) : Unit
+          (let ((scroll (mainUiScrollView activity)))
+            (begin
+              (mainUiScrollViewFillViewportSet scroll #f)
+              (mainUiScrollViewAddLinearLayout
+                scroll
+                (mainUiControls activity))
+              (mainUiLinearLayoutAddScrollView
+                root
+                scroll
+                (mainUiLinearLayoutParamsNoWeight
+                  (mainUiMatchParent)
+                  (mainUiWrapContent))))))
+        (def (mainActivityBuildUi
+               (activity : MainActivity)) : LinearLayout
+          (let ((root (mainUiLinearLayout activity)))
+            (begin
+              (mainUiLinearLayoutOrientationSet
+                root
+                (mainUiOrientationVertical))
+              (mainUiLinearLayoutSetPadding
+                root
+                (int32 12)
+                (int32 12)
+                (int32 12)
+                (int32 12))
+              (mainUiInstallStatusView activity root)
+              (mainUiInstallReviewView activity root)
+              (mainUiAddControlsScroll root activity)
+              root)))))
+
     (kotlin-file-lines "com/sfb/ssdreview/MainActivity.kt"
       (
        "package com.sfb.ssdreview"
@@ -12660,71 +13232,7 @@
 	       "        mainActivityPersistCurrentPdfState(this, true)"
        "    }"
        ""
-       "    private fun buildUi(): View {"
-       "        val root = LinearLayout(this).apply {"
-       "            orientation = LinearLayout.VERTICAL"
-       "            setPadding(12, 12, 12, 12)"
-       "        }"
-       "        mainActivitySetStatusView(this, TextView(this).apply {"
-       "            textSize = 14f"
-       "            setPadding(8, 8, 8, 10)"
-       "        })"
-       "        root.addView(status)"
-	       "        mainActivitySetReviewView(this, SsdReviewView(this).apply {"
-       "            mainActivityInstallReviewViewCallbacks(this@MainActivity, this, truthStore, HapticFeedbackConstants.CLOCK_TICK, HapticFeedbackConstants.CONFIRM)"
-	       "        })"
-       "        root.addView(reviewView, LinearLayout.LayoutParams("
-       "            LinearLayout.LayoutParams.MATCH_PARENT,"
-       "            0,"
-       "            1f"
-       "        ))"
-       "        val controls = LinearLayout(this).apply {"
-       "            orientation = LinearLayout.VERTICAL"
-       "            addView(mainActivityActionRow(this@MainActivity, LinearLayout.HORIZONTAL, Gravity.CENTER_VERTICAL,"
-	       "                mainActivityButton(this@MainActivity, \"Open SSDs\", ButtonKind.PRIMARY) { mainActivityOpenPdf(this@MainActivity, REQ_OPEN_PDF, REQ_OPEN_SSD_PDF_TREE, REQ_READ_STORAGE, PREF_SSD_PDF_TREE_URI, PREF_LAST_PDF_URI, Build.VERSION.SDK_INT, Build.VERSION_CODES.R, Build.VERSION_CODES.M, Manifest.permission.READ_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED, Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) },"
-	       "                mainActivityButton(this@MainActivity, \"Detect\", ButtonKind.ACCENT) { mainActivityDetectCurrentForceWithState(this@MainActivity, DPI, FAST_TRUTH_GROUP_THRESHOLD, 120, CLIENT_LOG_READ_TIMEOUT_MS) },"
-	       "                mainActivityButton(this@MainActivity, \"Set SSD Area\", ButtonKind.MODE) { mainActivityStartSsdAreaMode(this@MainActivity, reviewView, currentSession, selectedGroupId, HapticFeedbackConstants.CLOCK_TICK) },"
-	       "            ))"
-	       "            addView(mainActivityActionRow(this@MainActivity, LinearLayout.HORIZONTAL, Gravity.CENTER_VERTICAL,"
-	       "                mainActivityButton(this@MainActivity, \"Open Any\") { mainActivityOpenAnyPdf(this@MainActivity, REQ_OPEN_PDF, PREF_SSD_PDF_TREE_URI, PREF_LAST_PDF_URI) },"
-	       "                mainActivityButton(this@MainActivity, \"Rotate\") { mainActivityRotatePage(this@MainActivity, reviewView, loadGeneration, currentSession) },"
-	       "                mainActivityButton(this@MainActivity, \"Fit\") { reviewViewFitImage(reviewView) },"
-	       "            ))"
-	       "            addView(mainActivityActionRow(this@MainActivity, LinearLayout.HORIZONTAL, Gravity.CENTER_VERTICAL,"
-	       "                mainActivityButton(this@MainActivity, \"Prev Page\") { mainActivityChangePage(this@MainActivity, pdfUri, pageCount, pageIndex, -1) },"
-	       "                mainActivityButton(this@MainActivity, \"Page #\") { mainActivityShowPageDialog(this@MainActivity, pdfUri, pageCount, pageIndex) },"
-	       "                mainActivityButton(this@MainActivity, \"Next Page\") { mainActivityChangePage(this@MainActivity, pdfUri, pageCount, pageIndex, 1) },"
-	       "            ))"
-	       "            addView(mainActivityActionRow(this@MainActivity, LinearLayout.HORIZONTAL, Gravity.CENTER_VERTICAL,"
-	       "                mainActivityButton(this@MainActivity, \"Pan\", ButtonKind.NEUTRAL) { mainActivityApplySelectMode(this@MainActivity, reviewView, ssdAreaMode, appendMode, false) },"
-	       "                mainActivityButton(this@MainActivity, \"Select Area\", ButtonKind.PRIMARY) { mainActivityApplySelectMode(this@MainActivity, reviewView, ssdAreaMode, appendMode, true) },"
-	       "                mainActivityButton(this@MainActivity, \"Add\", ButtonKind.ACCENT) { mainActivityStartAppendMode(this@MainActivity, reviewView, currentSession, selectedGroupId) },"
-	       "            ))"
-	       "            addView(mainActivityActionRow(this@MainActivity, LinearLayout.HORIZONTAL, Gravity.CENTER_VERTICAL,"
-	       "                mainActivityButton(this@MainActivity, \"Prev\", ButtonKind.NAV) { mainActivitySelectRelativeGroup(this@MainActivity, reviewView, currentSession, selectedGroupId, -1, HapticFeedbackConstants.CLOCK_TICK) },"
-	       "                mainActivityButton(this@MainActivity, \"Next\", ButtonKind.PRIMARY) { mainActivitySelectRelativeGroup(this@MainActivity, reviewView, currentSession, selectedGroupId, 1, HapticFeedbackConstants.CLOCK_TICK) },"
-	       "                mainActivityButton(this@MainActivity, \"Edit\") { mainActivityEditSelectedGroup(this@MainActivity, reviewView, truthStore, currentSession, selectedGroupId, boxTypeDisplays, HapticFeedbackConstants.CONFIRM, HapticFeedbackConstants.REJECT) },"
-	       "            ))"
-	       "            addView(mainActivityActionRow(this@MainActivity, LinearLayout.HORIZONTAL, Gravity.CENTER_VERTICAL,"
-	       "                mainActivityButton(this@MainActivity, \"Approve\", ButtonKind.ACCENT) { mainActivityApproveSelectedGroup(this@MainActivity, reviewView, truthStore, currentSession, selectedGroupId, HapticFeedbackConstants.CONFIRM) },"
-	       "                mainActivityButton(this@MainActivity, \"Delete\", ButtonKind.DANGER) { mainActivityDeleteSelectedGroup(this@MainActivity, reviewView, truthStore, currentSession, selectedGroupId, HapticFeedbackConstants.REJECT) },"
-	       "                mainActivityButton(this@MainActivity, \"Save\") { mainActivitySaveTruth(this@MainActivity, reviewView, truthStore, currentSession) },"
-	       "            ))"
-       "            addView(mainActivityActionRow(this@MainActivity, LinearLayout.HORIZONTAL, Gravity.CENTER_VERTICAL,"
-       "                mainActivityButton(this@MainActivity, \"Pull Truth\") { mainActivityPullTruthDumpAsync(this@MainActivity, truthStore) },"
-       "                mainActivityButton(this@MainActivity, \"Push Truth\") { mainActivityPushTruthDumpAsync(this@MainActivity, truthStore) },"
-       "                mainActivityButton(this@MainActivity, \"Sync Folder\") { mainActivitySyncTruthFolder(this@MainActivity, REQ_SYNC_TREE) },"
-	       "            ))"
-	       "        }"
-       "        root.addView(ScrollView(this).apply {"
-       "            isFillViewport = false"
-       "            addView(controls)"
-       "        }, LinearLayout.LayoutParams("
-       "            LinearLayout.LayoutParams.MATCH_PARENT,"
-       "            LinearLayout.LayoutParams.WRAP_CONTENT"
-       "        ))"
-       "        return root"
-       "    }"
+       "    private fun buildUi(): View = mainActivityBuildUi(this)"
        ""
        "    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {"
        "        super.onActivityResult(requestCode, resultCode, data)"