diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts
index 6ad6bf9a1ec638f7fe15f93038552f8bf0c3521a..a7029afc90f32e9216bd7913df3fbb256adfe40a 100644
--- a/build-logic/build.gradle.kts
+++ b/build-logic/build.gradle.kts
@@ -6,8 +6,6 @@ plugins {
 dependencies {
     implementation(libs.build.androidLibrary)
     implementation(libs.build.spotless)
-    implementation(libs.build.composeCompiler)
-    implementation(libs.build.jetbrainsCmp)
     implementation(libs.build.gitSemVer)
 }
 
diff --git a/build-logic/src/main/kotlin/convention.composeComp.gradle.kts b/build-logic/src/main/kotlin/convention.composeComp.gradle.kts
deleted file mode 100644
index e8c2dda5ef647479d736625c5553377f4175ff11..0000000000000000000000000000000000000000
--- a/build-logic/src/main/kotlin/convention.composeComp.gradle.kts
+++ /dev/null
@@ -1,8 +0,0 @@
-plugins {
-    id("org.jetbrains.kotlin.plugin.compose")
-}
-
-composeCompiler {
-    // Needed to enable Layout Inspector
-    includeSourceInformation.set(true)
-}
\ No newline at end of file
diff --git a/build-logic/src/main/kotlin/convention.formattingLib.gradle.kts b/build-logic/src/main/kotlin/convention.formatting.gradle.kts
similarity index 100%
rename from build-logic/src/main/kotlin/convention.formattingLib.gradle.kts
rename to build-logic/src/main/kotlin/convention.formatting.gradle.kts
diff --git a/build-logic/src/main/kotlin/convention.formattingCmp.gradle.kts b/build-logic/src/main/kotlin/convention.formattingCmp.gradle.kts
deleted file mode 100644
index 74450627e31e4a9ca2835e44b7aa4703e935b7e1..0000000000000000000000000000000000000000
--- a/build-logic/src/main/kotlin/convention.formattingCmp.gradle.kts
+++ /dev/null
@@ -1,38 +0,0 @@
-plugins {
-    id("com.diffplug.spotless")
-}
-spotless {
-    kotlin {
-        target("**/*.kt")
-        targetExclude("${layout.buildDirectory}/**/*.kt")
-        ktlint().editorConfigOverride(
-            mapOf(
-                "indent_size" to "2",
-                "continuation_indent_size" to "2"
-            )
-        )
-        .customRuleSets(
-            listOf(
-                "io.nlopez.compose.rules:ktlint:0.4.10"
-            )
-        )
-        licenseHeaderFile(rootProject.file("spotless/appHeader.kt"))
-        trimTrailingWhitespace()
-        endWithNewline()
-    }
-    format("kts") {
-        target("**/*.kts")
-        targetExclude("${layout.buildDirectory}/**/*.kts")
-        // Adapted from https://github.com/GetStream/whatsApp-clone-compose/blob/d14a5e02ea4db4b586d855d9c61db51f99b9c962/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt#L27
-        // Look for the first XML tag that isn't a comment (<!--) or the xml declaration (<?xml)
-        licenseHeaderFile(rootProject.file("spotless/appHeader.kt"), "(^(?![\\/ ]\\*).*\$)")
-        trimTrailingWhitespace()
-        endWithNewline()
-    }
-    format("xml") {
-        target("**/*.xml")
-        licenseHeaderFile(rootProject.file("spotless/appHeader.xml"), "(<[^!?])")
-        trimTrailingWhitespace()
-        endWithNewline()
-    }
-}
\ No newline at end of file
diff --git a/build-logic/src/main/kotlin/convention.jetbrainsCmp.gradle.kts b/build-logic/src/main/kotlin/convention.jetbrainsCmp.gradle.kts
deleted file mode 100644
index 6449a59464d9aafd6abc2f1351e972fcdaa769c1..0000000000000000000000000000000000000000
--- a/build-logic/src/main/kotlin/convention.jetbrainsCmp.gradle.kts
+++ /dev/null
@@ -1,4 +0,0 @@
-plugins {
-    id("convention.composeComp")
-    id("org.jetbrains.compose")
-}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index ae61907b2112e32da89562ee4df66b8c3cf34bcf..c57c17de0c4be86a20cdbabaf13fe34a0c721e43 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -8,11 +8,8 @@ plugins {
     alias(libs.plugins.kotlinxSerialization) apply false
     alias(libs.plugins.ktorfit) apply false
     alias(libs.plugins.kotestMultiplatform) apply false
-    alias(libs.plugins.jetbrainsCompose) apply false
-    alias(libs.plugins.composeCompiler) apply false
     alias(libs.plugins.spotless) apply false
     alias(libs.plugins.dokka) apply false
     alias(libs.plugins.gitSemVer) apply false
     alias(libs.plugins.dataframe) apply false
-    alias(libs.plugins.room) apply false
 }
\ No newline at end of file
diff --git a/compose-desktop/.gitignore b/compose-desktop/.gitignore
deleted file mode 100644
index 797ca4d1e519b7f376d5d3f74b9564fe39bd2079..0000000000000000000000000000000000000000
--- a/compose-desktop/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-
-.env*
-.flaskenv*
-!.env.project
-!.env.vault
\ No newline at end of file
diff --git a/compose-desktop/LICENSE b/compose-desktop/LICENSE
deleted file mode 100644
index 19dc35b2433851a0e8fd866a5d323b2ba18c12ed..0000000000000000000000000000000000000000
--- a/compose-desktop/LICENSE
+++ /dev/null
@@ -1,175 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
\ No newline at end of file
diff --git a/compose-desktop/README.md b/compose-desktop/README.md
deleted file mode 100644
index a7cabaab9d1652ecd1c8e2377af2dda0c8b5fbc0..0000000000000000000000000000000000000000
--- a/compose-desktop/README.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Temerity Demo App
-
-Kotlin Multiplatform App using Compose
-
-### Run/build platform artifacts
-
-#### Compose Desktop app
-
-## To run:
-- Run `./gradlew runRelease`
-- Output: Desktop app running
-
-## To run full binary image:
-- Run `./gradlew runReleaseDistributable`
-- Output: Desktop app running
-
-## To build:
-- Run `./gradlew packageReleaseDistributionForCurrentOS`
-- Output: A binary for your platform
\ No newline at end of file
diff --git a/compose-desktop/build.gradle.kts b/compose-desktop/build.gradle.kts
deleted file mode 100644
index f58c601bc3f47bd9d45e285bb180ecc44172e6db..0000000000000000000000000000000000000000
--- a/compose-desktop/build.gradle.kts
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import org.jetbrains.compose.desktop.application.dsl.TargetFormat
-
-plugins {
-    alias(libs.plugins.kotlinMultiplatform)
-    id("convention.jetbrainsCmp")
-    id("convention.formattingCmp")
-}
-
-kotlin {
-    jvmToolchain(libs.versions.java.get().toInt())
-
-    jvm("desktop")
-
-    sourceSets {
-        val desktopMain by getting {
-            dependencies {
-                implementation(compose.desktop.currentOs)
-                implementation(compose.desktop.macos_arm64)
-                implementation(project(":shared:compose"))
-            }
-        }
-    }
-}
-
-val appVersion = "1.0.0"
-version = appVersion
-
-compose.desktop {
-
-    application {
-        mainClass = "MainKt"
-
-        // Required to build minified native distributions
-        buildTypes.release {
-            proguard {
-                version.set("7.4.2")
-                isEnabled.set(false)
-                optimize.set(false)
-            }
-        }
-
-        nativeDistributions {
-            includeAllModules = true
-            targetFormats(TargetFormat.Dmg, TargetFormat.Pkg, TargetFormat.Msi, TargetFormat.Exe, TargetFormat.Deb)
-
-            packageName = "Temerity"
-            description = "Temerity is a Kotlin Multiplatform library and desktop app for utilizing the YuJa Enterprise Video Platform API"
-            copyright = "© 2024 The Regents of the University of California. All rights reserved."
-            vendor = "ITS Division, University of California, Santa Cruz"
-            licenseFile.set(project.file("LICENSE"))
-
-            val iconsRoot = project.file("desktop-icons")
-            macOS {
-                bundleID = "edu.ucsc.its.temerity.desktop"
-                dockName = "Temerity"
-                packageVersion = appVersion
-                dmgPackageVersion = appVersion
-                pkgPackageVersion = appVersion
-            }
-            windows {
-                packageVersion = appVersion
-                exePackageVersion = appVersion
-                msiPackageVersion = appVersion
-
-                menu = true
-                // Allow Windows users to customize install location
-                dirChooser = true
-                perUserInstall = true
-            }
-            linux {
-                debMaintainer = "wnwalker@ucsc.edu"
-            }
-        }
-    }
-}
diff --git a/compose-desktop/src/desktopMain/kotlin/Main.kt b/compose-desktop/src/desktopMain/kotlin/Main.kt
deleted file mode 100644
index f3ee01640a3337cb90aa287a71a7ee5249123379..0000000000000000000000000000000000000000
--- a/compose-desktop/src/desktopMain/kotlin/Main.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.window.Window
-import androidx.compose.ui.window.application
-import androidx.compose.ui.window.rememberWindowState
-import edu.ucsc.its.temerity.shared.ui.MainLayout
-
-fun main() = application {
-  val windowState = rememberWindowState(width = 640.dp, height = 480.dp)
-
-  Window(
-    onCloseRequest = { exitApplication() },
-    title = "Temerity",
-    state = windowState,
-  ) {
-    MainLayout()
-  }
-}
diff --git a/console/LICENSE b/console/LICENSE
deleted file mode 100644
index 19dc35b2433851a0e8fd866a5d323b2ba18c12ed..0000000000000000000000000000000000000000
--- a/console/LICENSE
+++ /dev/null
@@ -1,175 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
\ No newline at end of file
diff --git a/console/build.gradle.kts b/console/build.gradle.kts
deleted file mode 100644
index 32218643d5ceffeeb8260508704096ef9435c142..0000000000000000000000000000000000000000
--- a/console/build.gradle.kts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-plugins {
-    kotlin("jvm")
-    id("convention.composeComp")
-    id("application")
-
-    id("convention.formattingCmp")
-}
-
-dependencies {
-    implementation(project(":temerity"))
-    implementation(libs.jline)
-    implementation(libs.mosaic)
-}
-
-kotlin {
-    jvmToolchain(libs.versions.java.get().toInt())
-}
-
-application {
-    mainClass = "edu.ucsc.its.temerity.console.ConsoleMainKt"
-}
-
-java {
-    sourceCompatibility = JavaVersion.toVersion(libs.versions.java.get())
-    targetCompatibility = JavaVersion.toVersion(libs.versions.java.get())
-}
diff --git a/console/src/main/kotlin/edu/ucsc/its/temerity/console/ConsoleMain.kt b/console/src/main/kotlin/edu/ucsc/its/temerity/console/ConsoleMain.kt
deleted file mode 100644
index eb781a78f3fc1e72565dfc04f0ab0b21078e2489..0000000000000000000000000000000000000000
--- a/console/src/main/kotlin/edu/ucsc/its/temerity/console/ConsoleMain.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.console
-
-import com.jakewharton.mosaic.LocalTerminal
-import com.jakewharton.mosaic.runMosaicBlocking
-import com.jakewharton.mosaic.text.SpanStyle
-import com.jakewharton.mosaic.text.buildAnnotatedString
-import com.jakewharton.mosaic.text.withStyle
-import com.jakewharton.mosaic.ui.Color
-import com.jakewharton.mosaic.ui.Text
-import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.suspendCancellableCoroutine
-import kotlinx.coroutines.withContext
-import org.jline.terminal.TerminalBuilder
-
-fun main(): Unit = runMosaicBlocking {
-  setContent {
-    val terminal = LocalTerminal.current
-    Text(
-      buildAnnotatedString {
-        append("Terminal(")
-        withStyle(SpanStyle(color = Color.Green)) {
-          append("width=")
-        }
-        withStyle(SpanStyle(color = Color.Blue)) {
-          append(terminal.size.width.toString())
-        }
-        append(", ")
-        withStyle(SpanStyle(color = Color.Green)) {
-          append("height=")
-        }
-        withStyle(SpanStyle(color = Color.Blue)) {
-          append(terminal.size.height.toString())
-        }
-        append(")")
-      },
-    )
-  }
-
-  withContext(IO) {
-    val terminal = TerminalBuilder.terminal()
-  }
-
-  // Run forever!
-  suspendCancellableCoroutine { }
-}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 4cc239f93dca70175de051edbb1e6c5364011575..0070fa1bb5ece7cfb86312628307ca39e1160568 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,4 @@
 [versions]
-compose-multiplatform = "1.7.1"
 agp = "8.2.2"
 java = "17"
 kotlin = "2.1.0"
@@ -16,32 +15,16 @@ ktorfit = "2.2.0"
 coroutines = "1.10.1"
 datetime = "0.6.1"
 sandwich = "2.0.10"
-arrow = "1.2.4"
+arrow = "2.0.0"
 # Main Koin version - for core, android deps
 koin = "4.0.1"
 koinTest = "4.0.1"
 gradleBuildConfigPlugin = "5.5.1"
 akkurate = "0.11.0"
-# Koin version for Compose multiplatform
-koinComposeMultiplatform = "4.0.1"
-mosaic = "0.13.0"
-molecule = "2.0.0"
-adaptive = "1.0.1"
-adaptive-navigation = "1.0.0"
-jetbrainsNavigationCompose = "2.8.0-alpha09"
-jetbrainsLifecycle = "2.8.4"
-androidxRoom = "2.7.0-alpha11"
-sqlite = "2.5.0-SNAPSHOT"
-androidxDatastore = "1.1.1"
 exposed = "0.56.0"
 
-landscapistCoil3 = "2.3.6"
-composetheme = "1.2.0-alpha"
-voyager = "1.1.0-beta02"
-
 dotenv-vault = "0.0.3"
 kermit = "2.0.4"
-jline = "3.27.1"
 appdirs = "1.2.0"
 kstore = "0.9.1"
 kmpIo = "0.1.5"
@@ -54,12 +37,6 @@ klaxon = "5.6"
 kotest = "6.0.0.M1"
 kotest-datatest = "5.9.1"
 
-composables-unstyled = "1.19.1"
-bottomsheet = "0.1.5"
-alertKmp = "1.0.7"
-filekit = "0.8.7"
-composetray = "0.4.0"
-
 dokka = "2.0.0"
 spotless = "7.0.0.BETA4"
 gitSemVer = "3.1.7"
@@ -88,7 +65,6 @@ slf4j-api = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
 kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
 kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
 kotlinx-coroutines-debug = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-debug", version.ref = "coroutines" }
-kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" }
 kotlinx-coroutines-slf4j = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-slf4j", version.ref = "coroutines" }
 kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
 kotlinx-io = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" }
@@ -98,7 +74,6 @@ ktorfit-lib = { module = "de.jensklingenberg.ktorfit:ktorfit-lib-light", version
 kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }
 kermit-koin = { module = "co.touchlab:kermit-koin", version.ref = "kermit" }
 
-jline = { module = "org.jline:jline", version.ref = "jline" }
 appdirs = { module = "ca.gosyer:kotlin-multiplatform-appdirs", version.ref = "appdirs" }
 kstore = { module = "io.github.xxfast:kstore", version.ref = "kstore" }
 kstore-file = { module = "io.github.xxfast:kstore-file", version.ref = "kstore" }
@@ -119,47 +94,7 @@ arrow-optics = { module = "io.arrow-kt:arrow-optics", version.ref = "arrow" }
 arrow-opticsKspPlugin = { module = "io.arrow-kt:arrow-optics-ksp-plugin", version.ref = "arrow" }
 akkurate = { module = "dev.nesk.akkurate:akkurate-core", version.ref = "akkurate" }
 
-mosaic = { module = "com.jakewharton.mosaic:mosaic-runtime", version.ref = "mosaic" }
-koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koinComposeMultiplatform" }
-# Koin version for Compose on Android: koin-androidx-compose
-koin-composeVm = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koinComposeMultiplatform" }
-jetbrains-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "jetbrainsLifecycle"}
-jetbrains-lifecycle-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "jetbrainsLifecycle" }
-adaptive = { module = "org.jetbrains.compose.material3.adaptive:adaptive", version.ref = "adaptive" }
-adaptive-layout = { module = "org.jetbrains.compose.material3.adaptive:adaptive-layout", version.ref = "adaptive" }
-adaptive-navigation = { module = "org.jetbrains.compose.material3.adaptive:adaptive-navigation", version.ref = "adaptive-navigation" }
-composeTheme = { module = "com.composables:composetheme", version.ref = "composetheme" }
-composeTheme-material3 = { module = "com.composables:composetheme-material3", version.ref = "composetheme" }
-voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
-voyager-bottomSheetNavigator = { module = "cafe.adriel.voyager:voyager-bottom-sheet-navigator", version.ref = "voyager" }
-voyager-tabNavigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" }
-voyager-lifecycle-kmp = { module = "cafe.adriel.voyager:voyager-lifecycle-kmp", version.ref = "voyager" }
-voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" }
-voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voyager" }
-
-landscapist-coil3 = { module = "com.github.skydoves:landscapist-coil3", version.ref = "landscapistCoil3" }
-composablesUnstyled = { module = "com.composables:core", version.ref = "composables-unstyled" }
-flexible-bottomsheet = { module = "com.github.skydoves:flexible-bottomsheet", version.ref = "bottomsheet" }
-alertKmp = { module = "io.github.khubaibkhan4:alert-kmp", version.ref = "alertKmp" }
-filekit-core = { group = "io.github.vinceglb", name = "filekit-core", version.ref = "filekit" }
-filekit-compose = { group = "io.github.vinceglb", name = "filekit-compose", version.ref = "filekit" }
-composeTray = { module = "io.github.kdroidfilter:composenativetray", version.ref = "composetray" }
-
-# Shared presenter code deps (some usages are platform-specific)
-molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" }
-datastore-preferences = { module = "androidx.datastore:datastore-preferences-core", version.ref = "androidxDatastore" }
-jetbrains-navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "jetbrainsNavigationCompose" }
-androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "androidxRoom" }
-androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "androidxRoom" }
-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" }
-exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }
-exposed-crypt = { module = "org.jetbrains.exposed:exposed-crypt", version.ref = "exposed" }
-exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
-exposed-kotlinDatetime = { module = "org.jetbrains.exposed:exposed-kotlin-datetime", version.ref = "exposed" }
-
 build-androidLibrary = { module = "com.android.library:com.android.library.gradle.plugin", version.ref = "agp"}
-build-composeCompiler = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
-build-jetbrainsCmp = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose-multiplatform" }
 build-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
 
 dokka-base = { module = "org.jetbrains.dokka:dokka-base", version.ref = "dokka" }
