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")