diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56ef963..1de46c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,10 @@ jobs: with: distribution: 'temurin' java-version: ${{env.JAVA_VERSION}} + - uses: actions-rs/toolchain@v1 + if: matrix.os == 'windows-latest' + with: + toolchain: 'stable' - name: Setup MacOS signing if: matrix.os == 'macos-latest' env: @@ -90,10 +94,14 @@ jobs: New-Item -ItemType directory -Path certificate Set-Content -Path certificate\certificate.txt -Value '${{ secrets.WINDOWS_CERTIFICATE }}' certutil -decode certificate\certificate.txt certificate\certificate.pfx + - name: Build MSIX + if: matrix.os == 'windows-latest' + run: | + & 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe' pack /d app/desktop/build/msix-workspace /p Tonbrett.msix - name: Code Sign 2021 if: matrix.os == 'windows-latest' run: | - & 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe' sign /f certificate\certificate.pfx /p '${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}' /t http://timestamp.sectigo.com/ /d Tonbrett app/desktop/build/compose/binaries/main-release/msi/*.msi + & 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe' sign /f certificate\certificate.pfx /p '${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}' /t http://timestamp.sectigo.com/ /d Tonbrett Tonbrett.msix - name: Notarize MacOS installer #if: matrix.os == 'macos-latest' # waiting for https://github.com/JetBrains/compose-multiplatform/issues/3208 @@ -108,9 +116,8 @@ jobs: with: name: desktopapp-${{ matrix.os }} path: | + *.msix app/desktop/build/compose/binaries/main-release/deb/*.deb - app/desktop/build/compose/binaries/main-release/msi/*.msi - app/desktop/build/compose/binaries/main-release/pkg/*.pkg app/desktop/build/compose/binaries/main-release/pkg/*.pkg app/desktop/build/distributions/*.tar.gz build_android_app: @@ -206,7 +213,7 @@ jobs: files: | compose/binaries/main-release/deb/*.deb compose/binaries/main-release/pkg/*.pkg - compose/binaries/main-release/msi/*.msi + *.msix distributions/*.tar.gz *.zip *-signed.apk diff --git a/.gitignore b/.gitignore index a20ec59..e617be5 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,6 @@ out/ .settings .springBeans .sts4-cache -bin/ !**/src/main/**/bin/ !**/src/test/**/bin/ @@ -56,3 +55,5 @@ app/ios/iosApp.xcworkspace/* app/ios/iosApp.xcodeproj/* !app/ios/iosApp.xcodeproj/project.pbxproj app/ios/ios.podspec + +**/target diff --git a/app/desktop/build.gradle.kts b/app/desktop/build.gradle.kts index e344946..da3096b 100644 --- a/app/desktop/build.gradle.kts +++ b/app/desktop/build.gradle.kts @@ -1,4 +1,5 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat +import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask import org.jetbrains.kotlin.org.jline.utils.OSUtils import kotlin.io.path.pathString @@ -25,7 +26,7 @@ compose.desktop { "java.naming" // required by logback ) when { - OSUtils.IS_WINDOWS -> targetFormats(TargetFormat.Msi) + OSUtils.IS_WINDOWS -> targetFormats(TargetFormat.AppImage) OSUtils.IS_OSX -> targetFormats(TargetFormat.Pkg) else -> targetFormats(TargetFormat.Deb) } @@ -78,4 +79,36 @@ tasks { compression = Compression.GZIP archiveExtension = "tar.gz" } + + val buildUwpHelper by creating(Exec::class) { + inputs.dir("uwp_helper/src") + outputs.dir("uwp_helper/target") + + workingDir = file("uwp_helper") + commandLine("cargo", "build", "--release") + } + + val prepareUwpWorkspace by creating(Copy::class) { + dependsOn(buildUwpHelper) + afterEvaluate { + from(named("packageReleaseAppImage")) { + eachFile { + path = path.substringAfter("Tonbrett") + } + } + } + from(file("uwp_helper/target/release")) { + include("*.exe") + } + from(file("msix")) + into(buildDir.resolve("msix-workspace")) + } + + afterEvaluate { + "packageReleaseDistributionForCurrentOS" { + if (OSUtils.IS_WINDOWS) { + dependsOn(prepareUwpWorkspace) + } + } + } } diff --git a/app/desktop/msix/appxmanifest.xml b/app/desktop/msix/appxmanifest.xml new file mode 100644 index 0000000..9d388bd --- /dev/null +++ b/app/desktop/msix/appxmanifest.xml @@ -0,0 +1,47 @@ + + + + + Tonbrett + Schlaubi + Companion app for Discord soundboard bot + logo.png + + + + + + + + + + + + + + + + + + + + + + + Tonbrett Protocol + + + + + + diff --git a/app/desktop/msix/logo.png b/app/desktop/msix/logo.png new file mode 100644 index 0000000..e69de29 diff --git a/app/desktop/src/main/kotlin/Main.kt b/app/desktop/src/main/kotlin/Main.kt index e121b64..09f6775 100644 --- a/app/desktop/src/main/kotlin/Main.kt +++ b/app/desktop/src/main/kotlin/Main.kt @@ -22,14 +22,9 @@ import androidx.compose.ui.window.* import dev.schlaubi.tonbrett.app.ColorScheme import dev.schlaubi.tonbrett.app.ProvideImageLoader import dev.schlaubi.tonbrett.app.TonbrettApp -import dev.schlaubi.tonbrett.app.api.AppContext -import dev.schlaubi.tonbrett.app.api.ProvideContext -import dev.schlaubi.tonbrett.app.api.getConfig -import dev.schlaubi.tonbrett.app.api.getUrl +import dev.schlaubi.tonbrett.app.api.* import dev.schlaubi.tonbrett.app.strings.LocalStrings import dev.schlaubi.tonbrett.app.title -import dev.schlaubi.tonbrett.client.href -import dev.schlaubi.tonbrett.common.Route import io.ktor.http.* import mu.KotlinLogging import java.net.URI @@ -37,12 +32,31 @@ import java.awt.Window as AWTWindow private val LOG = KotlinLogging.logger { } -fun main() = main(reAuthorize = false) { startApplication() } +fun main(args: Array) { + if (windowsAppDataFolder != null) { + System.setProperty("user.home", windowsAppDataFolder!!) + } + + val argsString = args.joinToString(" ") + if (argsString.startsWith("tonbrett://login")) { + try { + LOG.info { "Launched App with $argsString saving token now" } + val token = Url(argsString).parameters["token"] + saveConfig(Config(token)) + } catch (e: Exception) { + e.printStackTrace() + Thread.sleep(50000) + } + startApplication() + } else { + main(reAuthorize = false) { startApplication() } + } +} fun main(reAuthorize: Boolean, onAuth: () -> Unit) { val config = getConfig() - if (reAuthorize || config.sessionToken == null) { - browseUrl(href(Route.Auth(Route.Auth.Type.APP), URLBuilder(getUrl())).build().toURI()) + if (true && config.sessionToken == null) { + //browseUrl(href(Route.Auth(Route.Auth.Type.APP), URLBuilder(getUrl())).build().toURI()) startAuthorizationServer(reAuthorize, onAuth) } else { startApplication() diff --git a/app/desktop/src/main/kotlin/URIUtil.kt b/app/desktop/src/main/kotlin/URIUtil.kt index 283a7a2..86e2492 100644 --- a/app/desktop/src/main/kotlin/URIUtil.kt +++ b/app/desktop/src/main/kotlin/URIUtil.kt @@ -4,10 +4,17 @@ import java.awt.Desktop import java.net.URI fun browseUrl(url: URI) { - val desktop = Desktop.getDesktop() - if (desktop.isSupported(Desktop.Action.BROWSE)) { - desktop.browse(url) + // Desktop#browse() internally uses ShellExecute, which doesn't work in UWP apps, therefore, + // We use a Rust binary, which calls: + // https://learn.microsoft.com/de-de/uwp/api/windows.system.launcher.launchuriasync?view=winrt-22621 + if (System.getProperty("os.name").contains("windows", ignoreCase = true)) { + Runtime.getRuntime().exec(arrayOf("url_launcher.exe", "-u", url.toString())) } else { - Runtime.getRuntime().exec(arrayOf("xdg-open", url.toString())) + val desktop = Desktop.getDesktop() + if (desktop.isSupported(Desktop.Action.BROWSE)) { + desktop.browse(url) + } else { + Runtime.getRuntime().exec(arrayOf("xdg-open", url.toString())) + } } } diff --git a/app/desktop/uwp_helper/Cargo.lock b/app/desktop/uwp_helper/Cargo.lock new file mode 100644 index 0000000..38f6394 --- /dev/null +++ b/app/desktop/uwp_helper/Cargo.lock @@ -0,0 +1,443 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "clap" +version = "4.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9394150f5b4273a1763355bd1c2ec54cc5a2593f790587bcd6b2c947cfa9211" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a78fbdd3cc2914ddf37ba444114bc7765bbdcb55ec9cbe6fa054f0137400717" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "proc-macro2" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustix" +version = "0.37.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +dependencies = [ + "autocfg", + "num_cpus", + "pin-project-lite", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uwp_helper" +version = "0.1.0" +dependencies = [ + "clap", + "tokio", + "windows", +] + +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/app/desktop/uwp_helper/Cargo.toml b/app/desktop/uwp_helper/Cargo.toml new file mode 100644 index 0000000..67bb2df --- /dev/null +++ b/app/desktop/uwp_helper/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "uwp_helper" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "url_launcher" +path = "src/bin/url_launcher.rs" + +[[bin]] +name = "get_appdata_folder" +path = "src/bin/get_appdata_folder.rs" + +[dependencies.clap] +version = "4" +features = ["derive"] + +[dependencies.windows] +version = "0.44.0" +features = ["System", "Foundation", "Storage"] + +[dependencies.tokio] +version = "1.25.0" +features = ["macros", "rt-multi-thread"] diff --git a/app/desktop/uwp_helper/src/bin/get_appdata_folder.rs b/app/desktop/uwp_helper/src/bin/get_appdata_folder.rs new file mode 100644 index 0000000..a2b54ea --- /dev/null +++ b/app/desktop/uwp_helper/src/bin/get_appdata_folder.rs @@ -0,0 +1,11 @@ +use windows::{ + core::Result, + Storage::ApplicationData +}; + +#[tokio::main] +async fn main() -> Result<()> { + let folder = ApplicationData::Current()?.RoamingFolder()?.Path()?; + print!("{}", folder); + Ok(()) +} diff --git a/app/desktop/uwp_helper/src/bin/url_launcher.rs b/app/desktop/uwp_helper/src/bin/url_launcher.rs new file mode 100644 index 0000000..62e2b3e --- /dev/null +++ b/app/desktop/uwp_helper/src/bin/url_launcher.rs @@ -0,0 +1,19 @@ +use clap::Parser; +use windows::{core::{Result}, Foundation::Uri, System::Launcher}; +use windows::core::HSTRING; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = "Launches URL using UWP APIs")] +struct Args { + // Uri + #[arg(short, long)] + uri: String, +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Args::parse(); + + let uri = Uri::CreateUri(&HSTRING::from(args.uri))?; + Launcher::LaunchUriAsync(&uri)?.await.map(|_| { () }) +} diff --git a/app/shared/src/desktopMain/kotlin/dev/schlaubi/tonbrett/app/api/ConfigFile.kt b/app/shared/src/desktopMain/kotlin/dev/schlaubi/tonbrett/app/api/ConfigFile.kt index 24fccd8..1d506ab 100644 --- a/app/shared/src/desktopMain/kotlin/dev/schlaubi/tonbrett/app/api/ConfigFile.kt +++ b/app/shared/src/desktopMain/kotlin/dev/schlaubi/tonbrett/app/api/ConfigFile.kt @@ -8,20 +8,45 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream import kotlinx.serialization.json.encodeToStream +import mu.KotlinLogging import java.nio.file.Path import java.nio.file.StandardOpenOption import kotlin.io.path.* +private val LOG = KotlinLogging.logger { } + +val windowsAppDataFolder by lazy { + runCatching { + val process = ProcessBuilder() + .command("get_appdata_folder.exe") + .redirectError(ProcessBuilder.Redirect.INHERIT) + .start() + process.waitFor() + + process.inputStream.readAllBytes().decodeToString().also { + LOG.debug { "AppData determined to be $it" } + } + }.getOrNull() +} + @Serializable data class Config(@EncodeDefault(EncodeDefault.Mode.NEVER) val sessionToken: String? = null) fun getAppDataFolder(): Path { val os = System.getProperty("os.name") val basePath = when { - os.contains("windows", ignoreCase = true) -> - Path(System.getenv("APPDATA")) + os.contains("windows", ignoreCase = true) -> { + val uwpFolder = windowsAppDataFolder + if (uwpFolder == null) { + Path(System.getenv("APPDATA")) + } else { + Path(uwpFolder) + } + } + os.contains("mac", ignoreCase = true) -> Path(System.getenv("HOME")) / "Library" / "Application Support" + else -> Path(System.getProperty("user.home")) } return basePath / "Tonbrett"