@@ -184,14 +119,10 @@ konsist = { module = "com.lemonappdev:konsist", version.ref = "konsist" }
 [bundles]
 ktor = ["ktor-client-logging", "ktor-client-serialization", "kotlinx-serialization-json"]
 sandwich = ["sandwich", "sandwich-ktor", "sandwich-ktorfit"]
-voyager = ["voyager-navigator", "voyager-bottomSheetNavigator", "voyager-tabNavigator", "voyager-lifecycle-kmp", "voyager-transitions", "voyager-koin"]
-exposed = ["exposed-core", "exposed-crypt", "exposed-dao", "exposed-kotlinDatetime"]
 
 [plugins]
 androidApplication = { id = "com.android.application", version.ref = "agp" }
 androidLibrary = { id = "com.android.library", version.ref = "agp" }
-jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
-composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
 kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
 ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
 ktorfit = { id = "de.jensklingenberg.ktorfit", version.ref = "ktorfit" }
@@ -202,4 +133,3 @@ dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
 spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
 gitSemVer = { id = "org.danilopianini.git-sensitive-semantic-versioning", version.ref = "gitSemVer" }
 dataframe = { id = "org.jetbrains.kotlinx.dataframe", version.ref = "kotlinx-dataframe" }
-room = { id = "androidx.room", version.ref = "androidxRoom" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d9a15e5af808390c423889b46d8a9cd7a95ecf1d..39566c1f42262e7270ecef1b3ffe1ce9be07a6cf 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,7 +1,6 @@
 @file:Suppress("UnstableApiUsage")
 
-import java.util.*
-
+import java.util.Locale
 
 pluginManagement {
     repositories {
@@ -19,9 +18,6 @@ dependencyResolutionManagement {
         google()
         mavenCentral()
         maven { url = uri("https://jitpack.io") }
-        maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
-        maven("https://maven.pkg.jetbrains.space/kotlin/p/wasm/experimental")
-        maven("https://androidx.dev/storage/compose-compiler/repository")
         maven("https://maven.pkg.jetbrains.space/public/p/ktor/eap")
         maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
         maven("https://plugins.gradle.org/m2")
@@ -32,8 +28,4 @@ dependencyResolutionManagement {
 rootProject.name = "Temerity".lowercase(Locale.getDefault())
 includeBuild("build-logic")
 include("temerity")
-include(":shared:shared")
-include(":shared:compose")
-include("compose-desktop")
-include("console")
 
diff --git a/shared/compose/LICENSE b/shared/compose/LICENSE
deleted file mode 100644
index 19dc35b2433851a0e8fd866a5d323b2ba18c12ed..0000000000000000000000000000000000000000
--- a/shared/compose/LICENSE
+++ /dev/null
@@ -1,175 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
\ No newline at end of file
diff --git a/shared/compose/NOTICE b/shared/compose/NOTICE
deleted file mode 100644
index 7f911ebb67bc4177934ec90349458e0e4d150886..0000000000000000000000000000000000000000
--- a/shared/compose/NOTICE
+++ /dev/null
@@ -1,28 +0,0 @@
---------------------------------------------
-
-This product includes software developed by The Android Open Source Project.
-
-File(s): WindowStateUtils.kt
-Description: A utility class for managing window state in a Compose application.
-License: Apache License, Version 2.0
-
---------------------------------------------
-
-This product includes software developed by Abdul Basit.
-
-File(s): Gradient.kt
-Description: A utility function for displaying a Gradient effect Composable in an application.
-License: None
-
---------------------------------------------
-
-This product includes software developed by Composable Horizons (Alex Styl)
-
-File(s): ListDetailLayoutWithSearchBar.kt, UserEditScreen.kt, Utility.kt
-Descriptions:
-    - A material 3 responsive layout built using the canonical list-detail pattern.
-    - A screen containing a form for editing user details.
-    - A simple dropdown menu with chevron down icon, basic text items
-License: Purchased 06/2024
-
---------------------------------------------
\ No newline at end of file
diff --git a/shared/compose/README.md b/shared/compose/README.md
deleted file mode 100644
index a7cabaab9d1652ecd1c8e2377af2dda0c8b5fbc0..0000000000000000000000000000000000000000
--- a/shared/compose/README.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Temerity Demo App
-
-Kotlin Multiplatform App using Compose
-
-### Run/build platform artifacts
-
-#### Compose Desktop app
-
-## To run:
-- Run `./gradlew runRelease`
-- Output: Desktop app running
-
-## To run full binary image:
-- Run `./gradlew runReleaseDistributable`
-- Output: Desktop app running
-
-## To build:
-- Run `./gradlew packageReleaseDistributionForCurrentOS`
-- Output: A binary for your platform
\ No newline at end of file
diff --git a/shared/compose/build.gradle.kts b/shared/compose/build.gradle.kts
deleted file mode 100644
index 1d7a7f41a6d874c46d7f630f5c9d676a147e9632..0000000000000000000000000000000000000000
--- a/shared/compose/build.gradle.kts
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-plugins {
-    alias(libs.plugins.kotlinMultiplatform)
-    alias(libs.plugins.kotlinxSerialization)
-    id("convention.composeComp")
-    id("convention.jetbrainsCmp")
-
-    id("convention.formattingCmp")
-}
-
-kotlin {
-    jvmToolchain(libs.versions.java.get().toInt())
-    jvm("desktop")
-    applyDefaultHierarchyTemplate()
-
-    sourceSets {
-        val commonMain by getting {
-            dependencies {
-                implementation(compose.ui)
-                implementation(compose.runtime)
-                implementation(compose.foundation)
-                implementation(compose.material3)
-                implementation(compose.materialIconsExtended)
-                implementation(compose.components.resources)
-
-                implementation(libs.koin.compose)
-                implementation(libs.koin.composeVm)
-
-                implementation(libs.jetbrains.lifecycle.viewmodel)
-                implementation(libs.jetbrains.lifecycle.compose)
-                implementation(libs.jetbrains.navigation.compose)
-
-                implementation(project(":shared:shared"))
-
-                implementation(libs.adaptive)
-                implementation(libs.adaptive.layout)
-                implementation(libs.adaptive.navigation)
-                implementation(compose.material3AdaptiveNavigationSuite)
-
-                implementation(libs.composeTheme)
-                implementation(libs.composeTheme.material3)
-                implementation(libs.bundles.voyager)
-                implementation(libs.alertKmp)
-                implementation(libs.composablesUnstyled)
-
-                implementation(libs.dotenv.vault)
-            }
-        }
-        val commonTest by getting {
-            dependencies {
-                @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
-                implementation(compose.uiTest)
-            }
-        }
-        val desktopMain by getting {
-            dependencies {
-                implementation(compose.desktop.common)
-            }
-        }
-        val desktopTest by getting {
-            dependencies {
-                implementation(compose.desktop.currentOs)
-            }
-        }
-    }
-}
-
-val appVersion = "1.0.0"
-version = appVersion
diff --git a/shared/compose/src/commonMain/composeResources/drawable/compose-multiplatform.xml b/shared/compose/src/commonMain/composeResources/drawable/compose-multiplatform.xml
deleted file mode 100644
index 727c8b0cb41db000385045990659c4629b08216e..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/composeResources/drawable/compose-multiplatform.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
-    Copyright 2022-2024 The Regents of the University of California. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector>
-</vector>
diff --git a/shared/compose/src/commonMain/composeResources/values/strings.xml b/shared/compose/src/commonMain/composeResources/values/strings.xml
deleted file mode 100644
index 606ba69c2e266d02fe891ff4f8f80c5ceac5a438..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/composeResources/values/strings.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
-    Copyright 2022-2024 The Regents of the University of California. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<resources>
-    <string name="app_name">Temerity</string>
-    <string name="login">Login</string>
-    <string name="main">Main</string>
-
-    <string name="notifications">Notifications</string>
-    <string name="notifications_short">Notifs.</string>
-    <string name="devices">Devices</string>
-    <string name="roster">Roster</string>
-    <string name="courses">Courses</string>
-    <string name="settings">Settings</string>
-
-    <!-- Strings used in the User Screens -->
-    <string name="user_edit">Edit User Record</string>
-    <string name="clear_field">Clear</string>
-    <string name="lock_user_role">Lock User Role</string>
-
-    <!-- Action item text -->
-    <string name="blank">No content</string>
-    <string name="save">Save</string>
-
-    <!-- Strings used in the Courses Screens -->
-    <string name="course_code_prefix">Course code: </string>
-    <string name="term_code_prefix">Term: </string>
-    <string name="direct_course_link_prefix">Direct course link: </string>
-    <string name="course_edit">Edit Course</string>
-
-</resources>
diff --git a/shared/compose/src/commonMain/kotlin/androidx/compose/desktop/ui/tooling/preview/Preview.kt b/shared/compose/src/commonMain/kotlin/androidx/compose/desktop/ui/tooling/preview/Preview.kt
deleted file mode 100644
index f5f2b7c97114d9e372a192a7c2334050bdcbf70f..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/androidx/compose/desktop/ui/tooling/preview/Preview.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.compose.desktop.ui.tooling.preview
-
-@OptIn(ExperimentalMultiplatform::class)
-@OptionalExpectation
-expect annotation class Preview()
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/LoginScreen.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/LoginScreen.kt
deleted file mode 100644
index a545a674e89b7b72bb1e1dd26c92ca65ce6eb5d5..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/LoginScreen.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.height
-import androidx.compose.material3.Button
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import edu.ucsc.its.temerity.shared.viewmodel.AppViewModel
-import edu.ucsc.its.temerity.shared.viewmodel.LoginViewModel
-import org.koin.compose.getKoin
-import org.koin.compose.viewmodel.koinViewModel
-import org.koin.core.parameter.parametersOf
-import org.koin.core.qualifier.named
-
-@Composable
-fun LoginScreen(
-  modifier: Modifier = Modifier,
-  appViewModel: AppViewModel = koinViewModel(),
-  viewModel: LoginViewModel = koinViewModel(),
-  onLogin: () -> Unit,
-) {
-  val uiState = viewModel.models.collectAsState()
-
-//  LaunchedEffect("loadAppState") {
-//    appStateViewModel.viewModelScope.launch {
-//      withContext(IO.limitedParallelism(1)){
-//        if (appStateStore.get() != null) {
-//          val prevAppState = appStateStore.get()!!
-//          appStateViewModel.updateServiceEndpoint(prevAppState.serviceEndpoint)
-//          appStateViewModel.updateServiceToken(prevAppState.serviceToken)
-//
-//          viewModel.updateServiceEndpoint(prevAppState.serviceEndpoint)
-//          viewModel.updateServiceToken(prevAppState.serviceToken)
-//
-//          onLogin()
-//        }
-//      }
-//      }
-//  }
-
-  Column(
-    modifier = modifier.fillMaxSize(),
-    verticalArrangement = Arrangement.Center,
-    horizontalAlignment = Alignment.CenterHorizontally,
-  ) {
-//    TextField(
-//      value = uiState.serviceEndpoint,
-//      onValueChange = { viewModel.updateServiceEndpoint(it) },
-//      label = { Text("Instance URL") },
-//    )
-    Spacer(modifier = Modifier.height(16.dp))
-//    TextField(
-//      value = uiState.serviceToken,
-//      onValueChange = { viewModel.updateServiceToken(it) },
-//      label = { Text("Authentication Token") },
-//      visualTransformation = PasswordVisualTransformation(),
-//      keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
-//    )
-    Spacer(modifier = Modifier.height(16.dp))
-    Text(
-      text = getKoin().get<String> {
-        named("appConfigDir")
-        parametersOf("edu.ucsc.its.temerity")
-      },
-    )
-    Spacer(modifier = Modifier.height(16.dp))
-    Button(
-      onClick = {
-//        appStateViewModel.updateServiceEndpoint(uiState.serviceEndpoint)
-//        appStateViewModel.updateServiceToken(uiState.serviceToken)
-//        appStateViewModel.updateUserLoggedIn(true)
-//        coroutineScope.launch {
-//          withContext(IO) {
-//            appStateStore.set(appStateViewModel.appState.value)
-//          }
-//        }
-
-        onLogin()
-      },
-    ) {
-      Text("Login")
-    }
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/MainScreen.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/MainScreen.kt
deleted file mode 100644
index 68353c32862465259f1a9e2ca455ca92c344948c..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/MainScreen.kt
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.itemsIndexed
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.text.KeyboardActions
-import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material.icons.Icons.Outlined
-import androidx.compose.material.icons.Icons.Rounded
-import androidx.compose.material.icons.outlined.AdUnits
-import androidx.compose.material.icons.outlined.Contacts
-import androidx.compose.material.icons.outlined.Edit
-import androidx.compose.material.icons.outlined.Group
-import androidx.compose.material.icons.outlined.Notifications
-import androidx.compose.material.icons.outlined.Settings
-import androidx.compose.material.icons.rounded.Clear
-import androidx.compose.material.icons.rounded.Search
-import androidx.compose.material3.ExtendedFloatingActionButton
-import androidx.compose.material3.FloatingActionButton
-import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.NavigationBar
-import androidx.compose.material3.NavigationBarItem
-import androidx.compose.material3.NavigationDrawerItem
-import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.OutlinedTextFieldDefaults
-import androidx.compose.material3.PermanentDrawerSheet
-import androidx.compose.material3.PermanentNavigationDrawer
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
-import androidx.compose.material3.minimumInteractiveComponentSize
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.text.input.ImeAction
-import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.unit.dp
-import androidx.lifecycle.viewModelScope
-import androidx.navigation.NavGraph
-import androidx.navigation.NavHostController
-import androidx.navigation.compose.composable
-import androidx.navigation.compose.rememberNavController
-import androidx.navigation.createGraph
-import androidx.navigation.toRoute
-import androidx.window.core.layout.WindowWidthSizeClass
-import com.composables.composetheme.ComposeTheme
-import com.composables.composetheme.material3.colorScheme
-import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.model.Course
-import edu.ucsc.its.temerity.model.Device
-import edu.ucsc.its.temerity.model.User
-import edu.ucsc.its.temerity.shared.ui.MainContentWindow.Courses
-import edu.ucsc.its.temerity.shared.ui.MainContentWindow.Devices
-import edu.ucsc.its.temerity.shared.ui.MainContentWindow.Notifications
-import edu.ucsc.its.temerity.shared.ui.MainContentWindow.Roster
-import edu.ucsc.its.temerity.shared.ui.MainContentWindow.Settings
-import edu.ucsc.its.temerity.shared.ui.UserDetailView.BlankScreen
-import edu.ucsc.its.temerity.shared.ui.UserDetailView.EditScreen
-import edu.ucsc.its.temerity.shared.ui.elements.CoursesList
-import edu.ucsc.its.temerity.shared.ui.elements.DeviceList
-import edu.ucsc.its.temerity.shared.ui.elements.NewNavHost
-import edu.ucsc.its.temerity.shared.ui.elements.UserList
-import edu.ucsc.its.temerity.shared.viewmodel.AppViewModel
-import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.encodeToString
-import kotlinx.serialization.json.Json
-import org.dotenv.vault.dotenvVault
-import org.jetbrains.compose.resources.StringResource
-import org.jetbrains.compose.resources.stringResource
-import org.koin.compose.getKoin
-import org.koin.compose.viewmodel.koinViewModel
-import org.koin.core.parameter.parametersOf
-import temerity.shared.compose.generated.resources.Res.string
-import temerity.shared.compose.generated.resources.courses
-import temerity.shared.compose.generated.resources.devices
-import temerity.shared.compose.generated.resources.notifications
-import temerity.shared.compose.generated.resources.notifications_short
-import temerity.shared.compose.generated.resources.roster
-import temerity.shared.compose.generated.resources.settings
-
-sealed class MainContentWindow {
-  @Serializable
-  data object Notifications : MainContentWindow()
-
-  @Serializable
-  data object Devices : MainContentWindow()
-
-  @Serializable
-  data object Roster : MainContentWindow()
-
-  @Serializable
-  data object Courses : MainContentWindow()
-
-  @Serializable
-  data object Settings : MainContentWindow()
-}
-
-sealed class UserDetailView {
-  @Serializable
-  data object BlankScreen : UserDetailView()
-
-  @Serializable
-  data class EditScreen(val user: String) : UserDetailView()
-}
-
-@Composable
-fun MainScreen(modifier: Modifier = Modifier) {
-  val appViewModel: AppViewModel = koinViewModel()
-  val appViewModelScope = appViewModel.viewModelScope
-  // Set initial main content pane to "Devices"
-  var navigationIndex by remember { mutableIntStateOf(1) }
-  val localWindowAdaptiveInfo = currentWindowAdaptiveInfo()
-  val windowSizeClass = localWindowAdaptiveInfo.windowSizeClass
-  val widthSizeClass = windowSizeClass.windowWidthSizeClass
-
-  val dotenv = dotenvVault {
-    directory = "../temerity"
-  }
-  val pc: Temerity = getKoin().get(parameters = { parametersOf(dotenv["YUJAPROD_API_URL"], dotenv["YUJAPROD_TOKEN"]) })
-  var devicesList by remember { mutableStateOf(listOf<Device>()) }
-  var usersList by remember { mutableStateOf(listOf<User>()) }
-  var coursesList by remember { mutableStateOf(listOf<Course>()) }
-  var searchQuery by remember { mutableStateOf(String()) }
-
-  LaunchedEffect(pc) {
-    appViewModelScope.launch {
-      withContext(IO) {
-        devicesList = pc.getDevices().sortedBy { it.stationName }
-        usersList = pc.getUsers().sortedBy { it.lastName }
-        coursesList = pc.getCourses()
-      }
-    }
-  }
-
-  val userDetailViewController = rememberNavController()
-  val userDetailViewGraph = userDetailViewController.createGraph(
-    startDestination = BlankScreen,
-  ) {
-    composable<BlankScreen> {
-      Box {
-      }
-    }
-    composable<EditScreen> {
-      val args = it.toRoute<EditScreen>()
-      val user = Json.decodeFromString<User>(args.user)
-      Box {
-        UserEditScreen(
-          user = user,
-        )
-      }
-    }
-  }
-
-  val contentPaneNavController = rememberNavController()
-  val contentPaneNavGraph = contentPaneNavController.createGraph(
-    startDestination = Devices,
-  ) {
-    composable<Notifications> {
-      // NotificationsScreen()
-    }
-    composable<Devices> {
-      DeviceList(
-        devicesList,
-      )
-    }
-    composable<Roster> {
-      UserList(
-        usersList,
-      ) {
-        userDetailViewController.popBackStack()
-        userDetailViewController.navigate(EditScreen(Json.encodeToString(it)))
-      }
-    }
-    composable<Courses> {
-      CoursesList(
-        coursesList,
-      ) {
-      }
-    }
-    composable<Settings> {
-      // SettingsScreen()
-    }
-  }
-
-  val navigationItems = listOf(
-    mapOf("icon" to Outlined.Notifications, "label" to if (widthSizeClass == WindowWidthSizeClass.COMPACT) string.notifications_short else string.notifications, "route" to Notifications),
-    mapOf("icon" to Outlined.AdUnits, "label" to string.devices, "route" to Devices),
-    mapOf("icon" to Outlined.Contacts, "label" to string.roster, "route" to Roster),
-    mapOf("icon" to Outlined.Group, "label" to string.courses, "route" to Courses),
-    mapOf("icon" to Outlined.Settings, "label" to string.settings, "route" to Settings),
-  )
-
-  if (widthSizeClass == WindowWidthSizeClass.COMPACT) {
-    CompactScreen(
-      modifier = modifier,
-      navigationIndex = navigationIndex,
-      navigationItems = navigationItems,
-      contentPaneNavController = contentPaneNavController,
-      contentPaneNavGraph = contentPaneNavGraph,
-      onSelectNavigationMenuItem = { index, route ->
-        navigationIndex = index
-        contentPaneNavController.popBackStack()
-        contentPaneNavController.navigate(route)
-      },
-    )
-  } else {
-    ExpandedScreen(
-      modifier = modifier,
-      navigationIndex = navigationIndex,
-      navigationItems = navigationItems,
-      contentPaneNavController = contentPaneNavController,
-      contentPaneNavGraph = contentPaneNavGraph,
-      userDetailViewController = userDetailViewController,
-      userDetailViewGraph = userDetailViewGraph,
-      widthSizeClass = widthSizeClass,
-      onSelectNavigationMenuItem = { index, route ->
-        navigationIndex = index
-        contentPaneNavController.popBackStack()
-        contentPaneNavController.navigate(route)
-      },
-    )
-  }
-}
-
-@Composable
-fun CompactScreen(
-  navigationIndex: Int,
-  navigationItems: List<Map<String, Any>>,
-  contentPaneNavController: NavHostController,
-  contentPaneNavGraph: NavGraph,
-  modifier: Modifier = Modifier,
-  onSelectNavigationMenuItem: (Int, MainContentWindow) -> Unit,
-) {
-  Scaffold(modifier = Modifier.fillMaxHeight(), floatingActionButton = {
-    FloatingActionButton(onClick = { /* TODO */ }) {
-      Icon(Outlined.Edit, "Compose new message")
-    }
-  }, bottomBar = {
-    NavigationBar {
-      navigationItems.forEachIndexed { index, _ ->
-        val item = navigationItems[index]
-        val icon = item["icon"] as ImageVector
-        val label = item["label"] as StringResource
-        val route = item["route"] as MainContentWindow
-        NavigationBarItem(selected = index == navigationIndex, icon = { Icon(icon, null) }, label = { Text(stringResource(label)) }, onClick = {
-          if (index != navigationIndex) {
-            onSelectNavigationMenuItem(index, route)
-          }
-        })
-      }
-    }
-  }) { padding ->
-    ContentPanel(
-      contentPaneNavController = contentPaneNavController,
-      contentPaneNavGraph = contentPaneNavGraph,
-      modifier = Modifier.fillMaxSize().padding(padding),
-    )
-  }
-}
-
-@Composable
-fun ExpandedScreen(
-  navigationIndex: Int,
-  navigationItems: List<Map<String, Any>>,
-  contentPaneNavController: NavHostController,
-  contentPaneNavGraph: NavGraph,
-  userDetailViewController: NavHostController,
-  userDetailViewGraph: NavGraph,
-  widthSizeClass: WindowWidthSizeClass,
-  modifier: Modifier = Modifier,
-  onSelectNavigationMenuItem: (Int, MainContentWindow) -> Unit,
-) {
-  Scaffold(modifier = modifier.fillMaxHeight()) {
-    PermanentNavigationDrawer(drawerContent = {
-      Row {
-        PermanentDrawerSheet(Modifier.width(220.dp).padding(vertical = 24.dp)) {
-          Column {
-            ExtendedFloatingActionButton(
-              onClick = { /*TODO*/ },
-              modifier = Modifier.padding(horizontal = 12.dp),
-            ) {
-              Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start)) {
-                Icon(Outlined.Edit, null)
-                Text("Compose")
-              }
-            }
-            Spacer(Modifier.height(24.dp))
-            LazyColumn {
-              itemsIndexed(navigationItems) { index, _ ->
-                val item = navigationItems[index]
-                val icon = item["icon"] as ImageVector
-                val label = item["label"] as StringResource
-                val route = item["route"] as MainContentWindow
-                NavigationDrawerItem(
-                  modifier = Modifier.padding(horizontal = 16.dp),
-                  selected = index == navigationIndex,
-                  icon = { Icon(icon, null) },
-                  label = { Text(stringResource(label)) },
-                  onClick = {
-                    if (index != navigationIndex) {
-                      onSelectNavigationMenuItem(index, route)
-                    }
-                  },
-                )
-              }
-            }
-          }
-        }
-        HorizontalDivider(modifier = Modifier.width(1.dp).fillMaxHeight())
-      }
-    }, content = {
-      Row {
-        ContentPanel(
-          contentPaneNavController = contentPaneNavController,
-          contentPaneNavGraph = contentPaneNavGraph,
-          modifier = Modifier.weight(1f).fillMaxHeight(),
-        )
-        if (widthSizeClass == WindowWidthSizeClass.EXPANDED) {
-          HorizontalDivider(modifier = Modifier.width(1.dp).fillMaxHeight())
-          DetailPanel(
-            detailPaneViewController = userDetailViewController,
-            detailPaneNavGraph = userDetailViewGraph,
-            modifier = Modifier.weight(1f).padding(top = 76.dp),
-          )
-        }
-      }
-    })
-  }
-}
-
-@Composable
-fun SearchBar(
-  searchQuery: String,
-  onSearchQueryChange: (String) -> Unit,
-  modifier: Modifier = Modifier,
-  onImeSearch: () -> Unit,
-) {
-  Box(modifier = modifier.padding(horizontal = 16.dp, vertical = 10.dp)) {
-    Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
-      OutlinedTextField(
-        colors = OutlinedTextFieldDefaults.colors(
-          unfocusedContainerColor = ComposeTheme.colorScheme.surface,
-          focusedContainerColor = ComposeTheme.colorScheme.surface,
-        ),
-        shape = RoundedCornerShape(100), placeholder = { Text("Search...") }, leadingIcon = {
-          Icon(imageVector = Rounded.Search, contentDescription = null, modifier = Modifier.minimumInteractiveComponentSize(), tint = ComposeTheme.colorScheme.onSurface.copy(alpha = 0.66f))
-        }, modifier = Modifier.weight(1f).minimumInteractiveComponentSize(), value = searchQuery, singleLine = true, keyboardActions = KeyboardActions(onSearch = { onImeSearch() }), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Search), onValueChange = onSearchQueryChange, trailingIcon = {
-          AnimatedVisibility(visible = searchQuery.isNotBlank(), enter = fadeIn(), exit = fadeOut()) {
-            IconButton(onClick = { onSearchQueryChange("") }) {
-              Icon(imageVector = Rounded.Clear, contentDescription = "Clear", tint = MaterialTheme.colorScheme.onSurface)
-            }
-          }
-        },
-      )
-    }
-  }
-}
-
-@Composable
-fun ContentPanel(contentPaneNavController: NavHostController, contentPaneNavGraph: NavGraph, modifier: Modifier = Modifier) {
-  var searchQuery = remember { mutableStateOf("") }
-  Column(modifier) {
-    SearchBar(
-      searchQuery = searchQuery.value,
-      onSearchQueryChange = {
-        searchQuery.value = it
-        contentPaneNavController.currentDestination!!.route?.let { currentNavDestination: String -> filterContent(currentNavDestination) }
-      },
-      onImeSearch = { /*TODO*/ },
-    )
-    Box(
-      modifier = Modifier
-        .weight(1f)
-        .fillMaxWidth()
-        .padding(16.dp)
-        .border(1.dp, ComposeTheme.colorScheme.outline, RoundedCornerShape(18.dp))
-        .clip(RoundedCornerShape(18.dp))
-        .background(ComposeTheme.colorScheme.surface),
-    ) {
-      NewNavHost(
-        navController = contentPaneNavController,
-        navGraph = contentPaneNavGraph,
-      )
-    }
-  }
-}
-
-@Composable
-fun DetailPanel(detailPaneViewController: NavHostController, detailPaneNavGraph: NavGraph, modifier: Modifier = Modifier) {
-  Box(
-    modifier
-      .fillMaxHeight()
-      .padding(16.dp)
-      .border(1.dp, ComposeTheme.colorScheme.outline, RoundedCornerShape(18.dp))
-      .clip(RoundedCornerShape(18.dp))
-      .background(ComposeTheme.colorScheme.surface),
-  ) {
-    NewNavHost(
-      navController = detailPaneViewController,
-      navGraph = detailPaneNavGraph,
-    )
-  }
-}
-
-fun filterContent(currentNavDestination: String) {
-//  when(contentPaneNavController.findDestination(currentNavDestination)) {
-//      is Devices -> {
-//        devicesList = devicesList.filter { it.stationName.contains(searchQuery, ignoreCase = true) }
-//      }
-//      is Roster -> {
-//        usersList = usersList.filter { it.loginId.contains(searchQuery, ignoreCase = true) }
-//      }
-//      is Courses -> {
-//        coursesList = coursesList.filter { it.courseCode.contains(searchQuery, ignoreCase = true) }
-//      }
-//
-//      Notifications -> TODO()
-//      Settings -> TODO()
-//  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/RootScreen.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/RootScreen.kt
deleted file mode 100644
index d88363d6f2fa94f954b0fed44a17df947c93cff8..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/RootScreen.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui
-
-import androidx.compose.runtime.Composable
-import androidx.navigation.compose.NavHost
-import androidx.navigation.compose.composable
-import androidx.navigation.compose.rememberNavController
-import androidx.navigation.createGraph
-import kotlinx.serialization.Serializable
-
-object TemerityWindow {
-  @Serializable
-  object Login
-
-  @Serializable
-  object Main
-}
-
-@Composable
-fun RootScreen() {
-  val navController = rememberNavController()
-  val navGraph = navController.createGraph(
-    startDestination = TemerityWindow.Login,
-  ) {
-    composable<TemerityWindow.Login> {
-      LoginScreen(onLogin = {
-        navController.navigate(TemerityWindow.Main)
-      })
-    }
-    composable<TemerityWindow.Main> {
-      MainScreen()
-    }
-  }
-
-  NavHost(
-    navController = navController,
-    graph = navGraph,
-  )
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/TemerityApp.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/TemerityApp.kt
deleted file mode 100644
index 2576730a378334602a2fc449d19e432b8ba93d96..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/TemerityApp.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui
-
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.Surface
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.composables.composetheme.ComposeTheme
-import com.composables.composetheme.material3.colorScheme
-import edu.ucsc.its.temerity.shared.data.repository.PlatformRepository
-import edu.ucsc.its.temerity.shared.di.initKoin
-import edu.ucsc.its.temerity.shared.ui.theme.DarkTheme
-import edu.ucsc.its.temerity.shared.ui.theme.LightTheme
-import edu.ucsc.its.temerity.shared.viewmodel.AppViewModel
-import edu.ucsc.its.temerity.shared.viewmodel.RootViewModel
-import org.koin.compose.koinInject
-import org.koin.compose.viewmodel.koinViewModel
-
-private val koin = initKoin().koin
-
-@Composable
-internal fun TemerityApp(
-  appStateViewModel: AppViewModel = koinViewModel(),
-  rootViewModel: RootViewModel = koinViewModel(),
-  platformRepository: PlatformRepository = koinInject(),
-) {
-  val appTheme = if (isSystemInDarkTheme()) DarkTheme else LightTheme
-
-  appTheme {
-    Surface(
-      modifier = Modifier.fillMaxSize(),
-      color = ComposeTheme.colorScheme.surface,
-    ) {
-      Box(modifier = Modifier.fillMaxSize()) {
-        RootScreen()
-      }
-    }
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/UserEditScreen.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/UserEditScreen.kt
deleted file mode 100644
index e38420cd7f146384f5c2ce2766757e0e1b64d974..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/UserEditScreen.kt
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.text.KeyboardActions
-import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.outlined.Abc
-import androidx.compose.material.icons.outlined.Cancel
-import androidx.compose.material.icons.outlined.Email
-import androidx.compose.material.icons.outlined.Person
-import androidx.compose.material.icons.outlined.Save
-import androidx.compose.material3.Checkbox
-import androidx.compose.material3.FloatingActionButton
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusDirection
-import androidx.compose.ui.platform.LocalFocusManager
-import androidx.compose.ui.text.input.ImeAction
-import androidx.compose.ui.text.input.KeyboardCapitalization
-import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.unit.dp
-import androidx.lifecycle.viewModelScope
-import com.composables.composetheme.ComposeTheme
-import com.composables.composetheme.material3.colorScheme
-import com.composables.composetheme.material3.typography
-import edu.ucsc.its.temerity.model.User
-import edu.ucsc.its.temerity.shared.ui.elements.DropdownMenu
-import edu.ucsc.its.temerity.shared.ui.elements.ScrollableContent
-import edu.ucsc.its.temerity.shared.viewmodel.UserEditViewModel
-import kotlinx.coroutines.launch
-import org.jetbrains.compose.resources.stringResource
-import org.koin.compose.viewmodel.koinViewModel
-import temerity.shared.compose.generated.resources.Res
-import temerity.shared.compose.generated.resources.clear_field
-import temerity.shared.compose.generated.resources.lock_user_role
-import temerity.shared.compose.generated.resources.save
-import temerity.shared.compose.generated.resources.user_edit
-
-@Composable
-fun UserEditScreen(
-  modifier: Modifier = Modifier,
-  user: User? = null,
-) {
-  val focusManager = LocalFocusManager.current
-  val viewmodel: UserEditViewModel = koinViewModel()
-  val viewModelScope = viewmodel.viewModelScope
-  LaunchedEffect(user) {
-    viewModelScope.launch { viewmodel.loadUser(user) }
-  }
-  val userEditState by viewmodel.models.collectAsState()
-
-  Scaffold(
-    floatingActionButton = {
-      FloatingActionButton(onClick = { viewModelScope.launch { viewmodel.saveUserEdits() } }) {
-        Icon(Icons.Outlined.Save, contentDescription = stringResource(Res.string.save))
-      }
-    },
-  ) {
-    ScrollableContent {
-      item {
-        Text(
-          text = stringResource(Res.string.user_edit),
-          modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 24.dp, bottom = 8.dp),
-          color = ComposeTheme.colorScheme.onSurface,
-          style = ComposeTheme.typography.titleMedium,
-        )
-      }
-      item {
-        val fieldName = "firstName"
-        Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp)) {
-          Icon(Icons.Outlined.Person, null)
-          OutlinedTextField(
-            modifier = Modifier.weight(1f),
-            label = { Text("First name") },
-            value = userEditState.firstName,
-            onValueChange = { viewModelScope.launch { viewmodel.updateField(fieldName, it) } },
-            singleLine = true,
-            trailingIcon = {
-              AnimatedVisibility(visible = userEditState.firstName.isNotBlank(), enter = fadeIn(), exit = fadeOut()) {
-                IconButton(onClick = { viewModelScope.launch { viewmodel.clearField(fieldName) } }) {
-                  Icon(Icons.Outlined.Cancel, stringResource(Res.string.clear_field))
-                }
-              }
-            },
-            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Next, capitalization = KeyboardCapitalization.Words),
-            keyboardActions = KeyboardActions {
-              focusManager.moveFocus(FocusDirection.Next)
-            },
-          )
-        }
-      }
-      item {
-        val fieldName = "lastName"
-        Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp)) {
-          Box(Modifier.size(24.dp))
-          OutlinedTextField(
-            modifier = Modifier.weight(1f),
-            label = { Text("Last name") },
-            value = userEditState.lastName,
-            onValueChange = { viewModelScope.launch { viewmodel.updateField(fieldName, it) } },
-            singleLine = true,
-            trailingIcon = {
-              AnimatedVisibility(visible = userEditState.lastName.isNotBlank(), enter = fadeIn(), exit = fadeOut()) {
-                IconButton(onClick = { viewModelScope.launch { viewmodel.clearField(fieldName) } }) {
-                  Icon(Icons.Outlined.Cancel, stringResource(Res.string.clear_field))
-                }
-              }
-            },
-            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Next, capitalization = KeyboardCapitalization.Words),
-            keyboardActions = KeyboardActions {
-              focusManager.moveFocus(FocusDirection.Next)
-            },
-          )
-        }
-      }
-      item { Spacer(Modifier.height(4.dp)) }
-      item {
-        val fieldName = "loginId"
-        Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp)) {
-          Icon(Icons.Outlined.Abc, null)
-          OutlinedTextField(
-            modifier = Modifier.weight(1f),
-            label = { Text("Login ID") },
-            value = userEditState.loginId,
-            onValueChange = { viewModelScope.launch { viewmodel.updateField(fieldName, it) } },
-            trailingIcon = {
-              AnimatedVisibility(visible = userEditState.loginId.isNotBlank(), enter = fadeIn(), exit = fadeOut()) {
-                IconButton(onClick = { viewModelScope.launch { viewmodel.clearField(fieldName) } }) {
-                  Icon(Icons.Outlined.Cancel, stringResource(Res.string.clear_field))
-                }
-              }
-            },
-            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Next),
-            keyboardActions = KeyboardActions {
-              focusManager.moveFocus(FocusDirection.Next)
-            },
-            singleLine = true,
-          )
-        }
-      }
-      item { Spacer(Modifier.height(4.dp)) }
-      item {
-        val fieldName = "emailAddress"
-        Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp)) {
-          Icon(Icons.Outlined.Email, null)
-          OutlinedTextField(
-            modifier = Modifier.weight(1f),
-            label = { Text("Email Address") },
-            value = userEditState.emailAddress,
-            onValueChange = { viewModelScope.launch { viewmodel.updateField(fieldName, it) } },
-            trailingIcon = {
-              AnimatedVisibility(visible = userEditState.emailAddress.isNotBlank(), enter = fadeIn(), exit = fadeOut()) {
-                IconButton(onClick = { viewModelScope.launch { viewmodel.clearField(fieldName) } }) {
-                  Icon(Icons.Outlined.Cancel, stringResource(Res.string.clear_field))
-                }
-              }
-            },
-            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email, imeAction = ImeAction.Done),
-            keyboardActions = KeyboardActions {
-              focusManager.clearFocus()
-            },
-            singleLine = true,
-          )
-        }
-      }
-      item { Spacer(Modifier.height(4.dp)) }
-      item {
-        Text(
-          text = "Timezone",
-          modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 24.dp, bottom = 8.dp),
-          color = ComposeTheme.colorScheme.onSurface,
-          style = ComposeTheme.typography.titleMedium,
-        )
-      }
-      item {
-        DropdownMenu(
-          items = listOf(
-            "America/Los_Angeles",
-            "America/New_York",
-            "Canada/East",
-          ),
-          onSelectItem = {},
-          modifier = Modifier.height(40.dp).fillMaxWidth(),
-        )
-      }
-      item {
-        Text(text = "User Role", style = ComposeTheme.typography.titleMedium, modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 24.dp, bottom = 8.dp))
-      }
-      item {
-        DropdownMenu(
-          items = listOf(
-            "Student",
-            "Instructor",
-            "IT Manager",
-          ),
-          onSelectItem = {},
-          modifier = Modifier.height(40.dp).fillMaxWidth(),
-        )
-      }
-      item {
-        Text(
-          text = "Extra Options",
-          modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 24.dp, bottom = 8.dp),
-          color = ComposeTheme.colorScheme.onSurface,
-          style = ComposeTheme.typography.titleMedium,
-        )
-      }
-      item {
-        var selected by remember { mutableStateOf(false) }
-        Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp), modifier = Modifier.clickable { selected = selected.not() }.fillMaxWidth().padding(16.dp)) {
-          Checkbox(checked = selected, onCheckedChange = null)
-          Text(text = stringResource(Res.string.lock_user_role))
-        }
-      }
-    }
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/CoursesElements.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/CoursesElements.kt
deleted file mode 100644
index ef978524114922aa5b4068b419f4e3db96e66740..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/CoursesElements.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material.Text
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Edit
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.LinkAnnotation
-import androidx.compose.ui.text.buildAnnotatedString
-import androidx.compose.ui.text.withLink
-import androidx.compose.ui.unit.dp
-import com.composables.composetheme.ComposeTheme
-import com.composables.composetheme.material3.colorScheme
-import com.composables.composetheme.material3.typography
-import edu.ucsc.its.temerity.model.Course
-import org.jetbrains.compose.resources.stringResource
-import temerity.shared.compose.generated.resources.Res
-import temerity.shared.compose.generated.resources.course_code_prefix
-import temerity.shared.compose.generated.resources.course_edit
-import temerity.shared.compose.generated.resources.direct_course_link_prefix
-import temerity.shared.compose.generated.resources.term_code_prefix
-
-@Preview
-@Composable
-private fun CoursesListPreview() {
-  val mockCourseList = listOf(
-    Course(),
-    Course(),
-    Course(),
-  )
-  PreviewThemeWrapper {
-    CoursesList(courseList = mockCourseList) {}
-  }
-}
-
-@Composable
-fun CoursesList(courseList: List<Course>, onEditClick: (Course) -> Unit) {
-  ScrollableList(courseList) {
-    CourseCardRow(course = it) {
-      onEditClick(it)
-    }
-  }
-}
-
-@Composable
-fun CourseCardRow(course: Course, modifier: Modifier = Modifier, onEditClick: () -> Unit) {
-  CardRow(
-    title = course.courseName,
-    subtitle = stringResource(Res.string.course_code_prefix) + course.courseCode,
-  ) {
-    LazyColumn(
-      verticalArrangement = Arrangement.spacedBy(16.dp),
-      modifier = modifier.height(190.dp),
-      contentPadding = PaddingValues(vertical = 8.dp),
-    ) {
-      item {
-        Row(
-          verticalAlignment = Alignment.CenterVertically,
-          horizontalArrangement = Arrangement.SpaceBetween,
-          modifier = Modifier.fillMaxWidth(),
-        ) {
-          Column {
-            Text(
-              text = stringResource(Res.string.term_code_prefix) + course.courseTerm,
-              color = ComposeTheme.colorScheme.primary,
-              style = ComposeTheme.typography.bodyMedium,
-            )
-            Spacer(modifier = Modifier.width(4.dp).background(ComposeTheme.colorScheme.background))
-            val directCourseLinkPrefix = stringResource(Res.string.direct_course_link_prefix)
-            val courseLinkText = remember {
-              buildAnnotatedString {
-                append(directCourseLinkPrefix)
-                withLink(
-                  link = LinkAnnotation.Url(
-                    url = course.directLink,
-                  ),
-                ) {
-                  append(" ")
-                  append(course.directLink)
-                }
-              }
-            }
-            Text(
-              text = courseLinkText,
-              color = ComposeTheme.colorScheme.primary,
-              style = ComposeTheme.typography.bodyMedium,
-            )
-          }
-          IconButton(
-            onClick = onEditClick,
-            modifier = Modifier.padding(8.dp),
-          ) {
-            Icon(imageVector = Icons.Default.Edit, contentDescription = stringResource(Res.string.course_edit))
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/DeviceElements.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/DeviceElements.kt
deleted file mode 100644
index 005a10c0f010066d0b201cb8a0ed687f1c94cf32..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/DeviceElements.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import com.composables.composetheme.ComposeTheme
-import com.composables.composetheme.material3.colorScheme
-import com.composables.composetheme.material3.typography
-import edu.ucsc.its.temerity.model.Device
-
-@Preview
-@Composable
-private fun DeviceListPreview() {
-  val deviceList = listOf(
-    Device(stationName = "oak105-capture-2.ucsc.edu", stationType = "hub"),
-    Device(stationName = "psb110-capture-2.ucsc.edu", stationType = "hub"),
-    Device(stationName = "krs3105-capture-2.ucsc.edu", stationType = "hub"),
-  )
-  PreviewThemeWrapper {
-    DeviceList(deviceList)
-  }
-}
-
-@Composable
-fun DeviceList(deviceList: List<Device>) {
-  ScrollableList(deviceList) {
-    DeviceCardRow(device = it)
-  }
-}
-
-@Composable
-fun DeviceCardRow(device: Device, modifier: Modifier = Modifier) {
-  CardRow(
-    title = device.stationName,
-    subtitle = if (device.stationType == "hub") "HUB Device" else "3rd Party Device",
-  ) {
-    LazyColumn(
-      verticalArrangement = Arrangement.spacedBy(16.dp),
-      modifier = modifier.height(190.dp),
-      contentPadding = PaddingValues(vertical = 8.dp),
-    ) {
-      item {
-        Text(
-          text = "Status:",
-          color = ComposeTheme.colorScheme.primary,
-          style = ComposeTheme.typography.bodyMedium,
-        )
-        Spacer(modifier = Modifier.width(4.dp).background(ComposeTheme.colorScheme.background))
-        Text(
-          text = "Sessions recording this term:",
-          color = ComposeTheme.colorScheme.primary,
-          style = ComposeTheme.typography.bodyMedium,
-        )
-      }
-    }
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ExpectedUiElements.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ExpectedUiElements.kt
deleted file mode 100644
index 2679727077c5264292d6ea222fbbd3a4512791b1..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ExpectedUiElements.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.foundation.ScrollbarStyle
-import androidx.compose.foundation.lazy.LazyListState
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.KeyEventType
-import androidx.compose.ui.input.key.key
-import androidx.compose.ui.input.key.onKeyEvent
-import androidx.compose.ui.input.key.type
-import androidx.compose.ui.unit.Dp
-
-internal expect val MARGIN_SCROLLBAR: Dp
-internal expect interface ScrollbarAdapter
-
-@Composable
-internal expect fun rememberScrollbarAdapter(scrollState: LazyListState): ScrollbarAdapter
-
-@Composable
-internal expect fun VerticalScrollbar(
-  adapter: ScrollbarAdapter,
-  style: ScrollbarStyle,
-  modifier: Modifier = Modifier,
-)
-
-internal fun Modifier.onKeyUp(key: Key, action: () -> Unit): Modifier =
-  onKeyEvent { event ->
-    if ((event.type == KeyEventType.KeyUp) && (event.key == key)) {
-      action()
-      true
-    } else {
-      false
-    }
-  }
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/Gradient.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/Gradient.kt
deleted file mode 100644
index da28767224aaafd3dd952aba5cc9102ebcc1151e..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/Gradient.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.drawWithContent
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Brush
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.layout.Layout
-
-// Based on code snippet available at: https://gist.github.com/SEAbdulbasit/5cfe055294e13cbb18bb202369f1a8d6
-
-@Composable
-fun Gradient(modifier: Modifier = Modifier) {
-  Layout(
-    content = {
-      Box(
-        modifier = Modifier.fillMaxSize().drawWithContent {
-          drawRect(
-            Brush.radialGradient(
-              colors = listOf(
-                Color(0xff3e91f0),
-                Color.Transparent,
-              ),
-              center = Offset(this.size.width * 0.05f, this.size.height / 2),
-              radius = size.width * 2,
-            ),
-          )
-        },
-      )
-      Box(
-        modifier = Modifier.fillMaxSize().drawWithContent {
-          drawRect(
-            Brush.radialGradient(
-              colors = listOf(
-                Color(0xffFF8A58),
-                Color.Transparent,
-              ),
-              center = Offset(0f, this.size.height),
-              radius = size.height,
-            ),
-          )
-        },
-      )
-      Box(
-        modifier = Modifier.fillMaxSize().drawWithContent {
-          drawRect(
-            Brush.radialGradient(
-              colors = listOf(
-                Color(0xff58EBFF),
-                Color.Transparent,
-              ),
-              center = Offset(
-                this.size.width * 1.1f,
-                this.size.height * .100f,
-              ),
-              radius = size.height,
-            ),
-          )
-        },
-      )
-      Box(
-        modifier = Modifier.fillMaxSize().drawWithContent {
-          drawRect(
-            Brush.radialGradient(
-              colors = listOf(
-                Color(0xff8c54eb),
-                Color.Transparent,
-              ),
-              center = Offset(
-                this.size.width,
-                this.size.height * 0.9f,
-              ),
-              radius = size.height,
-            ),
-          )
-        },
-      )
-    },
-    measurePolicy = { measurables, constraints ->
-      val placeables = measurables.map { it.measure(constraints) }
-      layout(constraints.maxWidth, constraints.maxHeight) {
-        placeables.forEach { it.place(0, 0) }
-      }
-    },
-    modifier = modifier,
-  )
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/PreviewThemeWrapper.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/PreviewThemeWrapper.kt
deleted file mode 100644
index f45362a73f83681fb1f2776fe78ddc7d937054e9..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/PreviewThemeWrapper.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.width
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import edu.ucsc.its.temerity.shared.ui.theme.DarkTheme
-import edu.ucsc.its.temerity.shared.ui.theme.LightTheme
-
-@Composable
-internal fun PreviewThemeWrapper(
-  modifier: Modifier = Modifier,
-  height: Dp = 480.dp,
-  width: Dp = 640.dp,
-  content: @Composable () -> Unit,
-) {
-  @Suppress("PropertyName")
-  val AppTheme = if (isSystemInDarkTheme()) DarkTheme else LightTheme
-  AppTheme {
-    Box(
-      modifier.apply {
-        height(height)
-        width(width)
-      },
-    ) {
-      content()
-    }
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/UserElements.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/UserElements.kt
deleted file mode 100644
index 8bf8bf112f5c726cced7e7236e421508f0455a3c..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/UserElements.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material.Text
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Edit
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import com.composables.composetheme.ComposeTheme
-import com.composables.composetheme.material3.colorScheme
-import com.composables.composetheme.material3.typography
-import edu.ucsc.its.temerity.model.User
-import org.jetbrains.compose.resources.stringResource
-import temerity.shared.compose.generated.resources.Res
-import temerity.shared.compose.generated.resources.user_edit
-
-@Preview
-@Composable
-private fun UserListPreview() {
-  val mockUserList = listOf(
-    User(),
-    User(),
-    User(),
-  )
-  PreviewThemeWrapper {
-    UserList(userList = mockUserList) {}
-  }
-}
-
-@Composable
-fun UserList(userList: List<User>, onEditClick: (User) -> Unit) {
-  ScrollableList(userList) {
-    UserCardRow(user = it, onEditClick = { onEditClick(it) })
-  }
-}
-
-@Composable
-fun UserCardRow(user: User, modifier: Modifier = Modifier, onEditClick: () -> Unit) {
-  Box(modifier = modifier) {
-    CardRow(
-      title = user.loginId,
-      subtitle = "Role: ${user.userType}",
-    ) {
-      LazyColumn(
-        verticalArrangement = Arrangement.spacedBy(16.dp),
-        modifier = Modifier.height(190.dp),
-        contentPadding = PaddingValues(vertical = 8.dp),
-      ) {
-        item {
-          Row(
-            verticalAlignment = Alignment.CenterVertically,
-            horizontalArrangement = Arrangement.SpaceBetween,
-            modifier = Modifier.fillMaxWidth(),
-          ) {
-            Column {
-              Text(
-                text = "Name: ${user.firstName} ${user.lastName}",
-                color = ComposeTheme.colorScheme.primary,
-                style = ComposeTheme.typography.bodyLarge,
-              )
-              Spacer(modifier = Modifier.width(4.dp).background(ComposeTheme.colorScheme.background))
-              Text(
-                text = "Login email: ${user.emailAddress}",
-                color = ComposeTheme.colorScheme.primary,
-                style = ComposeTheme.typography.bodyLarge,
-              )
-            }
-            IconButton(
-              onClick = onEditClick,
-              modifier = Modifier.padding(8.dp),
-            ) {
-              Icon(imageVector = Icons.Default.Edit, contentDescription = stringResource(Res.string.user_edit))
-            }
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/Utility.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/Utility.kt
deleted file mode 100644
index 2e90100e7cba0a07ddaee01d70ec1229bcffec7b..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/Utility.kt
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.AnimatedVisibilityScope
-import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.slideInHorizontally
-import androidx.compose.animation.slideOutHorizontally
-import androidx.compose.animation.slideOutVertically
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.ScrollbarStyle
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.gestures.draggable
-import androidx.compose.foundation.gestures.rememberDraggableState
-import androidx.compose.foundation.gestures.scrollBy
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.heightIn
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.layout.widthIn
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.LazyItemScope
-import androidx.compose.foundation.lazy.LazyListScope
-import androidx.compose.foundation.lazy.items
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.text.BasicText
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.rounded.ChevronRight
-import androidx.compose.material3.CardDefaults
-import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.OutlinedCard
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.rotate
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.PathFillType
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.StrokeCap
-import androidx.compose.ui.graphics.StrokeJoin
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.graphics.vector.path
-import androidx.compose.ui.layout.onSizeChanged
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.toSize
-import androidx.navigation.NavGraph
-import androidx.navigation.NavHostController
-import androidx.navigation.compose.NavHost
-import com.composables.composetheme.ComposeTheme
-import com.composables.composetheme.material3.colorScheme
-import com.composables.composetheme.material3.typography
-import com.composables.core.Menu
-import com.composables.core.MenuButton
-import com.composables.core.MenuContent
-import com.composables.core.MenuItem
-import com.composables.core.rememberMenuState
-import kotlinx.coroutines.launch
-
-/**
- * A composable function that creates a box with an adaptive aspect ratio.
- * The box maintains a specified aspect ratio until it reaches a maximum height,
- * beyond which the width can grow indefinitely while the height remains constant.
- *
- * @param modifier The [Modifier] to be applied to the box.
- * @param maxHeight The maximum height of the box in pixels. Once this height is reached, the width can grow indefinitely.
- * @param aspectRatio The aspect ratio (width / height) to maintain until the maximum height is reached.
- * @param content The content to be displayed inside the box. This is a composable lambda.
- */
-@Composable
-fun AdaptiveAspectRatioBox(
-  modifier: Modifier = Modifier,
-  maxHeight: Float = 250f,
-  aspectRatio: Float = 16f / 9f,
-  content: @Composable () -> Unit,
-) {
-  var size by remember { mutableStateOf(Size.Zero) }
-  val maxWidth = if (size.height >= maxHeight) Float.POSITIVE_INFINITY else maxHeight * aspectRatio
-
-  Box(
-    modifier = modifier
-      .onSizeChanged {
-        size = it.toSize()
-      }
-      .widthIn(max = maxWidth.dp)
-      .heightIn(max = maxHeight.dp),
-  ) {
-    content()
-  }
-}
-
-@Composable
-fun ScrollableContent(modifier: Modifier = Modifier, content: LazyListScope.() -> Unit) {
-  val unHoverColor = ComposeTheme.colorScheme.surfaceContainerHighest
-  val hoverColor = ComposeTheme.colorScheme.secondaryContainer
-  val scrollbarStyle = ScrollbarStyle(
-    minimalHeight = 32.dp,
-    thickness = 12.dp,
-    shape = RoundedCornerShape(8.dp),
-    hoverDurationMillis = 160,
-    unhoverColor = unHoverColor,
-    hoverColor = hoverColor,
-  )
-
-  val scrollState = rememberLazyListState()
-  val coroutineScope = rememberCoroutineScope()
-
-  Box(modifier = modifier.fillMaxSize()) {
-    LazyColumn(
-      modifier = Modifier
-        .draggable(
-          orientation = Orientation.Horizontal,
-          state = rememberDraggableState { delta ->
-            coroutineScope.launch {
-              scrollState.scrollBy(-delta)
-            }
-          },
-        )
-        .padding(horizontal = 4.dp),
-      state = scrollState,
-      verticalArrangement = Arrangement.spacedBy(12.dp),
-      contentPadding = PaddingValues(horizontal = 24.dp, vertical = 24.dp),
-    ) {
-      content()
-    }
-    VerticalScrollbar(
-      adapter = rememberScrollbarAdapter(scrollState),
-      modifier = Modifier
-        .align(Alignment.CenterEnd)
-        .fillMaxHeight()
-        .padding(MARGIN_SCROLLBAR),
-      style = scrollbarStyle,
-    )
-  }
-}
-
-@Composable
-fun <T> ScrollableList(items: List<T> = emptyList(), itemLayout: @Composable LazyItemScope.(T) -> Unit) {
-  val scrollableListItems = remember { mutableStateOf(items) }
-  ScrollableContent {
-    items(scrollableListItems.value) { item ->
-      itemLayout(item)
-    }
-  }
-}
-
-@Composable
-fun CardRow(
-  title: String,
-  subtitle: String,
-  modifier: Modifier = Modifier,
-  content: @Composable AnimatedVisibilityScope.() -> Unit,
-) {
-  val textColor = ComposeTheme.colorScheme.primary
-  val spacerColor = ComposeTheme.colorScheme.background
-
-  OutlinedCard {
-    var expanded by remember { mutableStateOf(false) }
-    val degrees by animateFloatAsState(if (expanded) -90f else 90f)
-
-    Column(
-      modifier = modifier
-        .fillMaxWidth()
-        .widthIn(min = 200.dp, max = 400.dp),
-    ) {
-      AdaptiveAspectRatioBox(
-        modifier = Modifier
-          .clip(CardDefaults.outlinedShape),
-      ) {
-        Gradient()
-      }
-      Column(Modifier.padding(start = 16.dp, end = 16.dp)) {
-        Row(verticalAlignment = Alignment.CenterVertically) {
-          Text(
-            text = title,
-            color = textColor,
-            style = ComposeTheme.typography.titleLarge,
-            modifier = Modifier.weight(1f),
-            maxLines = 1,
-            overflow = TextOverflow.Ellipsis,
-          )
-          IconButton(onClick = { expanded = expanded.not() }) {
-            Icon(
-              imageVector = Icons.Rounded.ChevronRight,
-              contentDescription = if (expanded) "Hide details" else "Show more details",
-              modifier = Modifier.rotate(degrees),
-            )
-          }
-        }
-        Row {
-          Text(
-            text = subtitle,
-            color = textColor,
-          )
-          Spacer(
-            modifier = Modifier
-              .width(8.dp)
-              .background(spacerColor),
-          )
-        }
-        Spacer(
-          modifier = Modifier
-            .height(16.dp)
-            .background(spacerColor),
-        )
-        Box {
-          this@Column.AnimatedVisibility(visible = expanded) {
-            content()
-          }
-          this@Column.AnimatedVisibility(visible = expanded) {
-            HorizontalDivider()
-          }
-        }
-      }
-    }
-  }
-}
-
-@Composable
-fun NewNavHost(navController: NavHostController, navGraph: NavGraph) = NavHost(
-  navController,
-  navGraph,
-  enterTransition = {
-    fadeIn() + slideInHorizontally(initialOffsetX = { it / 2 })
-  },
-  exitTransition = {
-    fadeOut() + slideOutHorizontally(targetOffsetX = { it / 2 })
-  },
-  popExitTransition = {
-    fadeOut() + slideOutVertically(targetOffsetY = { -it })
-  },
-)
-
-@Composable
-fun chevronDown(): ImageVector {
-  val iconColor = ComposeTheme.colorScheme.onSurface
-  return remember {
-    ImageVector.Builder(
-      name = "ChevronDown",
-      defaultWidth = 16.dp,
-      defaultHeight = 16.dp,
-      viewportWidth = 24f,
-      viewportHeight = 24f,
-    ).apply {
-      path(
-        fill = null,
-        fillAlpha = 1.0f,
-        stroke = SolidColor(iconColor),
-        strokeAlpha = 1.0f,
-        strokeLineWidth = 2f,
-        strokeLineCap = StrokeCap.Round,
-        strokeLineJoin = StrokeJoin.Round,
-        strokeLineMiter = 1.0f,
-        pathFillType = PathFillType.NonZero,
-      ) {
-        moveTo(6f, 9f)
-        lineToRelative(6f, 6f)
-        lineToRelative(6f, -6f)
-      }
-    }.build()
-  }
-}
-
-@Composable
-fun DropdownMenu(
-  items: List<String>,
-  onSelectItem: (String) -> Unit,
-  modifier: Modifier = Modifier,
-) {
-  val state = rememberMenuState(expanded = false)
-  var selectedItem by remember { mutableStateOf("Select") }
-  val surfaceColor = ComposeTheme.colorScheme.surface
-  val textColor = ComposeTheme.colorScheme.onSurface
-
-  Box(modifier = modifier) {
-    Menu(modifier = Modifier.align(Alignment.TopStart).width(240.dp), state = state) {
-      val degrees by animateFloatAsState(if (state.expanded) -180f else 0f)
-
-      MenuButton(
-        Modifier.clip(RoundedCornerShape(6.dp)).background(surfaceColor)
-          .border(1.dp, Color(0xFFBDBDBD), RoundedCornerShape(6.dp)),
-      ) {
-        Row(
-          verticalAlignment = Alignment.CenterVertically,
-          modifier = Modifier.padding(horizontal = 14.dp, vertical = 10.dp),
-        ) {
-          BasicText(selectedItem, modifier = Modifier.widthIn(min = 160.dp), style = TextStyle(fontWeight = FontWeight(500), color = textColor))
-          Spacer(Modifier.width(4.dp))
-          Image(chevronDown(), null, Modifier.rotate(degrees))
-        }
-      }
-
-      MenuContent(
-        modifier = Modifier.padding(top = 4.dp).width(320.dp).clip(RoundedCornerShape(6.dp))
-          .border(1.dp, Color(0xFFE0E0E0), RoundedCornerShape(6.dp)).background(surfaceColor).padding(4.dp),
-        exit = fadeOut(),
-      ) {
-        items.forEach {
-          MenuItem(modifier = Modifier.clip(RoundedCornerShape(6.dp)), onClick = {
-            selectedItem = it
-            onSelectItem(it)
-          }) {
-            BasicText(it, Modifier.fillMaxWidth().padding(vertical = 10.dp, horizontal = 10.dp), style = TextStyle(color = textColor))
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Color.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Color.kt
deleted file mode 100644
index f84d587f644d8c362e4f3cf3fda6840acc2c4f2d..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Color.kt
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.theme
-
-import androidx.compose.ui.graphics.Color
-
-internal val primaryLight = Color(0xFF3A608F)
-internal val onPrimaryLight = Color(0xFFFFFFFF)
-internal val primaryContainerLight = Color(0xFFD3E4FF)
-internal val onPrimaryContainerLight = Color(0xFF001C38)
-internal val secondaryLight = Color(0xFF755B0B)
-internal val onSecondaryLight = Color(0xFFFFFFFF)
-internal val secondaryContainerLight = Color(0xFFFFDF93)
-internal val onSecondaryContainerLight = Color(0xFF241A00)
-internal val tertiaryLight = Color(0xFF7B580D)
-internal val onTertiaryLight = Color(0xFFFFFFFF)
-internal val tertiaryContainerLight = Color(0xFFFFDEA9)
-internal val onTertiaryContainerLight = Color(0xFF271900)
-internal val errorLight = Color(0xFFBA1A1A)
-internal val onErrorLight = Color(0xFFFFFFFF)
-internal val errorContainerLight = Color(0xFFFFDAD6)
-internal val onErrorContainerLight = Color(0xFF410002)
-internal val backgroundLight = Color(0xFFF8F9FF)
-internal val onBackgroundLight = Color(0xFF191C20)
-internal val surfaceLight = Color(0xFFF8F9FF)
-internal val onSurfaceLight = Color(0xFF191C20)
-internal val surfaceVariantLight = Color(0xFFDFE2EB)
-internal val onSurfaceVariantLight = Color(0xFF43474E)
-internal val outlineLight = Color(0xFF73777F)
-internal val outlineVariantLight = Color(0xFFC3C6CF)
-internal val scrimLight = Color(0xFF000000)
-internal val inverseSurfaceLight = Color(0xFF2E3035)
-internal val inverseOnSurfaceLight = Color(0xFFEFF0F7)
-internal val inversePrimaryLight = Color(0xFFA3C9FE)
-internal val surfaceDimLight = Color(0xFFD8DAE0)
-internal val surfaceBrightLight = Color(0xFFF8F9FF)
-internal val surfaceContainerLowestLight = Color(0xFFFFFFFF)
-internal val surfaceContainerLowLight = Color(0xFFF2F3FA)
-internal val surfaceContainerLight = Color(0xFFECEDF4)
-internal val surfaceContainerHighLight = Color(0xFFE7E8EE)
-internal val surfaceContainerHighestLight = Color(0xFFE1E2E8)
-
-internal val primaryLightMediumContrast = Color(0xFF194471)
-internal val onPrimaryLightMediumContrast = Color(0xFFFFFFFF)
-internal val primaryContainerLightMediumContrast = Color(0xFF5176A7)
-internal val onPrimaryContainerLightMediumContrast = Color(0xFFFFFFFF)
-internal val secondaryLightMediumContrast = Color(0xFF544000)
-internal val onSecondaryLightMediumContrast = Color(0xFFFFFFFF)
-internal val secondaryContainerLightMediumContrast = Color(0xFF8D7123)
-internal val onSecondaryContainerLightMediumContrast = Color(0xFFFFFFFF)
-internal val tertiaryLightMediumContrast = Color(0xFF593E00)
-internal val onTertiaryLightMediumContrast = Color(0xFFFFFFFF)
-internal val tertiaryContainerLightMediumContrast = Color(0xFF946E24)
-internal val onTertiaryContainerLightMediumContrast = Color(0xFFFFFFFF)
-internal val errorLightMediumContrast = Color(0xFF8C0009)
-internal val onErrorLightMediumContrast = Color(0xFFFFFFFF)
-internal val errorContainerLightMediumContrast = Color(0xFFDA342E)
-internal val onErrorContainerLightMediumContrast = Color(0xFFFFFFFF)
-internal val backgroundLightMediumContrast = Color(0xFFF8F9FF)
-internal val onBackgroundLightMediumContrast = Color(0xFF191C20)
-internal val surfaceLightMediumContrast = Color(0xFFF8F9FF)
-internal val onSurfaceLightMediumContrast = Color(0xFF191C20)
-internal val surfaceVariantLightMediumContrast = Color(0xFFDFE2EB)
-internal val onSurfaceVariantLightMediumContrast = Color(0xFF3F434A)
-internal val outlineLightMediumContrast = Color(0xFF5B5F67)
-internal val outlineVariantLightMediumContrast = Color(0xFF777B83)
-internal val scrimLightMediumContrast = Color(0xFF000000)
-internal val inverseSurfaceLightMediumContrast = Color(0xFF2E3035)
-internal val inverseOnSurfaceLightMediumContrast = Color(0xFFEFF0F7)
-internal val inversePrimaryLightMediumContrast = Color(0xFFA3C9FE)
-internal val surfaceDimLightMediumContrast = Color(0xFFD8DAE0)
-internal val surfaceBrightLightMediumContrast = Color(0xFFF8F9FF)
-internal val surfaceContainerLowestLightMediumContrast = Color(0xFFFFFFFF)
-internal val surfaceContainerLowLightMediumContrast = Color(0xFFF2F3FA)
-internal val surfaceContainerLightMediumContrast = Color(0xFFECEDF4)
-internal val surfaceContainerHighLightMediumContrast = Color(0xFFE7E8EE)
-internal val surfaceContainerHighestLightMediumContrast = Color(0xFFE1E2E8)
-
-internal val primaryLightHighContrast = Color(0xFF002344)
-internal val onPrimaryLightHighContrast = Color(0xFFFFFFFF)
-internal val primaryContainerLightHighContrast = Color(0xFF194471)
-internal val onPrimaryContainerLightHighContrast = Color(0xFFFFFFFF)
-internal val secondaryLightHighContrast = Color(0xFF2D2100)
-internal val onSecondaryLightHighContrast = Color(0xFFFFFFFF)
-internal val secondaryContainerLightHighContrast = Color(0xFF544000)
-internal val onSecondaryContainerLightHighContrast = Color(0xFFFFFFFF)
-internal val tertiaryLightHighContrast = Color(0xFF301F00)
-internal val onTertiaryLightHighContrast = Color(0xFFFFFFFF)
-internal val tertiaryContainerLightHighContrast = Color(0xFF593E00)
-internal val onTertiaryContainerLightHighContrast = Color(0xFFFFFFFF)
-internal val errorLightHighContrast = Color(0xFF4E0002)
-internal val onErrorLightHighContrast = Color(0xFFFFFFFF)
-internal val errorContainerLightHighContrast = Color(0xFF8C0009)
-internal val onErrorContainerLightHighContrast = Color(0xFFFFFFFF)
-internal val backgroundLightHighContrast = Color(0xFFF8F9FF)
-internal val onBackgroundLightHighContrast = Color(0xFF191C20)
-internal val surfaceLightHighContrast = Color(0xFFF8F9FF)
-internal val onSurfaceLightHighContrast = Color(0xFF000000)
-internal val surfaceVariantLightHighContrast = Color(0xFFDFE2EB)
-internal val onSurfaceVariantLightHighContrast = Color(0xFF20242B)
-internal val outlineLightHighContrast = Color(0xFF3F434A)
-internal val outlineVariantLightHighContrast = Color(0xFF3F434A)
-internal val scrimLightHighContrast = Color(0xFF000000)
-internal val inverseSurfaceLightHighContrast = Color(0xFF2E3035)
-internal val inverseOnSurfaceLightHighContrast = Color(0xFFFFFFFF)
-internal val inversePrimaryLightHighContrast = Color(0xFFE3ECFF)
-internal val surfaceDimLightHighContrast = Color(0xFFD8DAE0)
-internal val surfaceBrightLightHighContrast = Color(0xFFF8F9FF)
-internal val surfaceContainerLowestLightHighContrast = Color(0xFFFFFFFF)
-internal val surfaceContainerLowLightHighContrast = Color(0xFFF2F3FA)
-internal val surfaceContainerLightHighContrast = Color(0xFFECEDF4)
-internal val surfaceContainerHighLightHighContrast = Color(0xFFE7E8EE)
-internal val surfaceContainerHighestLightHighContrast = Color(0xFFE1E2E8)
-
-internal val primaryDark = Color(0xFFA3C9FE)
-internal val onPrimaryDark = Color(0xFF00315C)
-internal val primaryContainerDark = Color(0xFF1F4876)
-internal val onPrimaryContainerDark = Color(0xFFD3E4FF)
-internal val secondaryDark = Color(0xFFE5C36C)
-internal val onSecondaryDark = Color(0xFF3E2E00)
-internal val secondaryContainerDark = Color(0xFF594400)
-internal val onSecondaryContainerDark = Color(0xFFFFDF93)
-internal val tertiaryDark = Color(0xFFEEBF6D)
-internal val onTertiaryDark = Color(0xFF422C00)
-internal val tertiaryContainerDark = Color(0xFF5E4100)
-internal val onTertiaryContainerDark = Color(0xFFFFDEA9)
-internal val errorDark = Color(0xFFFFB4AB)
-internal val onErrorDark = Color(0xFF690005)
-internal val errorContainerDark = Color(0xFF93000A)
-internal val onErrorContainerDark = Color(0xFFFFDAD6)
-internal val backgroundDark = Color(0xFF111418)
-internal val onBackgroundDark = Color(0xFFE1E2E8)
-internal val surfaceDark = Color(0xFF111418)
-internal val onSurfaceDark = Color(0xFFE1E2E8)
-internal val surfaceVariantDark = Color(0xFF43474E)
-internal val onSurfaceVariantDark = Color(0xFFC3C6CF)
-internal val outlineDark = Color(0xFF8D9199)
-internal val outlineVariantDark = Color(0xFF43474E)
-internal val scrimDark = Color(0xFF000000)
-internal val inverseSurfaceDark = Color(0xFFE1E2E8)
-internal val inverseOnSurfaceDark = Color(0xFF2E3035)
-internal val inversePrimaryDark = Color(0xFF3A608F)
-internal val surfaceDimDark = Color(0xFF111418)
-internal val surfaceBrightDark = Color(0xFF37393E)
-internal val surfaceContainerLowestDark = Color(0xFF0C0E13)
-internal val surfaceContainerLowDark = Color(0xFF191C20)
-internal val surfaceContainerDark = Color(0xFF1D2024)
-internal val surfaceContainerHighDark = Color(0xFF272A2F)
-internal val surfaceContainerHighestDark = Color(0xFF32353A)
-
-internal val primaryDarkMediumContrast = Color(0xFFAACDFF)
-internal val onPrimaryDarkMediumContrast = Color(0xFF00172F)
-internal val primaryContainerDarkMediumContrast = Color(0xFF6E93C5)
-internal val onPrimaryContainerDarkMediumContrast = Color(0xFF000000)
-internal val secondaryDarkMediumContrast = Color(0xFFEAC770)
-internal val onSecondaryDarkMediumContrast = Color(0xFF1E1500)
-internal val secondaryContainerDarkMediumContrast = Color(0xFFAB8D3D)
-internal val onSecondaryContainerDarkMediumContrast = Color(0xFF000000)
-internal val tertiaryDarkMediumContrast = Color(0xFFF3C470)
-internal val onTertiaryDarkMediumContrast = Color(0xFF201400)
-internal val tertiaryContainerDarkMediumContrast = Color(0xFFB38A3D)
-internal val onTertiaryContainerDarkMediumContrast = Color(0xFF000000)
-internal val errorDarkMediumContrast = Color(0xFFFFBAB1)
-internal val onErrorDarkMediumContrast = Color(0xFF370001)
-internal val errorContainerDarkMediumContrast = Color(0xFFFF5449)
-internal val onErrorContainerDarkMediumContrast = Color(0xFF000000)
-internal val backgroundDarkMediumContrast = Color(0xFF111418)
-internal val onBackgroundDarkMediumContrast = Color(0xFFE1E2E8)
-internal val surfaceDarkMediumContrast = Color(0xFF111418)
-internal val onSurfaceDarkMediumContrast = Color(0xFFFBFAFF)
-internal val surfaceVariantDarkMediumContrast = Color(0xFF43474E)
-internal val onSurfaceVariantDarkMediumContrast = Color(0xFFC7CBD3)
-internal val outlineDarkMediumContrast = Color(0xFF9FA3AB)
-internal val outlineVariantDarkMediumContrast = Color(0xFF7F838B)
-internal val scrimDarkMediumContrast = Color(0xFF000000)
-internal val inverseSurfaceDarkMediumContrast = Color(0xFFE1E2E8)
-internal val inverseOnSurfaceDarkMediumContrast = Color(0xFF272A2F)
-internal val inversePrimaryDarkMediumContrast = Color(0xFF204977)
-internal val surfaceDimDarkMediumContrast = Color(0xFF111418)
-internal val surfaceBrightDarkMediumContrast = Color(0xFF37393E)
-internal val surfaceContainerLowestDarkMediumContrast = Color(0xFF0C0E13)
-internal val surfaceContainerLowDarkMediumContrast = Color(0xFF191C20)
-internal val surfaceContainerDarkMediumContrast = Color(0xFF1D2024)
-internal val surfaceContainerHighDarkMediumContrast = Color(0xFF272A2F)
-internal val surfaceContainerHighestDarkMediumContrast = Color(0xFF32353A)
-
-internal val primaryDarkHighContrast = Color(0xFFFBFAFF)
-internal val onPrimaryDarkHighContrast = Color(0xFF000000)
-internal val primaryContainerDarkHighContrast = Color(0xFFAACDFF)
-internal val onPrimaryContainerDarkHighContrast = Color(0xFF000000)
-internal val secondaryDarkHighContrast = Color(0xFFFFFAF6)
-internal val onSecondaryDarkHighContrast = Color(0xFF000000)
-internal val secondaryContainerDarkHighContrast = Color(0xFFEAC770)
-internal val onSecondaryContainerDarkHighContrast = Color(0xFF000000)
-internal val tertiaryDarkHighContrast = Color(0xFFFFFAF7)
-internal val onTertiaryDarkHighContrast = Color(0xFF000000)
-internal val tertiaryContainerDarkHighContrast = Color(0xFFF3C470)
-internal val onTertiaryContainerDarkHighContrast = Color(0xFF000000)
-internal val errorDarkHighContrast = Color(0xFFFFF9F9)
-internal val onErrorDarkHighContrast = Color(0xFF000000)
-internal val errorContainerDarkHighContrast = Color(0xFFFFBAB1)
-internal val onErrorContainerDarkHighContrast = Color(0xFF000000)
-internal val backgroundDarkHighContrast = Color(0xFF111418)
-internal val onBackgroundDarkHighContrast = Color(0xFFE1E2E8)
-internal val surfaceDarkHighContrast = Color(0xFF111418)
-internal val onSurfaceDarkHighContrast = Color(0xFFFFFFFF)
-internal val surfaceVariantDarkHighContrast = Color(0xFF43474E)
-internal val onSurfaceVariantDarkHighContrast = Color(0xFFFBFAFF)
-internal val outlineDarkHighContrast = Color(0xFFC7CBD3)
-internal val outlineVariantDarkHighContrast = Color(0xFFC7CBD3)
-internal val scrimDarkHighContrast = Color(0xFF000000)
-internal val inverseSurfaceDarkHighContrast = Color(0xFFE1E2E8)
-internal val inverseOnSurfaceDarkHighContrast = Color(0xFF000000)
-internal val inversePrimaryDarkHighContrast = Color(0xFF002B51)
-internal val surfaceDimDarkHighContrast = Color(0xFF111418)
-internal val surfaceBrightDarkHighContrast = Color(0xFF37393E)
-internal val surfaceContainerLowestDarkHighContrast = Color(0xFF0C0E13)
-internal val surfaceContainerLowDarkHighContrast = Color(0xFF191C20)
-internal val surfaceContainerDarkHighContrast = Color(0xFF1D2024)
-internal val surfaceContainerHighDarkHighContrast = Color(0xFF272A2F)
-internal val surfaceContainerHighestDarkHighContrast = Color(0xFF32353A)
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Theme.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Theme.kt
deleted file mode 100644
index d2576287633a870d77a3c7b007451cef5173a71b..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Theme.kt
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-@file:Suppress("Duplicates")
-
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package edu.ucsc.its.temerity.shared.ui.theme
-
-import androidx.compose.material3.darkColorScheme
-import androidx.compose.material3.lightColorScheme
-import com.composables.composetheme.buildComposeTheme
-import com.composables.composetheme.material3.extendMaterial3
-
-/**
- * Material3 theme generated using the builder tool:
- * https://material-foundation.github.io/material-theme-builder/
- */
-
-internal val lightScheme = lightColorScheme(
-  primary = primaryLight,
-  onPrimary = onPrimaryLight,
-  primaryContainer = primaryContainerLight,
-  onPrimaryContainer = onPrimaryContainerLight,
-  secondary = secondaryLight,
-  onSecondary = onSecondaryLight,
-  secondaryContainer = secondaryContainerLight,
-  onSecondaryContainer = onSecondaryContainerLight,
-  tertiary = tertiaryLight,
-  onTertiary = onTertiaryLight,
-  tertiaryContainer = tertiaryContainerLight,
-  onTertiaryContainer = onTertiaryContainerLight,
-  error = errorLight,
-  onError = onErrorLight,
-  errorContainer = errorContainerLight,
-  onErrorContainer = onErrorContainerLight,
-  background = backgroundLight,
-  onBackground = onBackgroundLight,
-  surface = surfaceLight,
-  onSurface = onSurfaceLight,
-  surfaceVariant = surfaceVariantLight,
-  onSurfaceVariant = onSurfaceVariantLight,
-  outline = outlineLight,
-  outlineVariant = outlineVariantLight,
-  scrim = scrimLight,
-  inverseSurface = inverseSurfaceLight,
-  inverseOnSurface = inverseOnSurfaceLight,
-  inversePrimary = inversePrimaryLight,
-  surfaceDim = surfaceDimLight,
-  surfaceBright = surfaceBrightLight,
-  surfaceContainerLowest = surfaceContainerLowestLight,
-  surfaceContainerLow = surfaceContainerLowLight,
-  surfaceContainer = surfaceContainerLight,
-  surfaceContainerHigh = surfaceContainerHighLight,
-  surfaceContainerHighest = surfaceContainerHighestLight,
-)
-
-internal val darkScheme = darkColorScheme(
-  primary = primaryDark,
-  onPrimary = onPrimaryDark,
-  primaryContainer = primaryContainerDark,
-  onPrimaryContainer = onPrimaryContainerDark,
-  secondary = secondaryDark,
-  onSecondary = onSecondaryDark,
-  secondaryContainer = secondaryContainerDark,
-  onSecondaryContainer = onSecondaryContainerDark,
-  tertiary = tertiaryDark,
-  onTertiary = onTertiaryDark,
-  tertiaryContainer = tertiaryContainerDark,
-  onTertiaryContainer = onTertiaryContainerDark,
-  error = errorDark,
-  onError = onErrorDark,
-  errorContainer = errorContainerDark,
-  onErrorContainer = onErrorContainerDark,
-  background = backgroundDark,
-  onBackground = onBackgroundDark,
-  surface = surfaceDark,
-  onSurface = onSurfaceDark,
-  surfaceVariant = surfaceVariantDark,
-  onSurfaceVariant = onSurfaceVariantDark,
-  outline = outlineDark,
-  outlineVariant = outlineVariantDark,
-  scrim = scrimDark,
-  inverseSurface = inverseSurfaceDark,
-  inverseOnSurface = inverseOnSurfaceDark,
-  inversePrimary = inversePrimaryDark,
-  surfaceDim = surfaceDimDark,
-  surfaceBright = surfaceBrightDark,
-  surfaceContainerLowest = surfaceContainerLowestDark,
-  surfaceContainerLow = surfaceContainerLowDark,
-  surfaceContainer = surfaceContainerDark,
-  surfaceContainerHigh = surfaceContainerHighDark,
-  surfaceContainerHighest = surfaceContainerHighestDark,
-)
-
-private val mediumContrastLightColorScheme = lightColorScheme(
-  primary = primaryLightMediumContrast,
-  onPrimary = onPrimaryLightMediumContrast,
-  primaryContainer = primaryContainerLightMediumContrast,
-  onPrimaryContainer = onPrimaryContainerLightMediumContrast,
-  secondary = secondaryLightMediumContrast,
-  onSecondary = onSecondaryLightMediumContrast,
-  secondaryContainer = secondaryContainerLightMediumContrast,
-  onSecondaryContainer = onSecondaryContainerLightMediumContrast,
-  tertiary = tertiaryLightMediumContrast,
-  onTertiary = onTertiaryLightMediumContrast,
-  tertiaryContainer = tertiaryContainerLightMediumContrast,
-  onTertiaryContainer = onTertiaryContainerLightMediumContrast,
-  error = errorLightMediumContrast,
-  onError = onErrorLightMediumContrast,
-  errorContainer = errorContainerLightMediumContrast,
-  onErrorContainer = onErrorContainerLightMediumContrast,
-  background = backgroundLightMediumContrast,
-  onBackground = onBackgroundLightMediumContrast,
-  surface = surfaceLightMediumContrast,
-  onSurface = onSurfaceLightMediumContrast,
-  surfaceVariant = surfaceVariantLightMediumContrast,
-  onSurfaceVariant = onSurfaceVariantLightMediumContrast,
-  outline = outlineLightMediumContrast,
-  outlineVariant = outlineVariantLightMediumContrast,
-  scrim = scrimLightMediumContrast,
-  inverseSurface = inverseSurfaceLightMediumContrast,
-  inverseOnSurface = inverseOnSurfaceLightMediumContrast,
-  inversePrimary = inversePrimaryLightMediumContrast,
-  surfaceDim = surfaceDimLightMediumContrast,
-  surfaceBright = surfaceBrightLightMediumContrast,
-  surfaceContainerLowest = surfaceContainerLowestLightMediumContrast,
-  surfaceContainerLow = surfaceContainerLowLightMediumContrast,
-  surfaceContainer = surfaceContainerLightMediumContrast,
-  surfaceContainerHigh = surfaceContainerHighLightMediumContrast,
-  surfaceContainerHighest = surfaceContainerHighestLightMediumContrast,
-)
-
-private val highContrastLightColorScheme = lightColorScheme(
-  primary = primaryLightHighContrast,
-  onPrimary = onPrimaryLightHighContrast,
-  primaryContainer = primaryContainerLightHighContrast,
-  onPrimaryContainer = onPrimaryContainerLightHighContrast,
-  secondary = secondaryLightHighContrast,
-  onSecondary = onSecondaryLightHighContrast,
-  secondaryContainer = secondaryContainerLightHighContrast,
-  onSecondaryContainer = onSecondaryContainerLightHighContrast,
-  tertiary = tertiaryLightHighContrast,
-  onTertiary = onTertiaryLightHighContrast,
-  tertiaryContainer = tertiaryContainerLightHighContrast,
-  onTertiaryContainer = onTertiaryContainerLightHighContrast,
-  error = errorLightHighContrast,
-  onError = onErrorLightHighContrast,
-  errorContainer = errorContainerLightHighContrast,
-  onErrorContainer = onErrorContainerLightHighContrast,
-  background = backgroundLightHighContrast,
-  onBackground = onBackgroundLightHighContrast,
-  surface = surfaceLightHighContrast,
-  onSurface = onSurfaceLightHighContrast,
-  surfaceVariant = surfaceVariantLightHighContrast,
-  onSurfaceVariant = onSurfaceVariantLightHighContrast,
-  outline = outlineLightHighContrast,
-  outlineVariant = outlineVariantLightHighContrast,
-  scrim = scrimLightHighContrast,
-  inverseSurface = inverseSurfaceLightHighContrast,
-  inverseOnSurface = inverseOnSurfaceLightHighContrast,
-  inversePrimary = inversePrimaryLightHighContrast,
-  surfaceDim = surfaceDimLightHighContrast,
-  surfaceBright = surfaceBrightLightHighContrast,
-  surfaceContainerLowest = surfaceContainerLowestLightHighContrast,
-  surfaceContainerLow = surfaceContainerLowLightHighContrast,
-  surfaceContainer = surfaceContainerLightHighContrast,
-  surfaceContainerHigh = surfaceContainerHighLightHighContrast,
-  surfaceContainerHighest = surfaceContainerHighestLightHighContrast,
-)
-
-private val mediumContrastDarkColorScheme = darkColorScheme(
-  primary = primaryDarkMediumContrast,
-  onPrimary = onPrimaryDarkMediumContrast,
-  primaryContainer = primaryContainerDarkMediumContrast,
-  onPrimaryContainer = onPrimaryContainerDarkMediumContrast,
-  secondary = secondaryDarkMediumContrast,
-  onSecondary = onSecondaryDarkMediumContrast,
-  secondaryContainer = secondaryContainerDarkMediumContrast,
-  onSecondaryContainer = onSecondaryContainerDarkMediumContrast,
-  tertiary = tertiaryDarkMediumContrast,
-  onTertiary = onTertiaryDarkMediumContrast,
-  tertiaryContainer = tertiaryContainerDarkMediumContrast,
-  onTertiaryContainer = onTertiaryContainerDarkMediumContrast,
-  error = errorDarkMediumContrast,
-  onError = onErrorDarkMediumContrast,
-  errorContainer = errorContainerDarkMediumContrast,
-  onErrorContainer = onErrorContainerDarkMediumContrast,
-  background = backgroundDarkMediumContrast,
-  onBackground = onBackgroundDarkMediumContrast,
-  surface = surfaceDarkMediumContrast,
-  onSurface = onSurfaceDarkMediumContrast,
-  surfaceVariant = surfaceVariantDarkMediumContrast,
-  onSurfaceVariant = onSurfaceVariantDarkMediumContrast,
-  outline = outlineDarkMediumContrast,
-  outlineVariant = outlineVariantDarkMediumContrast,
-  scrim = scrimDarkMediumContrast,
-  inverseSurface = inverseSurfaceDarkMediumContrast,
-  inverseOnSurface = inverseOnSurfaceDarkMediumContrast,
-  inversePrimary = inversePrimaryDarkMediumContrast,
-  surfaceDim = surfaceDimDarkMediumContrast,
-  surfaceBright = surfaceBrightDarkMediumContrast,
-  surfaceContainerLowest = surfaceContainerLowestDarkMediumContrast,
-  surfaceContainerLow = surfaceContainerLowDarkMediumContrast,
-  surfaceContainer = surfaceContainerDarkMediumContrast,
-  surfaceContainerHigh = surfaceContainerHighDarkMediumContrast,
-  surfaceContainerHighest = surfaceContainerHighestDarkMediumContrast,
-)
-
-private val highContrastDarkColorScheme = darkColorScheme(
-  primary = primaryDarkHighContrast,
-  onPrimary = onPrimaryDarkHighContrast,
-  primaryContainer = primaryContainerDarkHighContrast,
-  onPrimaryContainer = onPrimaryContainerDarkHighContrast,
-  secondary = secondaryDarkHighContrast,
-  onSecondary = onSecondaryDarkHighContrast,
-  secondaryContainer = secondaryContainerDarkHighContrast,
-  onSecondaryContainer = onSecondaryContainerDarkHighContrast,
-  tertiary = tertiaryDarkHighContrast,
-  onTertiary = onTertiaryDarkHighContrast,
-  tertiaryContainer = tertiaryContainerDarkHighContrast,
-  onTertiaryContainer = onTertiaryContainerDarkHighContrast,
-  error = errorDarkHighContrast,
-  onError = onErrorDarkHighContrast,
-  errorContainer = errorContainerDarkHighContrast,
-  onErrorContainer = onErrorContainerDarkHighContrast,
-  background = backgroundDarkHighContrast,
-  onBackground = onBackgroundDarkHighContrast,
-  surface = surfaceDarkHighContrast,
-  onSurface = onSurfaceDarkHighContrast,
-  surfaceVariant = surfaceVariantDarkHighContrast,
-  onSurfaceVariant = onSurfaceVariantDarkHighContrast,
-  outline = outlineDarkHighContrast,
-  outlineVariant = outlineVariantDarkHighContrast,
-  scrim = scrimDarkHighContrast,
-  inverseSurface = inverseSurfaceDarkHighContrast,
-  inverseOnSurface = inverseOnSurfaceDarkHighContrast,
-  inversePrimary = inversePrimaryDarkHighContrast,
-  surfaceDim = surfaceDimDarkHighContrast,
-  surfaceBright = surfaceBrightDarkHighContrast,
-  surfaceContainerLowest = surfaceContainerLowestDarkHighContrast,
-  surfaceContainerLow = surfaceContainerLowDarkHighContrast,
-  surfaceContainer = surfaceContainerDarkHighContrast,
-  surfaceContainerHigh = surfaceContainerHighDarkHighContrast,
-  surfaceContainerHighest = surfaceContainerHighestDarkHighContrast,
-)
-
-val LightTheme = buildComposeTheme {
-  name = "UcscLightTheme"
-  extendMaterial3 {
-    colorScheme = lightScheme
-    typography = AppTypography
-  }
-}
-
-val DarkTheme = buildComposeTheme {
-  name = "UcscDarkTheme"
-  extendMaterial3 {
-    colorScheme = darkScheme
-    typography = AppTypography
-  }
-}
diff --git a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Type.kt b/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Type.kt
deleted file mode 100644
index 89e81698856807b777d903347f1a6eb6f42da01e..0000000000000000000000000000000000000000
--- a/shared/compose/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/ui/theme/Type.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.theme
-
-import androidx.compose.material3.Typography
-
-internal val AppTypography = Typography()
diff --git a/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/MainLayout.kt b/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/MainLayout.kt
deleted file mode 100644
index e2d1290582ff4f77f41ad740dbab9b55d71d6807..0000000000000000000000000000000000000000
--- a/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/MainLayout.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui
-
-import androidx.compose.runtime.Composable
-
-@Composable
-fun MainLayout() {
-  TemerityApp()
-}
diff --git a/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ActualUiElements.kt b/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ActualUiElements.kt
deleted file mode 100644
index 6d1993a74191c865287f214dd5bd4b09bbe74d17..0000000000000000000000000000000000000000
--- a/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ActualUiElements.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.foundation.ScrollbarStyle
-import androidx.compose.foundation.lazy.LazyListState
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-
-internal actual val MARGIN_SCROLLBAR: Dp = 8.dp
-
-@Suppress("ACTUAL_WITHOUT_EXPECT") // Workaround https://youtrack.jetbrains.com/issue/KT-37316
-internal actual typealias ScrollbarAdapter = androidx.compose.foundation.v2.ScrollbarAdapter
-
-@Composable
-internal actual fun rememberScrollbarAdapter(scrollState: LazyListState): ScrollbarAdapter =
-  androidx.compose.foundation.rememberScrollbarAdapter(scrollState)
-
-@Composable
-internal actual fun VerticalScrollbar(
-  adapter: ScrollbarAdapter,
-  style: ScrollbarStyle,
-  modifier: Modifier,
-) {
-  androidx.compose.foundation.VerticalScrollbar(
-    adapter = adapter,
-    modifier = modifier,
-    style = style,
-  )
-}
diff --git a/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/DockedSearchBar.kt b/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/DockedSearchBar.kt
deleted file mode 100644
index 3f9c9571d9c65b5a4c09f6db1600f476db411113..0000000000000000000000000000000000000000
--- a/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/DockedSearchBar.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.MoreVert
-import androidx.compose.material.icons.filled.Search
-import androidx.compose.material.icons.filled.Star
-import androidx.compose.material3.DockedSearchBar
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Icon
-import androidx.compose.material3.ListItem
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.semantics.isTraversalGroup
-import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.semantics.traversalIndex
-import androidx.compose.ui.unit.dp
-
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-internal fun DockedSearchBarSample() {
-  var text by rememberSaveable { mutableStateOf("") }
-  var active by rememberSaveable { mutableStateOf(false) }
-
-  Box(Modifier.fillMaxSize().semantics { isTraversalGroup = true }) {
-    DockedSearchBar(
-      modifier = Modifier
-        .align(Alignment.TopCenter)
-        .padding(top = 8.dp)
-        .semantics { traversalIndex = -1f },
-      query = text,
-      onQueryChange = { text = it },
-      onSearch = { active = false },
-      active = active,
-      onActiveChange = { active = it },
-      placeholder = { Text("Hinted search text") },
-      leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) },
-      trailingIcon = { Icon(Icons.Default.MoreVert, contentDescription = null) },
-    ) {
-      repeat(4) { idx ->
-        val resultText = "Suggestion $idx"
-        ListItem(
-          headlineContent = { Text(resultText) },
-          supportingContent = { Text("Additional info") },
-          leadingContent = { Icon(Icons.Filled.Star, contentDescription = null) },
-          modifier = Modifier
-            .clickable {
-              text = resultText
-              active = false
-            }
-            .fillMaxWidth()
-            .padding(horizontal = 16.dp, vertical = 4.dp),
-        )
-      }
-    }
-
-        /* LazyColumn(
-             contentPadding = PaddingValues(start = 16.dp, top = 72.dp, end = 16.dp, bottom = 16.dp),
-             verticalArrangement = Arrangement.spacedBy(8.dp)
-         ) {
-             val list = List(100) { "Text $it" }
-             items(count = list.size) {
-                 Text(list[it], Modifier.fillMaxWidth().padding(horizontal = 16.dp))
-             }
-         }*/
-  }
-}
diff --git a/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ExposedDropDownMenu.kt b/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ExposedDropDownMenu.kt
deleted file mode 100644
index 70ad7a9461960fde2f38b6bc82d4aecb8a907029..0000000000000000000000000000000000000000
--- a/shared/compose/src/desktopMain/kotlin/edu/ucsc/its/temerity/shared/ui/elements/ExposedDropDownMenu.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.ui.elements
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.material3.DropdownMenuItem
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.ExposedDropdownMenuBox
-import androidx.compose.material3.ExposedDropdownMenuDefaults
-import androidx.compose.material3.MenuAnchorType
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextField
-import androidx.compose.material3.TextFieldDefaults
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-internal fun ExposedDropdownMenu() {
-  var isExpand by remember { mutableStateOf(false) }
-  var gender by remember { mutableStateOf("") }
-
-  Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
-    ExposedDropdownMenuBox(
-      expanded = isExpand,
-      onExpandedChange = { isExpand = !isExpand },
-    ) {
-      TextField(
-        value = gender,
-        onValueChange = {},
-        readOnly = true,
-        trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = isExpand) },
-        colors = TextFieldDefaults.colors(),
-        modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable),
-      )
-      ExposedDropdownMenu(expanded = isExpand, onDismissRequest = { isExpand = false }) {
-        DropdownMenuItem(
-          text = { Text("Male") },
-          onClick = {
-            gender = "Male"
-            isExpand = false
-          },
-        )
-
-        DropdownMenuItem(
-          text = { Text("Female") },
-          onClick = {
-            gender = "Female"
-            isExpand = false
-          },
-        )
-
-        DropdownMenuItem(
-          text = { Text("Other") },
-          onClick = {
-            gender = "Other"
-            isExpand = false
-          },
-        )
-      }
-    }
-  }
-}
diff --git a/shared/shared/LICENSE b/shared/shared/LICENSE
deleted file mode 100644
index 19dc35b2433851a0e8fd866a5d323b2ba18c12ed..0000000000000000000000000000000000000000
--- a/shared/shared/LICENSE
+++ /dev/null
@@ -1,175 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
\ No newline at end of file
diff --git a/shared/shared/NOTICE b/shared/shared/NOTICE
deleted file mode 100644
index 8f5d546c262a64e3a8965eb81773bab7a5c0890c..0000000000000000000000000000000000000000
--- a/shared/shared/NOTICE
+++ /dev/null
@@ -1,7 +0,0 @@
-This product includes software developed by Square, Inc.
-
-File(s): MoleculeViewModel.kt
-Description: A ViewModel class for managing state and events in an application via the Compose runtime (Molecule).
-License: Apache License, Version 2.0
-
---------------------------------------------
\ No newline at end of file
diff --git a/shared/shared/build.gradle.kts b/shared/shared/build.gradle.kts
deleted file mode 100644
index 75bd6ae91b60ee86f6d024c73e43c0d6e59c05e8..0000000000000000000000000000000000000000
--- a/shared/shared/build.gradle.kts
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
-
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-plugins {
-    alias(libs.plugins.kotlinMultiplatform)
-    id("convention.composeComp")
-    alias(libs.plugins.kotlinxSerialization)
-    alias(libs.plugins.ksp)
-    alias(libs.plugins.room)
-
-    id("convention.formattingCmp")
-}
-
-kotlin {
-    jvmToolchain(libs.versions.java.get().toInt())
-    jvm()
-    applyDefaultHierarchyTemplate()
-    @OptIn(ExperimentalKotlinGradlePluginApi::class)
-    compilerOptions {
-        freeCompilerArgs.add("-Xexpect-actual-classes")
-    }
-
-    sourceSets {
-        val commonMain by getting {
-            dependencies {
-                api(libs.temerity)
-
-                api(libs.koin.core)
-                implementation(libs.koin.composeVm)
-                api(libs.kermit)
-                api(libs.kermit.koin)
-                implementation(libs.arrow.core)
-                implementation(libs.arrow.fxCoroutines)
-                implementation(libs.arrow.optics)
-                api(libs.kotlinx.serialization.json)
-                api(libs.kstore)
-                api(libs.kstore.file)
-
-                api(libs.molecule.runtime)
-                implementation(libs.kotlinx.coroutines.core)
-                api(libs.jetbrains.lifecycle.viewmodel)
-                implementation(libs.androidx.room.runtime)
-                implementation(libs.sqlite.bundled)
-                implementation(libs.datastore.preferences)
-                implementation(libs.bundles.exposed)
-                implementation(libs.kstore)
-                implementation(libs.kstore.file)
-            }
-        }
-        val jvmMain by getting {
-            dependencies {
-                // Required for molecule
-                implementation(libs.kotlinx.coroutines.swing)
-
-                api(libs.appdirs)
-                api(libs.slf4j)
-            }
-        }
-    }
-}
-
-dependencies {
-    ksp(libs.arrow.opticsKspPlugin)
-    add("kspCommonMainMetadata", libs.androidx.room.compiler)
-    add("kspJvm", libs.androidx.room.compiler)
-}
-
-room {
-    schemaDirectory("$projectDir/schemas")
-}
diff --git a/shared/shared/schemas/edu.ucsc.its.temerity.shared.database.AppDatabase/1.json b/shared/shared/schemas/edu.ucsc.its.temerity.shared.database.AppDatabase/1.json
deleted file mode 100644
index e8de3e7d14641229d48bc82e79c520143c0e3f28..0000000000000000000000000000000000000000
--- a/shared/shared/schemas/edu.ucsc.its.temerity.shared.database.AppDatabase/1.json
+++ /dev/null
@@ -1,205 +0,0 @@
-{
-  "formatVersion": 1,
-  "database": {
-    "version": 1,
-    "identityHash": "08fa5d3a5923c0c2017b4538a2daf463",
-    "entities": [
-      {
-        "tableName": "devices",
-        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `stationName` TEXT NOT NULL, `accessLevel` TEXT NOT NULL, `deviceId` INTEGER NOT NULL, `accessId` TEXT NOT NULL, `stationType` TEXT NOT NULL)",
-        "fields": [
-          {
-            "fieldPath": "id",
-            "columnName": "id",
-            "affinity": "INTEGER",
-            "notNull": true
-          },
-          {
-            "fieldPath": "stationName",
-            "columnName": "stationName",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "accessLevel",
-            "columnName": "accessLevel",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "deviceId",
-            "columnName": "deviceId",
-            "affinity": "INTEGER",
-            "notNull": true
-          },
-          {
-            "fieldPath": "accessId",
-            "columnName": "accessId",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "stationType",
-            "columnName": "stationType",
-            "affinity": "TEXT",
-            "notNull": true
-          }
-        ],
-        "primaryKey": {
-          "autoGenerate": true,
-          "columnNames": [
-            "id"
-          ]
-        }
-      },
-      {
-        "tableName": "users",
-        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`loginId` TEXT NOT NULL, `emailAddress` TEXT NOT NULL, `userType` TEXT NOT NULL, `userId` INTEGER NOT NULL, `timezone` TEXT NOT NULL, `customId` TEXT NOT NULL, `lastName` TEXT NOT NULL, `phoneNumber` TEXT NOT NULL, `firstName` TEXT NOT NULL, PRIMARY KEY(`userId`))",
-        "fields": [
-          {
-            "fieldPath": "loginId",
-            "columnName": "loginId",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "emailAddress",
-            "columnName": "emailAddress",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "userType",
-            "columnName": "userType",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "userId",
-            "columnName": "userId",
-            "affinity": "INTEGER",
-            "notNull": true
-          },
-          {
-            "fieldPath": "timezone",
-            "columnName": "timezone",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "customId",
-            "columnName": "customId",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "lastName",
-            "columnName": "lastName",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "phoneNumber",
-            "columnName": "phoneNumber",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "firstName",
-            "columnName": "firstName",
-            "affinity": "TEXT",
-            "notNull": true
-          }
-        ],
-        "primaryKey": {
-          "autoGenerate": false,
-          "columnNames": [
-            "userId"
-          ]
-        }
-      },
-      {
-        "tableName": "courses",
-        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`embedCode` TEXT NOT NULL, `courseId` INTEGER NOT NULL, `publishType` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `courseCode` TEXT NOT NULL, `courseName` TEXT NOT NULL, `ownerId` INTEGER NOT NULL, `sisId` TEXT NOT NULL, `courseSecurity` TEXT NOT NULL, `courseTerm` TEXT NOT NULL, `directLink` TEXT NOT NULL, PRIMARY KEY(`courseId`))",
-        "fields": [
-          {
-            "fieldPath": "embedCode",
-            "columnName": "embedCode",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "courseId",
-            "columnName": "courseId",
-            "affinity": "INTEGER",
-            "notNull": true
-          },
-          {
-            "fieldPath": "publishType",
-            "columnName": "publishType",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "isActive",
-            "columnName": "isActive",
-            "affinity": "INTEGER",
-            "notNull": true
-          },
-          {
-            "fieldPath": "courseCode",
-            "columnName": "courseCode",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "courseName",
-            "columnName": "courseName",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "ownerId",
-            "columnName": "ownerId",
-            "affinity": "INTEGER",
-            "notNull": true
-          },
-          {
-            "fieldPath": "sisId",
-            "columnName": "sisId",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "courseSecurity",
-            "columnName": "courseSecurity",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "courseTerm",
-            "columnName": "courseTerm",
-            "affinity": "TEXT",
-            "notNull": true
-          },
-          {
-            "fieldPath": "directLink",
-            "columnName": "directLink",
-            "affinity": "TEXT",
-            "notNull": true
-          }
-        ],
-        "primaryKey": {
-          "autoGenerate": false,
-          "columnNames": [
-            "courseId"
-          ]
-        }
-      }
-    ],
-    "setupQueries": [
-      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
-      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '08fa5d3a5923c0c2017b4538a2daf463')"
-    ]
-  }
-}
\ No newline at end of file
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/AppSettings.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/AppSettings.kt
deleted file mode 100644
index e0b26c2b386a013c429dbe1056b083148f2ce887..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/AppSettings.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared
-
-import androidx.datastore.core.DataStore
-import androidx.datastore.preferences.core.PreferenceDataStoreFactory
-import androidx.datastore.preferences.core.Preferences
-import androidx.datastore.preferences.core.edit
-import androidx.datastore.preferences.core.stringPreferencesKey
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
-import okio.Path.Companion.toPath
-
-fun createDataStore(
-  producePath: () -> String,
-): DataStore<Preferences> = PreferenceDataStoreFactory.createWithPath(
-  corruptionHandler = null,
-  migrations = emptyList(),
-  produceFile = { producePath().toPath() },
-)
-
-class AppSettings(private val dataStore: DataStore<Preferences>) {
-
-  val userServiceEndpoint: Flow<String> = dataStore.data.map { preferences ->
-    preferences[USER_ENDPOINT_URL_SETTING] ?: ""
-  }
-
-  val userAuthToken: Flow<String> = dataStore.data.map { preferences ->
-    preferences[USER_AUTH_TOKEN_SETTING] ?: ""
-  }
-
-  suspend fun updateServiceEndpoint(newEndpointUrl: String) {
-    dataStore.edit { preferences ->
-      preferences[USER_ENDPOINT_URL_SETTING] = newEndpointUrl
-    }
-  }
-
-  suspend fun updateUserAuthToken(newToken: String) {
-    dataStore.edit { preferences ->
-      preferences[USER_AUTH_TOKEN_SETTING] = newToken
-    }
-  }
-
-  companion object {
-    val USER_AUTH_TOKEN_SETTING = stringPreferencesKey("user_auth_token")
-    val USER_ENDPOINT_URL_SETTING = stringPreferencesKey("user_endpoint_url")
-  }
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/data/Expect.StorageModule.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/data/Expect.StorageModule.kt
deleted file mode 100644
index e46d86ad62440abb92fc3ae7f81113f12fcd5108..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/data/Expect.StorageModule.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.data
-
-import org.koin.core.module.Module
-
-internal expect fun storageModule(): Module
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/data/repository/PlatformRepository.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/data/repository/PlatformRepository.kt
deleted file mode 100644
index e2b02413e6f0fe875ae500bc8a5fcc8286a00db3..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/data/repository/PlatformRepository.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.data.repository
-
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import androidx.compose.runtime.mutableLongStateOf
-import co.touchlab.kermit.Logger
-import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.model.Device
-import edu.ucsc.its.temerity.model.Group
-import edu.ucsc.its.temerity.model.User
-import edu.ucsc.its.temerity.shared.AppSettings
-import edu.ucsc.its.temerity.shared.data.repository.PlatformRepositoryInterface.CacheFlag
-import edu.ucsc.its.temerity.shared.data.repository.PlatformRepositoryInterface.CacheFlag.DISABLE
-import edu.ucsc.its.temerity.shared.database.AppDatabase
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
-import org.koin.core.component.KoinComponent
-import org.koin.core.component.get
-import org.koin.core.component.inject
-import org.koin.core.parameter.parametersOf
-
-interface PlatformRepositoryInterface {
-
-  sealed class CacheFlag(val enable: Boolean) {
-    data object ENABLE : CacheFlag(true)
-    data object DISABLE : CacheFlag(false)
-  }
-
-  suspend fun fetchGroups(flag: CacheFlag = DISABLE): List<Group>
-  suspend fun fetchUsers(flag: CacheFlag = DISABLE): List<User>
-  suspend fun fetchDevices(flag: CacheFlag = DISABLE): List<Device>
-}
-
-class PlatformRepository :
-  KoinComponent,
-  PlatformRepositoryInterface {
-  private lateinit var temerity: Temerity
-  private val database: AppDatabase by inject()
-  private val appSettings: AppSettings by inject()
-
-  private val jobScope = CoroutineScope(Dispatchers.IO + Job())
-  var updateInterval = mutableLongStateOf(-1L)
-
-  val logger = Logger.withTag("PlatformRepository")
-
-  init {
-    jobScope.launch {
-      loadDataForAppStart()
-    }
-  }
-
-  private suspend fun updateServiceEndpoint(newEndpointUrl: String) {
-    appSettings.updateServiceEndpoint(newEndpointUrl)
-    temerity = get { parametersOf(appSettings.userServiceEndpoint, appSettings.userAuthToken) }
-    // TODO: Test new PC here
-  }
-
-  private suspend fun updateUserAuthToken(newToken: String) {
-    appSettings.updateUserAuthToken(newToken)
-    temerity = get { parametersOf(appSettings.userServiceEndpoint, appSettings.userAuthToken) }
-    // TODO: Test new PC here
-  }
-
-  private suspend fun loadDataForAppStart() {
-  }
-
-  override suspend fun fetchGroups(flag: CacheFlag): List<Group> {
-    TODO("Not yet implemented")
-  }
-
-  override suspend fun fetchUsers(flag: CacheFlag): List<User> {
-    TODO("Not yet implemented")
-  }
-
-  override suspend fun fetchDevices(flag: CacheFlag): List<Device> {
-    TODO("Not yet implemented")
-  }
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/AppDatabase.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/AppDatabase.kt
deleted file mode 100644
index 54dfbf2daf7c19320d39ae02ce4d0d56e05b4a3e..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/AppDatabase.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.database
-
-import CourseEntity
-import DeviceEntity
-import UserEntity
-import androidx.room.ConstructedBy
-import androidx.room.Database
-import androidx.room.RoomDatabase
-import androidx.room.RoomDatabaseConstructor
-import androidx.room.TypeConverter
-import androidx.room.TypeConverters
-import androidx.sqlite.driver.bundled.BundledSQLiteDriver
-import kotlinx.coroutines.Dispatchers
-import kotlinx.datetime.LocalDateTime
-
-internal const val DB_FILENAME = "temerity.db"
-
-@Database(entities = [DeviceEntity::class, UserEntity::class, CourseEntity::class], version = 1)
-@ConstructedBy(AppDatabaseConstructor::class)
-@TypeConverters(LocalDateTimeConverter::class)
-abstract class AppDatabase : RoomDatabase() {
-  internal abstract fun temerityDao(): TemerityDao
-}
-
-expect object AppDatabaseConstructor : RoomDatabaseConstructor<AppDatabase>
-
-fun getRoomDatabase(
-  builder: RoomDatabase.Builder<AppDatabase>,
-): AppDatabase = builder
-  .fallbackToDestructiveMigration(dropAllTables = true)
-  .setDriver(BundledSQLiteDriver())
-  .setQueryCoroutineContext(Dispatchers.IO)
-  .build()
-
-class LocalDateTimeConverter {
-  @TypeConverter
-  fun fromTimestamp(value: String?): LocalDateTime? = value?.let { LocalDateTime.parse(it) }
-
-  @TypeConverter
-  fun dateToTimestamp(date: LocalDateTime?): String? = date?.toString()
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/TemerityDao.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/TemerityDao.kt
deleted file mode 100644
index 61d56ececca7f0a2860f73a86a8fcb71871113f0..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/TemerityDao.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.database
-
-import CourseEntity
-import DeviceEntity
-import UserEntity
-import androidx.room.Dao
-import androidx.room.Insert
-import androidx.room.OnConflictStrategy
-
-@Dao
-internal interface TemerityDao {
-
-  @Insert(onConflict = OnConflictStrategy.REPLACE)
-  suspend fun insertDeviceList(deviceList: List<DeviceEntity>)
-
-  @Insert(onConflict = OnConflictStrategy.REPLACE)
-  suspend fun insertUserList(userList: List<UserEntity>)
-
-  @Insert(onConflict = OnConflictStrategy.REPLACE)
-  suspend fun insertCourseList(courseList: List<CourseEntity>)
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/TemerityEntities.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/TemerityEntities.kt
deleted file mode 100644
index 725d83cd1e0d180e0ae7146976f191ea74b69ce0..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/database/TemerityEntities.kt
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import androidx.room.Entity
-import androidx.room.PrimaryKey
-import edu.ucsc.its.temerity.model.Course
-import edu.ucsc.its.temerity.model.Device
-import edu.ucsc.its.temerity.model.User
-
-@Entity(tableName = "devices")
-data class DeviceEntity(
-  @PrimaryKey(autoGenerate = true) val id: Long = 0,
-  val stationName: String = "",
-  val accessLevel: String = "",
-  val deviceId: Long = -1,
-  val accessId: String = "",
-  val stationType: String = "",
-) {
-  companion object {
-    fun from(device: Device): DeviceEntity = DeviceEntity(
-      stationName = device.stationName,
-      accessLevel = device.accessLevel,
-      deviceId = device.deviceId,
-      accessId = device.accessId,
-      stationType = device.stationType,
-    )
-  }
-
-  fun toDevice(): Device = Device(
-    stationName = stationName,
-    accessLevel = accessLevel,
-    deviceId = deviceId,
-    accessId = accessId,
-    stationType = stationType,
-  )
-}
-
-@Entity(tableName = "users")
-data class UserEntity(
-  val loginId: String = "",
-  val emailAddress: String = "",
-  val userType: String = "",
-  @PrimaryKey(autoGenerate = false)
-  val userId: Long = -1,
-  val timezone: String = "",
-  val customId: String = "",
-  val lastName: String = "",
-  val phoneNumber: String = "",
-  val firstName: String = "",
-) {
-  companion object {
-    fun from(user: User): UserEntity = UserEntity(
-      loginId = user.loginId,
-      emailAddress = user.emailAddress,
-      userType = user.userType,
-      userId = user.userId,
-      timezone = user.timezone,
-      customId = user.customId,
-      lastName = user.lastName,
-      phoneNumber = user.phoneNumber,
-      firstName = user.firstName,
-    )
-  }
-
-  fun toUser(): User = User(
-    loginId = loginId,
-    emailAddress = emailAddress,
-    userType = userType,
-    userId = userId,
-    timezone = timezone,
-    customId = customId,
-    lastName = lastName,
-    phoneNumber = phoneNumber,
-    firstName = firstName,
-  )
-}
-
-@Entity(tableName = "courses")
-internal data class CourseEntity(
-  val embedCode: String = "",
-  @PrimaryKey(autoGenerate = false)
-  val courseId: Long = -1,
-  val publishType: String = "",
-  val isActive: Boolean = false,
-  val courseCode: String = "",
-  val courseName: String = "",
-  val ownerId: Long = -1,
-  val sisId: String = "",
-  val courseSecurity: String = "",
-  val courseTerm: String = "",
-  val directLink: String = "",
-) {
-  companion object {
-    fun from(course: Course): CourseEntity = CourseEntity(
-      embedCode = course.embedCode,
-      courseId = course.courseId,
-      publishType = course.publishType,
-      isActive = course.isActive,
-      courseCode = course.courseCode,
-      courseName = course.courseName,
-      ownerId = course.ownerId,
-      sisId = course.sisId,
-      courseSecurity = course.courseSecurity,
-      courseTerm = course.courseTerm,
-      directLink = course.directLink,
-    )
-  }
-  fun toCourse(): Course = Course(
-    embedCode = embedCode,
-    courseId = courseId,
-    publishType = publishType,
-    isActive = isActive,
-    courseCode = courseCode,
-    courseName = courseName,
-    ownerId = ownerId,
-    sisId = sisId,
-    courseSecurity = courseSecurity,
-    courseTerm = courseTerm,
-    directLink = directLink,
-  )
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/di/CommonModule.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/di/CommonModule.kt
deleted file mode 100644
index 7e7671a901aa9ba26105107ecb48cf4a39e839d6..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/di/CommonModule.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.di
-
-import ca.gosyer.appdirs.AppDirs
-import co.touchlab.kermit.Logger
-import co.touchlab.kermit.koin.kermitLoggerModule
-import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.shared.AppSettings
-import edu.ucsc.its.temerity.shared.data.repository.PlatformRepository
-import edu.ucsc.its.temerity.shared.data.storageModule
-import edu.ucsc.its.temerity.shared.viewmodel.AppViewModel
-import edu.ucsc.its.temerity.shared.viewmodel.LoginViewModel
-import edu.ucsc.its.temerity.shared.viewmodel.RootViewModel
-import edu.ucsc.its.temerity.shared.viewmodel.UserEditViewModel
-import org.koin.core.context.startKoin
-import org.koin.core.module.dsl.viewModelOf
-import org.koin.core.qualifier.named
-import org.koin.dsl.KoinAppDeclaration
-import org.koin.dsl.koinApplication
-import org.koin.dsl.module
-
-fun initKoin(enableNetworkLogs: Boolean = false, appDeclaration: KoinAppDeclaration = {}) =
-  startKoin {
-    appDeclaration()
-    modules(commonModule())
-  }
-
-internal fun commonModule(isDebuggingEnabled: Boolean = false) = module {
-  viewModelOf(::AppViewModel)
-  viewModelOf(::LoginViewModel)
-  viewModelOf(::RootViewModel)
-  viewModelOf(::UserEditViewModel)
-  single { (serviceEndpoint: String, serviceToken: String) ->
-    Temerity {
-      serviceUrl = serviceEndpoint
-      this.serviceToken = serviceToken
-      optDebugEnabled = isDebuggingEnabled
-    }
-  }
-  single { PlatformRepository() }
-  single { AppSettings(get()) }
-  single<String> { (packageName: String) ->
-    named("appConfigDir")
-    AppDirs("", packageName).getUserConfigDir(roaming = true)
-  }
-  single<String> { (packageName: String) ->
-    named("appDataDir")
-    AppDirs("", packageName).getUserDataDir(roaming = true)
-  }
-  includes(storageModule(), kermitLoggerModule(Logger.withTag("compose koin context")))
-}
-
-internal object AppKoinContext {
-  private val koinApp = koinApplication {
-    modules(commonModule())
-  }
-
-  val koin = koinApp.koin
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/AppViewModel.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/AppViewModel.kt
deleted file mode 100644
index 3d81b5024c922b697c78c2480b1fd6ece2c93d2f..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/AppViewModel.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.viewmodel
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import androidx.lifecycle.viewModelScope
-import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.shared.viewmodel.AppStateEvent.ServiceEndpointUpdated
-import edu.ucsc.its.temerity.shared.viewmodel.AppStateEvent.ServiceTokenUpdated
-import edu.ucsc.its.temerity.shared.viewmodel.AppStateEvent.UserLoggedIn
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.launch
-import org.koin.core.component.KoinComponent
-import org.koin.core.component.get
-import org.koin.core.parameter.parametersOf
-
-sealed interface AppStateEvent {
-  data class ServiceEndpointUpdated(val newEndpoint: String) : AppStateEvent
-  data class ServiceTokenUpdated(val newToken: String) : AppStateEvent
-  data class UserLoggedIn(val newStatus: Boolean) : AppStateEvent
-}
-
-data class AppState(
-  val serviceEndpoint: String = "",
-  val serviceToken: String = "",
-  val userLoggedIn: Boolean = false,
-)
-
-class AppViewModel :
-  MoleculeViewModel<AppStateEvent, AppState>(),
-  KoinComponent {
-  private var serviceEndpoint by mutableStateOf("")
-  private var serviceToken by mutableStateOf("")
-  private var userLoggedIn by mutableStateOf(false)
-
-  @Composable
-  override fun models(events: Flow<AppStateEvent>): AppState = presentAppState(events, get { parametersOf() })
-
-  @Composable
-  private fun presentAppState(events: Flow<AppStateEvent>, temerity: Temerity): AppState {
-    LaunchedEffect(Unit) {
-      events.collect { event ->
-        when (event) {
-          is ServiceEndpointUpdated -> {
-            viewModelScope.launch {
-              serviceEndpoint = event.newEndpoint
-            }
-          }
-          is ServiceTokenUpdated -> {
-            viewModelScope.launch {
-              serviceToken = event.newToken
-            }
-          }
-          is UserLoggedIn -> {
-            viewModelScope.launch {
-              attemptLogin()
-            }
-          }
-        }
-      }
-    }
-    return AppState(serviceEndpoint, serviceToken, userLoggedIn)
-  }
-
-  private fun attemptLogin() {
-  }
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/DevicesScreenViewModel.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/DevicesScreenViewModel.kt
deleted file mode 100644
index 28fdc083b0fd690d681f4d57cb9cd19af4f0f309..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/DevicesScreenViewModel.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.viewmodel
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.model.Device
-import kotlinx.coroutines.flow.Flow
-import org.koin.compose.getKoin
-
-sealed interface DevicesScreenEvent
-
-data class DevicesScreenState(
-  val loading: Boolean,
-  val devices: List<Device>,
-)
-
-class DevicesScreenViewModel : MoleculeViewModel<DevicesScreenEvent, DevicesScreenState>() {
-
-  @Composable
-  override fun models(events: Flow<DevicesScreenEvent>): DevicesScreenState = devicesScreenPresenter(events, getKoin().get())
-}
-
-@Composable
-fun devicesScreenPresenter(events: Flow<DevicesScreenEvent>, client: Temerity): DevicesScreenState {
-  var devices: List<Device> by remember { mutableStateOf(emptyList()) }
-
-  LaunchedEffect(Unit) {
-    devices = client.getDevices()
-  }
-
-  LaunchedEffect(Unit) {
-    events.collect { event ->
-    }
-  }
-
-  return DevicesScreenState(
-    loading = false,
-    devices = devices,
-  )
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/LoginViewModel.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/LoginViewModel.kt
deleted file mode 100644
index e1433096cf2020834e446df839299512478a4995..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/LoginViewModel.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.viewmodel
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.mutableStateOf
-import androidx.lifecycle.viewModelScope
-import edu.ucsc.its.temerity.shared.data.repository.PlatformRepository
-import edu.ucsc.its.temerity.shared.viewmodel.LoginEvent.AttemptLogin
-import edu.ucsc.its.temerity.shared.viewmodel.LoginEvent.LoginFailure
-import edu.ucsc.its.temerity.shared.viewmodel.LoginEvent.LoginSuccess
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.launch
-import org.koin.core.component.KoinComponent
-import org.koin.core.component.inject
-
-sealed interface LoginEvent {
-  data object AttemptLogin : LoginEvent
-  data object LoginSuccess : LoginEvent
-  data class LoginFailure(val message: String) : LoginEvent
-}
-
-data class LoginState(
-  val serviceToken: String,
-)
-
-class LoginViewModel :
-  MoleculeViewModel<LoginEvent, LoginState>(),
-  KoinComponent {
-
-  private val repository: PlatformRepository by inject()
-  private val serviceToken = mutableStateOf("")
-
-  @Composable
-  override fun models(events: Flow<LoginEvent>): LoginState = loginScreenPresenter(events)
-
-  @Composable
-  fun loginScreenPresenter(eventCollector: Flow<LoginEvent>): LoginState {
-    LaunchedEffect(Unit) {
-      eventCollector.collect { event ->
-        when (event) {
-          is AttemptLogin -> {
-            viewModelScope.launch(Dispatchers.IO) {
-              try {
-                // TODO: Update token and refresh platform client injected into repository here.
-                events.tryEmit(LoginSuccess)
-              } catch (e: Exception) {
-                events.tryEmit(LoginFailure(e.message ?: "Unknown error"))
-              }
-            }
-          }
-          is LoginSuccess -> {
-          }
-          is LoginFailure -> {
-          }
-        }
-      }
-    }
-
-    return LoginState("")
-  }
-
-  suspend fun tryLogin() {
-    events.tryEmit(AttemptLogin)
-  }
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/MoleculeViewModel.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/MoleculeViewModel.kt
deleted file mode 100644
index b8b257e0f3295507dc669ab5fdad6cab12b6cda7..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/MoleculeViewModel.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.viewmodel
-
-import androidx.compose.runtime.Composable
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import app.cash.molecule.RecompositionMode.Immediate
-import app.cash.molecule.launchMolecule
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.StateFlow
-
-abstract class MoleculeViewModel<Event, Model> : ViewModel() {
-  internal val events = MutableSharedFlow<Event>(extraBufferCapacity = 20)
-
-  val models: StateFlow<Model> by lazy(LazyThreadSafetyMode.NONE) {
-    viewModelScope.launchMolecule(mode = Immediate) {
-      models(events)
-    }
-  }
-
-  fun take(event: Event) {
-    if (!events.tryEmit(event)) {
-      error("Event buffer overflow.")
-    }
-  }
-
-  @Composable
-  protected abstract fun models(events: Flow<Event>): Model
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/RootViewModel.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/RootViewModel.kt
deleted file mode 100644
index bed6dbb97f7a1759eb1f383464c4e10b3f51a6e7..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/RootViewModel.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.viewmodel
-
-import androidx.compose.runtime.Composable
-import edu.ucsc.its.temerity.core.Temerity
-import kotlinx.coroutines.flow.Flow
-import org.koin.core.component.KoinComponent
-import org.koin.core.component.get
-
-sealed class RootEvent {
-  data object NavigateToDevicesPane : RootEvent()
-}
-
-data class RootState(
-  val loading: Boolean = false,
-)
-
-class RootViewModel :
-  MoleculeViewModel<RootEvent, RootState>(),
-  KoinComponent {
-
-  @Composable
-  override fun models(events: Flow<RootEvent>): RootState = rootPresenter(events, get<Temerity>())
-
-  private fun rootPresenter(events: Flow<RootEvent>, client: Temerity): RootState = RootState(false)
-}
diff --git a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/UserEditViewModel.kt b/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/UserEditViewModel.kt
deleted file mode 100644
index 40c6a7f46f71d06c25ba56b41d1043d48dcaccd9..0000000000000000000000000000000000000000
--- a/shared/shared/src/commonMain/kotlin/edu/ucsc/its/temerity/shared/viewmodel/UserEditViewModel.kt
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.viewmodel
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import edu.ucsc.its.temerity.model.User
-import edu.ucsc.its.temerity.shared.viewmodel.UserEditEvent.ClearField
-import edu.ucsc.its.temerity.shared.viewmodel.UserEditEvent.LoadUser
-import edu.ucsc.its.temerity.shared.viewmodel.UserEditEvent.Save
-import edu.ucsc.its.temerity.shared.viewmodel.UserEditEvent.UpdateField
-import kotlinx.coroutines.flow.Flow
-
-sealed class UserEditEvent {
-  data class LoadUser(val user: User?) : UserEditEvent()
-  data object Save : UserEditEvent()
-  data class ClearField(val fieldName: String) : UserEditEvent()
-  data class UpdateField(val fieldName: String, val value: String) : UserEditEvent()
-}
-
-data class UserEditState(
-  var firstName: String = "",
-  var lastName: String = "",
-  var loginId: String = "",
-  var emailAddress: String = "",
-  val timezone: String = "",
-  val role: String = "",
-  val lockUser: Boolean = false,
-)
-
-class UserEditViewModel : MoleculeViewModel<UserEditEvent, UserEditState>() {
-  @Composable
-  override fun models(events: Flow<UserEditEvent>): UserEditState = userEditPresenter(events)
-
-  @Composable
-  fun userEditPresenter(events: Flow<UserEditEvent>): UserEditState {
-    var state by remember { mutableStateOf(UserEditState()) }
-
-    LaunchedEffect(Unit) {
-      events.collect {
-        when (it) {
-          is LoadUser -> {
-            val user = it.user
-            if (user != null) {
-              state = state.copy(
-                firstName = user.firstName,
-                lastName = user.lastName,
-                loginId = user.loginId,
-                emailAddress = user.emailAddress,
-                timezone = user.timezone,
-                role = user.userType,
-              )
-            }
-          }
-          is Save -> {
-            // Save the user edits
-          }
-          is ClearField -> {
-            state = updateField(it.fieldName, "", state)
-          }
-
-          is UpdateField -> {
-            state = updateField(it.fieldName, it.value, state)
-          }
-        }
-      }
-    }
-    return state
-  }
-
-  private fun updateField(fieldName: String, value: String, state: UserEditState): UserEditState = when (fieldName) {
-    "firstName" -> state.copy(firstName = value)
-    "lastName" -> state.copy(lastName = value)
-    "loginId" -> state.copy(loginId = value)
-    "emailAddress" -> state.copy(emailAddress = value)
-    "timezone" -> state.copy(timezone = value)
-    "role" -> state.copy(role = value)
-    else -> state
-  }
-
-  suspend fun loadUser(user: User?) {
-    events.emit(LoadUser(user))
-  }
-
-  suspend fun clearField(fieldName: String) {
-    events.emit(ClearField(fieldName))
-  }
-
-  suspend fun updateField(fieldName: String, value: String) {
-    events.emit(UpdateField(fieldName, value))
-  }
-
-  suspend fun saveUserEdits() {
-    events.emit(Save)
-  }
-}
diff --git a/shared/shared/src/jvmMain/kotlin/edu/ucsc/its/temerity/shared/data/Actual.StorageModule.kt b/shared/shared/src/jvmMain/kotlin/edu/ucsc/its/temerity/shared/data/Actual.StorageModule.kt
deleted file mode 100644
index 450adb52947c0c32d6c8ce7ebffd4a4b98a8b7e4..0000000000000000000000000000000000000000
--- a/shared/shared/src/jvmMain/kotlin/edu/ucsc/its/temerity/shared/data/Actual.StorageModule.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.data
-
-import androidx.datastore.core.DataStore
-import androidx.datastore.preferences.core.Preferences
-import edu.ucsc.its.temerity.shared.createDataStore
-import org.koin.core.context.GlobalContext.get
-import org.koin.dsl.module
-
-internal actual fun storageModule() = module {
-  single { dataStore() }
-}
-
-fun dataStore(): DataStore<Preferences> =
-  createDataStore(
-    producePath = { "temerity.preferences_pb" },
-  )
diff --git a/shared/shared/src/jvmMain/kotlin/edu/ucsc/its/temerity/shared/database/AppDatabaseBuilder.kt b/shared/shared/src/jvmMain/kotlin/edu/ucsc/its/temerity/shared/database/AppDatabaseBuilder.kt
deleted file mode 100644
index 08b870e620c39645d9966382c118a750c18d2162..0000000000000000000000000000000000000000
--- a/shared/shared/src/jvmMain/kotlin/edu/ucsc/its/temerity/shared/database/AppDatabaseBuilder.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Designed and developed in 2022-2024 by William Walker (wnwalker@ucsc.edu)
- * Copyright 2022-2024 The Regents of the University of California. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package edu.ucsc.its.temerity.shared.database
-
-import androidx.room.Room
-import androidx.room.RoomDatabase
-import org.koin.core.context.GlobalContext.get
-import org.koin.core.parameter.parametersOf
-import org.koin.core.qualifier.named
-import java.io.File
-
-fun getRoomDbBuilder(): RoomDatabase.Builder<AppDatabase> {
-  val appDataDir = get().get<String> {
-    named("appDataDir")
-    parametersOf("edu.ucsc.its.temerity")
-  }
-  val dbFile = File(appDataDir, DB_FILENAME)
-  return Room.databaseBuilder<AppDatabase>(
-    name = dbFile.absolutePath,
-  )
-}
diff --git a/temerity/build.gradle.kts b/temerity/build.gradle.kts
index 62d36fb7861d2aed3a52e41b86aa2b1853b9b0ef..7c5a579fe1a9866d82881c43be2e0436ee07aecd 100644
--- a/temerity/build.gradle.kts
+++ b/temerity/build.gradle.kts
@@ -28,7 +28,7 @@ plugins {
     alias(libs.plugins.kotestMultiplatform)
     alias(libs.plugins.buildConfig)
 
-    id("convention.formattingLib")
+    id("convention.formatting")
     id("convention.version")
     alias(libs.plugins.dokka)
     id("convention.publication")