diff --git a/README.md b/README.md index 1740102..6f071cf 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -# UniScan +
+UniScan logo +

UniScan

![GitHub Release](https://img.shields.io/github/v/release/UniScanProject/UniScan?sort=date&filter=UniScan.Client.App%2F*&label=Client) ![GitHub Release](https://img.shields.io/github/v/release/UniScanProject/UniScan?sort=date&filter=UniScan.Server.Host%2F*&display_name=tag&label=Server) ---- +
Modular scanner/radio client and multi-broadcast server. Plug in a scanner, set it up in the server software, and open it up to the internet for others to listen to, and control it yourself by logging into an admin user. @@ -27,8 +29,12 @@ it up to the internet for others to listen to, and control it yourself by loggin | [UniScan.UserInterface](src/Core/UniScan.UserInterface) | 0.0.1 | Serverside UI definitions | | [UniScan.Client.Core](src/Client/UniScan.Client.Core) | 0.3.0 | Holds shared client code, no dep on Avalonia | | [UniScan.Client.App](src/Client/UniScan.Client.App) | 0.1.1 | UniScan client | -| [UniScan.Client.App.Platform.Android](src/Client/UniScan.Client.App.Platform.Android) | 0.0.5 | UniScan client for Android | -| [UniScan.Client.App.Platform.Browser](src/Client/UniScan.Client.App.Platform.Browser) | 0.1.3 | UniScan client for web browsers (https://uniscan.dexrn.me) | +| [UniScan.Client.App.Platform.Android](src/Client/UniScan.Client.App.Platform.Android) | 0.0.6 | UniScan client for Android | +| [UniScan.Client.App.Platform.Browser](src/Client/UniScan.Client.App.Platform.Browser) | 0.1.4 | UniScan client for web browsers (https://uniscan.dexrn.me) | | [UniScan.Client.App.Platform.Desktop](src/Client/UniScan.Client.App.Platform.Desktop) | 0.0.3 | UniScan client for desktop | | [UniScan.Client.App.Platform.iOS](src/Client/UniScan.Client.App.Platform.iOS) | 0.0.1 | UniScan client for iOS | -| [UniScan.Modules.DebugModule](src/Modules/UniScan.Modules.DebugModule) | 0.0.1 | | \ No newline at end of file +| [UniScan.Modules.DebugModule](src/Modules/UniScan.Modules.DebugModule) | 0.0.1 | | + +## Credits +(in the future, these will be included in the About page.) +- [Unobtainable Melon (Unomelon)](https://bsky.app/profile/unomelon.bsky.social) | Creating the base of the logo for me to work off of. (thus helping me learn a little about pixel art in the process) \ No newline at end of file diff --git a/branding/desktop/pixel/README.md b/branding/desktop/pixel/README.md new file mode 100644 index 0000000..7a055ff --- /dev/null +++ b/branding/desktop/pixel/README.md @@ -0,0 +1,5 @@ +Thanks to [Unobtainable Melon (Unomelon)](https://bsky.app/profile/unomelon.bsky.social) for drawing the bases of the logos for me to work off of to make the final product! + +There is also a handheld version that will be added when logo switching is added. + +In the future, the displays on the devices will be colorable as a setting. (kind of like how the BCD996P2 does it) \ No newline at end of file diff --git a/branding/desktop/pixel/alpha/logo.alpha.1024x1024.png b/branding/desktop/pixel/alpha/logo.alpha.1024x1024.png new file mode 100644 index 0000000..b969205 Binary files /dev/null and b/branding/desktop/pixel/alpha/logo.alpha.1024x1024.png differ diff --git a/branding/desktop/pixel/alpha/logo.alpha.128x128.png b/branding/desktop/pixel/alpha/logo.alpha.128x128.png new file mode 100644 index 0000000..afc537e Binary files /dev/null and b/branding/desktop/pixel/alpha/logo.alpha.128x128.png differ diff --git a/branding/desktop/pixel/alpha/logo.alpha.192x192.png b/branding/desktop/pixel/alpha/logo.alpha.192x192.png new file mode 100644 index 0000000..3bfd5bd Binary files /dev/null and b/branding/desktop/pixel/alpha/logo.alpha.192x192.png differ diff --git a/branding/desktop/pixel/alpha/logo.alpha.256x256.png b/branding/desktop/pixel/alpha/logo.alpha.256x256.png new file mode 100644 index 0000000..59d4eac Binary files /dev/null and b/branding/desktop/pixel/alpha/logo.alpha.256x256.png differ diff --git a/branding/desktop/pixel/alpha/logo.alpha.32x32.png b/branding/desktop/pixel/alpha/logo.alpha.32x32.png new file mode 100644 index 0000000..3c905ba Binary files /dev/null and b/branding/desktop/pixel/alpha/logo.alpha.32x32.png differ diff --git a/branding/desktop/pixel/alpha/logo.alpha.512x512.png b/branding/desktop/pixel/alpha/logo.alpha.512x512.png new file mode 100644 index 0000000..eac086a Binary files /dev/null and b/branding/desktop/pixel/alpha/logo.alpha.512x512.png differ diff --git a/branding/desktop/pixel/alpha/logo.alpha.64x64.png b/branding/desktop/pixel/alpha/logo.alpha.64x64.png new file mode 100644 index 0000000..1637879 Binary files /dev/null and b/branding/desktop/pixel/alpha/logo.alpha.64x64.png differ diff --git a/branding/desktop/pixel/alpha/logo.alpha.96x96.png b/branding/desktop/pixel/alpha/logo.alpha.96x96.png new file mode 100644 index 0000000..7bf9ed5 Binary files /dev/null and b/branding/desktop/pixel/alpha/logo.alpha.96x96.png differ diff --git a/branding/desktop/pixel/logo.1024x1024.png b/branding/desktop/pixel/logo.1024x1024.png new file mode 100644 index 0000000..d2f0e04 Binary files /dev/null and b/branding/desktop/pixel/logo.1024x1024.png differ diff --git a/branding/desktop/pixel/logo.128x128.png b/branding/desktop/pixel/logo.128x128.png new file mode 100644 index 0000000..bdeed9c Binary files /dev/null and b/branding/desktop/pixel/logo.128x128.png differ diff --git a/branding/desktop/pixel/logo.192x192.png b/branding/desktop/pixel/logo.192x192.png new file mode 100644 index 0000000..c19071e Binary files /dev/null and b/branding/desktop/pixel/logo.192x192.png differ diff --git a/branding/desktop/pixel/logo.256x256.png b/branding/desktop/pixel/logo.256x256.png new file mode 100644 index 0000000..92d4a27 Binary files /dev/null and b/branding/desktop/pixel/logo.256x256.png differ diff --git a/branding/desktop/pixel/logo.32x32.png b/branding/desktop/pixel/logo.32x32.png new file mode 100644 index 0000000..8a2ee01 Binary files /dev/null and b/branding/desktop/pixel/logo.32x32.png differ diff --git a/branding/desktop/pixel/logo.512x512.png b/branding/desktop/pixel/logo.512x512.png new file mode 100644 index 0000000..7dff1be Binary files /dev/null and b/branding/desktop/pixel/logo.512x512.png differ diff --git a/branding/desktop/pixel/logo.64x64.png b/branding/desktop/pixel/logo.64x64.png new file mode 100644 index 0000000..2fc0394 Binary files /dev/null and b/branding/desktop/pixel/logo.64x64.png differ diff --git a/branding/desktop/pixel/logo.96x96.png b/branding/desktop/pixel/logo.96x96.png new file mode 100644 index 0000000..87723a1 Binary files /dev/null and b/branding/desktop/pixel/logo.96x96.png differ diff --git a/branding/desktop/pixel/logo.ico b/branding/desktop/pixel/logo.ico new file mode 100644 index 0000000..9069329 Binary files /dev/null and b/branding/desktop/pixel/logo.ico differ diff --git a/branding/desktop/pixel/logo.svg b/branding/desktop/pixel/logo.svg new file mode 100644 index 0000000..df342ed --- /dev/null +++ b/branding/desktop/pixel/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.1024x1024.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.1024x1024.png new file mode 100644 index 0000000..a4fcc11 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.1024x1024.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.128x128.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.128x128.png new file mode 100644 index 0000000..43d3ae4 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.128x128.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.192x192.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.192x192.png new file mode 100644 index 0000000..9015b78 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.192x192.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.256x256.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.256x256.png new file mode 100644 index 0000000..8e99043 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.256x256.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.32x32.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.32x32.png new file mode 100644 index 0000000..8c5f645 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.32x32.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.512x512.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.512x512.png new file mode 100644 index 0000000..0044edc Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.512x512.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.64x64.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.64x64.png new file mode 100644 index 0000000..d8fc32b Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.64x64.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.96x96.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.96x96.png new file mode 100644 index 0000000..566dc9b Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.96x96.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.1024x1024.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.1024x1024.png new file mode 100644 index 0000000..a2678c6 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.1024x1024.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.128x128.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.128x128.png new file mode 100644 index 0000000..b523f13 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.128x128.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.192x192.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.192x192.png new file mode 100644 index 0000000..6677dbc Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.192x192.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.256x256.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.256x256.png new file mode 100644 index 0000000..535ed46 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.256x256.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.32x32.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.32x32.png new file mode 100644 index 0000000..51a33fe Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.32x32.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.512x512.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.512x512.png new file mode 100644 index 0000000..89389b4 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.512x512.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.64x64.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.64x64.png new file mode 100644 index 0000000..84440e9 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.64x64.png differ diff --git a/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.96x96.png b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.96x96.png new file mode 100644 index 0000000..0ca63a7 Binary files /dev/null and b/branding/desktop/pixel/mask/alpha/logo.alpha.mask.foreground.96x96.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.1024x1024.png b/branding/desktop/pixel/mask/logo.mask.1024x1024.png new file mode 100644 index 0000000..e1e01ab Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.1024x1024.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.128x128.png b/branding/desktop/pixel/mask/logo.mask.128x128.png new file mode 100644 index 0000000..4207f53 Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.128x128.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.192x192.png b/branding/desktop/pixel/mask/logo.mask.192x192.png new file mode 100644 index 0000000..76da48b Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.192x192.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.256x256.png b/branding/desktop/pixel/mask/logo.mask.256x256.png new file mode 100644 index 0000000..9172fbd Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.256x256.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.32x32.png b/branding/desktop/pixel/mask/logo.mask.32x32.png new file mode 100644 index 0000000..743a518 Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.32x32.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.512x512.png b/branding/desktop/pixel/mask/logo.mask.512x512.png new file mode 100644 index 0000000..371f72d Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.512x512.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.64x64.png b/branding/desktop/pixel/mask/logo.mask.64x64.png new file mode 100644 index 0000000..cf2f413 Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.64x64.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.96x96.png b/branding/desktop/pixel/mask/logo.mask.96x96.png new file mode 100644 index 0000000..6d32f4d Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.96x96.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.foreground.1024x1024.png b/branding/desktop/pixel/mask/logo.mask.foreground.1024x1024.png new file mode 100644 index 0000000..d84ba3d Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.foreground.1024x1024.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.foreground.128x128.png b/branding/desktop/pixel/mask/logo.mask.foreground.128x128.png new file mode 100644 index 0000000..ea37e0b Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.foreground.128x128.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.foreground.192x192.png b/branding/desktop/pixel/mask/logo.mask.foreground.192x192.png new file mode 100644 index 0000000..07c60e4 Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.foreground.192x192.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.foreground.256x256.png b/branding/desktop/pixel/mask/logo.mask.foreground.256x256.png new file mode 100644 index 0000000..e6dac7d Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.foreground.256x256.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.foreground.32x32.png b/branding/desktop/pixel/mask/logo.mask.foreground.32x32.png new file mode 100644 index 0000000..f08ca77 Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.foreground.32x32.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.foreground.512x512.png b/branding/desktop/pixel/mask/logo.mask.foreground.512x512.png new file mode 100644 index 0000000..dac53af Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.foreground.512x512.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.foreground.64x64.png b/branding/desktop/pixel/mask/logo.mask.foreground.64x64.png new file mode 100644 index 0000000..33c790b Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.foreground.64x64.png differ diff --git a/branding/desktop/pixel/mask/logo.mask.foreground.96x96.png b/branding/desktop/pixel/mask/logo.mask.foreground.96x96.png new file mode 100644 index 0000000..813d347 Binary files /dev/null and b/branding/desktop/pixel/mask/logo.mask.foreground.96x96.png differ diff --git a/src/Client/UniScan.Client.App.Platform.Android/Icon.png b/src/Client/UniScan.Client.App.Platform.Android/Icon.png deleted file mode 100755 index 3c39845..0000000 Binary files a/src/Client/UniScan.Client.App.Platform.Android/Icon.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App.Platform.Android/MainActivity.cs b/src/Client/UniScan.Client.App.Platform.Android/MainActivity.cs index f0d44e3..12aef3d 100755 --- a/src/Client/UniScan.Client.App.Platform.Android/MainActivity.cs +++ b/src/Client/UniScan.Client.App.Platform.Android/MainActivity.cs @@ -8,7 +8,7 @@ namespace UniScan.Client.App.Platform.Android; [Activity( Label = "UniScan", Theme = "@style/MyTheme.NoActionBar", - Icon = "@drawable/icon", + Icon = "@mipmap/ic_launcher", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] [IntentFilter(["android.intent.action.MAIN"], Categories = ["android.intent.category.LEANBACK_LAUNCHER"])] diff --git a/src/Client/UniScan.Client.App.Platform.Android/Properties/AndroidManifest.xml b/src/Client/UniScan.Client.App.Platform.Android/Properties/AndroidManifest.xml index b9f0c58..77a7ebd 100755 --- a/src/Client/UniScan.Client.App.Platform.Android/Properties/AndroidManifest.xml +++ b/src/Client/UniScan.Client.App.Platform.Android/Properties/AndroidManifest.xml @@ -1,7 +1,7 @@  - + diff --git a/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-night-v31/avalonia_anim.xml b/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-night-v31/avalonia_anim.xml deleted file mode 100755 index dde4b5a..0000000 --- a/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-night-v31/avalonia_anim.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-v31/avalonia_anim.xml b/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-v31/avalonia_anim.xml deleted file mode 100755 index 94f27d9..0000000 --- a/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-v31/avalonia_anim.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-xxxhdpi/ic_desktop.png b/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-xxxhdpi/ic_desktop.png new file mode 100644 index 0000000..7742027 Binary files /dev/null and b/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-xxxhdpi/ic_desktop.png differ diff --git a/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-xxxhdpi/ic_desktop_cutout.png b/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-xxxhdpi/ic_desktop_cutout.png new file mode 100644 index 0000000..18270f3 Binary files /dev/null and b/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable-xxxhdpi/ic_desktop_cutout.png differ diff --git a/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable/splash_screen.xml b/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable/splash_screen.xml index 2e920b4..d48db39 100755 --- a/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable/splash_screen.xml +++ b/src/Client/UniScan.Client.App.Platform.Android/Resources/drawable/splash_screen.xml @@ -5,7 +5,7 @@ - diff --git a/src/Client/UniScan.Client.App.Platform.Android/Resources/mipmap-anydpi-v26/ic_launcher.xml b/src/Client/UniScan.Client.App.Platform.Android/Resources/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..1256e1c --- /dev/null +++ b/src/Client/UniScan.Client.App.Platform.Android/Resources/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Client/UniScan.Client.App.Platform.Android/Resources/values-v31/styles.xml b/src/Client/UniScan.Client.App.Platform.Android/Resources/values-v31/styles.xml index c6fd4b5..1dc571f 100755 --- a/src/Client/UniScan.Client.App.Platform.Android/Resources/values-v31/styles.xml +++ b/src/Client/UniScan.Client.App.Platform.Android/Resources/values-v31/styles.xml @@ -8,8 +8,8 @@ false @null true - - @drawable/avalonia_anim + @color/splash_background + @drawable/ic_desktop 1000 @style/MyTheme.Main diff --git a/src/Client/UniScan.Client.App.Platform.Android/Resources/values/colors.xml b/src/Client/UniScan.Client.App.Platform.Android/Resources/values/colors.xml index 59279d5..6539c78 100755 --- a/src/Client/UniScan.Client.App.Platform.Android/Resources/values/colors.xml +++ b/src/Client/UniScan.Client.App.Platform.Android/Resources/values/colors.xml @@ -1,4 +1,5 @@  + #FFFFFF #FFFFFF diff --git a/src/Client/UniScan.Client.App.Platform.Android/UniScan.Client.App.Platform.Android.csproj b/src/Client/UniScan.Client.App.Platform.Android/UniScan.Client.App.Platform.Android.csproj index 54ffcb7..638c231 100755 --- a/src/Client/UniScan.Client.App.Platform.Android/UniScan.Client.App.Platform.Android.csproj +++ b/src/Client/UniScan.Client.App.Platform.Android/UniScan.Client.App.Platform.Android.csproj @@ -9,19 +9,13 @@ false UniScanProject UniScan Android - 0.0.5 - 0.0.5 - 1 + 0.0.6 + 0.0.6 + 2 $(AssemblyVersion) UniScan client for Android - - - Resources\drawable\Icon.png - - - diff --git a/src/Client/UniScan.Client.App.Platform.Browser/UniScan.Client.App.Platform.Browser.csproj b/src/Client/UniScan.Client.App.Platform.Browser/UniScan.Client.App.Platform.Browser.csproj index 5878497..8ea7673 100755 --- a/src/Client/UniScan.Client.App.Platform.Browser/UniScan.Client.App.Platform.Browser.csproj +++ b/src/Client/UniScan.Client.App.Platform.Browser/UniScan.Client.App.Platform.Browser.csproj @@ -11,7 +11,6 @@ false false - 0.0.2 UniScan Web UniScanProject UniScan client for web browsers (https://uniscan.dexrn.me) @@ -20,8 +19,8 @@ https://github.com/UniScanProject/UniScan UniScanProject UniScan Web - 0.1.3 - 0.1.3 + 0.1.4 + 0.1.4 @@ -42,4 +41,8 @@ + + + + diff --git a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/app.webmanifest b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/app.webmanifest index 5fdaad6..e7c7d64 100644 --- a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/app.webmanifest +++ b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/app.webmanifest @@ -3,17 +3,22 @@ "name": "UniScan Web", "icons": [ { - "src": "/assets/logo_128x128.png", + "src": "/assets/branding/desktop/pixel/logo.svg", + "sizes": "any", + "type": "image/svg+xml" + }, + { + "src": "/assets/branding/desktop/pixel/logo.128x128.png", "sizes": "128x128", "type": "image/png" }, { - "src": "/assets/logo_512x512.png", + "src": "/assets/branding/desktop/pixel/logo.192x192.png", "sizes": "192x192", "type": "image/png" }, { - "src": "/assets/logo_512x512.png", + "src": "/assets/branding/desktop/pixel/logo.512x512.png", "sizes": "512x512", "type": "image/png" } diff --git a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/README.md b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/README.md deleted file mode 100644 index 979155e..0000000 --- a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/README.md +++ /dev/null @@ -1 +0,0 @@ -AVALONIA LOGOS ARE TEMP UNTIL I CAN EITHER MAKE MY OWN LOGO OR FIND SOMEONE WHO WILL WANT TO MAKE ONE FOR ME \ No newline at end of file diff --git a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/branding b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/branding new file mode 120000 index 0000000..3d91304 --- /dev/null +++ b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/branding @@ -0,0 +1 @@ +../../../../../branding \ No newline at end of file diff --git a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_128x128.png b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_128x128.png deleted file mode 100644 index b704696..0000000 Binary files a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_128x128.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_192x192.png b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_192x192.png deleted file mode 100644 index 176aea8..0000000 Binary files a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_192x192.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_400x400.png b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_400x400.png deleted file mode 100644 index 3c39845..0000000 Binary files a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_400x400.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_512x512.png b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_512x512.png deleted file mode 100644 index 29b4d8c..0000000 Binary files a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/assets/logo_512x512.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/index.html b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/index.html index 5217ea7..3f4cfd3 100755 --- a/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/index.html +++ b/src/Client/UniScan.Client.App.Platform.Browser/wwwroot/index.html @@ -4,7 +4,15 @@ UniScan Web - + + + + + + + + + @@ -34,12 +42,11 @@ - - - - - - + + + + + diff --git a/src/Client/UniScan.Client.App/Assets/Branding b/src/Client/UniScan.Client.App/Assets/Branding new file mode 120000 index 0000000..1c99f10 --- /dev/null +++ b/src/Client/UniScan.Client.App/Assets/Branding @@ -0,0 +1 @@ +../../../../branding \ No newline at end of file diff --git a/src/Client/UniScan.Client.App/Assets/README.md b/src/Client/UniScan.Client.App/Assets/README.md deleted file mode 100644 index 979155e..0000000 --- a/src/Client/UniScan.Client.App/Assets/README.md +++ /dev/null @@ -1 +0,0 @@ -AVALONIA LOGOS ARE TEMP UNTIL I CAN EITHER MAKE MY OWN LOGO OR FIND SOMEONE WHO WILL WANT TO MAKE ONE FOR ME \ No newline at end of file diff --git a/src/Client/UniScan.Client.App/Assets/avalonia-logo.ico b/src/Client/UniScan.Client.App/Assets/avalonia-logo.ico deleted file mode 100755 index f7da8bb..0000000 Binary files a/src/Client/UniScan.Client.App/Assets/avalonia-logo.ico and /dev/null differ diff --git a/src/Client/UniScan.Client.App/Assets/logo_128x128.png b/src/Client/UniScan.Client.App/Assets/logo_128x128.png deleted file mode 100644 index b704696..0000000 Binary files a/src/Client/UniScan.Client.App/Assets/logo_128x128.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App/Assets/logo_192x192.png b/src/Client/UniScan.Client.App/Assets/logo_192x192.png deleted file mode 100644 index 176aea8..0000000 Binary files a/src/Client/UniScan.Client.App/Assets/logo_192x192.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App/Assets/logo_400x400.png b/src/Client/UniScan.Client.App/Assets/logo_400x400.png deleted file mode 100644 index 3c39845..0000000 Binary files a/src/Client/UniScan.Client.App/Assets/logo_400x400.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App/Assets/logo_512x512.png b/src/Client/UniScan.Client.App/Assets/logo_512x512.png deleted file mode 100644 index 29b4d8c..0000000 Binary files a/src/Client/UniScan.Client.App/Assets/logo_512x512.png and /dev/null differ diff --git a/src/Client/UniScan.Client.App/Core/Module/IUniScanClientAppModule.cs b/src/Client/UniScan.Client.App/Core/Module/IUniScanClientAppModule.cs index 7c0de1c..6ff5fbf 100755 --- a/src/Client/UniScan.Client.App/Core/Module/IUniScanClientAppModule.cs +++ b/src/Client/UniScan.Client.App/Core/Module/IUniScanClientAppModule.cs @@ -2,13 +2,15 @@ using Microsoft.Extensions.DependencyInjection; using Shiki.ModuleManagement; using Shiki.ModuleManagement.Module; +using UniScan.Core.Settings; using UniScan.Platform; namespace UniScan.Client.App.Core.Module; -public class UniScanClientAppModuleInitializationArgs(UniScanApp app) : EventArgs +public class UniScanClientAppModuleInitializationArgs(UniScanApp app, SettingsManagerBuilder settingsBuilder) : EventArgs { public UniScanApp App { get; } + public SettingsManagerBuilder SettingsBuilder { get; } = settingsBuilder; } public interface IUniScanClientAppModule : IModule diff --git a/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.Initializers.cs b/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.Initializers.cs index 55c0373..eb6f7fe 100644 --- a/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.Initializers.cs +++ b/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.Initializers.cs @@ -65,8 +65,15 @@ public static async Task InitializeEnvironment(TaskContexts.PreEnvironment ctx, Log.Debug("Cache path: {Path}", ctx.StandardPaths.CachePath); #endif } + + public static void InitializeSettingsBuilder(UniScanAppInitializationPipeline.TaskContexts.PreSettings ctx, ITaskExecutionContext execCtx) + { + execCtx.Status.Value = "Initializing Settings builder"; + + //nothing to do here for now + } - public static void SetupClientMessagePackResolvers(TaskContexts.PreTranslations ctx, + public static void SetupClientMessagePackResolvers(TaskContexts.PreSettings ctx, ITaskExecutionContext execCtx) { execCtx.Status.Value = "Initializing client MessagePack resolvers"; @@ -82,7 +89,7 @@ public static void SetupClientMessagePackResolvers(TaskContexts.PreTranslations MessagePackSerializer.DefaultOptions = MessagePackSerializer.DefaultOptions.WithResolver(resolver); } - public static void InitializeSoftwareInfo(UniScanAppInitializationPipeline.TaskContexts.PreTranslations ctx, ITaskExecutionContext execCtx) + public static void InitializeSoftwareInfo(UniScanAppInitializationPipeline.TaskContexts.PreSettings ctx, ITaskExecutionContext execCtx) { execCtx.Status.Value = "Initializing SoftwareInfo"; @@ -90,7 +97,7 @@ public static void InitializeSoftwareInfo(UniScanAppInitializationPipeline.TaskC Log.Information("{Info}", UniScanApp.SoftwareInfo); } - public static void SetupBindableRegistry(TaskContexts.PreTranslations ctx, + public static void SetupBindableRegistry(TaskContexts.PreSettings ctx, ITaskExecutionContext execCtx) { execCtx.Status.Value = "Initializing bindables"; @@ -126,7 +133,7 @@ await mgr.ApplyLanguagesFromSourceAsync(new DirectoryKeyValueLanguageSource( return new TaskContexts.PreServiceProvider(ctx.UniScanApp, ctx.ServiceCollection, mgr, ctx.PlatformStandardPaths, ctx.PlatformFileManager, - ctx.PlatformDirectoryManager); + ctx.PlatformDirectoryManager, ctx.SettingsManager); } public static void SetupTextComponentResolver(TaskContexts.PreServiceProvider ctx, @@ -142,12 +149,12 @@ public static void SetupTextComponentResolver(TaskContexts.PreServiceProvider ct ctx.ServiceCollection.AddSingleton(); } - public static void SetupSSRSlotRegistry(TaskContexts.PreTranslations ctx, ITaskExecutionContext execCtx) + public static void SetupSSRSlotRegistry(TaskContexts.PreSettings ctx, ITaskExecutionContext execCtx) { execCtx.Status.Value = "Initializing serverside UI rendering slot registry"; ctx.ServiceCollection.AddSingleton(); } - + public static void SetupSSRUI(TaskContexts.PreServiceProvider ctx, ITaskExecutionContext execCtx) { execCtx.Status.Value = "Initializing serverside UI rendering"; @@ -183,7 +190,7 @@ public static TaskContexts.UniScanAppReady InitializeServiceProvider(TaskContext { execCtx.Status.Value = "Building ServiceProvider"; - return new TaskContexts.UniScanAppReady(ctx.UniScanApp, ctx.ServiceCollection.BuildServiceProvider()); + return new TaskContexts.UniScanAppReady(ctx.UniScanApp, ctx.SettingsManager, ctx.ServiceCollection.BuildServiceProvider()); } public static async Task InitializeRemotes(TaskContexts.UniScanAppReady ctx, diff --git a/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.TaskContexts.cs b/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.TaskContexts.cs index 2e5c563..b905ac3 100644 --- a/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.TaskContexts.cs +++ b/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.TaskContexts.cs @@ -3,6 +3,7 @@ using Shiki.FileSystem.Abstractions; using Shiki.Internationalization.Translation; using Shiki.TaskPipeline.Context; +using UniScan.Core.Settings; using UniScan.Platform; namespace UniScan.Client.App.Core.Pipeline.Initialization; @@ -20,13 +21,22 @@ public record PreEnvironment(UniScanApp UniScanApp) : ITaskContext public IPlatformDirectoryManager? DirectoryManager { get; set; } public IPlatformSerilogInitializer? SerilogInitializer { get; set; } } + + public record PreSettings(UniScanApp UniScanApp, ServiceCollection ServiceCollection, IPlatformStandardPaths PlatformStandardPaths, IPlatformFileManager PlatformFileManager, IPlatformDirectoryManager PlatformDirectoryManager) + : ITransitionableTaskContext + { + public SettingsManagerBuilder SettingsBuilder { get; } = new SettingsManagerBuilder(); + public SettingsManager? SettingsManager { get; set; } + + public static PreSettings TransitionFrom(PreEnvironment oldContext) => new(oldContext.UniScanApp, oldContext.ServiceCollection, oldContext.StandardPaths ?? throw new NullReferenceException(), oldContext.FileManager ?? throw new NullReferenceException(), oldContext.DirectoryManager ?? throw new NullReferenceException()); + } - public record PreTranslations(UniScanApp UniScanApp, ServiceCollection ServiceCollection, IPlatformStandardPaths PlatformStandardPaths, IPlatformFileManager PlatformFileManager, IPlatformDirectoryManager PlatformDirectoryManager) - : ITransitionableTaskContext + public record PreTranslations(UniScanApp UniScanApp, ServiceCollection ServiceCollection, IPlatformStandardPaths PlatformStandardPaths, IPlatformFileManager PlatformFileManager, IPlatformDirectoryManager PlatformDirectoryManager, SettingsManager SettingsManager) + : ITransitionableTaskContext { public TranslationManager? TranslationManager { get; set; } - public static PreTranslations TransitionFrom(PreEnvironment oldContext) => new(oldContext.UniScanApp, oldContext.ServiceCollection, oldContext.StandardPaths ?? throw new NullReferenceException(), oldContext.FileManager ?? throw new NullReferenceException(), oldContext.DirectoryManager ?? throw new NullReferenceException()); + public static PreTranslations TransitionFrom(PreSettings oldContext) => new(oldContext.UniScanApp, oldContext.ServiceCollection, oldContext.PlatformStandardPaths, oldContext.PlatformFileManager, oldContext.PlatformDirectoryManager, oldContext.SettingsManager ?? throw new NullReferenceException()); } public record PreServiceProvider( @@ -35,9 +45,10 @@ public record PreServiceProvider( TranslationManager TranslationManager, IPlatformStandardPaths PlatformStandardPaths, IPlatformFileManager PlatformFileManager, - IPlatformDirectoryManager PlatformDirectoryManager) + IPlatformDirectoryManager PlatformDirectoryManager, + SettingsManager SettingsManager) : ITaskContext; - public record UniScanAppReady(UniScanApp UniScanApp, IServiceProvider ServiceProvider) : ITaskContext; + public record UniScanAppReady(UniScanApp UniScanApp, SettingsManager SettingsManager, IServiceProvider ServiceProvider) : ITaskContext; } } \ No newline at end of file diff --git a/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.cs b/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.cs index b09e82f..ab9514d 100644 --- a/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.cs +++ b/src/Client/UniScan.Client.App/Core/Pipeline/Initialization/UniScanAppInitializationPipeline.cs @@ -22,12 +22,15 @@ public UniScanAppInitializationPipeline(UniScanApp app) { _logger = Log.ForContext(); }) - .ThenTransitionTo() + .ThenTransitionTo()//settingsbuilder created in here + .ThenRun(Initializers.InitializeSettingsBuilder) .ThenRun(Initializers.SetupClientMessagePackResolvers) .ThenRun(Initializers.InitializeSoftwareInfo) .ThenRun(Initializers.SetupSSRSlotRegistry) .ThenRunAsync(app.InitializeModules) .ThenRun(Initializers.SetupBindableRegistry) + .ThenRunAsync(app.InitializeSettings) + .ThenTransitionTo() .ThenRunToTransitionToAsync(Initializers.SetupTranslations) .ThenRun(Initializers.SetupTextComponentResolver) .ThenRun(Initializers.SetupSSRUI) diff --git a/src/Client/UniScan.Client.App/UniScan.Client.App.csproj b/src/Client/UniScan.Client.App/UniScan.Client.App.csproj index 19bfd96..c5e858b 100755 --- a/src/Client/UniScan.Client.App/UniScan.Client.App.csproj +++ b/src/Client/UniScan.Client.App/UniScan.Client.App.csproj @@ -196,19 +196,19 @@ - + true PreserveNewest - + true PreserveNewest - + true PreserveNewest - + true PreserveNewest diff --git a/src/Client/UniScan.Client.App/UniScanApp.Initializers.cs b/src/Client/UniScan.Client.App/UniScanApp.Initializers.cs index fbd3ea6..f045348 100644 --- a/src/Client/UniScan.Client.App/UniScanApp.Initializers.cs +++ b/src/Client/UniScan.Client.App/UniScanApp.Initializers.cs @@ -13,36 +13,45 @@ using UniScan.Client.App.Core.Module.Modules.Internal; using UniScan.Client.App.Core.Pipeline.Initialization; using UniScan.Client.Core; +using UniScan.Core.Settings; using UniScan.Platform; namespace UniScan.Client.App; public partial class UniScanApp { - internal async Task InitializeModules(UniScanAppInitializationPipeline.TaskContexts.PreTranslations ctx, ITaskExecutionContext execCtx) + internal async Task InitializeSettings(UniScanAppInitializationPipeline.TaskContexts.PreSettings ctx, + ITaskExecutionContext execCtx) + { + execCtx.Status.Value = "Loading settings"; + + var res = await ctx.SettingsBuilder.BuildAndLoadAsync(); + + ctx.SettingsManager = res.settingsManager; + ctx.ServiceCollection.AddSingleton(_ => res.settingsManager); + } + + + internal async Task InitializeModules(UniScanAppInitializationPipeline.TaskContexts.PreSettings ctx, ITaskExecutionContext execCtx) { execCtx.Status.Value = "Initializing modules"; var moduleStorageBuilder = new ModuleStorageBuilder() .WithModuleOfType(null); - - await using ServiceProvider serviceProvider = ctx.ServiceCollection.BuildServiceProvider(); - IPlatformStandardPaths standardPaths = serviceProvider.GetRequiredService(); - IPlatformDirectoryManager directoryManager = serviceProvider.GetRequiredService(); - string moduleDir = Path.Combine(standardPaths.DataPath, "modules"); - if (!(await directoryManager.ExistsAsync(moduleDir))) + string moduleDir = Path.Combine(ctx.PlatformStandardPaths.DataPath, "modules"); + if (!(await ctx.PlatformDirectoryManager.ExistsAsync(moduleDir))) { Log.Information("Creating new modules folder"); - await directoryManager.CreateDirectoryAsync(moduleDir); + await ctx.PlatformDirectoryManager.CreateDirectoryAsync(moduleDir); } - moduleStorageBuilder.WithSource(new AssembliesModuleSource(moduleDir), new UniScanClientAppModuleInitializationArgs(this)); + moduleStorageBuilder.WithSource(new AssembliesModuleSource(moduleDir), new UniScanClientAppModuleInitializationArgs(this, ctx.SettingsBuilder)); string localModules = Path.Combine(Environment.CurrentDirectory, "modules"); - if (await directoryManager.ExistsAsync(localModules)) + if (await ctx.PlatformDirectoryManager.ExistsAsync(localModules)) { - moduleStorageBuilder.WithSource(new AssembliesModuleSource(localModules), new UniScanClientAppModuleInitializationArgs(this)); + moduleStorageBuilder.WithSource(new AssembliesModuleSource(localModules), new UniScanClientAppModuleInitializationArgs(this, ctx.SettingsBuilder)); } ModuleStorage = await moduleStorageBuilder.BuildAsync(); diff --git a/src/Client/UniScan.Client.App/UniScanApp.axaml.cs b/src/Client/UniScan.Client.App/UniScanApp.axaml.cs index f06211c..6945043 100755 --- a/src/Client/UniScan.Client.App/UniScanApp.axaml.cs +++ b/src/Client/UniScan.Client.App/UniScanApp.axaml.cs @@ -23,6 +23,7 @@ using UniScan.Client.Core; using UniScan.Client.Core.DI.Factory; using UniScan.Client.Core.Module.Modules.Internal; +using UniScan.Core.Settings; using UniScan.Network.Data.Info.Software; using UniScan.Platform; using MainView = UniScan.Client.App.Views.MainView; @@ -63,6 +64,8 @@ public partial class UniScanApp : Application public static string VersionString => $"UniScan Client v{SoftwareInfo.AppInfo.Version} ({PlatformAttribute!.Identifier} v{PlatformVersion})"; + public SettingsManager Manager { get; private set; } = null!; + public ModuleStorage? ModuleStorage { get; diff --git a/src/Client/UniScan.Client.App/Views/Global/LoadingView.axaml b/src/Client/UniScan.Client.App/Views/Global/LoadingView.axaml index 0e0887e..9b1f353 100644 --- a/src/Client/UniScan.Client.App/Views/Global/LoadingView.axaml +++ b/src/Client/UniScan.Client.App/Views/Global/LoadingView.axaml @@ -9,7 +9,7 @@ x:DataType="global:LoadingViewModel"> - + diff --git a/src/Client/UniScan.Client.App/Views/MainWindow.axaml b/src/Client/UniScan.Client.App/Views/MainWindow.axaml index 2ff741c..a5a1103 100755 --- a/src/Client/UniScan.Client.App/Views/MainWindow.axaml +++ b/src/Client/UniScan.Client.App/Views/MainWindow.axaml @@ -5,7 +5,7 @@ xmlns:views2="clr-namespace:UniScan.Client.App.Views" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="UniScan.Client.App.Views.MainWindow" - Icon="/Assets/avalonia-logo.ico" + Icon="/Assets/Branding/desktop/pixel/logo.ico" Title="UniScan"> diff --git a/src/Core/UniScan.Core/Bootstrap.cs b/src/Core/UniScan.Core/Bootstrap.cs index 69dedbc..df7fd13 100644 --- a/src/Core/UniScan.Core/Bootstrap.cs +++ b/src/Core/UniScan.Core/Bootstrap.cs @@ -11,7 +11,7 @@ using Shiki.Internationalization; using Shiki.Internationalization.Component; using UniScan.Core.State.Node; -using UniScan.Network.Formatter.Device; +using UniScan.Core.State.Node.Formatter; namespace UniScan.Core; diff --git a/src/Core/UniScan.Core/Settings/IOption.cs b/src/Core/UniScan.Core/Settings/IOption.cs new file mode 100644 index 0000000..4456504 --- /dev/null +++ b/src/Core/UniScan.Core/Settings/IOption.cs @@ -0,0 +1,79 @@ +using ObservableCollections; +using R3; +using Shiki.Common.Identity; +using Shiki.Common.Result; +using Shiki.Internationalization.Component; + +namespace UniScan.Core.Settings; + +public interface IReadOnlyOption +{ + Identifier Identifier { get; } + + ITextComponent Name { get; } + ITextComponent Description { get; } + + Observable ValueChanged { get; } + + Type Type { get; } + + object? GetValue(); +} + +public interface IOption : IReadOnlyOption +{ + BooleanResult SetValue(object? value); +} + +public interface IReadOnlyOption : IReadOnlyOption +{ + new T GetValue(); +} + +public interface IOption : IOption, IReadOnlyOption +{ + Observable IReadOnlyOption.ValueChanged => Value.AsObservable().Select(_ => Unit.Default).Skip(1); + + IBindableReactiveProperty Value { get; } + + Type IReadOnlyOption.Type => typeof(T); + + + BooleanResult IOption.SetValue(object? value) => value is T v ? SetValue(v) : new InvalidOperationException("Given value is not of type " + typeof(T)); + BooleanResult SetValue(T value); + + object? IReadOnlyOption.GetValue() => GetValue(); + T IReadOnlyOption.GetValue() => Value.Value; +} + +public class SettingOption : IOption +{ + public Identifier Identifier { get; } + public Identifier CategoryIdentifier { get; } + + public required ITextComponent Name { get; init; } + public required ITextComponent Description { get; init; } + + public IBindableReactiveProperty Value { get; } + + public SettingOption(Identifier id, Identifier category, T defaultValue) + { + Identifier = id; + CategoryIdentifier = category; + Value = new BindableReactiveProperty(defaultValue); + } + + public BooleanResult SetValue(T value) + { + Value.Value = value; + return BooleanResult.Successful; + } +} + +public class SettingsCategory(Identifier id, ITextComponent name) +{ + public Identifier Id { get; } = id; + public ITextComponent Name { get; } = name; + + public Identifier? Parent { get; init; } +} \ No newline at end of file diff --git a/src/Core/UniScan.Core/Settings/SettingsManager.cs b/src/Core/UniScan.Core/Settings/SettingsManager.cs new file mode 100644 index 0000000..92b2879 --- /dev/null +++ b/src/Core/UniScan.Core/Settings/SettingsManager.cs @@ -0,0 +1,178 @@ +using System.Collections.Immutable; +using ObservableCollections; +using R3; +using Serilog; +using Shiki.Common.Identity; +using Shiki.Common.Result; +using Shiki.FileSystem.Storage; +using UniScan.Core.Settings.Storage; + +namespace UniScan.Core.Settings; + +public class SettingsManagerBuilder +{ + public readonly record struct OptionMetadata(IOption Option, Identifier Storage); + + private readonly Dictionary _options = []; + private readonly Dictionary _categories = []; + private readonly Dictionary _storages = []; + + public BooleanResult TryAddCategory(SettingsCategory category) + { + if (!_categories.TryAdd(category.Id, category)) + return new InvalidOperationException("Category already exists"); + + return BooleanResult.Successful; + } + + public BooleanResult TryAddOption(IOption option, Identifier storage) + { + if (!_storages.ContainsKey(storage)) + { + return new KeyNotFoundException("Storage not found"); + } + + if (!_options.TryAdd(option.Identifier, new OptionMetadata(option, storage))) + { + return new InvalidOperationException("Option already exists"); + } + + return BooleanResult.Successful; + } + + public BooleanResult TryAddStorage(Identifier id, IOptionStorage storage) + { + if (!_storages.TryAdd(id, storage)) + throw new InvalidOperationException("Storage already exists"); + + return BooleanResult.Successful; + } + + public SettingsManager Build() + { + //todo + return new SettingsManager(_options, _categories, _storages); + } + + public async ValueTask<(SettingsManager settingsManager, IReadOnlyCollection> Errors)> BuildAndLoadAsync()//todo we can create another result type later that holds the value with errors + { + SettingsManager b = Build(); + var errors = await b.LoadAsync(); + + return (b, errors); + } +} + +public class SettingsManager : IDisposable +{ + private readonly record struct LockableOptionStorageHolder(IOptionStorage OptionStorage, SemaphoreSlim Semaphore); + + private readonly CompositeDisposable _disposables = new CompositeDisposable(); + + private readonly Dictionary _options = []; + private readonly Dictionary _categories = []; + private readonly Dictionary _storages = []; + + private readonly Subject _dirty = new(); + + private bool _loadLock = false; + + private ILogger _logger = Log.ForContext(); + + internal SettingsManager(Dictionary options, Dictionary categories, Dictionary storages) + { + _options = options; + _categories = categories; + _storages = storages.ToDictionary(kvp => kvp.Key, kvp => new LockableOptionStorageHolder(kvp.Value, new SemaphoreSlim(1,1))); + + foreach (SettingsManagerBuilder.OptionMetadata option in _options.Values) + { + option.Option.ValueChanged.Where(_ => !_loadLock).Subscribe(_ => _dirty.OnNext(option)).AddTo(_disposables); + } + + _dirty.Chunk(TimeSpan.FromMilliseconds(500), TimeProvider.System) + .Where(c => c.Length > 0) + .Subscribe(ids => + { + var u = ids.DistinctBy(m => m.Option.Identifier).GroupBy(m => m.Storage).ToImmutableArray(); + + foreach (var g in u) + { + if (_storages.TryGetValue(g.Key, out LockableOptionStorageHolder storage)) + { + //TODO this is probably slow, lets fix it later. + var changed = g.Select(m => m.Option).ToImmutableList(); + var all = _options.Values.Where(m => m.Storage == g.Key) + .Select(m => m.Option) + .ToImmutableList(); + + _ = RunObservedSave(storage, changed, all); + } + } + }).AddTo(_disposables); + } + + private async Task RunObservedSave(LockableOptionStorageHolder holder, + IReadOnlyCollection changed, + IReadOnlyCollection allOptions) + { + BooleanResult res = await RunSave(holder, changed, allOptions); + if (!res.IsSuccessful) + { + _logger.Error(res.Error, "Observed save failed!"); + } + } + + private async ValueTask> RunSave(LockableOptionStorageHolder holder, + IReadOnlyCollection changed, + IReadOnlyCollection allOptions) + { + await holder.Semaphore.WaitAsync(); + + var res = await holder.OptionStorage.SaveAsync(changed, allOptions); + holder.Semaphore.Release(); + + return res; + } + + public async ValueTask>> LoadAsync() + { + _loadLock = true;//maybe should use volatile or some lock but too lazy + try + { + var t = _storages.Select(async kvp => + { + LockableOptionStorageHolder holder = kvp.Value; + + var opt = _options.Values.Where(m => m.Storage == kvp.Key).Select(m => m.Option).ToImmutableList(); + + await holder.Semaphore.WaitAsync(); + try + { + return await holder.OptionStorage.LoadAsync(opt); + } + finally + { + holder.Semaphore.Release(); + } + }); + + return await Task.WhenAll(t);//maybe should make ResultCollection later + } + finally + { + _loadLock = false; + } + } + + public void Dispose() + { + _dirty.Dispose(); + _disposables.Dispose(); + + foreach (LockableOptionStorageHolder holder in _storages.Values) + { + holder.Semaphore.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/Core/UniScan.Core/Settings/Storage/IOptionStorage.cs b/src/Core/UniScan.Core/Settings/Storage/IOptionStorage.cs new file mode 100644 index 0000000..05cd736 --- /dev/null +++ b/src/Core/UniScan.Core/Settings/Storage/IOptionStorage.cs @@ -0,0 +1,54 @@ +using Shiki.Common.Result; +using Shiki.FileSystem.Storage; + +namespace UniScan.Core.Settings.Storage; + +public interface IOptionStorage +{ + ValueTask> LoadAsync(IReadOnlyCollection options); + ValueTask> SaveAsync(IReadOnlyCollection changed, IReadOnlyCollection allOptions); +} + +public class SingleOptionStorage(IStorage> storage) : IOptionStorage +{ + public async ValueTask> LoadAsync(IReadOnlyCollection options) + { + if (options.Count == 0) + return new ArgumentException("Options is empty", nameof(options)); + + if (options.Count > 1) + return new ArgumentException("Multiple options provided for single option storage", nameof(options)); + + IOption opt = options.First(); + + try + { + T loaded = await storage.LoadAsync(); + opt.SetValue(loaded); + } + catch (Exception e) + { + return e; + } + + return BooleanResult.Successful; + } + + public async ValueTask> SaveAsync(IReadOnlyCollection changed, + IReadOnlyCollection allOptions) + { + if (changed.Count == 0) + return new ArgumentException("Options is empty", nameof(allOptions)); + + if (changed.Count > 1) + return new ArgumentException("Multiple options provided for single option storage", nameof(allOptions)); + + IOption opt = changed.First(); + + if (opt.GetValue() is not T d) + return new ArgumentException("Changed value is not of correct type for this option storage"); + + await storage.SaveAsync(d); + return BooleanResult.Successful; + } +} \ No newline at end of file diff --git a/src/Core/UniScan.Core/State/Node/Formatter/DeviceNodeFormatter.cs b/src/Core/UniScan.Core/State/Node/Formatter/DeviceNodeFormatter.cs index 59f5c83..fcb5323 100644 --- a/src/Core/UniScan.Core/State/Node/Formatter/DeviceNodeFormatter.cs +++ b/src/Core/UniScan.Core/State/Node/Formatter/DeviceNodeFormatter.cs @@ -2,15 +2,12 @@ using System.Reflection; using MessagePack; using MessagePack.Formatters; -using Serilog; using Shiki.Common.Identity; -using Shiki.Common.Serialization.Polymorphism; using Shiki.Common.Serialization.Registry; using Shiki.Common.Serialization.Registry.Validators; -using UniScan.Core.State.Node; using UniScan.Core.State.Node.Nodes; -namespace UniScan.Network.Formatter.Device; +namespace UniScan.Core.State.Node.Formatter; public abstract class DeviceNodeTypeRegistryValidator : IHasAttributeTypeRegistryValidator { diff --git a/src/Server/UniScan.Server.Core/UniScanServer.cs b/src/Server/UniScan.Server.Core/UniScanServer.cs index c31227f..bdfeead 100755 --- a/src/Server/UniScan.Server.Core/UniScanServer.cs +++ b/src/Server/UniScan.Server.Core/UniScanServer.cs @@ -87,7 +87,7 @@ public class UniScanServer Uri("https://github.com/UniScanProject/UniScan")), new RemoteLink(new - Uri("https://uniscan.dexrn.me/assets/logo_512x512.png"), + Uri("https://uniscan.dexrn.me/assets/branding/desktop/pixel/logo.512x512.png"), "UniScan Web", new Uri("https://uniscan.dexrn.me")), diff --git a/template/README.md.template b/template/README.md.template index 2520378..36f89e2 100644 --- a/template/README.md.template +++ b/template/README.md.template @@ -1,8 +1,10 @@ -# UniScan +
+UniScan logo +

UniScan

![GitHub Release](https://img.shields.io/github/v/release/UniScanProject/UniScan?sort=date&filter=UniScan.Client.App%2F*&label=Client) ![GitHub Release](https://img.shields.io/github/v/release/UniScanProject/UniScan?sort=date&filter=UniScan.Server.Host%2F*&display_name=tag&label=Server) ---- +
Modular scanner/radio client and multi-broadcast server. Plug in a scanner, set it up in the server software, and open it up to the internet for others to listen to, and control it yourself by logging into an admin user. @@ -11,4 +13,8 @@ it up to the internet for others to listen to, and control it yourself by loggin | Name | Version | Description | |:-----------------------------------------------------------------------------------------------:|:-------:|------------------------------------------------| -{ProjectRows} \ No newline at end of file +{ProjectRows} + +## Credits +(in the future, these will be included in the About page.) +- [Unobtainable Melon (Unomelon)](https://bsky.app/profile/unomelon.bsky.social) | Creating the base of the logo for me to work off of. (thus helping me learn a little about pixel art in the process) \ No newline at end of file