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"