diff --git a/.github/workflows/ApiReleaseDeployAction.yml b/.github/workflows/ApiReleaseDeployAction.yml new file mode 100644 index 00000000..8a706188 --- /dev/null +++ b/.github/workflows/ApiReleaseDeployAction.yml @@ -0,0 +1,68 @@ +name: Build and Publish Api NuGet + +on: + push: + tags: + - "api-v*" + +jobs: + build: + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/api-v') + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '8.0.x' + + - name: Setup NuGet config + env: + NUGET_USERNAME: ${{ secrets.USER_NAME }} + NUGET_PASSWORD: ${{ secrets.GIHUB_NUGET_AUTH_TOKEN }} + run: | + echo "" > nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + echo "" >> nuget.config + + - name: Install dependencies + run: dotnet restore ./src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj + + - name: Build + run: dotnet build ./src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj --configuration Release --no-restore + + - name: Set version variable + env: + TAG: ${{ github.ref_name }} + run: echo "VERSION=${TAG#api-v}" >> $GITHUB_ENV + + - name: Read version from Directory.Build.props + id: read-version + run: echo "::set-output name=version::$(grep -oP '\K[^<]+' ./src/Directory.Build.props)" + + - name: Compare tag with NuGet package version + run: | + if [ "${{ steps.read-version.outputs.version }}" != "${{ env.VERSION }}" ]; then + echo "Error: Tag does not match NuGet package version" + exit 1 + fi + + - name: Pack package + run: dotnet pack ./src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj -c Release /p:Version=${VERSION} --no-build -o . + + - name: List output files + run: ls -la + + - name: Push package to GitHub + run: dotnet nuget push Asv.Drones.Gui.Api.${VERSION}.nupkg --api-key ${{ secrets.GIHUB_NUGET_AUTH_TOKEN }} --skip-duplicate --source "https://nuget.pkg.github.com/asv-soft/index.json" \ No newline at end of file diff --git a/api_build.bat b/api_build.bat new file mode 100644 index 00000000..a0b21e49 --- /dev/null +++ b/api_build.bat @@ -0,0 +1,32 @@ +@echo off +setlocal enabledelayedexpansion +rem ====== projects ====== + +set project=Asv.Drones.Gui.Api + + +set "file=.\src\Directory.Build.props" + + +:: Èùåì ñòðîêó ñ ApiVersion è èçâëåêàåì çíà÷åíèå +for /f "tokens=2 delims=> " %%a in ('findstr /i /c:"" "%file%"') do ( + set "line=%%a" + for /f "tokens=1 delims=<" %%b in ("!line!") do ( + set "ApiVersion=%%b" + ) +) + +:: Ïðîâåðÿåì è âûâîäèì ðåçóëüòàò +if defined ApiVersion ( + echo ApiVersion: %ApiVersion% + dotnet restore ./src/%project%/%project%.csproj + dotnet build /p:SolutionDir=../;ProductVersion=%ApiVersion% ./src/%project%/%project%.csproj -c Release + dotnet pack ./src/%project%/%project%.csproj -c Release + + +) else ( + echo ApiVersion not found +) + +endlocal +pause \ No newline at end of file diff --git a/api_publish_github.bat b/api_publish_github.bat new file mode 100644 index 00000000..639afff2 --- /dev/null +++ b/api_publish_github.bat @@ -0,0 +1,35 @@ +@echo off +setlocal enabledelayedexpansion +rem ====== projects ====== + +set project=Asv.Drones.Gui.Api + + +set "file=.\src\Directory.Build.props" + + +:: Èùåì ñòðîêó ñ ApiVersion è èçâëåêàåì çíà÷åíèå +for /f "tokens=2 delims=> " %%a in ('findstr /i /c:"" "%file%"') do ( + set "line=%%a" + for /f "tokens=1 delims=<" %%b in ("!line!") do ( + set "ApiVersion=%%b" + ) +) + +:: Ïðîâåðÿåì è âûâîäèì ðåçóëüòàò +if defined ApiVersion ( + echo ApiVersion: %ApiVersion% + cd src\%project%\bin\Release\ +rem dotnet nuget push %project%.%ApiVersion%.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json + dotnet nuget push %project%.%ApiVersion%.nupkg --skip-duplicate --source https://nuget.pkg.github.com/asv-soft/index.json + + +) else ( + echo ApiVersion not found +) + +endlocal +pause + + + diff --git a/publish.bat b/publish.bat new file mode 100644 index 00000000..d73d3fb6 --- /dev/null +++ b/publish.bat @@ -0,0 +1,144 @@ +cd publish + +for /d %%i in (".\*") do ( + rmdir /s /q "%%i" +) + +cd ../src/Asv.Drones.Gui.Desktop + +dotnet publish -c Release -r win-arm --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/win-arm/app +dotnet publish -c Release -r win-arm64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/win-arm64/app +dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/win-x64/app +dotnet publish -c Release -r win-x86 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/win-x86/app + +dotnet publish -c Release -r linux-arm --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/linux-arm/app +dotnet publish -c Release -r linux-arm64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/linux-arm64/app +dotnet publish -c Release -r linux-musl-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/linux-musl-x64/app +dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/linux-x64/app + +dotnet publish -c Release -r osx-arm64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/osx-arm64/app +dotnet publish -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ~/../../../publish/osx-x64/app + +cd ../../publish +del /S *.pdb + +cd win-arm/app +move Asv.Drones.Gui.Desktop.exe asv-drones-win-arm.exe +cd ../../win-arm64/app +move Asv.Drones.Gui.Desktop.exe asv-drones-win-arm64.exe +cd ../../win-x64/app +move Asv.Drones.Gui.Desktop.exe asv-drones-win-x64.exe +cd ../../win-x86/app +move Asv.Drones.Gui.Desktop.exe asv-drones-win-x86.exe + +cd ../../linux-arm/app +move Asv.Drones.Gui.Desktop asv-drones-linux-arm +cd ../../linux-arm64/app +move Asv.Drones.Gui.Desktop asv-drones-linux-arm64 +cd ../../linux-musl-x64/app +move Asv.Drones.Gui.Desktop asv-drones-linux-musl-x64 +cd ../../linux-x64/app +move Asv.Drones.Gui.Desktop asv-drones-linux-x64 + +cd ../../osx-arm64/app +move Asv.Drones.Gui.Desktop asv-drones-osx-arm64 +cd ../../osx-x64/app +move Asv.Drones.Gui.Desktop asv-drones-osx-x64 +cd ../../.. + +setlocal enabledelayedexpansion + +set "xmlFile=src\Directory.Build.props" + +for /f "tokens=2 delims=<> " %%a in ('findstr /i "" "%xmlFile%"') do ( + set "productVersion=%%a" +) + +set "issFile=win-arm-install.iss" + +set "tempFile=%temp%\temp.iss" + +for /f "tokens=*" %%a in ('type "%issFile%"') do ( + set "line=%%a" + + echo !line! | findstr /C:"#define MyAppVersion" > nul + + if !errorlevel! == 0 ( + echo #define MyAppVersion "%productVersion%" >> "%tempFile%" + ) else ( + echo !line! >> "%tempFile%" + ) +) + +move /y "%tempFile%" "%issFile%" > nul + +set "issFile=win-arm64-install.iss" + +set "tempFile=%temp%\temp.iss" + +for /f "tokens=*" %%a in ('type "%issFile%"') do ( + set "line=%%a" + + echo !line! | findstr /C:"#define MyAppVersion" > nul + + if !errorlevel! == 0 ( + echo #define MyAppVersion "%productVersion%" >> "%tempFile%" + ) else ( + echo !line! >> "%tempFile%" + ) +) + +move /y "%tempFile%" "%issFile%" > nul + +set "issFile=win-x64-install.iss" + +set "tempFile=%temp%\temp.iss" + +for /f "tokens=*" %%a in ('type "%issFile%"') do ( + set "line=%%a" + + echo !line! | findstr /C:"#define MyAppVersion" > nul + + if !errorlevel! == 0 ( + echo #define MyAppVersion "%productVersion%" >> "%tempFile%" + ) else ( + echo !line! >> "%tempFile%" + ) +) + +move /y "%tempFile%" "%issFile%" > nul + +set "issFile=win-x86-install.iss" + +set "tempFile=%temp%\temp.iss" + +for /f "tokens=*" %%a in ('type "%issFile%"') do ( + set "line=%%a" + + echo !line! | findstr /C:"#define MyAppVersion" > nul + + if !errorlevel! == 0 ( + echo #define MyAppVersion "%productVersion%" >> "%tempFile%" + ) else ( + echo !line! >> "%tempFile%" + ) +) + +move /y "%tempFile%" "%issFile%" > nul + +endlocal + +cd publish + +iscc ../win-arm-install.iss +iscc ../win-arm64-install.iss +iscc ../win-x86-install.iss +iscc ../win-x64-install.iss + + +wsl sed -i 's/\r//' linux_packages.sh +wsl sed -i 's/\r//' osx_packages.sh + +wsl ../linux_packages.sh + +wsl ../osx_packages.sh \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Android/Asv.Drones.Gui.Android.csproj b/src/Asv.Drones.Gui.Android/Asv.Drones.Gui.Android.csproj index ff2f4c25..9bf0a4ca 100644 --- a/src/Asv.Drones.Gui.Android/Asv.Drones.Gui.Android.csproj +++ b/src/Asv.Drones.Gui.Android/Asv.Drones.Gui.Android.csproj @@ -1,27 +1,15 @@ - - ../Asv.Drones.Gui.Custom.props - $(SolutionDir)Asv.Drones.Gui.Custom.props - - Exe - net7.0-android + net8.0-android 21 enable me.asv.drones.gui 1 1.0 apk - false - false - None - false - Debug;Release - AnyCPU + False - - @@ -31,6 +19,7 @@ + diff --git a/src/Asv.Drones.Gui.Android/MainActivity.cs b/src/Asv.Drones.Gui.Android/MainActivity.cs index 037bba7d..28e82d98 100644 --- a/src/Asv.Drones.Gui.Android/MainActivity.cs +++ b/src/Asv.Drones.Gui.Android/MainActivity.cs @@ -1,18 +1,28 @@ using Android.App; using Android.Content.PM; +using Android.OS; using Avalonia; using Avalonia.Android; using Avalonia.ReactiveUI; +using Environment = System.Environment; namespace Asv.Drones.Gui.Android; -[Activity(Label = "Asv.Drones.Gui.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", - LaunchMode = LaunchMode.SingleTop, MainLauncher = true, +[Activity( + Label = "Asv.Drones.Gui.Android", + Theme = "@style/MyTheme.NoActionBar", + Icon = "@drawable/icon", + MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] public class MainActivity : AvaloniaMainActivity { protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) { + AppArgs.Instance.TryParse(Environment.GetCommandLineArgs()); + AppArgs.Instance.TryParseFile(); + // this is required to use the AndroidHttpClientHandler in main thread + StrictMode.SetThreadPolicy(new StrictMode.ThreadPolicy.Builder().PermitAll().Build()); + return base.CustomizeAppBuilder(builder) .WithInterFont() .UseReactiveUI(); diff --git a/src/Asv.Drones.Gui.Android/Resources/AboutResources.txt b/src/Asv.Drones.Gui.Android/Resources/AboutResources.txt new file mode 100644 index 00000000..c2bca974 --- /dev/null +++ b/src/Asv.Drones.Gui.Android/Resources/AboutResources.txt @@ -0,0 +1,44 @@ +Images, layout descriptions, binary blobs and string dictionaries can be included +in your application as resource files. Various Android APIs are designed to +operate on the resource IDs instead of dealing with images, strings or binary blobs +directly. + +For example, a sample Android app that contains a user interface layout (main.axml), +an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) +would keep its resources in the "Resources" directory of the application: + +Resources/ + drawable/ + icon.png + + layout/ + main.axml + + values/ + strings.xml + +In order to get the build system to recognize Android resources, set the build action to +"AndroidResource". The native Android APIs do not operate directly with filenames, but +instead operate on resource IDs. When you compile an Android application that uses resources, +the build system will package the resources for distribution and generate a class called "R" +(this is an Android convention) that contains the tokens for each one of the resources +included. For example, for the above Resources layout, this is what the R class would expose: + +public class R { + public class drawable { + public const int icon = 0x123; + } + + public class layout { + public const int main = 0x456; + } + + public class strings { + public const int first_string = 0xabc; + public const int second_string = 0xbcd; + } +} + +You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main +to reference the layout/main.axml file, or R.strings.first_string to reference the first +string in the dictionary file values/strings.xml. \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Android/Resources/drawable-night-v31/avalonia_anim.xml b/src/Asv.Drones.Gui.Android/Resources/drawable-night-v31/avalonia_anim.xml new file mode 100644 index 00000000..fb8ed421 --- /dev/null +++ b/src/Asv.Drones.Gui.Android/Resources/drawable-night-v31/avalonia_anim.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Asv.Drones.Gui.Android/Resources/drawable-v31/avalonia_anim.xml b/src/Asv.Drones.Gui.Android/Resources/drawable-v31/avalonia_anim.xml new file mode 100644 index 00000000..149badfc --- /dev/null +++ b/src/Asv.Drones.Gui.Android/Resources/drawable-v31/avalonia_anim.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Asv.Drones.Gui.Android/Resources/drawable/splash_screen.xml b/src/Asv.Drones.Gui.Android/Resources/drawable/splash_screen.xml index 2e920b4b..fcceec62 100644 --- a/src/Asv.Drones.Gui.Android/Resources/drawable/splash_screen.xml +++ b/src/Asv.Drones.Gui.Android/Resources/drawable/splash_screen.xml @@ -1,13 +1,13 @@  - - - + + + - + diff --git a/src/Asv.Drones.Gui.Android/Resources/values-night/colors.xml b/src/Asv.Drones.Gui.Android/Resources/values-night/colors.xml index 3d47b6fc..3c9f0b1e 100644 --- a/src/Asv.Drones.Gui.Android/Resources/values-night/colors.xml +++ b/src/Asv.Drones.Gui.Android/Resources/values-night/colors.xml @@ -1,4 +1,4 @@  - #212121 + #212121 diff --git a/src/Asv.Drones.Gui.Android/Resources/values-v31/styles.xml b/src/Asv.Drones.Gui.Android/Resources/values-v31/styles.xml new file mode 100644 index 00000000..a93e7c47 --- /dev/null +++ b/src/Asv.Drones.Gui.Android/Resources/values-v31/styles.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/src/Asv.Drones.Gui.Android/Resources/values/colors.xml b/src/Asv.Drones.Gui.Android/Resources/values/colors.xml index 59279d5d..53097afb 100644 --- a/src/Asv.Drones.Gui.Android/Resources/values/colors.xml +++ b/src/Asv.Drones.Gui.Android/Resources/values/colors.xml @@ -1,4 +1,4 @@  - #FFFFFF + #FFFFFF diff --git a/src/Asv.Drones.Gui.Android/Resources/values/styles.xml b/src/Asv.Drones.Gui.Android/Resources/values/styles.xml index 2759d290..2deaa4c7 100644 --- a/src/Asv.Drones.Gui.Android/Resources/values/styles.xml +++ b/src/Asv.Drones.Gui.Android/Resources/values/styles.xml @@ -1,17 +1,12 @@  - - - - - - + + + diff --git a/src/Asv.Drones.Gui.Api/App.axaml b/src/Asv.Drones.Gui.Api/App.axaml new file mode 100644 index 00000000..efc3b285 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/App.axaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj b/src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj new file mode 100644 index 00000000..cc25d583 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj @@ -0,0 +1,84 @@ + + + + net8.0 + enable + enable + $(ApiVersion) + true + $(ApiVersion) + https://github.com/asv-soft + API reference for Asv.Drones GUI application + https://github.com/asv-soft + true + $(ApiVersion) + true + $(ApiPrevVersion) + + + + + + + + + + + + + + + + + + + + + all + + + + + PublicResXFileCodeGenerator + RS.Designer.cs + + + + + True + True + RS.resx + + + Code + AttitudeIndicator.axaml + + + TreePageExampleView.axaml + Code + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj.DotSettings b/src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj.DotSettings new file mode 100644 index 00000000..7bcf04b5 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Asv.Drones.Gui.Api.csproj.DotSettings @@ -0,0 +1,67 @@ + + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/CompatibilitySuppressions.xml b/src/Asv.Drones.Gui.Api/CompatibilitySuppressions.xml new file mode 100644 index 00000000..277a2ac9 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/CompatibilitySuppressions.xml @@ -0,0 +1,11 @@ + + + + + CP0006 + P:Asv.Drones.Gui.Api.ILocalizationService.Accuracy + lib/net8.0/Asv.Drones.Gui.Api.dll + lib/net8.0/Asv.Drones.Gui.Api.dll + true + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/FodyWeavers.xml b/src/Asv.Drones.Gui.Api/FodyWeavers.xml similarity index 100% rename from src/Asv.Drones.Gui.Core/FodyWeavers.xml rename to src/Asv.Drones.Gui.Api/FodyWeavers.xml diff --git a/src/Asv.Drones.Gui.Api/RS.Designer.cs b/src/Asv.Drones.Gui.Api/RS.Designer.cs new file mode 100644 index 00000000..6fe140e4 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/RS.Designer.cs @@ -0,0 +1,557 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Asv.Drones.Gui.Api { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class RS { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal RS() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Asv.Drones.Gui.Api.RS", typeof(RS).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Vibration and clipping of UAV. + /// + public static string AltitudeIndicator_Vibration_ToolTip { + get { + return ResourceManager.GetString("AltitudeIndicator_Vibration_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Copy. + /// + public static string Anchor_Editor_Action_Copy { + get { + return ResourceManager.GetString("Anchor_Editor_Action_Copy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Paste. + /// + public static string Anchor_Editor_Action_Paste { + get { + return ResourceManager.GetString("Anchor_Editor_Action_Paste", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Altitude. + /// + public static string AnchorsEditorView_TextBlock_Altitude_Text { + get { + return ResourceManager.GetString("AnchorsEditorView_TextBlock_Altitude_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Latitude. + /// + public static string AnchorsEditorView_TextBlock_Latitude_Text { + get { + return ResourceManager.GetString("AnchorsEditorView_TextBlock_Latitude_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Longitude. + /// + public static string AnchorsEditorView_TextBlock_Longitude_Text { + get { + return ResourceManager.GetString("AnchorsEditorView_TextBlock_Longitude_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Altitude. + /// + public static string AttitudeIndicator_Altitude_ToolTip { + get { + return ResourceManager.GetString("AttitudeIndicator_Altitude_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compass. + /// + public static string AttitudeIndicator_Compass_ToolTip { + get { + return ResourceManager.GetString("AttitudeIndicator_Compass_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Velocity. + /// + public static string AttitudeIndicator_Velocity_ToolTip { + get { + return ResourceManager.GetString("AttitudeIndicator_Velocity_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Delete. + /// + public static string HierarchicalStoreView_Button_DeleteFile { + get { + return ResourceManager.GetString("HierarchicalStoreView_Button_DeleteFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rename. + /// + public static string HierarchicalStoreView_Button_EditFileName { + get { + return ResourceManager.GetString("HierarchicalStoreView_Button_EditFileName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move To Folder. + /// + public static string HierarchicalStoreView_Button_MovefileToFolder { + get { + return ResourceManager.GetString("HierarchicalStoreView_Button_MovefileToFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create New File. + /// + public static string HierarchicalStoreView_Button_ToolTip_CreateNewFile { + get { + return ResourceManager.GetString("HierarchicalStoreView_Button_ToolTip_CreateNewFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create New Folder. + /// + public static string HierarchicalStoreView_Button_ToolTip_CreateNewFolder { + get { + return ResourceManager.GetString("HierarchicalStoreView_Button_ToolTip_CreateNewFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Refresh . + /// + public static string HierarchicalStoreView_Button_ToolTip_Refresh { + get { + return ResourceManager.GetString("HierarchicalStoreView_Button_ToolTip_Refresh", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Delete File. + /// + public static string HierarchicalStoreView_File_Button_DeleteFile { + get { + return ResourceManager.GetString("HierarchicalStoreView_File_Button_DeleteFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rename File. + /// + public static string HierarchicalStoreView_File_Button_EditeFileName { + get { + return ResourceManager.GetString("HierarchicalStoreView_File_Button_EditeFileName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move File. + /// + public static string HierarchicalStoreView_File_Button_MoveFile { + get { + return ResourceManager.GetString("HierarchicalStoreView_File_Button_MoveFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Delete Folder. + /// + public static string HierarchicalStoreView_Folder_Button_DeleteFolder { + get { + return ResourceManager.GetString("HierarchicalStoreView_Folder_Button_DeleteFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rename Folder. + /// + public static string HierarchicalStoreView_Folder_Button_EditFolderName { + get { + return ResourceManager.GetString("HierarchicalStoreView_Folder_Button_EditFolderName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move Folder. + /// + public static string HierarchicalStoreView_Folder_Button_MoveFolderToFolder { + get { + return ResourceManager.GetString("HierarchicalStoreView_Folder_Button_MoveFolderToFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cancel. + /// + public static string HierarchicalStoreView_TextBlock_Text_Cancel { + get { + return ResourceManager.GetString("HierarchicalStoreView_TextBlock_Text_Cancel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move Folder. + /// + public static string HierarchicalStoreView_TextBlock_Text_MoveFolder { + get { + return ResourceManager.GetString("HierarchicalStoreView_TextBlock_Text_MoveFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move Here. + /// + public static string HierarchicalStoreView_TextBlock_Text_MoveHere { + get { + return ResourceManager.GetString("HierarchicalStoreView_TextBlock_Text_MoveHere", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Search. + /// + public static string HierarhicalStoreView_Search_Textbox_Watermark { + get { + return ResourceManager.GetString("HierarhicalStoreView_Search_Textbox_Watermark", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move anchors. + /// + public static string MapMoverActionView_Title { + get { + return ResourceManager.GetString("MapMoverActionView_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fixed wing. + /// + public static string MavlinkHelper_GetTypeName_FixedWing { + get { + return ResourceManager.GetString("MavlinkHelper_GetTypeName_FixedWing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Helicopter. + /// + public static string MavlinkHelper_GetTypeName_Helicopter { + get { + return ResourceManager.GetString("MavlinkHelper_GetTypeName_Helicopter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hexarotor. + /// + public static string MavlinkHelper_GetTypeName_HexaRotor { + get { + return ResourceManager.GetString("MavlinkHelper_GetTypeName_HexaRotor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Octorotor. + /// + public static string MavlinkHelper_GetTypeName_OctoRotor { + get { + return ResourceManager.GetString("MavlinkHelper_GetTypeName_OctoRotor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quadrotor. + /// + public static string MavlinkHelper_GetTypeName_QuadRotor { + get { + return ResourceManager.GetString("MavlinkHelper_GetTypeName_QuadRotor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tricopter. + /// + public static string MavlinkHelper_GetTypeName_TriCopter { + get { + return ResourceManager.GetString("MavlinkHelper_GetTypeName_TriCopter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown type. + /// + public static string MavlinkHelper_GetTypeName_UnknownType { + get { + return ResourceManager.GetString("MavlinkHelper_GetTypeName_UnknownType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value must be a number. + /// + public static string MeasureUnitBase_ErrorMessage_NotANumber { + get { + return ResourceManager.GetString("MeasureUnitBase_ErrorMessage_NotANumber", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value can't be null or white space. + /// + public static string MeasureUnitBase_ErrorMessage_NullOrWhiteSpace { + get { + return ResourceManager.GetString("MeasureUnitBase_ErrorMessage_NullOrWhiteSpace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value must be greater than {0} ({1}). + /// + public static string MeasureUnitExtensions_ErrorMessage_GreaterValue { + get { + return ResourceManager.GetString("MeasureUnitExtensions_ErrorMessage_GreaterValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value must be less than {0} ({1}). + /// + public static string MeasureUnitExtensions_ErrorMessage_LesserValue { + get { + return ResourceManager.GetString("MeasureUnitExtensions_ErrorMessage_LesserValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remove all pinned parameters. + /// + public static string ParametersEditorPageView_PinsOffButton_ToolTip { + get { + return ResourceManager.GetString("ParametersEditorPageView_PinsOffButton_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Star this parameter. + /// + public static string ParametersEditorPageView_StarButton_ToolTip { + get { + return ResourceManager.GetString("ParametersEditorPageView_StarButton_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show only starred parameters. + /// + public static string ParametersEditorPageView_StarsToggleButton_ToolTip { + get { + return ResourceManager.GetString("ParametersEditorPageView_StarsToggleButton_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Update all parameters. + /// + public static string ParametersEditorPageView_UpdateButton_ToolTip { + get { + return ResourceManager.GetString("ParametersEditorPageView_UpdateButton_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Search. + /// + public static string ParametersEditorPageViewModel_Search { + get { + return ResourceManager.GetString("ParametersEditorPageViewModel_Search", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parameters editor [{0}]. + /// + public static string ParametersEditorPageViewModel_Title { + get { + return ResourceManager.GetString("ParametersEditorPageViewModel_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Total: {0}. + /// + public static string ParametersEditorPageViewModel_Total { + get { + return ResourceManager.GetString("ParametersEditorPageViewModel_Total", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On/off pin for this parameter. + /// + public static string ParametersEditorParameterView_PinToggleButton_ToolTip { + get { + return ResourceManager.GetString("ParametersEditorParameterView_PinToggleButton_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reboot required. + /// + public static string ParametersEditorParameterView_RebootRequired { + get { + return ResourceManager.GetString("ParametersEditorParameterView_RebootRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Update. + /// + public static string ParametersEditorParameterView_UpdateButton { + get { + return ResourceManager.GetString("ParametersEditorParameterView_UpdateButton", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Update this parameter from UAV. + /// + public static string ParametersEditorParameterView_UpdateButton_ToolTip { + get { + return ResourceManager.GetString("ParametersEditorParameterView_UpdateButton_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write. + /// + public static string ParametersEditorParameterView_WriteButton { + get { + return ResourceManager.GetString("ParametersEditorParameterView_WriteButton", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write this parameter to UAV. + /// + public static string ParametersEditorParameterView_WriteButton_ToolTip { + get { + return ResourceManager.GetString("ParametersEditorParameterView_WriteButton_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cancel. + /// + public static string ParamPageViewModel_DataLossDialog_CloseButtonText { + get { + return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_CloseButtonText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You're trying to open another menu folder, but you have unsaved changes in the current one. Do you want to save them?. + /// + public static string ParamPageViewModel_DataLossDialog_Content { + get { + return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_Content", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Save. + /// + public static string ParamPageViewModel_DataLossDialog_PrimaryButtonText { + get { + return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_PrimaryButtonText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Don't save. + /// + public static string ParamPageViewModel_DataLossDialog_SecondaryButtonText { + get { + return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_SecondaryButtonText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Potential data loss warning. + /// + public static string ParamPageViewModel_DataLossDialog_Title { + get { + return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_Title", resourceCulture); + } + } + } +} diff --git a/src/Asv.Drones.Gui.Api/RS.resx b/src/Asv.Drones.Gui.Api/RS.resx new file mode 100644 index 00000000..c1d9ae68 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/RS.resx @@ -0,0 +1,193 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Value can't be null or white space + + + Value must be a number + + + Value must be greater than {0} ({1}) + + + Value must be less than {0} ({1}) + + + + + Move anchors + + + Latitude + + + Altitude + + + Longitude + + + Vibration and clipping of UAV + + + Velocity + + + Altitude + + + Compass + + + Refresh + + + Create New Folder + + + Create New File + + + Rename Folder + + + Move Folder + + + Delete Folder + + + Delete File + + + Delete + + + Rename + + + Move To Folder + + + Rename File + + + Move File + + + Search + + + Move Folder + + + Move Here + + + Cancel + + + On/off pin for this parameter + + + Update this parameter from UAV + + + Write this parameter to UAV + + + Reboot required + + + Update + + + Write + + + Potential data loss warning + + + You're trying to open another menu folder, but you have unsaved changes in the current one. Do you want to save them? + + + Save + + + Don't save + + + Cancel + + + Show only starred parameters + + + Update all parameters + + + Remove all pinned parameters + + + Parameters editor [{0}] + + + Search + + + Total: {0} + + + Star this parameter + + + Fixed wing + + + Quadrotor + + + Hexarotor + + + Octorotor + + + Helicopter + + + Tricopter + + + Unknown type + + + Copy + + + Paste + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/RS.ru.resx b/src/Asv.Drones.Gui.Api/RS.ru.resx new file mode 100644 index 00000000..5c30337d --- /dev/null +++ b/src/Asv.Drones.Gui.Api/RS.ru.resx @@ -0,0 +1,189 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + sdsd + + + Значение не должно быть пуÑтым или пробелом + + + Значение должно быть чиÑлом + + + Значение должно быть больше чем {0} ({1}) + + + Значение должно быть меньше чем {0} ({1}) + + + + + ПеремеÑтить ÑÐºÐ¾Ñ€Ñ + + + Широта + + + Ð’Ñ‹Ñота + + + Долгота + + + Ð’Ð¸Ð±Ñ€Ð°Ñ†Ð¸Ñ Ð¸ клиппинг БПЛР+ + + СкороÑÑ‚ÑŒ + + + Ð’Ñ‹Ñота + + + ÐšÐ¾Ð¼Ð¿Ð°Ñ + + + Обновить + + + Удалить Файл + + + Переименовать + + + ПеремеÑтить + + + ПеремеÑтить папку + + + Переименовать папку + + + Удалить файл + + + Переименовать файл + + + ПеремеÑтить файл + + + Удалить папку + + + ПоиÑк + + + ПеремеÑтить папку + + + ПеремеÑтить Ñюда + + + Отмена + + + Включить/выключить закрепление Ñтого параметра + + + Обновить Ñтот парметр из БПЛР+ + + ЗапиÑать Ñтот парметр в БПЛР+ + + ТребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° + + + Обновить + + + ЗапиÑать + + + Отмена + + + Ð’Ñ‹ пытаетеÑÑŒ открыть другой пункт меню, но в текущем у Ð²Ð°Ñ ÐµÑÑ‚ÑŒ неÑохраненные изменениÑ. Хотите Ñохранить их? + + + Сохранить + + + Ðе ÑохранÑÑ‚ÑŒ + + + Предупреждение о возможной потере данных + + + Показать только избранные параметры + + + Обновить вÑе параметры + + + Убрать вÑе прикреплённые параметры + + + + Добавить параметр в избранные + + + Редактор параметров [{0}] + + + Ðайти + + + Ð’Ñего: {0} + + + Создать файл + + + Создать папку + + + Ðеподвижное крыло + + + Вертолёт + + + ГекÑакоптер + + + Октокоптер + + + Квадрокоптер + + + Трикоптер + + + ÐеизвеÑтный тип + + + Копировать + + + Ð’Ñтавить + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/AppHost/IAppArgs.cs b/src/Asv.Drones.Gui.Api/Services/AppHost/IAppArgs.cs new file mode 100644 index 00000000..8ab49860 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/AppHost/IAppArgs.cs @@ -0,0 +1,12 @@ +namespace Asv.Drones.Gui.Api; + +public interface IAppArgs +{ + IReadOnlyDictionary Args { get; } + IReadOnlySet Tags { get; } + + bool TryParse(IEnumerable args); + bool TryParseFile(string argsFile = "app.args"); + + string this[string key, string defaultValue] { get; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/AppHost/IAppInfo.cs b/src/Asv.Drones.Gui.Api/Services/AppHost/IAppInfo.cs new file mode 100644 index 00000000..b170420e --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/AppHost/IAppInfo.cs @@ -0,0 +1,34 @@ +namespace Asv.Drones.Gui.Api; + +public interface IAppInfo +{ + /// + /// Application title + /// + string Name { get; } + + /// + /// Application version + /// + string Version { get; } + + /// + /// Authors + /// + string Author { get; } + + /// + /// Application home page URL + /// + string AppUrl { get; } + + /// + /// Licence name + /// + string AppLicense { get; } + + /// + /// Avalonia UI package version + /// + string AvaloniaVersion { get; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/AppHost/IAppPathInfo.cs b/src/Asv.Drones.Gui.Api/Services/AppHost/IAppPathInfo.cs new file mode 100644 index 00000000..a775b62d --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/AppHost/IAppPathInfo.cs @@ -0,0 +1,15 @@ +namespace Asv.Drones.Gui.Api; + +/// +/// Information about the application's path +/// +public interface IAppPathInfo +{ + /// + /// The folder where the application stores its data. + /// This is the folder where the application stores its data, such as configuration files, logs, and plugins. + /// Folder is created by the application if it does not exist. + /// The folder is created in the user's home directory and will not be deleted when the application is uninstalled or updated. + /// + string AppDataFolder { get; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/AppHost/IApplicationHost.cs b/src/Asv.Drones.Gui.Api/Services/AppHost/IApplicationHost.cs new file mode 100644 index 00000000..b9f1890c --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/AppHost/IApplicationHost.cs @@ -0,0 +1,74 @@ +using System.Collections.Specialized; +using System.Composition.Hosting; +using Asv.Cfg; +using Asv.Common; +using Avalonia.Controls.Templates; + +namespace Asv.Drones.Gui.Api; + +/// +/// Application host +/// +public interface IApplicationHost +{ + /// + /// Application args + /// + IAppArgs Args { get; } + /// + /// Base information about current application + /// + IAppInfo Info { get; } + + /// + /// Path helper + /// + IAppPathInfo Paths { get; } + + /// + /// Host for add data templates + /// + IDataTemplateHost DataTemplateHost { get; } + + /// + /// Configuration of the application + /// + IConfiguration Configuration { get; } + + ILocalizationService Localization { get; } + ILogService Logs { get; } + IPluginManager PluginManager { get; } + + /// + /// IoC container + /// + CompositionHost Container { get; } + + /// + /// Gets an enumerable collection of theme items. + /// + /// + /// An enumerable collection of theme items. + /// + IEnumerable Themes { get; } + + /// + /// Gets the current theme of the application. + /// + /// + /// This property returns an instance of which represents the current theme. + /// + /// + /// An instance representing the current theme of the application. + /// + IRxEditableValue CurrentTheme { get; } + /// + /// Main application view. Can be NULL! before main activity is loading + /// + IShell? Shell { get; } + /// + /// Try to restart application + /// + void RestartApplication(); + +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/AppHost/IThemeInfo.cs b/src/Asv.Drones.Gui.Api/Services/AppHost/IThemeInfo.cs new file mode 100644 index 00000000..4039c3ff --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/AppHost/IThemeInfo.cs @@ -0,0 +1,10 @@ +namespace Asv.Drones.Gui.Api; + +/// +/// Represents a theme item. +/// +public interface IThemeInfo +{ + string Id { get; } + string Name { get; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Localization/ILocalizationService.cs b/src/Asv.Drones.Gui.Api/Services/Localization/ILocalizationService.cs new file mode 100644 index 00000000..d9ac76c2 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Localization/ILocalizationService.cs @@ -0,0 +1,182 @@ +using Asv.Common; + +namespace Asv.Drones.Gui.Api +{ + public interface ILocalizationService + { + /// + /// Allows you to select or get the current application language + /// + IRxEditableValue CurrentLanguage { get; } + + /// + /// Returns the list of available languages + /// + IEnumerable AvailableLanguages { get; } + + #region Units + + /// + /// Convert bytes rate to short localized string + /// For example: 1024 => 1 KB/s + /// + /// + IReadOnlyMeasureUnit ByteRate { get; } + + /// + /// Convert items rate to short localized string + /// For example: 1000 => 1 KHz + /// + /// + IReadOnlyMeasureUnit ItemsRate { get; } + + /// + /// Convert bytes count to short localized string + /// For example: 1024 => 1 KB + /// + /// + IReadOnlyMeasureUnit ByteSize { get; } + + IReadOnlyMeasureUnit RelativeTime { get; } + + IReadOnlyMeasureUnit Voltage { get; } + + IReadOnlyMeasureUnit Current { get; } + IReadOnlyMeasureUnit MAh { get; } + + IMeasureUnit Altitude { get; } + + IMeasureUnit Distance { get; } + + IMeasureUnit Accuracy { get; } // field for gbs plugin only + + IMeasureUnit Latitude { get; } + IMeasureUnit Longitude { get; } + + IMeasureUnit Velocity { get; } + + IMeasureUnit DdmLlz { get; } + IMeasureUnit DdmGp { get; } + + IMeasureUnit Sdm { get; } + + IMeasureUnit Power { get; } + IMeasureUnit AmplitudeModulation { get; } + IMeasureUnit Frequency { get; } + IMeasureUnit Phase { get; } + IMeasureUnit Bearing { get; } + IMeasureUnit Temperature { get; } + IMeasureUnit Degree { get; } + IMeasureUnit FieldStrength { get; } + + #endregion + + public GeoPoint ToSiGeoPoint(string? latitude, string? longitude, string? altitude) + { + var lat = Latitude.IsValid(latitude) ? Latitude.ConvertToSi(latitude) : double.NaN; + var lon = Longitude.IsValid(longitude) ? Longitude.ConvertToSi(longitude) : double.NaN; + var alt = Altitude.IsValid(altitude) ? Altitude.ConvertToSi(altitude) : double.NaN; + return new GeoPoint(lat, lon, alt); + } + } + + public interface ILanguageInfo + { + string Id { get; } + string DisplayName { get; } + } + + public enum AltitudeUnits + { + Meters, + Feets + } + + public enum AmplitudeModulationUnits + { + Percent, + InParts + } + + public enum BearingUnits + { + Degree, + DegreesMinutes + } + + public enum DdmUnits + { + InParts, + Percent, + MicroAmp, + MicroAmpRu + } + + public enum DegreeUnits + { + Degrees, + MinutesSeconds, + DegreesMinutesSeconds + } + + public enum DistanceUnits + { + Meters, + NauticalMiles + } + + public enum FieldStrengthUnits + { + MicroVoltsPerMeter + } + + public enum FrequencyUnits + { + Hz, + KHz, + MHz, + GHz + } + + public enum LatitudeUnits + { + Deg, + Dms + } + + public enum LongitudeUnits + { + Deg, + Dms + } + + public enum PhaseUnits + { + Degree, + Radian + } + + public enum PowerUnits + { + Dbm + } + + public enum SdmUnits + { + Percent + } + + public enum TemperatureUnits + { + Celsius, + Farenheit, + Kelvin + } + + public enum VelocityUnits + { + MetersPerSecond, + KilometersPerHour, + MilesPerHour + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Localization/IMeasureUnit.cs b/src/Asv.Drones.Gui.Api/Services/Localization/IMeasureUnit.cs new file mode 100644 index 00000000..1a1647f7 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Localization/IMeasureUnit.cs @@ -0,0 +1,145 @@ +#nullable enable +using System.Globalization; +using Asv.Common; +using Avalonia; +using Avalonia.Data.Converters; + +namespace Asv.Drones.Gui.Api +{ + public interface IMeasureUnitItem + { + public string Title { get; } + public string Unit { get; } + public bool IsSiUnit { get; } + public TValue ConvertFromSi(TValue siValue); + public TValue ConvertToSi(TValue value); + public TValue Parse(string? value); + bool IsValid(string? value); + string? GetErrorMessage(string? value); + string Print(TValue value); + string PrintWithUnits(TValue value); + + public TValue ConvertToSi(string? value) + { + return ConvertToSi(Parse(value)); + } + + public string FromSiToString(TValue value) + { + return Print(ConvertFromSi(value)); + } + + public string FromSiToStringWithUnits(TValue value) + { + return PrintWithUnits(ConvertFromSi(value)); + } + } + + public interface IMeasureUnitItem : IMeasureUnitItem + { + public TEnum Id { get; } + } + + public interface IMeasureUnit + { + string Title { get; } + string Description { get; } + IEnumerable> AvailableUnits { get; } + IRxEditableValue> CurrentUnit { get; } + IMeasureUnitItem SiUnit { get; } + + public string FromSiToStringWithUnits(TValue value) + { + return CurrentUnit.Value.FromSiToStringWithUnits(value); + } + + public string FromSiToString(TValue value) + { + return CurrentUnit.Value.FromSiToString(value); + } + + public TValue ConvertFromSi(TValue value) + { + return CurrentUnit.Value.ConvertFromSi(value); + } + + public TValue ConvertToSi(TValue value) + { + return CurrentUnit.Value.ConvertToSi(value); + } + + public TValue ConvertToSi(string? value) + { + return CurrentUnit.Value.ConvertToSi(value); + } + + public bool IsValid(string? value) + { + return CurrentUnit.Value.IsValid(value); + } + } + + public static class MeasureUnitExtensions + { + public static bool IsValid(this IMeasureUnit src, double minSiValue, double maxSiValue, + string value) + { + if (src.CurrentUnit.Value.IsValid(value) == false) return false; + if (src.CurrentUnit.Value.ConvertToSi(value) < minSiValue) return false; + if (src.CurrentUnit.Value.ConvertToSi(value) > maxSiValue) return false; + return true; + } + + public static string? GetErrorMessage(this IMeasureUnit src, string? value) + { + return src.CurrentUnit.Value.GetErrorMessage(value); + } + + public static string? GetErrorMessage(this IMeasureUnit src, double minSiValue, + double maxSiValue, string? value) + { + var msg = src.CurrentUnit.Value.GetErrorMessage(value); + if (string.IsNullOrWhiteSpace(msg) == false) return msg; + var siValue = src.CurrentUnit.Value.ConvertToSi(value); + if (siValue < minSiValue) + return string.Format(RS.MeasureUnitExtensions_ErrorMessage_GreaterValue, + src.CurrentUnit.Value.FromSiToStringWithUnits(minSiValue), + src.SiUnit.FromSiToStringWithUnits(siValue)); + if (siValue > maxSiValue) + return string.Format(RS.MeasureUnitExtensions_ErrorMessage_LesserValue, + src.CurrentUnit.Value.FromSiToStringWithUnits(minSiValue), + src.SiUnit.FromSiToStringWithUnits(siValue)); + return null; + } + } + + + public static class MeasureUnitConverter + { + static MeasureUnitConverter() + { + DoubleInstance = new MeasureUnitConverter(); + UlongInstance = new MeasureUnitConverter(); + } + + public static MeasureUnitConverter UlongInstance { get; set; } + public static MeasureUnitConverter DoubleInstance { get; } + } + + + public class MeasureUnitConverter : IMultiValueConverter + { + public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) + { + if (values.Count == 1) + return System.Convert.ChangeType(values[0], targetType, culture); + if (values is [_, IMeasureUnitItem measureUnit, ..]) + { + var value = (TValue)System.Convert.ChangeType(values[0], typeof(TValue), culture)!; + return measureUnit.Print(value); + } + + return AvaloniaProperty.UnsetValue; + } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Localization/IReadOnlyMeasureUnit.cs b/src/Asv.Drones.Gui.Api/Services/Localization/IReadOnlyMeasureUnit.cs new file mode 100644 index 00000000..876aa55d --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Localization/IReadOnlyMeasureUnit.cs @@ -0,0 +1,15 @@ +namespace Asv.Drones.Gui.Api; + +public interface IReadOnlyMeasureUnit +{ + string? GetUnit(TValue value); + string ConvertToString(TValue value); +} + +public static class ReadOnlyMeasureUnitExtensions +{ + public static string ConvertToStringWithUnits(this IReadOnlyMeasureUnit src, TValue value) + { + return src.ConvertToString(value) + src.GetUnit(value); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/LocalizationHelper.cs b/src/Asv.Drones.Gui.Api/Services/Localization/LocalizationHelper.cs similarity index 86% rename from src/Asv.Drones.Gui.Core/Services/Localization/LocalizationHelper.cs rename to src/Asv.Drones.Gui.Api/Services/Localization/LocalizationHelper.cs index 6fcd2251..c057d9c1 100644 --- a/src/Asv.Drones.Gui.Core/Services/Localization/LocalizationHelper.cs +++ b/src/Asv.Drones.Gui.Api/Services/Localization/LocalizationHelper.cs @@ -6,7 +6,7 @@ using ReactiveUI.Validation.Extensions; using ReactiveUI.Validation.Helpers; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; public static class LocalizationHelper { @@ -16,10 +16,11 @@ public static IDisposable BindMeasureUnit(this TObject sourc IMeasureUnitItem measureUnit) where TObject : IReactiveObject, IValidatableViewModel { - return new MeasureUnitBind(source, valuePropertyAccessor, setter, stringPropertyAccessor, stringSetter, measureUnit); + return new MeasureUnitBind(source, valuePropertyAccessor, setter, stringPropertyAccessor, + stringSetter, measureUnit); } - class MeasureUnitBind:IDisposable + class MeasureUnitBind : IDisposable where TObject : IReactiveObject, IValidatableViewModel { private readonly ValidationHelper _sub1; @@ -31,7 +32,8 @@ public MeasureUnitBind(TObject source, Expression> stringProperty, Action stringSetter, IMeasureUnitItem measureUnit) { - _sub1 = source.ValidationRule(stringProperty, measureUnit.IsValid, x => measureUnit.GetErrorMessage(x) ?? string.Empty); + _sub1 = source.ValidationRule(stringProperty, measureUnit.IsValid, + x => measureUnit.GetErrorMessage(x) ?? string.Empty); _sub2 = source.WhenValueChanged(valueProperty).Select(measureUnit.FromSiToString!).Subscribe(stringSetter); _sub3 = source.WhenValueChanged(stringProperty).Select(measureUnit.ConvertToSi).Subscribe(setter); } diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/MeasureUnitBase.cs b/src/Asv.Drones.Gui.Api/Services/Localization/MeasureUnitBase.cs similarity index 86% rename from src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/MeasureUnitBase.cs rename to src/Asv.Drones.Gui.Api/Services/Localization/MeasureUnitBase.cs index 1fe94b8e..64fdbf91 100644 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/MeasureUnitBase.cs +++ b/src/Asv.Drones.Gui.Api/Services/Localization/MeasureUnitBase.cs @@ -4,11 +4,11 @@ using Asv.Cfg; using Asv.Common; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; public abstract class MeasureUnitBase : DisposableOnceWithCancel, IMeasureUnit { - protected MeasureUnitBase(IConfiguration cfgSvc,string cfgKey,IMeasureUnitItem[] items) + protected MeasureUnitBase(IConfiguration cfgSvc, string cfgKey, IMeasureUnitItem[] items) { if (cfgSvc == null) throw new ArgumentNullException(nameof(cfgSvc)); if (cfgKey == null) throw new ArgumentNullException(nameof(cfgKey)); @@ -22,13 +22,10 @@ protected MeasureUnitBase(IConfiguration cfgSvc,string cfgKey,IMeasureUnitItem>(item).DisposeItWith(Disposable); CurrentUnit.DistinctUntilChanged(_ => _.Id) - .Subscribe(_ => - { - cfgSvc.Set(cfgKey, _.Id); - }) + .Subscribe(_ => { cfgSvc.Set(cfgKey, _.Id); }) .DisposeItWith(Disposable); - } + public abstract string Title { get; } public abstract string Description { get; } public IEnumerable> AvailableUnits { get; } @@ -41,7 +38,8 @@ public class DoubleMeasureUnitItem : IMeasureUnitItem private readonly string _formatString; private readonly double _multiplierCoef; - public DoubleMeasureUnitItem(TEnum id, string title, string unit, bool isSiUnit,string formatString, double multiplierCoef) + public DoubleMeasureUnitItem(TEnum id, string title, string unit, bool isSiUnit, string formatString, + double multiplierCoef) { _formatString = formatString; _multiplierCoef = multiplierCoef; @@ -50,10 +48,12 @@ public DoubleMeasureUnitItem(TEnum id, string title, string unit, bool isSiUnit, Unit = unit; IsSiUnit = isSiUnit; } + public TEnum Id { get; } public string Title { get; } public string Unit { get; } public bool IsSiUnit { get; } + public virtual double ConvertFromSi(double siValue) { return siValue / _multiplierCoef; @@ -70,6 +70,7 @@ public double Parse(string? value) value = value.Replace(',', '.'); return double.Parse(value, NumberStyles.Any, CultureInfo.InvariantCulture); } + public string Print(double value) { return value.ToString(_formatString, CultureInfo.InvariantCulture); @@ -91,9 +92,8 @@ public virtual bool IsValid(string? value) { if (value.IsNullOrWhiteSpace()) return RS.MeasureUnitBase_ErrorMessage_NullOrWhiteSpace; value = value.Replace(',', '.'); - return double.TryParse(value,NumberStyles.Any, CultureInfo.InvariantCulture, out _) == false ? RS.MeasureUnitBase_ErrorMessage_NotANumber : null; + return double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out _) == false + ? RS.MeasureUnitBase_ErrorMessage_NotANumber + : null; } - - - } \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/LogService/ILogService.cs b/src/Asv.Drones.Gui.Api/Services/LogService/ILogService.cs new file mode 100644 index 00000000..e66d11ea --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/LogService/ILogService.cs @@ -0,0 +1,74 @@ +namespace Asv.Drones.Gui.Api; + +public interface ILogService +{ + IObservable OnMessage { get; } + void SaveMessage(LogMessage logMessage); + IEnumerable LoadItemsFromLogFile(); + void DeleteLogFile(); + + public void Fatal(string sender, string message, + Exception ex = default) + { + SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Fatal, sender, message, ex?.Message)); + } + + public void Error(string sender, string message, + Exception ex = default) + { + SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Error, sender, message, ex?.Message)); + } + + public void Info(string sender, string message) + { + SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Info, sender, message, default)); + } + + public void Warning(string sender, string message) + { + SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Warning, sender, message, default)); + } + + public void Trace(string sender, string message) + { + SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Trace, sender, message, default)); + } + + public void Debug(string sender, string message) + { + SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Debug, sender, message, default)); + } +} + +public enum LogMessageType +{ + Trace, + Debug, + Info, + Warning, + Error, + Fatal +} + +public class LogMessage +{ + public LogMessage(DateTime dateTime, LogMessageType type, string source, string message, string? description) + { + Type = type; + Source = source; + Message = message; + Description = description; + DateTime = dateTime; + } + + public DateTime DateTime { get; } + public LogMessageType Type { get; } + public string Source { get; internal set; } + public string Message { get; } + public string? Description { get; } + + public override string ToString() + { + return $"{Type} {Message}"; + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/LogService/NullLogService.cs b/src/Asv.Drones.Gui.Api/Services/LogService/NullLogService.cs new file mode 100644 index 00000000..f52ced5c --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/LogService/NullLogService.cs @@ -0,0 +1,28 @@ +using System.Reactive.Subjects; + +namespace Asv.Drones.Gui.Api; + +public class NullLogService : ILogService +{ + public static NullLogService Instance { get; } = new(); + + public NullLogService() + { + OnMessage = new Subject(); + } + + public IObservable OnMessage { get; } + + public void SaveMessage(LogMessage logMessage) + { + } + + public IEnumerable LoadItemsFromLogFile() + { + return Array.Empty(); + } + + public void DeleteLogFile() + { + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Map/IMapService.cs b/src/Asv.Drones.Gui.Api/Services/Map/IMapService.cs new file mode 100644 index 00000000..c792da93 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Map/IMapService.cs @@ -0,0 +1,16 @@ +using Asv.Avalonia.Map; +using Asv.Common; + +namespace Asv.Drones.Gui.Api +{ + public interface IMapService + { + long CalculateMapCacheSize(); + void SetMapCacheDirectory(string path); + string MapCacheDirectory { get; } + IRxEditableValue CurrentMapProvider { get; } + IEnumerable AvailableProviders { get; } + IRxEditableValue CurrentMapAccessMode { get; } + IEnumerable AvailableAccessModes { get; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Mavlink/IMavlinkDevicesService.cs b/src/Asv.Drones.Gui.Api/Services/Mavlink/IMavlinkDevicesService.cs new file mode 100644 index 00000000..f5a0ce84 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Mavlink/IMavlinkDevicesService.cs @@ -0,0 +1,65 @@ +using Asv.Common; +using Asv.Mavlink; +using DynamicData; + +namespace Asv.Drones.Gui.Api +{ + public interface IMavlinkDevicesService + { + /// + /// Collection with all devices in network + /// + IObservable> Devices { get; } + + /// + /// Timeout for device connection. If device not response in this time, device will be removed from collection + /// + IRxEditableValue DeviceTimeout { get; } + + /// + /// Mavlink router + /// + IMavlinkRouter Router { get; } + + /// + /// Specify that need reload app to apply new config + /// + IRxValue NeedReloadToApplyConfig { get; } + + /// + /// ComponentId identifier of this app in mavlink network + /// + IRxEditableValue ComponentId { get; } + + /// + /// SystemId identifier of this app in mavlink network + /// + IRxEditableValue SystemId { get; } + + /// + /// Rate of heartbeat packets for sending to network + /// + IRxEditableValue HeartbeatRate { get; } + + IObservable> AllDevices { get; } + + /// + /// List of all founded vehicles in network + /// + IObservable> Vehicles { get; } + + /// + /// Gets vehicle by it's id + /// + /// Id of searched vehicle + /// Vehicle object + IVehicleClient? GetVehicleByFullId(ushort id); + + IObservable> BaseStations { get; } + IGbsClientDevice? GetGbsByFullId(ushort id); + IObservable> Payloads { get; } + ISdrClientDevice? GetPayloadsByFullId(ushort id); + IObservable> AdsbDevices { get; } + IAdsbClientDevice? GetAdsbVehicleByFullId(ushort id); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/MavlinkDevices/MavlinkHelper.cs b/src/Asv.Drones.Gui.Api/Services/Mavlink/MavlinkHelper.cs similarity index 88% rename from src/Asv.Drones.Gui.Core/Services/MavlinkDevices/MavlinkHelper.cs rename to src/Asv.Drones.Gui.Api/Services/Mavlink/MavlinkHelper.cs index 50e7a2d5..419266a1 100644 --- a/src/Asv.Drones.Gui.Core/Services/MavlinkDevices/MavlinkHelper.cs +++ b/src/Asv.Drones.Gui.Api/Services/Mavlink/MavlinkHelper.cs @@ -3,7 +3,7 @@ using Asv.Mavlink.V2.Minimal; using Material.Icons; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { public static class MavlinkHelper { @@ -11,7 +11,7 @@ public static string GetTitle(this MavCmd cmd) { return cmd.ToString("G").Replace("MavCmd", ""); } - + public static MaterialIconKind GetIcon(MavType type) { return type switch @@ -51,8 +51,10 @@ public static MaterialIconKind GetIcon(DeviceClass type) { DeviceClass.Plane => MaterialIconKind.Plane, DeviceClass.Copter => MaterialIconKind.Navigation, - DeviceClass.Unknown => MaterialIconKind.Navigation, - _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) + DeviceClass.SdrPayload => MaterialIconKind.Radio, + DeviceClass.GbsRtk => MaterialIconKind.RouterWireless, + DeviceClass.Adsb => MaterialIconKind.Radar, + _ => MaterialIconKind.Navigation, }; } } diff --git a/src/Asv.Drones.Gui.Core/Services/MissionPlaning/IPlaningMission.cs b/src/Asv.Drones.Gui.Api/Services/MissionPlaning/IPlaningMission.cs similarity index 96% rename from src/Asv.Drones.Gui.Core/Services/MissionPlaning/IPlaningMission.cs rename to src/Asv.Drones.Gui.Api/Services/MissionPlaning/IPlaningMission.cs index 5f6bca5a..cb6f94bf 100644 --- a/src/Asv.Drones.Gui.Core/Services/MissionPlaning/IPlaningMission.cs +++ b/src/Asv.Drones.Gui.Api/Services/MissionPlaning/IPlaningMission.cs @@ -1,6 +1,6 @@ using Asv.Mavlink; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; /// /// Represents a planning mission. diff --git a/src/Asv.Drones.Gui.Api/Services/MissionPlaning/PlaningMissionFile.cs b/src/Asv.Drones.Gui.Api/Services/MissionPlaning/PlaningMissionFile.cs new file mode 100644 index 00000000..c1df2748 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/MissionPlaning/PlaningMissionFile.cs @@ -0,0 +1,31 @@ +using Asv.Cfg; +using Asv.Cfg.Json; +using Asv.Common; + +namespace Asv.Drones.Gui.Api; + +public class PlaningMissionFile : ZipJsonVersionedFile +{ + public static readonly SemVersion Version1_0_0 = new(1, 0, 0); + public static readonly SemVersion LastVersion = Version1_0_0; + private const string FileType = "AsvDronesMission"; + + + public PlaningMissionFile(Stream stream, Guid id, string name) : base(stream, LastVersion, FileType, true) + { + } + + public PlaningMissionFile(Stream stream) : base(stream, LastVersion, FileType, false) + { + } + + public PlaningMissionModel Load() + { + return this.Get(); + } + + public void Save(PlaningMissionModel model) + { + this.Set(model); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/MissionPlaning/PlaningMissionModel.cs b/src/Asv.Drones.Gui.Api/Services/MissionPlaning/PlaningMissionModel.cs new file mode 100644 index 00000000..11b4a038 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/MissionPlaning/PlaningMissionModel.cs @@ -0,0 +1,59 @@ +using Asv.Common; +using Asv.Mavlink.V2.Common; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api; + +public record PlaningMissionModel +{ + public List Points { get; set; } = new(); +} + +public class PlaningMissionPointModel +{ + /// + /// Item index + /// + [Reactive] + public int Index { get; set; } + + /// + /// Command type + /// + [Reactive] + public MavCmd Type { get; set; } + + /// + /// Location + /// + [Reactive] + public GeoPoint Location { get; set; } + + /// + /// PARAM1, see MAV_CMD enum + /// OriginName: param1, Units: , IsExtended: false + /// + [Reactive] + public float Param1 { get; set; } + + /// + /// PARAM2, see MAV_CMD enum + /// OriginName: param2, Units: , IsExtended: false + /// + [Reactive] + public float Param2 { get; set; } + + /// + /// PARAM3, see MAV_CMD enum + /// OriginName: param3, Units: , IsExtended: false + /// + [Reactive] + public float Param3 { get; set; } + + /// + /// PARAM4, see MAV_CMD enum + /// OriginName: param4, Units: , IsExtended: false + /// + [Reactive] + public float Param4 { get; set; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Plugins/ILocalPluginInfo.cs b/src/Asv.Drones.Gui.Api/Services/Plugins/ILocalPluginInfo.cs new file mode 100644 index 00000000..a879b434 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Plugins/ILocalPluginInfo.cs @@ -0,0 +1,29 @@ +namespace Asv.Drones.Gui.Api; + +public interface ILocalPluginInfo : IPluginSpecification +{ + string Id => $"{SourceUri}|{PackageId}"; + string SourceUri { get; } + string LocalFolder { get; } + string Version { get; } + bool IsUninstalled { get; } + bool IsLoaded { get; } + string LoadingError { get; } +} + +public interface IPluginSearchInfo : IPluginSpecification +{ + string Id => $"{Source.SourceUri}|{PackageId}"; + IPluginServerInfo Source { get; } + string LastVersion { get; } + long? DownloadCount { get; } +} + +public interface IPluginSpecification +{ + string PackageId { get; } + string? Title { get; } + public string? Description { get; } + string? Authors { get; } + string? Tags { get; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Plugins/IPluginEntryPoint.cs b/src/Asv.Drones.Gui.Api/Services/Plugins/IPluginEntryPoint.cs new file mode 100644 index 00000000..ebb912d3 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Plugins/IPluginEntryPoint.cs @@ -0,0 +1,32 @@ +namespace Asv.Drones.Gui.Api +{ + /// + /// This interface is used as the entry point when loading plugins + /// + public interface IPluginEntryPoint + { + /// + /// Call when initializes the application Application.Initialize() + /// Will be called before main window\activity is shown + /// + void Initialize(); + + /// + /// Will be called after main window\activity is shown and Application.nFrameworkInitializationCompleted() + /// + void OnFrameworkInitializationCompleted(); + } + + + public interface IPluginMetadata + { + string[] Dependency { get; } + string Name { get; } + } + + public class PluginMetadata : IPluginMetadata + { + public string[] Dependency { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Plugins/IPluginManager.cs b/src/Asv.Drones.Gui.Api/Services/Plugins/IPluginManager.cs new file mode 100644 index 00000000..7dc6a6b9 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Plugins/IPluginManager.cs @@ -0,0 +1,51 @@ +using DynamicData; + +namespace Asv.Drones.Gui.Api; + +public class PluginServer(string name, string sourceUri, string? username = null, string? password = null) +{ + public string Name => name; + public string SourceUri => sourceUri; + public string? Username => username; + public string? Password => password; +} + +public interface IPluginServerInfo +{ + public string Name { get; } + public string SourceUri { get; } + public string? Username { get; } +} + +public interface IPluginManager +{ + IReadOnlyList Servers { get; } + void AddServer(PluginServer server); + void RemoveServer(IPluginServerInfo server); + Task> Search(SearchQuery query, CancellationToken cancel); + + Task Install(IPluginServerInfo source, string packageId, string version, IProgress? progress, + CancellationToken cancel); + + void Uninstall(ILocalPluginInfo plugin); + void CancelUninstall(ILocalPluginInfo pluginInfo); + IEnumerable Installed { get; } + bool IsInstalled(string packageId, out ILocalPluginInfo? info); +} + +public class SearchQuery +{ + public static readonly SearchQuery Empty = new() + { + Name = null, + IncludePrerelease = false, + Skip = 0, + Take = 20 + }; + + public string? Name { get; set; } + public bool IncludePrerelease { get; set; } + public int Skip { get; set; } = 0; + public int Take { get; set; } = 20; + public HashSet Sources { get; } = new(); +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Plugins/NullPluginManager.cs b/src/Asv.Drones.Gui.Api/Services/Plugins/NullPluginManager.cs new file mode 100644 index 00000000..e9ac553b --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Plugins/NullPluginManager.cs @@ -0,0 +1,46 @@ +namespace Asv.Drones.Gui.Api; + +public class NullPluginManager : IPluginManager +{ + public static IPluginManager Instance { get; } = new NullPluginManager(); + + public IReadOnlyList Sources { get; } = new List(); + + + public IReadOnlyList Servers { get; } + + public void AddServer(PluginServer server) + { + } + + public void RemoveServer(IPluginServerInfo server) + { + } + + public Task> Search(SearchQuery query, CancellationToken cancel) + { + return Task.FromResult((IReadOnlyList)new List()); + } + + public Task Install(IPluginServerInfo source, string packageId, string version, + IProgress? progress, CancellationToken cancel) + { + return Task.CompletedTask; + } + + public void Uninstall(ILocalPluginInfo plugin) + { + } + + public void CancelUninstall(ILocalPluginInfo pluginInfo) + { + } + + public IEnumerable Installed { get; } = new List(); + + public bool IsInstalled(string packageId, out ILocalPluginInfo? info) + { + info = null; + return false; + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/Plugins/PluginEntryPointAttribute.cs b/src/Asv.Drones.Gui.Api/Services/Plugins/PluginEntryPointAttribute.cs new file mode 100644 index 00000000..4da4ec1b --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/Plugins/PluginEntryPointAttribute.cs @@ -0,0 +1,23 @@ +using System.Composition; + +namespace Asv.Drones.Gui.Api; + +/// +/// This attribute is used to find a matching plugin entry points +/// +[MetadataAttribute] +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] +public class PluginEntryPointAttribute : ExportAttribute, IPluginMetadata +{ + public PluginEntryPointAttribute(string name, params string[] dependency) + : base(typeof(IPluginEntryPoint)) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("Value cannot be null or whitespace.", nameof(name)); + Name = name; + Dependency = dependency; + } + + public string[] Dependency { get; } + public string Name { get; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Services/SdrStore/ISdrStoreService.cs b/src/Asv.Drones.Gui.Api/Services/SdrStore/ISdrStoreService.cs new file mode 100644 index 00000000..7c79373b --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/SdrStore/ISdrStoreService.cs @@ -0,0 +1,17 @@ +using Asv.Mavlink; + +namespace Asv.Drones.Gui.Api; + +/// +/// Represents a service for storing and retrieving data files associated with ASV SDR record file metadata. +/// +public interface ISdrStoreService +{ + /// + /// Represents a hierarchical store that stores a collection of IListDataFile with AsvSdrRecordFileMetadata metadata, using Guid as the key. + /// + /// + /// The hierarchical store. + /// + IHierarchicalStore> Store { get; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/ServiceWithConfigBase.cs b/src/Asv.Drones.Gui.Api/Services/ServiceWithConfigBase.cs similarity index 83% rename from src/Asv.Drones.Gui.Core/Services/ServiceWithConfigBase.cs rename to src/Asv.Drones.Gui.Api/Services/ServiceWithConfigBase.cs index 9af4fa46..448bb345 100644 --- a/src/Asv.Drones.Gui.Core/Services/ServiceWithConfigBase.cs +++ b/src/Asv.Drones.Gui.Api/Services/ServiceWithConfigBase.cs @@ -1,15 +1,15 @@ using Asv.Cfg; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { - public class ServiceWithConfigBase:DisposableReactiveObject + public class ServiceWithConfigBase : DisposableReactiveObject where TConfig : new() { private readonly IConfiguration _cfgService; private readonly object _sync = new(); private readonly TConfig _config; - public ServiceWithConfigBase(IConfiguration cfg) + protected ServiceWithConfigBase(IConfiguration cfg) { _cfgService = cfg ?? throw new ArgumentNullException(nameof(cfg)); _config = cfg.Get(); diff --git a/src/Asv.Drones.Gui.Api/Services/SoundNotification/ISoundNotificationService.cs b/src/Asv.Drones.Gui.Api/Services/SoundNotification/ISoundNotificationService.cs new file mode 100644 index 00000000..ed5d1776 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Services/SoundNotification/ISoundNotificationService.cs @@ -0,0 +1,6 @@ +namespace Asv.Drones.Gui.Api; + +public interface ISoundNotificationService +{ + public void Notify(); +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/Header/DefaultHeaderMenuProvider.cs b/src/Asv.Drones.Gui.Api/Shell/Header/DefaultHeaderMenuProvider.cs new file mode 100644 index 00000000..1147b947 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Header/DefaultHeaderMenuProvider.cs @@ -0,0 +1,15 @@ +using System.Composition; +using DynamicData; + +namespace Asv.Drones.Gui.Api +{ + [Export(WellKnownUri.ShellHeaderMenu, typeof(IViewModelProvider))] + public class DefaultHeaderMenuProvider : ViewModelProviderBase + { + [ImportingConstructor] + public DefaultHeaderMenuProvider([ImportMany(WellKnownUri.ShellHeaderMenu)] IEnumerable menuItems) + { + Source.AddOrUpdate(menuItems); + } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/Header/IMenuItem.cs b/src/Asv.Drones.Gui.Api/Shell/Header/IMenuItem.cs new file mode 100644 index 00000000..1da77078 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Header/IMenuItem.cs @@ -0,0 +1,21 @@ +using System.Collections.ObjectModel; +using System.Windows.Input; +using Avalonia.Input; +using Material.Icons; + +namespace Asv.Drones.Gui.Api +{ + public interface IMenuItem : IViewModel + { + int Order { get; } + MaterialIconKind Icon { get; } + string Header { get; } + ICommand Command { get; } + object? CommandParameter { get; } + bool IsVisible { get; } + bool StaysOpenOnClick { get; } + ReadOnlyObservableCollection? Items { get; set; } + public bool IsEnabled { get; } + public KeyGesture? HotKey { get; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/Header/MenuItem.cs b/src/Asv.Drones.Gui.Api/Shell/Header/MenuItem.cs new file mode 100644 index 00000000..b82ac929 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Header/MenuItem.cs @@ -0,0 +1,30 @@ +using System.Collections.ObjectModel; +using System.Windows.Input; +using Avalonia.Input; +using Material.Icons; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api +{ + public class MenuItem : ViewModelBase, IMenuItem + { + public MenuItem(Uri id) : base(id) + { + } + + public MenuItem(string id) : base(id) + { + } + + [Reactive] public int Order { get; set; } + [Reactive] public MaterialIconKind Icon { get; set; } + [Reactive] public string Header { get; set; } + [Reactive] public ICommand Command { get; set; } + [Reactive] public object? CommandParameter { get; set; } + [Reactive] public bool IsVisible { get; set; } = true; + [Reactive] public bool StaysOpenOnClick { get; set; } + [Reactive] public bool IsEnabled { get; set; } = true; + public virtual ReadOnlyObservableCollection? Items { get; set; } + [Reactive] public KeyGesture? HotKey { get; set; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/IShell.cs b/src/Asv.Drones.Gui.Api/Shell/IShell.cs new file mode 100644 index 00000000..825b113b --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/IShell.cs @@ -0,0 +1,11 @@ +namespace Asv.Drones.Gui.Api +{ + /// + /// Main view interface + /// + public interface IShell + { + Task GoTo(Uri uri); + IShellPage? CurrentPage { get; set; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/Menu/IShellMenuItem.cs b/src/Asv.Drones.Gui.Api/Shell/Menu/IShellMenuItem.cs new file mode 100644 index 00000000..4ef98ff7 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Menu/IShellMenuItem.cs @@ -0,0 +1,39 @@ +using System.Collections.ObjectModel; +using FluentAvalonia.UI.Controls; + +namespace Asv.Drones.Gui.Api +{ + public interface IShellMenuItem : IViewModel + { + InfoBadge InfoBadge { get; set; } + IShellMenuItem? Parent { get; set; } + string Name { get; set; } + Uri NavigateTo { get; set; } + string Icon { get; } + ShellMenuPosition Position { get; } + ShellMenuItemType Type { get; } + int Order { get; } + ReadOnlyObservableCollection? Items { get; } + bool IsSelected { get; set; } + bool IsVisible { get; set; } + } + + public enum ShellMenuPosition + { + Top, + Bottom, + } + + public enum ShellMenuItemType + { + Header, + Group, + PageNavigation + } + + + public interface IShellMenuItem : IShellMenuItem + { + IShellMenuItem Init(TTarget target); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Menu/ShellMenuItem.cs b/src/Asv.Drones.Gui.Api/Shell/Menu/ShellMenuItem.cs similarity index 83% rename from src/Asv.Drones.Gui.Core/Shell/Menu/ShellMenuItem.cs rename to src/Asv.Drones.Gui.Api/Shell/Menu/ShellMenuItem.cs index 279c864d..733081d1 100644 --- a/src/Asv.Drones.Gui.Core/Shell/Menu/ShellMenuItem.cs +++ b/src/Asv.Drones.Gui.Api/Shell/Menu/ShellMenuItem.cs @@ -5,7 +5,7 @@ using FluentAvalonia.UI.Controls; using ReactiveUI.Fody.Helpers; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { public class ShellMenuItem : ViewModelBase, IShellMenuItem { @@ -14,20 +14,17 @@ public class ShellMenuItem : ViewModelBase, IShellMenuItem public ShellMenuItem(Uri id) : base(id) { } + public ShellMenuItem(string id) : base(id) { - } public InfoBadge InfoBadge { get; set; } public IShellMenuItem Parent { get; set; } - [Reactive] - public string Name { get; set; } - [Reactive] - public Uri NavigateTo { get; set; } - [Reactive] - public string Icon { get; init; } + [Reactive] public string Name { get; set; } + [Reactive] public Uri NavigateTo { get; set; } + [Reactive] public string Icon { get; init; } public ShellMenuPosition Position { get; init; } public ShellMenuItemType Type { get; init; } public int Order { get; init; } @@ -43,6 +40,7 @@ public ReadOnlyObservableCollection? Items { item.Parent = this; } + value.ObserveCollectionChanges().Subscribe(_ => { if (_.EventArgs.NewItems == null) return; @@ -51,12 +49,10 @@ public ReadOnlyObservableCollection? Items (newItem as IShellMenuItem)!.Parent = this; } }).DisposeItWith(Disposable); - } } - [Reactive] - public bool IsSelected { get; set; } + [Reactive] public bool IsSelected { get; set; } [Reactive] public bool IsVisible { get; set; } = true; } diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/ExportShellPageAttribute.cs b/src/Asv.Drones.Gui.Api/Shell/Pages/ExportShellPageAttribute.cs similarity index 84% rename from src/Asv.Drones.Gui.Core/Shell/Pages/ExportShellPageAttribute.cs rename to src/Asv.Drones.Gui.Api/Shell/Pages/ExportShellPageAttribute.cs index f8aa6704..69f9858c 100644 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/ExportShellPageAttribute.cs +++ b/src/Asv.Drones.Gui.Api/Shell/Pages/ExportShellPageAttribute.cs @@ -1,6 +1,6 @@ -using System.ComponentModel.Composition; +using System.Composition; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { /// /// Define this attribute to export shell page @@ -12,8 +12,6 @@ public class ExportShellPageAttribute : ExportAttribute public ExportShellPageAttribute(string baseUri) : base(new Uri(baseUri).AbsolutePath, typeof(IShellPage)) { - } - } } \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/Pages/IShellPage.cs b/src/Asv.Drones.Gui.Api/Shell/Pages/IShellPage.cs new file mode 100644 index 00000000..384901f0 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Pages/IShellPage.cs @@ -0,0 +1,24 @@ +using System.Collections.Specialized; +using DynamicData; +using Material.Icons; + +namespace Asv.Drones.Gui.Api +{ + /// + /// All pages in shell must implement this interface + /// + public interface IShellPage : IViewModel + { + MaterialIconKind Icon { get; } + string Title { get; } + IObservable> HeaderItems { get; } + IObservable> StatusItems { get; } + + /// + /// Addition arguments for page + /// + void SetArgs(NameValueCollection args); + + Task TryClose(); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/Pages/LogViewer/LogItemViewModel.cs b/src/Asv.Drones.Gui.Api/Shell/Pages/LogViewer/LogItemViewModel.cs new file mode 100644 index 00000000..cddfd78d --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Pages/LogViewer/LogItemViewModel.cs @@ -0,0 +1,38 @@ +using Material.Icons; + +namespace Asv.Drones.Gui.Api; + +public class LogItemViewModel( + int itemIndex, + string threadId, + LogMessageType itemLevel, + DateTime itemTimeStamp, + string itemClass, + string itemMessage) : DisposableReactiveObject +{ + public int Index { get; } = itemIndex; + + public MaterialIconKind Kind { get; } = itemLevel switch + { + LogMessageType.Debug => MaterialIconKind.Bug, + LogMessageType.Trace => MaterialIconKind.Tractor, + LogMessageType.Info => MaterialIconKind.Info, + LogMessageType.Warning => MaterialIconKind.Bullhorn, + LogMessageType.Error => MaterialIconKind.Fire, + LogMessageType.Fatal => MaterialIconKind.FlashAlert, + _ => MaterialIconKind.QuestionMark + }; + + public DateTime Timestamp { get; } = itemTimeStamp; + public LogMessageType Level { get; } = itemLevel; + public string Class { get; } = itemClass; + public string Message { get; set; } = itemMessage; + public string ThreadId { get; } = threadId; + + public bool IsTrace { get; } = itemLevel == LogMessageType.Trace; + public bool IsDebug { get; } = itemLevel == LogMessageType.Debug; + public bool IsInfo { get; } = itemLevel == LogMessageType.Info; + public bool IsWarning { get; } = itemLevel == LogMessageType.Warning; + public bool IsError { get; } = itemLevel == LogMessageType.Error; + public bool IsFatal { get; } = itemLevel == LogMessageType.Fatal; +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/DefaultPacketConverter.cs b/src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/DefaultPacketConverter.cs similarity index 87% rename from src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/DefaultPacketConverter.cs rename to src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/DefaultPacketConverter.cs index 5a4352ef..d498b85c 100644 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/DefaultPacketConverter.cs +++ b/src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/DefaultPacketConverter.cs @@ -1,22 +1,21 @@ -using System.ComponentModel.Composition; +using System.Composition; using Asv.Mavlink; using Newtonsoft.Json; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; /// /// Default packet converter. Used when there is no specialized converter for some packet type. /// [Export(typeof(IPacketConverter))] -[PartCreationPolicy(CreationPolicy.Shared)] public class DefaultPacketConverter : IPacketConverter { - public int Order => int.MaxValue; + public int Order => int.MaxValue; public bool CanConvert(IPacketV2 packet) { if (packet == null) throw new ArgumentException("Incoming packet was not initialized!"); - + return true; } @@ -24,9 +23,9 @@ public string Convert(IPacketV2 packet, PacketFormatting formatting = { if (packet == null) throw new ArgumentException("Incoming packet was not initialized!"); if (!CanConvert(packet)) throw new ArgumentException("Converter can not convert incoming packet!"); - + string result = string.Empty; - + if (formatting == PacketFormatting.None) { result = JsonConvert.SerializeObject(packet.Payload, Formatting.None); diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/IPacketConverter.cs b/src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/IPacketConverter.cs similarity index 97% rename from src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/IPacketConverter.cs rename to src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/IPacketConverter.cs index ef212c9d..eff10921 100644 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/IPacketConverter.cs +++ b/src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/IPacketConverter.cs @@ -1,6 +1,6 @@ using Asv.Mavlink; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; /// /// Represents the formatting options for packet data. diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/StatusTextConverter.cs b/src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/StatusTextConverter.cs similarity index 91% rename from src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/StatusTextConverter.cs rename to src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/StatusTextConverter.cs index 1a80ac97..97dccade 100644 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Converters/StatusTextConverter.cs +++ b/src/Asv.Drones.Gui.Api/Shell/Pages/PacketViewer/Converters/StatusTextConverter.cs @@ -1,18 +1,17 @@ -using System.ComponentModel.Composition; +using System.Composition; using System.Text; using Asv.Mavlink; using Asv.Mavlink.V2.Common; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; /// /// StatusText packet converter. /// [Export(typeof(IPacketConverter))] -[PartCreationPolicy(CreationPolicy.Shared)] public class StatusTextConverter : IPacketConverter { - public int Order => 0; + public int Order => 0; public bool CanConvert(IPacketV2 packet) { @@ -25,9 +24,9 @@ public string Convert(IPacketV2 packet, PacketFormatting formatting = { if (packet == null) throw new ArgumentException("Incoming packet was not initialized!"); if (!CanConvert(packet)) throw new ArgumentException("Converter can not convert incoming packet!"); - + StringBuilder sb = new StringBuilder(); - + var payload = packet.Payload as StatustextPayload; if (formatting == PacketFormatting.None) diff --git a/src/Asv.Drones.Gui.Api/Shell/Pages/Settings/ISettingsPageContext.cs b/src/Asv.Drones.Gui.Api/Shell/Pages/Settings/ISettingsPageContext.cs new file mode 100644 index 00000000..18a6ace8 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Pages/Settings/ISettingsPageContext.cs @@ -0,0 +1,6 @@ +namespace Asv.Drones.Gui.Api; + +public interface ISettingsPageContext : ITreePageContext +{ + void SetRebootRequired(); +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/Pages/ShellPage.cs b/src/Asv.Drones.Gui.Api/Shell/Pages/ShellPage.cs new file mode 100644 index 00000000..9d84b79a --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Pages/ShellPage.cs @@ -0,0 +1,39 @@ +using System.Collections.Specialized; +using Asv.Common; +using DynamicData; +using Material.Icons; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api; + +public class ShellPage : ViewModelBase, IShellPage +{ + protected ShellPage(Uri uri) : base(uri) + { + HeaderItemsSource = new SourceCache(x => x.Id).DisposeItWith(Disposable); + StatusItemsSource = new SourceCache(x => x.Id).DisposeItWith(Disposable); + } + + protected ShellPage(string uri) : this(new Uri(uri)) + { + } + + [Reactive] public MaterialIconKind Icon { get; set; } + [Reactive] public string Title { get; set; } + + protected ISourceCache HeaderItemsSource { get; } + protected ISourceCache StatusItemsSource { get; } + + public IObservable> HeaderItems => HeaderItemsSource.Connect(); + + public IObservable> StatusItems => StatusItemsSource.Connect(); + + public virtual void SetArgs(NameValueCollection args) + { + } + + public virtual Task TryClose() + { + return Task.FromResult(true); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Shell/Status/IShellStatusItem.cs b/src/Asv.Drones.Gui.Api/Shell/Status/IShellStatusItem.cs new file mode 100644 index 00000000..b0a0b851 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Shell/Status/IShellStatusItem.cs @@ -0,0 +1,13 @@ +namespace Asv.Drones.Gui.Api +{ + /// + /// All status items in shell must implement this interface + /// + public interface IShellStatusItem : IViewModel + { + /// + /// Display order + /// + int Order { get; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Status/ShellStatusItem.cs b/src/Asv.Drones.Gui.Api/Shell/Status/ShellStatusItem.cs similarity index 83% rename from src/Asv.Drones.Gui.Core/Shell/Status/ShellStatusItem.cs rename to src/Asv.Drones.Gui.Api/Shell/Status/ShellStatusItem.cs index 1f04bfc7..bd18bc2e 100644 --- a/src/Asv.Drones.Gui.Core/Shell/Status/ShellStatusItem.cs +++ b/src/Asv.Drones.Gui.Api/Shell/Status/ShellStatusItem.cs @@ -1,14 +1,13 @@ -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { public abstract class ShellStatusItem : ViewModelBase, IShellStatusItem { protected ShellStatusItem(Uri id) : base(id) { - } + protected ShellStatusItem(string id) : base(id) { - } public abstract int Order { get; } diff --git a/src/Asv.Drones.Gui.Api/Tools/Behavior/LostFocusUpdateBindingBehavior.cs b/src/Asv.Drones.Gui.Api/Tools/Behavior/LostFocusUpdateBindingBehavior.cs new file mode 100644 index 00000000..38decfe3 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Behavior/LostFocusUpdateBindingBehavior.cs @@ -0,0 +1,87 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Xaml.Interactivity; + +namespace Asv.Drones.Gui.Api; + +public class LostFocusUpdateBindingBehavior : Behavior +{ + static LostFocusUpdateBindingBehavior() + { + TextProperty.Changed.Subscribe(e => { ((LostFocusUpdateBindingBehavior)e.Sender).OnBindingValueChanged(); }); + } + + protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error) + { + base.UpdateDataValidation(property, state, error); + if (property == TextProperty && AssociatedObject != null) + { + if (error != null) + { + DataValidationErrors.SetError(AssociatedObject, error); + } + else + { + DataValidationErrors.ClearErrors(AssociatedObject); + } + } + } + + + protected override void OnAttached() + { + if (AssociatedObject != null) + { + AssociatedObject.LostFocus += OnLostFocus; + AssociatedObject.KeyDown += OnKeyDown; + } + + base.OnAttached(); + } + + protected override void OnDetaching() + { + if (AssociatedObject != null) + { + AssociatedObject.LostFocus -= OnLostFocus; + AssociatedObject.KeyDown -= OnKeyDown; + } + + base.OnDetaching(); + } + + private void OnKeyDown(object sender, KeyEventArgs e) + { + if (AssociatedObject != null && e.Key == Key.Enter) + { + Text = AssociatedObject.Text; + } + } + + private void OnLostFocus(object sender, RoutedEventArgs e) + { + if (AssociatedObject != null) + Text = AssociatedObject.Text; + } + + private void OnBindingValueChanged() + { + if (AssociatedObject != null) + AssociatedObject.Text = Text; + } + + public static readonly DirectProperty TextProperty + = AvaloniaProperty.RegisterDirect(nameof(Text), o => o.Text, + (o, v) => o.Text = v, null, BindingMode.TwoWay, true); + + private string _text; + + public string Text + { + get { return _text; } + set { this.SetAndRaise(TextProperty, ref _text, value); } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Attitude/AttitudeIndicator.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Attitude/AttitudeIndicator.axaml new file mode 100644 index 00000000..71ea8929 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Attitude/AttitudeIndicator.axaml @@ -0,0 +1,428 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Uav/Controls/AttitudeIndicator.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Attitude/AttitudeIndicator.axaml.cs similarity index 80% rename from src/Asv.Drones.Gui.Uav/Controls/AttitudeIndicator.axaml.cs rename to src/Asv.Drones.Gui.Api/Tools/Controls/Attitude/AttitudeIndicator.axaml.cs index fb5d6802..2ac0d890 100644 --- a/src/Asv.Drones.Gui.Uav/Controls/AttitudeIndicator.axaml.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Attitude/AttitudeIndicator.axaml.cs @@ -6,7 +6,7 @@ using Avalonia.Media; using ReactiveUI; -namespace Asv.Drones.Gui.Uav +namespace Asv.Drones.Gui.Api { public class AttitudeIndicator : TemplatedControl { @@ -40,8 +40,9 @@ public class AttitudeIndicator : TemplatedControl private Color _brushVibrationX; - public static readonly DirectProperty brushVibrationXProperty = AvaloniaProperty.RegisterDirect( - nameof(BrushVibrationX), o => o.BrushVibrationX, (o, v) => o.BrushVibrationX = v); + public static readonly DirectProperty brushVibrationXProperty = + AvaloniaProperty.RegisterDirect( + nameof(BrushVibrationX), o => o.BrushVibrationX, (o, v) => o.BrushVibrationX = v); public Color BrushVibrationX { @@ -51,81 +52,90 @@ public Color BrushVibrationX private Color _brushVibrationY; - public static readonly DirectProperty brushVibrationYProperty = AvaloniaProperty.RegisterDirect( - nameof(BrushVibrationY), o => o.BrushVibrationY, (o, v) => o.BrushVibrationY = v); + public static readonly DirectProperty brushVibrationYProperty = + AvaloniaProperty.RegisterDirect( + nameof(BrushVibrationY), o => o.BrushVibrationY, (o, v) => o.BrushVibrationY = v); public Color BrushVibrationY { get => _brushVibrationY; set => SetAndRaise(brushVibrationYProperty, ref _brushVibrationY, value); } - + private Color _brushVibrationZ; - public static readonly DirectProperty brushVibrationZProperty = AvaloniaProperty.RegisterDirect( - nameof(BrushVibrationZ), o => o.BrushVibrationZ, (o, v) => o.BrushVibrationZ = v); + public static readonly DirectProperty brushVibrationZProperty = + AvaloniaProperty.RegisterDirect( + nameof(BrushVibrationZ), o => o.BrushVibrationZ, (o, v) => o.BrushVibrationZ = v); public Color BrushVibrationZ { get => _brushVibrationZ; set => SetAndRaise(brushVibrationZProperty, ref _brushVibrationZ, value); } - - public static readonly StyledProperty VibrationXProperty = AvaloniaProperty.Register( - nameof(VibrationX), defaultValue: -1); - + + public static readonly StyledProperty VibrationXProperty = + AvaloniaProperty.Register( + nameof(VibrationX), defaultValue: -1); + public float VibrationX { get => GetValue(VibrationXProperty); set => SetValue(VibrationXProperty, value); } - - public static readonly StyledProperty VibrationYProperty = AvaloniaProperty.Register( - nameof(VibrationY), defaultValue: -1); + + public static readonly StyledProperty VibrationYProperty = + AvaloniaProperty.Register( + nameof(VibrationY), defaultValue: -1); public float VibrationY { get => GetValue(VibrationYProperty); set => SetValue(VibrationYProperty, value); } - - public static readonly StyledProperty VibrationZProperty = AvaloniaProperty.Register( - nameof(VibrationZ), defaultValue: -1); + + public static readonly StyledProperty VibrationZProperty = + AvaloniaProperty.Register( + nameof(VibrationZ), defaultValue: -1); public float VibrationZ { get => GetValue(VibrationZProperty); set => SetValue(VibrationZProperty, value); } - - public static readonly StyledProperty Clipping0Property = AvaloniaProperty.Register( - nameof(Clipping0)); + + public static readonly StyledProperty Clipping0Property = + AvaloniaProperty.Register( + nameof(Clipping0)); public uint Clipping0 { get => GetValue(Clipping0Property); set => SetValue(Clipping0Property, value); } - - public static readonly StyledProperty Clipping1Property = AvaloniaProperty.Register( - nameof(Clipping1)); + + public static readonly StyledProperty Clipping1Property = + AvaloniaProperty.Register( + nameof(Clipping1)); public uint Clipping1 { get => GetValue(Clipping1Property); set => SetValue(Clipping1Property, value); } - - public static readonly StyledProperty Clipping2Property = AvaloniaProperty.Register( - nameof(Clipping2)); + + public static readonly StyledProperty Clipping2Property = + AvaloniaProperty.Register( + nameof(Clipping2)); public uint Clipping2 { get => GetValue(Clipping2Property); set => SetValue(Clipping2Property, value); } - - public static readonly StyledProperty RollAngleProperty = AvaloniaProperty.Register(nameof(RollAngle), default(double)); + + public static readonly StyledProperty RollAngleProperty = + AvaloniaProperty.Register(nameof(RollAngle), default(double)); public double RollAngle { @@ -133,7 +143,8 @@ public double RollAngle set => SetValue(RollAngleProperty, value); } - public static readonly StyledProperty PitchAngleProperty = AvaloniaProperty.Register(nameof(PitchAngle), default(double)); + public static readonly StyledProperty PitchAngleProperty = + AvaloniaProperty.Register(nameof(PitchAngle), default(double)); public double PitchAngle { @@ -149,8 +160,9 @@ public double Velocity get => GetValue(VelocityProperty); set => SetValue(VelocityProperty, value); } - - public static readonly StyledProperty AltitudeProperty = AvaloniaProperty.Register(nameof(Altitude), default(double)); + + public static readonly StyledProperty AltitudeProperty = + AvaloniaProperty.Register(nameof(Altitude), default(double)); public double Altitude { @@ -158,7 +170,8 @@ public double Altitude set => SetValue(AltitudeProperty, value); } - public static readonly StyledProperty HeadingProperty = AvaloniaProperty.Register(nameof(Heading), default(double)); + public static readonly StyledProperty HeadingProperty = + AvaloniaProperty.Register(nameof(Heading), default(double)); public double Heading { @@ -166,7 +179,8 @@ public double Heading set => SetValue(HeadingProperty, value); } - public static readonly StyledProperty HomeAzimuthProperty = AvaloniaProperty.Register(nameof(HomeAzimuth), default(double?)); + public static readonly StyledProperty HomeAzimuthProperty = + AvaloniaProperty.Register(nameof(HomeAzimuth), default(double?)); public double? HomeAzimuth { @@ -174,7 +188,8 @@ public double? HomeAzimuth set => SetValue(HomeAzimuthProperty, value); } - public static readonly StyledProperty IsArmedProperty = AvaloniaProperty.Register(nameof(IsArmed), default(bool)); + public static readonly StyledProperty IsArmedProperty = + AvaloniaProperty.Register(nameof(IsArmed), default(bool)); public bool IsArmed { @@ -202,49 +217,14 @@ public string RightStatusText set => SetAndRaise(RightStatusTextProperty, ref _rightStatusText, value); } - public static readonly StyledProperty ArmedTimeProperty = AvaloniaProperty.Register(nameof(ArmedTime), default(TimeSpan)); - + public static readonly StyledProperty ArmedTimeProperty = + AvaloniaProperty.Register(nameof(ArmedTime), default(TimeSpan)); + public TimeSpan ArmedTime { get => GetValue(ArmedTimeProperty); set => SetValue(ArmedTimeProperty, value); } - - public static readonly StyledProperty> AltitudePolygonPointsProperty = - AvaloniaProperty.Register>(nameof(AltitudePolygonPoints), new List()); - - public List AltitudePolygonPoints - { - get => GetValue(AltitudePolygonPointsProperty); - set => SetValue(AltitudePolygonPointsProperty, value); - } - - public static readonly StyledProperty> VelocityPolygonPointsProperty = - AvaloniaProperty.Register>(nameof(VelocityPolygonPoints), new List()); - - public List VelocityPolygonPoints - { - get => GetValue(VelocityPolygonPointsProperty); - set => SetValue(VelocityPolygonPointsProperty, value); - } - - public static readonly StyledProperty> HomePolygonPointsProperty = - AvaloniaProperty.Register>(nameof(HomePolygonPoints), new List()); - - public List HomePolygonPoints - { - get => GetValue(HomePolygonPointsProperty); - set => SetValue(HomePolygonPointsProperty, value); - } - - public static readonly StyledProperty> RollPolygonPointsProperty = - AvaloniaProperty.Register>(nameof(RollPolygonPoints), new List()); - - public List RollPolygonPoints - { - get => GetValue(RollPolygonPointsProperty); - set => SetValue(RollPolygonPointsProperty, value); - } #region Internal direct property @@ -342,7 +322,7 @@ private IEnumerable HeadingItems AvaloniaProperty.RegisterDirect(nameof(HomeAzimuthPosition), _ => _.HomeAzimuthPosition, (_, value) => _.HomeAzimuthPosition = value); - + private double HomeAzimuthPosition { get => _homeAzimuthPosition; @@ -356,12 +336,9 @@ public AttitudeIndicator() { if (Design.IsDesignMode) { - var status = new[] { "Armed", "Disarmed" }; - Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1),RxApp.MainThreadScheduler).Subscribe(_ => - { - StatusText = status[_ % 2]; - }); + Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), RxApp.MainThreadScheduler) + .Subscribe(_ => { StatusText = status[_ % 2]; }); StatusText = status[1]; } @@ -372,21 +349,34 @@ public AttitudeIndicator() new RollItem(0), new RollItem(10), new RollItem(20), new RollItem(30), new RollItem(45), new RollItem(60), new RollItem(300), new RollItem(315), new RollItem(330), new RollItem(340), new RollItem(350)); - + PitchItems = new AvaloniaList( - new PitchItem(135, Scale, false), new PitchItem(130, Scale), new PitchItem(125, Scale, false), new PitchItem(120, Scale), - new PitchItem(115, Scale, false), new PitchItem(110, Scale), new PitchItem(105, Scale, false), new PitchItem(100, Scale), - new PitchItem(95, Scale, false), new PitchItem(90, Scale), new PitchItem(85, Scale, false), new PitchItem(80, Scale), - new PitchItem(75, Scale, false), new PitchItem(70, Scale), new PitchItem(65, Scale, false), new PitchItem(60, Scale), - new PitchItem(55, Scale, false), new PitchItem(50, Scale), new PitchItem(45, Scale, false), new PitchItem(40, Scale), - new PitchItem(35, Scale, false), new PitchItem(30, Scale), new PitchItem(25, Scale, false), new PitchItem(20, Scale), - new PitchItem(15, Scale, false), new PitchItem(10, Scale), new PitchItem(5, Scale, false), new PitchItem(0, Scale), - new PitchItem(-5, Scale, false), new PitchItem(-10, Scale), new PitchItem(-15, Scale, false), new PitchItem(-20, Scale), - new PitchItem(-25, Scale, false), new PitchItem(-30, Scale), new PitchItem(-35, Scale, false), new PitchItem(-40, Scale), - new PitchItem(-45, Scale, false), new PitchItem(-50, Scale), new PitchItem(-55, Scale, false), new PitchItem(-60, Scale), - new PitchItem(-65, Scale, false), new PitchItem(-70, Scale), new PitchItem(-75, Scale, false), new PitchItem(-80, Scale), - new PitchItem(-85, Scale, false), new PitchItem(-90, Scale), new PitchItem(-95, Scale, false), new PitchItem(-100, Scale), - new PitchItem(-105, Scale, false), new PitchItem(-110, Scale), new PitchItem(-115, Scale, false), new PitchItem(-120, Scale), + new PitchItem(135, Scale, false), new PitchItem(130, Scale), new PitchItem(125, Scale, false), + new PitchItem(120, Scale), + new PitchItem(115, Scale, false), new PitchItem(110, Scale), new PitchItem(105, Scale, false), + new PitchItem(100, Scale), + new PitchItem(95, Scale, false), new PitchItem(90, Scale), new PitchItem(85, Scale, false), + new PitchItem(80, Scale), + new PitchItem(75, Scale, false), new PitchItem(70, Scale), new PitchItem(65, Scale, false), + new PitchItem(60, Scale), + new PitchItem(55, Scale, false), new PitchItem(50, Scale), new PitchItem(45, Scale, false), + new PitchItem(40, Scale), + new PitchItem(35, Scale, false), new PitchItem(30, Scale), new PitchItem(25, Scale, false), + new PitchItem(20, Scale), + new PitchItem(15, Scale, false), new PitchItem(10, Scale), new PitchItem(5, Scale, false), + new PitchItem(0, Scale), + new PitchItem(-5, Scale, false), new PitchItem(-10, Scale), new PitchItem(-15, Scale, false), + new PitchItem(-20, Scale), + new PitchItem(-25, Scale, false), new PitchItem(-30, Scale), new PitchItem(-35, Scale, false), + new PitchItem(-40, Scale), + new PitchItem(-45, Scale, false), new PitchItem(-50, Scale), new PitchItem(-55, Scale, false), + new PitchItem(-60, Scale), + new PitchItem(-65, Scale, false), new PitchItem(-70, Scale), new PitchItem(-75, Scale, false), + new PitchItem(-80, Scale), + new PitchItem(-85, Scale, false), new PitchItem(-90, Scale), new PitchItem(-95, Scale, false), + new PitchItem(-100, Scale), + new PitchItem(-105, Scale, false), new PitchItem(-110, Scale), new PitchItem(-115, Scale, false), + new PitchItem(-120, Scale), new PitchItem(-125, Scale, false), new PitchItem(-130, Scale), new PitchItem(-135, Scale, false) ); @@ -395,7 +385,7 @@ public AttitudeIndicator() VelocityItems = new AvaloniaList(Enumerable.Range(0, VelocityItemCount).Select(_ => new ScaleItem(0, VelocityValueRange, _, VelocityItemCount, velocityControlLength + velocityItemLength, velocityControlLength, showNegative: false))); - + var altitudeControlLength = smallerSide * AltitudeControlLengthPrc; var altitudeItemLength = altitudeControlLength / (AltitudeItemCount - 1); AltitudeItems = new AvaloniaList(Enumerable.Range(0, AltitudeItemCount).Select(_ => @@ -408,11 +398,10 @@ public AttitudeIndicator() new HeadingScaleItem(0, HeadingValueRange, _, HeadingItemCount, headingControlLength + headingItemLength, headingControlLength))); - var headingItemStep = (headingControlLength + headingItemLength) / (HeadingItemCount % 2 != 0 ? HeadingItemCount - 1 : HeadingItemCount); + var headingItemStep = (headingControlLength + headingItemLength) / + (HeadingItemCount % 2 != 0 ? HeadingItemCount - 1 : HeadingItemCount); _headingPositionStep = -1 * headingItemStep / HeadingValueRange; _headingCenterPosition = headingControlLength / 2; - - SetUpPolygonPoints(); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) @@ -464,56 +453,56 @@ private static void UpdateColorX(AvaloniaObject source) { if (source is not AttitudeIndicator indicator) return; - if (indicator.VibrationX < 0.30) + if (indicator.VibrationX < 30) { indicator.BrushVibrationX = Colors.Red; } - else if (indicator.VibrationX > 0.30 & indicator.VibrationX < 0.60) + else if (indicator.VibrationX > 30 & indicator.VibrationX < 60) { indicator.BrushVibrationX = Colors.Yellow; } - else if (indicator.VibrationX > 0.60) + else if (indicator.VibrationX > 60) { indicator.BrushVibrationX = Colors.GreenYellow; } } - + private static void UpdateColorY(AvaloniaObject source) { if (source is not AttitudeIndicator indicator) return; - if (indicator.VibrationY < 0.30) + if (indicator.VibrationY < 30) { indicator.BrushVibrationY = Colors.Red; } - else if (indicator.VibrationY > 0.30 & indicator.VibrationY < 0.60) + else if (indicator.VibrationY > 30 & indicator.VibrationY < 60) { indicator.BrushVibrationY = Colors.Yellow; } - else if (indicator.VibrationY > 0.60) + else if (indicator.VibrationY > 60) { indicator.BrushVibrationY = Colors.GreenYellow; } } - + private static void UpdateColorZ(AvaloniaObject source) { if (source is not AttitudeIndicator indicator) return; - if (indicator.VibrationZ < 0.30) + if (indicator.VibrationZ < 30) { indicator.BrushVibrationZ = Colors.Red; } - else if (indicator.VibrationZ > 0.30 & indicator.VibrationZ < 0.60) + else if (indicator.VibrationZ > 30 & indicator.VibrationZ < 60) { indicator.BrushVibrationZ = Colors.Yellow; } - else if (indicator.VibrationZ > 0.60) + else if (indicator.VibrationZ > 60) { indicator.BrushVibrationZ = Colors.GreenYellow; } } - + private static void UpdateAngle(AvaloniaObject source) { if (source is not AttitudeIndicator indicator) return; @@ -562,6 +551,7 @@ private static void UpdateHeadingItems(AvaloniaObject source) { item.UpdateValue(heading); } + indicator.HomeAzimuthPosition = GetHomeAzimuthPosition(indicator.HomeAzimuth, indicator.Heading); } @@ -583,30 +573,6 @@ private static double GetHomeAzimuthPosition(double? value, double headingValue) return _headingCenterPosition + distance * _headingPositionStep; } - - //TODO: Remove this and polygon styled properties when Avalonia will fix Points nullable attributes - private void SetUpPolygonPoints() - { - AltitudePolygonPoints.Add(new Point(105,5)); - AltitudePolygonPoints.Add(new Point(105,55)); - AltitudePolygonPoints.Add(new Point(15,55)); - AltitudePolygonPoints.Add(new Point(0,30)); - AltitudePolygonPoints.Add(new Point(15,5)); - - VelocityPolygonPoints.Add(new Point(2,5)); - VelocityPolygonPoints.Add(new Point(2,55)); - VelocityPolygonPoints.Add(new Point(90,55)); - VelocityPolygonPoints.Add(new Point(105,30)); - VelocityPolygonPoints.Add(new Point(90,5)); - - HomePolygonPoints.Add(new Point(-15,0)); - HomePolygonPoints.Add(new Point(0,15)); - HomePolygonPoints.Add(new Point(15,0)); - - RollPolygonPoints.Add(new Point(0,1)); - RollPolygonPoints.Add(new Point(1,0)); - RollPolygonPoints.Add(new Point(2,1)); - } } @@ -623,14 +589,15 @@ public class ScaleItem : AvaloniaObject private double _position; private bool _isVisible; - public ScaleItem(double value, double valueRange, int index, int itemCount, double fullLength, double length, bool isInverse = false, bool showNegative = true, string fixedTitle = null) + public ScaleItem(double value, double valueRange, int index, int itemCount, double fullLength, double length, + bool isInverse = false, bool showNegative = true, string fixedTitle = null) { _valueRange = valueRange; _showNegative = showNegative; _isFixedTitle = fixedTitle != null; var step = fullLength / (itemCount % 2 != 0 ? itemCount - 1 : itemCount); _positionStep = step / valueRange; - + if (!isInverse) { _startPosition = (length - fullLength) / 2.0 + step * index; @@ -642,7 +609,7 @@ public ScaleItem(double value, double valueRange, int index, int itemCount, doub } var centerIndex = itemCount % 2 == 0 ? itemCount / 2 : itemCount / 2 + 1; - + var indexOffset = index - centerIndex; _valueOffset = -1 * valueRange * indexOffset; @@ -661,7 +628,7 @@ public void UpdateValue(double value) protected virtual string GetTitle(double value) { - return Math.Round(value).ToString("F0"); + return Math.Round(value).ToString("F0"); } private double GetValue(double value) @@ -717,9 +684,9 @@ public double Position public class HeadingScaleItem : ScaleItem { - public HeadingScaleItem(double value, double valueRange, int index, int itemCount, double fullLength, double length) : base(value, valueRange, index, itemCount, fullLength, length, true) + public HeadingScaleItem(double value, double valueRange, int index, int itemCount, double fullLength, + double length) : base(value, valueRange, index, itemCount, fullLength, length, true) { - } protected override string GetTitle(double value) @@ -815,7 +782,7 @@ public string Title public static readonly DirectProperty ValueProperty = AvaloniaProperty.RegisterDirect(nameof(Value), _ => _.Value, (_, value) => _.Value = value); - + public double Value { get => _value; @@ -826,7 +793,7 @@ public double Value AvaloniaProperty.RegisterDirect(nameof(IsVisible), _ => _.IsVisible, (_, value) => _.IsVisible = value); - + public bool IsVisible { get => _isVisible; diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryTagViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryTagViewModel.cs new file mode 100644 index 00000000..a00f6f74 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryTagViewModel.cs @@ -0,0 +1,14 @@ +using System.Windows.Input; +using Avalonia.Media; +using Material.Icons; +using ReactiveUI; + +namespace Asv.Drones.Gui.Api; + +public class HierarchicalStoreEntryTagViewModel : ReactiveObject +{ + public MaterialIconKind Icon { get; set; } = MaterialIconKind.Tag; + public IBrush Color { get; set; } + public string Name { get; set; } + public ICommand? Remove { get; set; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs similarity index 75% rename from src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs rename to src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs index 07c789bd..88860e84 100644 --- a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs @@ -7,8 +7,7 @@ using ReactiveUI; using ReactiveUI.Fody.Helpers; -namespace Asv.Drones.Gui.Core; - +namespace Asv.Drones.Gui.Api; public enum HierarchicalStoreEntryAction { @@ -16,106 +15,87 @@ public enum HierarchicalStoreEntryAction Delete } -public class HierarchicalStoreEntryViewModel:DisposableReactiveObject +public class HierarchicalStoreEntryViewModel : DisposableReactiveObject { public HierarchicalStoreEntryViewModel() { - BeginEditName = ReactiveCommand.Create(()=> { IsInEditNameMode = true; }).DisposeItWith(Disposable);; + BeginEditName = ReactiveCommand.Create(() => { IsInEditNameMode = true; }).DisposeItWith(Disposable); + ; EndEditName = ReactiveCommand.Create(() => { IsInEditNameMode = false; Rename(Name); }).DisposeItWith(Disposable); EndEditName.ThrownExceptions - .Subscribe(ex => OnError(HierarchicalStoreEntryAction.Rename,ex)) + .Subscribe(ex => OnError(HierarchicalStoreEntryAction.Rename, ex)) .DisposeItWith(Disposable); DeleteEntry = ReactiveCommand.Create(Delete) .DisposeItWith(Disposable); DeleteEntry.ThrownExceptions - .Subscribe(ex => OnError(HierarchicalStoreEntryAction.Delete,ex)) + .Subscribe(ex => OnError(HierarchicalStoreEntryAction.Delete, ex)) .DisposeItWith(Disposable); - - BeginMove = ReactiveCommand.Create(() => - { - IsInMoveMode = true; - }).DisposeItWith(Disposable); - CancelMove = ReactiveCommand.Create(() => - { - IsInMoveMode = false; - }).DisposeItWith(Disposable); + + BeginMove = ReactiveCommand.Create(() => { IsInMoveMode = true; }).DisposeItWith(Disposable); + CancelMove = ReactiveCommand.Create(() => { IsInMoveMode = false; }).DisposeItWith(Disposable); EndMove = ReactiveCommand.Create(() => { IsInMoveMode = false; Move(); }).DisposeItWith(Disposable); - + this.WhenValueChanged(x => x.IsInMoveMode) .Subscribe(x => IsNotInMoveMode = !x) .DisposeItWith(Disposable); this.WhenValueChanged(x => x.IsNotInMoveMode) .Subscribe(x => IsInMoveMode = !x) .DisposeItWith(Disposable); - } - - [Reactive] - public bool IsInMoveMode { get; set; } - [Reactive] - public bool IsNotInMoveMode { get; set; } + [Reactive] public bool IsInMoveMode { get; set; } + [Reactive] public bool IsNotInMoveMode { get; set; } public object Id { get; set; } public object ParentId { get; set; } public bool IsFolder { get; set; } public bool IsFile { get; set; } public FolderStoreEntryType Type { get; set; } - [Reactive] - public string Name { get; set; } - [Reactive] - public bool IsExpanded { get; set; } - [Reactive] - public bool IsSelected { get; set; } - + [Reactive] public string Name { get; set; } + [Reactive] public bool IsExpanded { get; set; } + [Reactive] public bool IsSelected { get; set; } + public virtual ReadOnlyObservableCollection Items { get; set; } - [Reactive] - public bool IsInEditNameMode { get; set; } = false; - - public ReactiveCommand DeleteEntry { get; } - public ReactiveCommand BeginEditName { get; } - public ReactiveCommand EndEditName { get; } - public ReactiveCommand BeginMove { get; } - public ReactiveCommand EndMove { get;} - public ReactiveCommand CancelMove { get;} - + [Reactive] public bool IsInEditNameMode { get; set; } = false; + + public ReactiveCommand DeleteEntry { get; } + public ReactiveCommand BeginEditName { get; } + public ReactiveCommand EndEditName { get; } + public ReactiveCommand BeginMove { get; } + public ReactiveCommand EndMove { get; } + public ReactiveCommand CancelMove { get; } + public virtual ReadOnlyObservableCollection Tags { get; set; } - - [Reactive] - public string Description { get; set; } + + [Reactive] public string Description { get; set; } protected virtual void OnError(HierarchicalStoreEntryAction action, Exception exception) { - } protected virtual void Rename(string? name) { - } protected virtual void Delete() { - } - + protected virtual void Move() { - } public virtual void Refresh() { - } public HierarchicalStoreEntryViewModel? FindAndSelect(object id) @@ -136,13 +116,13 @@ public virtual void Refresh() return find; } } + return null; } } - -public class HierarchicalStoreEntryViewModel:HierarchicalStoreEntryViewModel - where TKey : notnull +public class HierarchicalStoreEntryViewModel : HierarchicalStoreEntryViewModel + where TKey : notnull where TFile : IDisposable { private readonly Node, TKey> _node; @@ -150,16 +130,18 @@ public class HierarchicalStoreEntryViewModel:HierarchicalStoreEntryV private readonly ILogService _log; private readonly ReadOnlyObservableCollection _items; private ReadOnlyObservableCollection _tags; - private readonly SourceCache _tagsSource; + private readonly SourceCache _tagsSource; private bool _isAlreadyFillTags; - public HierarchicalStoreEntryViewModel(Node, TKey> node, HierarchicalStoreViewModel context, ILogService log) + public HierarchicalStoreEntryViewModel(Node, TKey> node, + HierarchicalStoreViewModel context, ILogService log) { _node = node; _context = context; _log = log; node.Children.Connect() - .Transform(x => (HierarchicalStoreEntryViewModel)new HierarchicalStoreEntryViewModel(x,context,log)) + .Transform(x => + (HierarchicalStoreEntryViewModel)new HierarchicalStoreEntryViewModel(x, context, log)) .Bind(out _items) .DisposeMany() .Subscribe() diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreView.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreView.axaml new file mode 100644 index 00000000..528127c4 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreView.axaml @@ -0,0 +1,275 @@ + + + + + + 18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreView.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreView.axaml.cs similarity index 86% rename from src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreView.axaml.cs rename to src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreView.axaml.cs index 8e437efa..e6e3a50d 100644 --- a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreView.axaml.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreView.axaml.cs @@ -1,6 +1,6 @@ using Avalonia.ReactiveUI; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; public partial class HierarchicalStoreView : ReactiveUserControl { diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs new file mode 100644 index 00000000..20b077e5 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs @@ -0,0 +1,372 @@ +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using Asv.Common; +using Asv.Mavlink; +using Avalonia.Controls; +using Avalonia.Media; +using DynamicData; +using DynamicData.Binding; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api; + +public class HierarchicalStoreViewModel : ViewModelBase +{ + protected HierarchicalStoreViewModel(Uri id) : base(id) + { + CreateNewFile = ReactiveCommand.Create(CreateNewFileImpl) + .DisposeItWith(Disposable); + CreateNewFile.ThrownExceptions + .Subscribe(ex => OnError(HierarchicalStoreAction.CreateFile, ex)) + .DisposeItWith(Disposable); + + CreateNewFolder = ReactiveCommand.Create(CreateNewFolderImpl) + .DisposeItWith(Disposable); + CreateNewFolder.ThrownExceptions + .Subscribe(ex => OnError(HierarchicalStoreAction.CreateFolder, ex)) + .DisposeItWith(Disposable); + + Refresh = ReactiveCommand.Create(() => + { + var selectedId = SelectedItem?.Id; + var selectedParentId = SelectedItem?.ParentId; + RefreshImpl(); + if (TrySelect(selectedId) == false) + { + TrySelect(selectedParentId); + } + }) + .DisposeItWith(Disposable); + Refresh.ThrownExceptions + .Subscribe(ex => OnError(HierarchicalStoreAction.Refresh, ex)) + .DisposeItWith(Disposable); + } + + + public HierarchicalStoreViewModel() : this(WellKnownUri.UndefinedUri) + { + DesignTime.ThrowIfNotDesignMode(); + Items = new ReadOnlyObservableCollection( + new ObservableCollection(new List + { + new() + { + Id = Guid.NewGuid(), + Name = "Record1", + Tags = new ReadOnlyObservableCollection( + new ObservableCollection( + new List + { + new() + { + Color = Brushes.CornflowerBlue, + Name = "Latitude: 55.1234567", + }, + new() + { + Color = Brushes.DarkOrange, + Name = "Short", + }, + new() + { + Color = new SolidColorBrush(Color.Parse("#FBC02D")), + Name = "Longitude: 66.1234567", + }, + new() + { + Color = new SolidColorBrush(Color.Parse("#FE8256")), + Name = "Longitude: 66.1234567", + }, + new() + { + Color = new SolidColorBrush(Color.Parse("#ACC865")), + Name = "ACC865:66.1234567", + }, + new() + { + Color = new SolidColorBrush(Color.Parse("#CD91B6")), + Name = "ShortShort", + }, + })), + IsFile = true, + }, + new() + { + Id = Guid.NewGuid(), + Name = "Folder", + IsFolder = true, + Items = new ReadOnlyObservableCollection( + new ObservableCollection( + new List + { + new() + { + Id = Guid.NewGuid(), + Name = "Record 2", + IsFile = true, + }, + })) + }, + })); + FolderItems = new ReadOnlyObservableCollection( + new ObservableCollection(new List + { + new() + { + Id = Guid.NewGuid(), + Name = "Folder", + IsFolder = true, + Items = new ReadOnlyObservableCollection( + new ObservableCollection( + new List + { + new() + { + Id = Guid.NewGuid(), + Name = "Folder 2", + IsFolder = true, + }, + })) + }, + })); + } + + [Reactive] public string SearchText { get; set; } + [Reactive] public string DisplayName { get; set; } + public virtual ReadOnlyObservableCollection Items { get; } + public virtual ReadOnlyObservableCollection FolderItems { get; } + [Reactive] public HierarchicalStoreEntryViewModel? SelectedItem { get; set; } + public ReactiveCommand CreateNewFolder { get; set; } + public ReactiveCommand CreateNewFile { get; set; } + public ReactiveCommand Refresh { get; set; } + public bool IsHeaderVisible { get; set; } = true; + + public bool TrySelect(object? selectedId) + { + if (selectedId == null) return false; + foreach (var item in Items) + { + var find = item.FindAndSelect(selectedId); + if (find == null) continue; + find.IsSelected = true; + return true; + } + + return false; + } + + protected virtual void RefreshImpl() + { + } + + protected virtual void CreateNewFileImpl() + { + } + + protected virtual void CreateNewFolderImpl() + { + } + + protected virtual void OnError(HierarchicalStoreAction action, Exception ex) + { + } + + [Reactive] public bool IsCreateFolderAvailable { get; set; } = true; + [Reactive] public bool IsCreateFileAvailable { get; set; } = true; + + [Reactive] public HierarchicalStoreEntryViewModel? SelectedItemMoveTo { get; set; } +} + +public abstract class HierarchicalStoreViewModel : HierarchicalStoreViewModel + where TFile : IDisposable where TKey : notnull +{ + private readonly IHierarchicalStore _store; + private readonly ILogService _log; + private readonly SourceCache, TKey> _source; + private readonly ReadOnlyObservableCollection _tree; + private readonly ReadOnlyObservableCollection _treeFolder; + + + public HierarchicalStoreViewModel() : base(WellKnownUri.UndefinedUri) + { + DesignTime.ThrowIfNotDesignMode(); + } + + public HierarchicalStoreViewModel(Uri id, IHierarchicalStore store, ILogService log) : base(id) + { + _store = store; + _log = log; + _source = new SourceCache, TKey>(x => x.Id) + .DisposeItWith(Disposable); + var filterPipe = new Subject, bool>>() + .DisposeItWith(Disposable); + this.WhenValueChanged(x => x.SearchText) + .Throttle(TimeSpan.FromMilliseconds(500), RxApp.MainThreadScheduler) + .Subscribe(search => filterPipe.OnNext(item => search.IsNullOrWhiteSpace() || item.Name.Contains(search))) + .DisposeItWith(Disposable); + + _source + .Connect() + .Filter(filterPipe) + .TransformToTree(x => x.ParentId) + .Transform(x => + (HierarchicalStoreEntryViewModel)new HierarchicalStoreEntryViewModel(x, this, log)) + .DisposeMany() + .Bind(out _tree) + .Subscribe() + .DisposeItWith(Disposable); + + _source + .Connect() + .Filter(x => x.Type == FolderStoreEntryType.Folder) + .TransformToTree(x => x.ParentId) + .Transform(x => + (HierarchicalStoreEntryViewModel)new HierarchicalStoreEntryViewModel(x, this, log)) + .DisposeMany() + .Bind(out _treeFolder) + .Subscribe() + .DisposeItWith(Disposable); + + this.WhenValueChanged(x => x.SelectedItem) + .Subscribe(x => x?.Refresh()).DisposeItWith(Disposable); + } + + protected override void OnError(HierarchicalStoreAction action, Exception ex) + { + _log.Error(DisplayName, $"Error to '{action:G}'", ex); + } + + protected override void CreateNewFolderImpl() + { + TKey parentId; + if (SelectedItem != null) + { + parentId = + (TKey)(SelectedItem.Type == FolderStoreEntryType.Folder ? SelectedItem.Id : SelectedItem.ParentId); + } + else + { + parentId = _store.RootFolderId; + } + + var attempt = 0; + start: + var name = $"New folder {++attempt}"; + try + { + _store.CreateFolder(GenerateNewId(), name, parentId); + } + catch (HierarchicalStoreFolderAlreadyExistException) + { + goto start; + } + + Refresh.Execute().Subscribe(_ => { }); + } + + protected abstract TKey GenerateNewId(); + + protected override void CreateNewFileImpl() + { + TKey parentId; + if (SelectedItem != null) + { + parentId = + (TKey)(SelectedItem.Type == FolderStoreEntryType.Folder ? SelectedItem.Id : SelectedItem.ParentId); + } + else + { + parentId = _store.RootFolderId; + } + + var attempt = 0; + start: + var name = $"New file {++attempt}"; + try + { + using var file = _store.CreateFile(GenerateNewId(), name, parentId); + } + catch (HierarchicalStoreFolderAlreadyExistException) + { + goto start; + } + + Refresh.Execute().Subscribe(_ => { }); + } + + protected override void RefreshImpl() + { + _source.Clear(); + _source.AddOrUpdate(_store.GetEntries()); + } + + + public override ReadOnlyObservableCollection Items => _tree; + public override ReadOnlyObservableCollection FolderItems => _treeFolder; + + public void DeleteEntryImpl(TKey itemId) + { + _store.DeleteEntry(itemId); + Refresh.Execute().Subscribe(); + } + + public void RenameEntryImpl(TKey itemId, string name) + { + _store.RenameEntry(itemId, name); + Refresh.Execute().Subscribe(); + } + + public void MoveEntryImpl(TKey id, TKey parentId) + { + _store.MoveEntry(id, parentId); + Refresh.Execute().Subscribe(); + } + + public IReadOnlyCollection GetEntryTags(TKey id) + { + var item = _source.Lookup(id); + return !item.HasValue + ? ArraySegment.Empty + : InternalGetEntryTags(item.Value); + } + + protected virtual IReadOnlyCollection InternalGetEntryTags( + IHierarchicalStoreEntry itemValue) + { + return ArraySegment.Empty; + } + + + public virtual string GetEntryDescription(IHierarchicalStoreEntry nodeItem) + { + var entry = nodeItem as FileSystemHierarchicalStoreEntry; + + if (entry == null) return string.Empty; + + if (nodeItem.Type == FolderStoreEntryType.Folder) + { + var info = new DirectoryInfo(entry.FullPath); + return info.CreationTime.ToString(CultureInfo.CurrentCulture); + } + + if (nodeItem.Type == FolderStoreEntryType.File) + { + var info = new FileInfo(entry.FullPath); + return info.CreationTime.ToString(CultureInfo.CurrentCulture); + } + + return string.Empty; + } +} + +public enum HierarchicalStoreAction +{ + Refresh, + CreateFile, + CreateFolder +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/BatteryIndicator.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/BatteryIndicator.axaml new file mode 100644 index 00000000..da0c179c --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/BatteryIndicator.axaml @@ -0,0 +1,48 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/BatteryIndicator.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/BatteryIndicator.axaml.cs similarity index 79% rename from src/Asv.Drones.Gui.Core/Controls/BatteryIndicator.axaml.cs rename to src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/BatteryIndicator.axaml.cs index a48fd14c..ee0575f1 100644 --- a/src/Asv.Drones.Gui.Core/Controls/BatteryIndicator.axaml.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/BatteryIndicator.axaml.cs @@ -3,34 +3,37 @@ using Avalonia.Controls.Metadata; using Material.Icons; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; [PseudoClasses(":critical", ":warning", ":normal", ":unknown")] public class BatteryIndicator : IndicatorBase { #region Styled Props - - public static readonly StyledProperty CriticalValueProperty = AvaloniaProperty.Register( - nameof(CriticalValue), 20); + + public static readonly StyledProperty CriticalValueProperty = + AvaloniaProperty.Register( + nameof(CriticalValue), 20); public double CriticalValue { get => GetValue(CriticalValueProperty); set => SetValue(CriticalValueProperty, value); } - - public static readonly StyledProperty WarningValueProperty = AvaloniaProperty.Register( - nameof(WarningValue),50); + + public static readonly StyledProperty WarningValueProperty = + AvaloniaProperty.Register( + nameof(WarningValue), 50); public double WarningValue { get => GetValue(WarningValueProperty); set => SetValue(WarningValueProperty, value); } - - public static readonly StyledProperty MaxValueProperty = AvaloniaProperty.Register( - nameof(MaxValue), 100); - + + public static readonly StyledProperty MaxValueProperty = + AvaloniaProperty.Register( + nameof(MaxValue), 100); + public double MaxValue { get => GetValue(MaxValueProperty); @@ -45,34 +48,33 @@ public double? Value get => GetValue(ValueProperty); set => SetValue(ValueProperty, value); } - + #endregion public BatteryIndicator() { - } private static void SetPseudoClass(BatteryIndicator indicator) { - } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); - if (change.Property == ValueProperty || change.Property == MaxValueProperty || change.Property == CriticalValueProperty || change.Property == WarningValueProperty) + if (change.Property == ValueProperty || change.Property == MaxValueProperty || + change.Property == CriticalValueProperty || change.Property == WarningValueProperty) { - var value = Value; + var value = Value; PseudoClasses.Set(":unknown", value == null || double.IsFinite(value.Value) == false || value > MaxValue); PseudoClasses.Set(":critical", value <= CriticalValue); PseudoClasses.Set(":warning", value > CriticalValue & value <= WarningValue); PseudoClasses.Set(":normal", value > WarningValue & value <= MaxValue); if (MaxValue == 0 || double.IsFinite(MaxValue) == false) { - } - IconKind = GetIcon(Value/MaxValue); + + IconKind = GetIcon(Value / MaxValue); } } @@ -81,9 +83,9 @@ private static MaterialIconKind GetIcon(double? normalizedValue) return (normalizedValue ?? double.NaN) switch { (< 0 or > 1 - or double.NegativeInfinity - or double.PositiveInfinity - or double.NaN) => MaterialIconKind.BatteryUnknown, + or double.NegativeInfinity + or double.PositiveInfinity + or double.NaN) => MaterialIconKind.BatteryUnknown, (0) => MaterialIconKind.Battery0, (> 0 and <= 0.10) => MaterialIconKind.Battery10, (> 0.10 and <= 0.20) => MaterialIconKind.Battery20, @@ -97,6 +99,4 @@ or double.PositiveInfinity (> 0.90 and <= 1) => MaterialIconKind.Battery100 }; } - - } \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/ConnectionQuality.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/ConnectionQuality.axaml new file mode 100644 index 00000000..83c8972d --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/ConnectionQuality.axaml @@ -0,0 +1,49 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/ConnectionQuality.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/ConnectionQuality.axaml.cs new file mode 100644 index 00000000..1e0acecd --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/ConnectionQuality.axaml.cs @@ -0,0 +1,101 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Metadata; +using Avalonia.Media; +using Material.Icons; + +namespace Asv.Drones.Gui.Api; + +[PseudoClasses(":critical", ":warning", ":normal", ":unknown")] +public class ConnectionQuality : IndicatorBase +{ + #region Styled Props + + public static readonly StyledProperty CriticalValueProperty = + AvaloniaProperty.Register( + nameof(CriticalValue), 0.2); + + public double CriticalValue + { + get => GetValue(CriticalValueProperty); + set => SetValue(CriticalValueProperty, value); + } + + public static readonly StyledProperty WarningValueProperty = + AvaloniaProperty.Register( + nameof(WarningValue), 0.5); + + public double WarningValue + { + get => GetValue(WarningValueProperty); + set => SetValue(WarningValueProperty, value); + } + + public static readonly StyledProperty MaxValueProperty = + AvaloniaProperty.Register( + nameof(MaxValue), 1); + + public double MaxValue + { + get => GetValue(MaxValueProperty); + set => SetValue(MaxValueProperty, value); + } + + public static readonly StyledProperty ValueProperty = + AvaloniaProperty.Register( + nameof(Value), default(double?)); + + public double? Value + { + get => GetValue(ValueProperty); + set => SetValue(ValueProperty, value); + } + + public static readonly StyledProperty IconKindProperty = + AvaloniaProperty.Register( + nameof(IconKind), MaterialIconKind.WifiStrengthAlertOutline); + + public MaterialIconKind IconKind + { + get => GetValue(IconKindProperty); + set => SetValue(IconKindProperty, value); + } + + #endregion + + public ConnectionQuality() + { + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == ValueProperty) + { + var value = Value; + PseudoClasses.Set(":unknown", value == null || double.IsFinite(value.Value) == false || value > MaxValue); + PseudoClasses.Set(":critical", value <= CriticalValue); + PseudoClasses.Set(":warning", value > CriticalValue & value <= WarningValue); + PseudoClasses.Set(":normal", value > WarningValue & value <= MaxValue); + IconKind = GetIcon(Value / MaxValue); + } + } + + + private static MaterialIconKind GetIcon(double? normalizedValue) + { + return (normalizedValue ?? double.NaN) switch + { + (< 0 or > 1 + or double.NegativeInfinity + or double.PositiveInfinity + or double.NaN) => MaterialIconKind.WifiStrengthAlertOutline, + (0) => MaterialIconKind.WifiStrength0, + (> 0 and <= 0.2) => MaterialIconKind.WifiStrength0, + (> 0.2 and <= 0.4) => MaterialIconKind.WifiStrength1, + (> 0.4 and <= 0.6) => MaterialIconKind.WifiStrength2, + (> 0.6 and <= 0.8) => MaterialIconKind.WifiStrength3, + (> 0.8 and <= 1.0) => MaterialIconKind.WifiStrength4, + }; + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/DigitIndicator.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/DigitIndicator.axaml new file mode 100644 index 00000000..03d08f3e --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/DigitIndicator.axaml @@ -0,0 +1,28 @@ + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/DigitIndicator.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/DigitIndicator.axaml.cs new file mode 100644 index 00000000..2b8c181f --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/DigitIndicator.axaml.cs @@ -0,0 +1,119 @@ +using Avalonia; + +namespace Asv.Drones.Gui.Api; + +public class DigitIndicator : IndicatorBase +{ + #region Direct properties + + private string _title; + + public static readonly DirectProperty TitleProperty = + AvaloniaProperty.RegisterDirect( + nameof(Title), o => o.Title, (o, v) => o.Title = v); + + public string Title + { + get => _title; + set => SetAndRaise(TitleProperty, ref _title, value); + } + + private string _units; + + public static readonly DirectProperty UnitsProperty = + AvaloniaProperty.RegisterDirect( + nameof(Units), o => o.Units, (o, v) => o.Units = v); + + public string Units + { + get => _units; + set => SetAndRaise(UnitsProperty, ref _units, value); + } + + private double _value; + + public static readonly DirectProperty ValueProperty = + AvaloniaProperty.RegisterDirect( + nameof(Value), o => o.Value, (o, v) => o.Value = v); + + public double Value + { + get => _value; + set + { + if (Math.Abs(value - _value) < double.Epsilon) + { + IsDecreased = false; + IsIncreased = false; + } + else if (value > _value) + { + IsDecreased = false; + IsIncreased = true; + } + else if (value < _value) + { + IsDecreased = true; + IsIncreased = false; + } + + SetAndRaise(ValueProperty, ref _value, value); + FormatedValue = Value.ToString(FormatString); + } + } + + private string _formatString; + + public static readonly DirectProperty FormatStringProperty = + AvaloniaProperty.RegisterDirect( + nameof(FormatString), o => o.FormatString, (o, v) => o.FormatString = v); + + public string FormatString + { + get => _formatString; + set => SetAndRaise(FormatStringProperty, ref _formatString, value); + } + + private bool _isIncreased; + + public static readonly DirectProperty IsIncreasedProperty = + AvaloniaProperty.RegisterDirect( + nameof(IsIncreased), o => o.IsIncreased, (o, v) => o.IsIncreased = v); + + public bool IsIncreased + { + get => _isIncreased; + set => SetAndRaise(IsIncreasedProperty, ref _isIncreased, value); + } + + private bool _isDecreased; + + public static readonly DirectProperty IsDecreasedProperty = + AvaloniaProperty.RegisterDirect( + nameof(IsDecreased), o => o.IsDecreased, (o, v) => o.IsDecreased = v); + + public bool IsDecreased + { + get => _isDecreased; + set => SetAndRaise(IsDecreasedProperty, ref _isDecreased, value); + } + + #endregion + + private string _formatedValue; + + public static readonly DirectProperty FormatedValueProperty = + AvaloniaProperty.RegisterDirect( + nameof(FormatedValue), o => o.FormatedValue, (o, v) => o.FormatedValue = v); + + public string FormatedValue + { + get => _formatedValue; + set => SetAndRaise(FormatedValueProperty, ref _formatedValue, value); + } + + public DigitIndicator() + { + FormatString = ""; + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/GpsStatusIndicator.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/GpsStatusIndicator.axaml new file mode 100644 index 00000000..e1515b50 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/GpsStatusIndicator.axaml @@ -0,0 +1,48 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/GpsStatusIndicator.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/GpsStatusIndicator.axaml.cs similarity index 90% rename from src/Asv.Drones.Gui.Core/Controls/GpsStatusIndicator.axaml.cs rename to src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/GpsStatusIndicator.axaml.cs index 8e701e64..6587f2d3 100644 --- a/src/Asv.Drones.Gui.Core/Controls/GpsStatusIndicator.axaml.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/GpsStatusIndicator.axaml.cs @@ -5,7 +5,7 @@ using Avalonia.Controls.Metadata; using Material.Icons; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; [PseudoClasses(":critical", ":warning", ":normal", ":unknown")] public class GpsStatusIndicator : IndicatorBase @@ -14,7 +14,7 @@ public class GpsStatusIndicator : IndicatorBase public static readonly StyledProperty FixTypeProperty = AvaloniaProperty.Register( - nameof(FixType), GpsFixType.GpsFixTypeNoGps,coerce: UpdateValue); + nameof(FixType), GpsFixType.GpsFixTypeNoGps, coerce: UpdateValue); public GpsFixType FixType { @@ -34,7 +34,7 @@ public string ToolTipText public static readonly StyledProperty DopStatusProperty = AvaloniaProperty.Register( - nameof(DopStatus), DopStatusEnum.Unknown, coerce:UpdateValue); + nameof(DopStatus), DopStatusEnum.Unknown, coerce: UpdateValue); private static DopStatusEnum UpdateValue(AvaloniaObject arg1, DopStatusEnum arg2) { @@ -57,8 +57,9 @@ public static void SetPseudoClass(GpsStatusIndicator indicator) indicator.PseudoClasses.Set(":unknown", dopStatus == DopStatusEnum.Unknown); indicator.PseudoClasses.Set(":critical", dopStatus is DopStatusEnum.Fair or DopStatusEnum.Poor); indicator.PseudoClasses.Set(":warning", dopStatus == DopStatusEnum.Moderate); - indicator.PseudoClasses.Set(":normal", dopStatus is DopStatusEnum.Ideal or DopStatusEnum.Excellent or DopStatusEnum.Good); - + indicator.PseudoClasses.Set(":normal", + dopStatus is DopStatusEnum.Ideal or DopStatusEnum.Excellent or DopStatusEnum.Good); + indicator.IconKind = GetIcon(indicator.FixType); indicator.ToolTipText = indicator.FixType.GetShortDisplayName(); } diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/IndicatorBase.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/IndicatorBase.cs new file mode 100644 index 00000000..fe103932 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/IndicatorBase.cs @@ -0,0 +1,60 @@ +using Avalonia; +using Avalonia.Controls.Primitives; +using Avalonia.Media; +using Material.Icons; + +namespace Asv.Drones.Gui.Api; + +public abstract class IndicatorBase : TemplatedControl +{ + #region Brushes + + public static readonly StyledProperty UnknownBrushProperty = AvaloniaProperty.Register( + "UnknownBrush"); + + public Brush UnknownBrush + { + get => GetValue(UnknownBrushProperty); + set => SetValue(UnknownBrushProperty, value); + } + + public static readonly StyledProperty CriticalBrushProperty = + AvaloniaProperty.Register( + "CriticalBrush"); + + public Brush CriticalBrush + { + get => GetValue(CriticalBrushProperty); + set => SetValue(CriticalBrushProperty, value); + } + + public static readonly StyledProperty WarningBrushProperty = AvaloniaProperty.Register( + "WarningBrush"); + + public Brush WarningBrush + { + get => GetValue(WarningBrushProperty); + set => SetValue(WarningBrushProperty, value); + } + + public static readonly StyledProperty NormalBrushProperty = AvaloniaProperty.Register( + "NormalBrush"); + + public Brush NormalBrush + { + get => GetValue(NormalBrushProperty); + set => SetValue(NormalBrushProperty, value); + } + + #endregion + + public static readonly StyledProperty IconKindProperty = + AvaloniaProperty.Register( + nameof(IconKind), MaterialIconKind.BatteryUnknown); + + public MaterialIconKind IconKind + { + get => GetValue(IconKindProperty); + set => SetValue(IconKindProperty, value); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/LevelIndicator.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/LevelIndicator.axaml new file mode 100644 index 00000000..0bffa2ea --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/LevelIndicator.axaml @@ -0,0 +1,137 @@ + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/LevelIndicator.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/LevelIndicator.axaml.cs similarity index 95% rename from src/Asv.Drones.Gui.Core/Controls/LevelIndicator.axaml.cs rename to src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/LevelIndicator.axaml.cs index 1fd6f940..be5d36c1 100644 --- a/src/Asv.Drones.Gui.Core/Controls/LevelIndicator.axaml.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/LevelIndicator.axaml.cs @@ -1,31 +1,31 @@ using Avalonia; using Avalonia.Controls.Primitives; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; public class LevelIndicator : TemplatedControl { public static readonly StyledProperty ValueFromProperty = AvaloniaProperty.Register( nameof(ValueFrom), 100); - + public double ValueFrom { get => GetValue(ValueFromProperty); set => SetValue(ValueFromProperty, value); } - + public static readonly StyledProperty ValueToProperty = AvaloniaProperty.Register( nameof(ValueTo), 100); - + public double ValueTo { get => GetValue(ValueToProperty); set => SetValue(ValueToProperty, value); } - + public static readonly StyledProperty LevelProperty = AvaloniaProperty.Register( nameof(Level)); - + public double? Level { get => GetValue(LevelProperty); @@ -40,12 +40,13 @@ public double? Value get => GetValue(ValueProperty); set => SetValue(ValueProperty, value); } - + private static void UpdateValueLimits(AvaloniaObject source) { if (source is not LevelIndicator indicator) return; - if (indicator.ValueTo <= indicator.ValueFrom || double.IsFinite(indicator.ValueTo) == false || double.IsFinite(indicator.ValueTo) == false) + if (indicator.ValueTo <= indicator.ValueFrom || double.IsFinite(indicator.ValueTo) == false || + double.IsFinite(indicator.ValueTo) == false) { indicator.Value = indicator.ValueFrom; } @@ -70,7 +71,7 @@ private static void UpdateValue(AvaloniaObject source) indicator.Level = 0; return; } - + if (indicator.Value > indicator.ValueTo) { indicator.Level = 350; @@ -86,7 +87,6 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang if (change.Property == ValueFromProperty || change.Property == ValueToProperty) { UpdateValueLimits(change.Sender); - } else if (change.Property == ValueProperty) { @@ -95,6 +95,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang } private Random _random = new Random(); + public LevelIndicator() { // if (Design.IsDesignMode) @@ -114,7 +115,5 @@ public LevelIndicator() // Value = _random.NextDouble() * 140 + ValueFrom; // }); // } - - } } \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/StringIndicator.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/StringIndicator.axaml new file mode 100644 index 00000000..5dc73882 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/StringIndicator.axaml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/StringIndicator.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/StringIndicator.axaml.cs new file mode 100644 index 00000000..7f1cdeec --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Indicators/StringIndicator.axaml.cs @@ -0,0 +1,34 @@ +using Avalonia; + +namespace Asv.Drones.Gui.Api; + +public class StringIndicator : IndicatorBase +{ + #region Directed properties + + private string _title; + + public static readonly DirectProperty TitleProperty = + AvaloniaProperty.RegisterDirect( + nameof(Title), o => o.Title, (o, v) => o.Title = v); + + public string Title + { + get => _title; + set => SetAndRaise(TitleProperty, ref _title, value); + } + + private string _value; + + public static readonly DirectProperty ValueProperty = + AvaloniaProperty.RegisterDirect( + nameof(Value), o => o.Value, (o, v) => o.Value = v); + + public string Value + { + get => _value; + set => SetAndRaise(ValueProperty, ref _value, value); + } + + #endregion +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/IMapAction.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/IMapAction.cs new file mode 100644 index 00000000..d2517367 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/IMapAction.cs @@ -0,0 +1,27 @@ +using Avalonia.Controls; + +namespace Asv.Drones.Gui.Api; + +/// +/// IMapAction provides a contract for a Map Action. +/// It's part of the Asv.Drones.Gui.Core project which uses AvaloniaUI for the User Interface. +/// +public interface IMapAction : IViewModel +{ + /// + /// Position on the control where an element/border should be docked. + /// + Dock Dock { get; } + + /// + /// Represents the order or sequence of the map actions. + /// + int Order { get; } + + /// + /// Initializes a map action using the provided context. + /// + /// An instance of IMap to be used for initiation. + /// An instance of IMapAction. + IMapAction Init(IMap context); +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/MapActionBase.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/MapActionBase.cs similarity index 85% rename from src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/MapActionBase.cs rename to src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/MapActionBase.cs index 86a120a2..9043e707 100644 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/MapActionBase.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/MapActionBase.cs @@ -1,7 +1,7 @@ using Avalonia.Controls; using ReactiveUI.Fody.Helpers; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; public class MapActionBase : ViewModelBase, IMapAction { @@ -12,10 +12,11 @@ protected MapActionBase(Uri id) : base(id) protected MapActionBase(string id) : base(id) { } - [Reactive] - public Dock Dock { get; set; } = Dock.Right; + + [Reactive] public Dock Dock { get; set; } = Dock.Right; public int Order { get; set; } public IMap? Map { get; private set; } + public virtual IMapAction Init(IMap context) { Map = context; diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionView.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionView.axaml new file mode 100644 index 00000000..6c80d1dd --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionView.axaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionView.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionView.axaml.cs new file mode 100644 index 00000000..fbc0ce87 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionView.axaml.cs @@ -0,0 +1,14 @@ +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.ReactiveUI; + +namespace Asv.Drones.Gui.Api; + +[ExportView(typeof(MapMoverActionViewModel))] +public partial class MapMoverActionView : ReactiveUserControl +{ + public MapMoverActionView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionViewModel.cs new file mode 100644 index 00000000..1ff92500 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Mover/MapMoverActionViewModel.cs @@ -0,0 +1,31 @@ +using Avalonia.Controls; + +namespace Asv.Drones.Gui.Api; + +public class MapMoverActionViewModel : ViewModelBase, IMapAction +{ + private IMap _map; + + public MapMoverActionViewModel() : base(WellKnownUri.UndefinedUri) + { + DesignTime.ThrowIfNotDesignMode(); + } + + protected MapMoverActionViewModel(Uri id) : base(id) + { + } + + protected MapMoverActionViewModel(string id) : base(id) + { + } + + public IMapAction Init(IMap context) + { + _map = context; + return this; + } + + public IMap Map => _map; + public Dock Dock { get; } + public int Order => 0; +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionView.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionView.axaml new file mode 100644 index 00000000..f9399ea3 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionView.axaml @@ -0,0 +1,29 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionView.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionView.axaml.cs new file mode 100644 index 00000000..40f997d8 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionView.axaml.cs @@ -0,0 +1,15 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Asv.Drones.Gui.Api; + +[ExportView(typeof(MapRulerActionViewModel))] +public partial class MapRulerActionView : ReactiveUserControl +{ + public MapRulerActionView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionViewModel.cs new file mode 100644 index 00000000..e02afc62 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Ruler/MapRulerActionViewModel.cs @@ -0,0 +1,190 @@ +using System.Collections.ObjectModel; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using Asv.Avalonia.Map; +using Asv.Common; +using Asv.Mavlink.Vehicle; +using Avalonia.Collections; +using Avalonia.Media; +using DynamicData; +using DynamicData.Binding; +using Material.Icons; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api; + +public class MapRulerActionViewModel : MapActionBase +{ + private readonly ILocalizationService _loc; + private CancellationTokenSource? _tokenSource; + private RulerStartAnchor? _startAnchor; + private RulerStopAnchor? _stopAnchor; + private RulerPolygon? _rulerPolygon; + + public MapRulerActionViewModel() : base(WellKnownUri.UndefinedUri) + { + DesignTime.ThrowIfNotDesignMode(); + } + + public MapRulerActionViewModel(string id, ILocalizationService loc) : base(id) + { + _loc = loc; + this.WhenValueChanged(m => m.IsRulerEnabled, false) + .Subscribe(SetUpRuler) + .DisposeItWith(Disposable); + Disposable.AddAction(() => { SetUpRuler(false); }); + } + + private async void SetUpRuler(bool isEnabled) + { + if (Map == null) return; + if (isEnabled) + { + _tokenSource?.Cancel(false); + _tokenSource?.Dispose(); + _tokenSource = new CancellationTokenSource(); + try + { + var startPoint = await Map.ShowTargetDialog("Select ruler starting point", _tokenSource.Token); + if (double.IsNaN(startPoint.Altitude)) + { + IsRulerEnabled = false; + return; + } + + _startAnchor = new RulerStartAnchor(new Uri(Id, "start"), startPoint); + Map.AdditionalAnchorsSource.AddOrUpdate(_startAnchor); + var stopPoint = await Map.ShowTargetDialog("Select ruler stopping point", _tokenSource.Token); + if (double.IsNaN(stopPoint.Altitude)) + { + IsRulerEnabled = false; + return; + } + + _stopAnchor = new RulerStopAnchor(new Uri(Id, "stop"), _startAnchor, _loc, stopPoint); + Map.AdditionalAnchorsSource.AddOrUpdate(_stopAnchor); + + _rulerPolygon = new RulerPolygon(new Uri(Id, "ruler"), _startAnchor, _stopAnchor); + Map.AdditionalAnchorsSource.AddOrUpdate(_rulerPolygon); + } + catch (TaskCanceledException) + { + DisableRulerOnClick(); + } + } + else + { + DisableRulerOnClick(); + } + } + + private void DisableRulerOnClick() + { + _tokenSource?.Cancel(); + + if (Map == null) return; + + if (_startAnchor != null) + { + Map.AdditionalAnchorsSource.Remove(_startAnchor.Id); + _startAnchor.Dispose(); + _startAnchor = null; + } + + if (_stopAnchor != null) + { + Map.AdditionalAnchorsSource.Remove(_stopAnchor.Id); + _stopAnchor.Dispose(); + _stopAnchor = null; + } + + if (_rulerPolygon != null) + { + Map.AdditionalAnchorsSource.Remove(_rulerPolygon.Id); + _rulerPolygon.Dispose(); + _rulerPolygon = null; + } + + IsRulerEnabled = false; + } + + [Reactive] public bool IsRulerEnabled { get; set; } +} + +public class RulerStartAnchor : MapAnchorBase +{ + public RulerStartAnchor(Uri id, GeoPoint startPoint) : base(id) + { + Size = 48; + BaseSize = 48; + OffsetX = OffsetXEnum.Center; + OffsetY = OffsetYEnum.Bottom; + StrokeThickness = 1; + BaseStrokeThickness = 1; + IconBrush = Brushes.Indigo; + Stroke = Brushes.White; + IsVisible = true; + Icon = MaterialIconKind.MapMarker; + IsEditable = true; + Location = startPoint; + } +} + +public class RulerStopAnchor : MapAnchorBase +{ + public RulerStopAnchor(Uri id, RulerStartAnchor start, ILocalizationService loc, GeoPoint stopPoint) : base(id) + { + Size = 48; + BaseSize = 48; + OffsetX = OffsetXEnum.Center; + OffsetY = OffsetYEnum.Bottom; + StrokeThickness = 1; + BaseStrokeThickness = 1; + IconBrush = Brushes.Indigo; + Stroke = Brushes.White; + IsVisible = true; + Icon = MaterialIconKind.MapMarker; + IsEditable = true; + Location = stopPoint; + this.WhenValueChanged(x => x.Location, false) + .Merge(start.WhenValueChanged(x => x.Location, false)) + .Throttle(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler) + .Subscribe(x => + { + Title = loc.Distance.FromSiToStringWithUnits(GeoMath.Distance(start.Location, Location)); + }).DisposeItWith(Disposable); + Title = loc.Distance.FromSiToStringWithUnits(GeoMath.Distance(start.Location, Location)); + } +} + +public class RulerPolygon : MapAnchorBase +{ + private readonly ReadOnlyObservableCollection _path; + + public RulerPolygon(Uri id, RulerStartAnchor start, RulerStopAnchor stop) : base(id) + { + ZOrder = -1000; + OffsetX = 0; + OffsetY = 0; + PathOpacity = 0.6; + StrokeThickness = 5; + Stroke = Brushes.Purple; + IsVisible = true; + StrokeDashArray = new AvaloniaList(2, 2); + + var cache = new SourceList().DisposeItWith(Disposable); + cache.Add(new GeoPoint(0, 0, 0)); + cache.Add(new GeoPoint(0, 0, 0)); + + start.WhenValueChanged(x => x.Location).Subscribe(x => cache.ReplaceAt(0, x)).DisposeItWith(Disposable); + stop.WhenValueChanged(x => x.Location).Subscribe(x => cache.ReplaceAt(1, x)).DisposeItWith(Disposable); + + cache.Connect() + .Bind(out _path) + .Subscribe() + .DisposeWith(Disposable); + } + + public override ReadOnlyObservableCollection Path => _path; +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Zoom/MapZoomActionView.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Zoom/MapZoomActionView.axaml new file mode 100644 index 00000000..828a33f4 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Actions/Zoom/MapZoomActionView.axaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0,0,0,0 + 0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/AnchorEditor/AnchorsEditorView.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/AnchorEditor/AnchorsEditorView.axaml.cs new file mode 100644 index 00000000..b03beac0 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/AnchorEditor/AnchorsEditorView.axaml.cs @@ -0,0 +1,35 @@ +using Avalonia.Layout; +using Avalonia.ReactiveUI; +using DynamicData.Binding; + +namespace Asv.Drones.Gui.Api; + +[ExportView(typeof(AnchorsEditorViewModel))] +public partial class AnchorsEditorView : ReactiveUserControl +{ + private IDisposable? _subscribe; + private double? _lastWidth = null; + + public AnchorsEditorView() + { + InitializeComponent(); + this.WhenValueChanged(x => x.ViewModel).Subscribe(OnViewModel); + } + + + private void OnViewModel(AnchorsEditorViewModel? vm) + { + if (vm == null) return; + _subscribe?.Dispose(); + } + + private void Layoutable_OnEffectiveViewportChanged(object? sender, EffectiveViewportChangedEventArgs e) + { + ViewModel.IsCompactMode = PART_Grid.Bounds.Width switch + { + < 500 => true, + > 500 => false, + _ => ViewModel.IsCompactMode + }; + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/AnchorEditor/AnchorsEditorViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/AnchorEditor/AnchorsEditorViewModel.cs new file mode 100644 index 00000000..8f79ea2d --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/AnchorEditor/AnchorsEditorViewModel.cs @@ -0,0 +1,285 @@ +using System.Collections.ObjectModel; +using System.Globalization; +using System.Net.Mime; +using System.Reactive; +using System.Windows; +using Asv.Avalonia.Map; +using Asv.Common; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Input.Platform; +using Avalonia.Threading; +using DynamicData.Binding; +using Material.Icons; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; +using ReactiveUI.Validation.Extensions; + +namespace Asv.Drones.Gui.Api; + +public class AnchorsEditorViewModel : MapWidgetBase +{ + private readonly ILocalizationService _loc; + private bool _internalChange; + private IDisposable? _locationSubscription; + private IMapAnchor? _prevAnchor; + #region ifDEBUG + public AnchorsEditorViewModel() : base(WellKnownUri.UndefinedUri) + { + DesignTime.ThrowIfNotDesignMode(); + if (Design.IsDesignMode) + { + IsVisible = true; + IsEditable = true; + IsCompactMode = true; + Actions = new[] + { + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = "TakeOff" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = "ROI" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = "Land" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = "Reboot" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = "Start Mission" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = "" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = "Action" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = ":Some" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = ":Action" + }, + new MapAnchorActionViewModel() + { + Icon = MaterialIconKind.Accelerometer, + Title = "SuperAction" + }, + }; + } + } + #endregion + + protected AnchorsEditorViewModel(Uri id, ILocalizationService loc) : base(id) + { + _loc = loc; + Title = "Anchor Editor"; + Icon = MaterialIconKind.MapMarker; + Location = WidgetLocation.Bottom; + Disposable.AddAction(() => { _locationSubscription?.Dispose(); }); + Order = 0; + + CopyCommand = ReactiveCommand.Create(CopyGeoPoint).DisposeItWith(Disposable); + PasteCommand = ReactiveCommand.Create(PasteGeoPoint).DisposeItWith(Disposable); + + this.WhenAnyValue(_ => _.Latitude) + .Subscribe(UpdateLatitude) + .DisposeItWith(Disposable); + this.WhenAnyValue(_ => _.Longitude) + .Subscribe(UpdateLongitude) + .DisposeItWith(Disposable); + this.WhenAnyValue(_ => _.Altitude) + .Subscribe(UpdateAltitude) + .DisposeItWith(Disposable); + + this.ValidationRule(x => x.Latitude, + _ => _loc.Latitude.IsValid(_), + _ => _loc.Latitude.GetErrorMessage(_) ?? string.Empty) + .DisposeItWith(Disposable); + + this.ValidationRule(x => x.Longitude, + _ => _loc.Longitude.IsValid(_), + _ => _loc.Longitude.GetErrorMessage(_) ?? string.Empty) + .DisposeItWith(Disposable); + + this.ValidationRule(x => x.Altitude, + _ => _loc.Altitude.IsValid(_), + _ => _loc.Altitude.GetErrorMessage(_) ?? string.Empty) + .DisposeItWith(Disposable); + } + + protected AnchorsEditorViewModel(string id, ILocalizationService loc) : this(new Uri(id), loc) + { + } + [Reactive] public bool IsTitleCompactMode { get; set; } + [Reactive] public bool IsCompactMode { get; set; } + + [Reactive] public bool IsVisible { get; set; } + + [Reactive] public string Latitude { get; set; } + + [Reactive] public string LatitudeUnits { get; set; } + + [Reactive] public string Longitude { get; set; } + + [Reactive] public string LongitudeUnits { get; set; } + + [Reactive] public string Altitude { get; set; } + + [Reactive] public string AltitudeUnits { get; set; } + + [Reactive] public bool IsEditable { get; set; } + + [Reactive] public ReactiveCommand CopyCommand { get; set; } + [Reactive] public ReactiveCommand PasteCommand { get; set; } + + [Reactive] private GeoPoint CopiedPoint { get; set; } + [Reactive] public IEnumerable Actions { get; set; } + + + + private void CopyGeoPoint() + { + CopiedPoint = new GeoPoint(_loc.Latitude.ConvertToSi(Latitude), _loc.Longitude.ConvertToSi(Longitude), + _loc.Altitude.ConvertToSi(Altitude)); + } + + private void PasteGeoPoint() + { + Latitude = CopiedPoint.Latitude.ToString(CultureInfo.InvariantCulture); + Longitude = CopiedPoint.Longitude.ToString(CultureInfo.InvariantCulture); + Altitude = CopiedPoint.Altitude.ToString(CultureInfo.InvariantCulture); + } + + + private void UpdateLatitude(string latitude) + { + if (_internalChange) return; + if (!string.IsNullOrWhiteSpace(latitude) && _loc.Latitude.IsValid(latitude)) + { + var prevLocation = _prevAnchor.Location; + var newLocation = _prevAnchor.Location = new GeoPoint( + _loc.Latitude.CurrentUnit.Value.ConvertToSi(latitude), + prevLocation.Longitude, prevLocation.Altitude); + // if new location is equal to previous location then we need to update longitude string + if (prevLocation.Equals(newLocation)) + { + _internalChange = true; + Latitude = _loc.Longitude.FromSiToString(prevLocation.Latitude); + _internalChange = false; + } + else + { + _prevAnchor.Location = newLocation; + } + } + } + + private void UpdateLongitude(string longitude) + { + if (_internalChange) return; + if (!string.IsNullOrWhiteSpace(longitude) && _loc.Longitude.IsValid(longitude)) + { + var prevLocation = _prevAnchor.Location; + var newLocation = new GeoPoint(prevLocation.Latitude, + _loc.Longitude.CurrentUnit.Value.ConvertToSi(longitude), + prevLocation.Altitude); + // if new location is equal to previous location then we need to update longitude string + if (prevLocation.Equals(newLocation)) + { + _internalChange = true; + Longitude = _loc.Longitude.FromSiToString(prevLocation.Longitude); + _internalChange = false; + } + else + { + _prevAnchor.Location = newLocation; + } + } + } + + private void UpdateAltitude(string altitude) + { + if (_internalChange) return; + if (!string.IsNullOrWhiteSpace(altitude) && _loc.Altitude.IsValid(altitude)) + { + var prevLocation = _prevAnchor.Location; + var newLocation = _prevAnchor.Location = new GeoPoint(prevLocation.Latitude, + prevLocation.Longitude, + _loc.Altitude.CurrentUnit.Value.ConvertToSi(altitude)); + // if new location is equal to previous location then we need to update string + if (prevLocation.Equals(newLocation)) + { + _internalChange = true; + Altitude = _loc.Altitude.FromSiToString(prevLocation.Altitude); + _internalChange = false; + } + else + { + _prevAnchor.Location = newLocation; + } + } + } + + protected override void InternalAfterMapInit(IMap context) + { + LatitudeUnits = _loc.Latitude.CurrentUnit.Value.Unit; + LongitudeUnits = _loc.Longitude.CurrentUnit.Value.Unit; + AltitudeUnits = _loc.Altitude.CurrentUnit.Value.Unit; + context.WhenValueChanged(_ => _.SelectedItem) + .Subscribe(_ => + { + if (_prevAnchor != null && _prevAnchor.IsInEditMode) + { + UpdateLatitude(Latitude); + UpdateLongitude(Longitude); + UpdateAltitude(Altitude); + } + + _locationSubscription?.Dispose(); + _locationSubscription = null; + + if (_ != null) + { + Actions = _.Actions; + _prevAnchor = _; + IsVisible = true; + IsEditable = _.IsEditable; + _locationSubscription = _.WhenAnyValue(_ => _.Location) + .Subscribe(_ => + { + _internalChange = true; + Latitude = _loc.Latitude.FromSiToString(_.Latitude); + Longitude = _loc.Longitude.FromSiToString(_.Longitude); + Altitude = _loc.Altitude.FromSiToString(_.Altitude); + _internalChange = false; + }); + } + else + { + IsVisible = false; + } + }) + .DisposeItWith(Disposable); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/IMapWidget.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/IMapWidget.cs new file mode 100644 index 00000000..136fa130 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/IMapWidget.cs @@ -0,0 +1,47 @@ +using Material.Icons; + +namespace Asv.Drones.Gui.Api; + +/// +/// Enumeration to specify the location of a widget on the map. +/// +public enum WidgetLocation +{ + Left, + Right, + Bottom +} + +/// +/// An interface that describes the structure and behavior of a Map Widget. +/// Map Widget represents an interface element on the map. +/// +public interface IMapWidget : IViewModel +{ + /// + /// Gets the location of the widget on the map. + /// + WidgetLocation Location { get; } + + /// + /// Gets the title of the widget. + /// + string Title { get; } + + /// + /// Gets the order of the widget. + /// + int Order { get; } + + /// + /// Gets the icon associated with the widget. + /// + MaterialIconKind Icon { get; } + + /// + /// Initializes the Map Widget with a reference to a Map it belongs to. + /// + /// The map the widget is associated with. + /// The initialized MapWidget. + IMapWidget Init(IMap context); +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/MapWidgetBase.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/MapWidgetBase.cs new file mode 100644 index 00000000..67ebef05 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Map/Widgets/MapWidgetBase.cs @@ -0,0 +1,32 @@ +using Material.Icons; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api +{ + public abstract class MapWidgetBase : ViewModelBaseWithValidation, IMapWidget + { + protected MapWidgetBase(Uri id) : base(id) + { + } + + protected MapWidgetBase(string id) : base(id) + { + } + + [Reactive] public WidgetLocation Location { get; set; } + [Reactive] public string Title { get; set; } + public int Order { get; set; } + [Reactive] public MaterialIconKind Icon { get; set; } + + public IMapWidget Init(IMap context) + { + Map = context; + InternalAfterMapInit(context); + return this; + } + + protected abstract void InternalAfterMapInit(IMap context); + + public IMap Map { get; private set; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/OptionsDisplayItem/OptionsDisplayItem.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/OptionsDisplayItem/OptionsDisplayItem.cs similarity index 98% rename from src/Asv.Drones.Gui.Core/Controls/OptionsDisplayItem/OptionsDisplayItem.cs rename to src/Asv.Drones.Gui.Api/Tools/Controls/OptionsDisplayItem/OptionsDisplayItem.cs index 51c70c98..e16b746b 100644 --- a/src/Asv.Drones.Gui.Core/Controls/OptionsDisplayItem/OptionsDisplayItem.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/OptionsDisplayItem/OptionsDisplayItem.cs @@ -6,7 +6,7 @@ using Avalonia.Interactivity; using FAIconElement = FluentAvalonia.UI.Controls.FAIconElement; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; public class OptionsDisplayItem : TemplatedControl { @@ -93,7 +93,8 @@ public ICommand NavigationCommand } public static readonly RoutedEvent NavigationRequestedEvent = - RoutedEvent.Register(nameof(NavigationRequested), RoutingStrategies.Bubble); + RoutedEvent.Register(nameof(NavigationRequested), + RoutingStrategies.Bubble); public event EventHandler NavigationRequested { @@ -177,4 +178,4 @@ private void OnLayoutRootPointerCaptureLost(object sender, PointerCaptureLostEve private bool _isPressed; private bool _isExpanded; private Border _layoutRoot; -} +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/OptionsDisplayItem/OptionsDisplayItemStyles.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/OptionsDisplayItem/OptionsDisplayItemStyles.axaml new file mode 100644 index 00000000..ca219142 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/OptionsDisplayItem/OptionsDisplayItemStyles.axaml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamItemView.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamItemView.axaml new file mode 100644 index 00000000..1a6bd596 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamItemView.axaml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamPageView.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamPageView.axaml.cs new file mode 100644 index 00000000..67a97cf4 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamPageView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Asv.Drones.Gui.Api; + +[ExportView(typeof(ParamPageViewModel))] +public partial class ParamPageView : ReactiveUserControl +{ + public ParamPageView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamPageViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamPageViewModel.cs new file mode 100644 index 00000000..752a77ee --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/Params/ParamPageViewModel.cs @@ -0,0 +1,291 @@ +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Composition; +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Web; +using Asv.Cfg; +using Asv.Common; +using Asv.Mavlink; +using DynamicData; +using DynamicData.Binding; +using FluentAvalonia.UI.Controls; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api; + +public class ParamsConfig +{ + public List Params { get; set; } = new(); +} + +public class ParamPageViewModel : ShellPage +{ + private readonly IMavlinkDevicesService _svc; + private readonly ILogService _log; + private readonly IConfiguration _cfg; + private CancellationTokenSource _cancellationTokenSource; + private readonly ReadOnlyObservableCollection _viewedParams; + private ObservableAsPropertyHelper _isRefreshing; + private readonly SourceList _viewedParamsList; + private ParamItemViewModel _selectedItem; + private readonly Subject _canClearSearchText = new(); + private readonly ParamsConfig _config; + private IParamsClientEx _paramsIfc; + + #region Uri + + public static Uri GenerateUri(string baseUri, ushort deviceFullId, DeviceClass @class) => + new($"{baseUri}?id={deviceFullId}&class={@class:G}"); + + #endregion + + public ParamPageViewModel() : base(WellKnownUri.UndefinedUri) + { + DesignTime.ThrowIfNotDesignMode(); + DeviceName = "Params"; + } + + protected ParamPageViewModel(string id, IMavlinkDevicesService svc, ILogService log, IConfiguration cfg) : base(id) + { + _svc = svc ?? throw new ArgumentNullException(nameof(svc)); + _log = log ?? throw new ArgumentNullException(nameof(log)); + _cfg = cfg ?? throw new ArgumentNullException(nameof(cfg)); + _config = _cfg.Get(); + FilterPipe.DisposeItWith(Disposable); + this.WhenAnyValue(_ => _.SearchText, _ => _.ShowStaredOnly) + .Throttle(TimeSpan.FromMilliseconds(100), RxApp.MainThreadScheduler) + .Subscribe(_ => FilterPipe.OnNext(item => item.Filter(SearchText, ShowStaredOnly))) + .DisposeItWith(Disposable); + _viewedParamsList = new SourceList().DisposeItWith(Disposable); + _cancellationTokenSource = new CancellationTokenSource().DisposeItWith(Disposable); + _viewedParamsList.Connect() + .Bind(out _viewedParams) + .Subscribe() + .DisposeItWith(Disposable); + this.WhenValueChanged(_ => _.SearchText) + .Subscribe(_ => { _canClearSearchText.OnNext(!string.IsNullOrWhiteSpace(_)); }) + .DisposeItWith(Disposable); + + Clear = ReactiveCommand.Create(() => { SearchText = string.Empty; }, _canClearSearchText) + .DisposeItWith(Disposable); + + Disposable.AddAction(() => + { + _config.Params = _config.Params.Where(_ => _.IsStarred).ToList(); + _cfg.Set(_config); + }); + } + + public override void SetArgs(NameValueCollection args) + { + base.SetArgs(args); + if (ushort.TryParse(args["id"], out var id) == false) return; + if (Enum.TryParse(args["class"], true, out var deviceClass) == false) return; + var ifc = GetParamsClient(_svc, id, deviceClass); + if (ifc == null) return; + + Icon = MavlinkHelper.GetIcon(deviceClass); + + switch (deviceClass) + { + case DeviceClass.Plane: + var plane = _svc.GetVehicleByFullId(id); + if (plane == null) break; + DeviceName = plane.Name.Value; + break; + case DeviceClass.Copter: + var copter = _svc.GetVehicleByFullId(id); + if (copter == null) break; + DeviceName = copter.Name.Value; + break; + case DeviceClass.GbsRtk: + var gbs = _svc.GetGbsByFullId(id); + if (gbs == null) break; + DeviceName = gbs.Name.Value; + break; + case DeviceClass.SdrPayload: + var sdr = _svc.GetPayloadsByFullId(id); + if (sdr == null) break; + DeviceName = sdr.Name.Value; + break; + case DeviceClass.Adsb: + var adsb = _svc.GetAdsbVehicleByFullId(id); + if (adsb == null) break; + DeviceName = adsb.Name.Value; + break; + } + + InternalInit(ifc); + } + + public virtual IParamsClientEx? GetParamsClient(IMavlinkDevicesService svc, ushort fullId, DeviceClass @class) + { + return null; + } + + protected void InternalInit(IParamsClientEx paramsIfc) + { + @paramsIfc.RemoteCount.Where(_ => _.HasValue).Subscribe(_ => Total = _.Value).DisposeItWith(Disposable); + var inputPipe = @paramsIfc.Items + .Transform(_ => new ParamItemViewModel(Id, _, _log)) + .DisposeMany() + .RefCount(); + inputPipe + .Bind(out var allItems) + .Subscribe(_ => + { + foreach (var item in _config.Params) + { + var existItem = _.FirstOrDefault(_ => _.Current.Name == item.Name); + if (existItem == null) continue; + existItem.Current?.SetConfig(item); + } + }) + .DisposeItWith(Disposable); + inputPipe + .Filter(FilterPipe) + .SortBy(_ => _.Name) + .AutoRefresh(v => v.IsSynced) + .Bind(out var leftItems) + .Subscribe() + .DisposeItWith(Disposable); + inputPipe + .AutoRefresh(_ => _.IsStarred) + .Filter(_ => _.IsStarred) + .Subscribe(_ => + { + foreach (var item in _) + { + var existItem = _config.Params.FirstOrDefault(__ => __.Name == item.Current.Name); + + if (existItem != null) _config.Params.Remove(existItem); + + _config.Params.Add(new ParamItemViewModelConfig + { + IsStarred = item.Current.IsStarred, + Name = item.Current.Name + }); + } + }) + .DisposeItWith(Disposable); + + FilterPipe.OnNext(_ => true); + Params = leftItems; + + UpdateParams = ReactiveCommand.CreateFromTask(async cancel => + { + _cancellationTokenSource = new CancellationTokenSource().DisposeItWith(Disposable); + var viewed = _viewedParamsList.Items.Select(_ => _.GetConfig()).ToArray(); + _viewedParamsList.Clear(); + try + { + await paramsIfc.ReadAll(new Progress(_ => Progress = _), _cancellationTokenSource.Token); + } + catch (TaskCanceledException) + { + _log.Info("User", "Canceled updating params"); + } + finally + { + foreach (var item in viewed) + { + var existItem = allItems.FirstOrDefault(_ => _.Name == item.Name); + if (existItem == null) continue; + existItem.SetConfig(item); + _viewedParamsList.Add(existItem); + } + } + }).DisposeItWith(Disposable); + UpdateParams.IsExecuting.ToProperty(this, _ => _.IsRefreshing, out _isRefreshing).DisposeItWith(Disposable); + UpdateParams.ThrownExceptions.Subscribe(OnRefreshError).DisposeItWith(Disposable); + StopUpdateParams = ReactiveCommand.Create(() => { _cancellationTokenSource.Cancel(); }); + RemoveAllPins = ReactiveCommand.Create(() => + { + _viewedParamsList.Edit(_ => + { + foreach (var item in _) + { + item.IsPinned = false; + } + }); + }).DisposeItWith(Disposable); + } + + public override async Task TryClose() + { + var notSyncedParams = _viewedParamsList.Items.Where(_ => !_.IsSynced).ToArray(); + + if (notSyncedParams.Any()) + { + var dialog = new ContentDialog() + { + Title = RS.ParamPageViewModel_DataLossDialog_Title, + Content = RS.ParamPageViewModel_DataLossDialog_Content, + IsSecondaryButtonEnabled = true, + PrimaryButtonText = RS.ParamPageViewModel_DataLossDialog_PrimaryButtonText, + SecondaryButtonText = RS.ParamPageViewModel_DataLossDialog_SecondaryButtonText, + CloseButtonText = RS.ParamPageViewModel_DataLossDialog_CloseButtonText + }; + + var result = await dialog.ShowAsync(); + + if (result == ContentDialogResult.Primary) + { + foreach (var param in notSyncedParams) + { + param.WriteParamData(); + param.IsSynced = true; + } + + return true; + } + + if (result == ContentDialogResult.Secondary) return true; + + if (result == ContentDialogResult.None) return false; + } + + return true; + } + + private void OnRefreshError(Exception ex) + { + _log.Error("Params view", "Error to read all params items", ex); + } + + public bool IsRefreshing => _isRefreshing.Value; + [Reactive] public bool ShowStaredOnly { get; set; } + [Reactive] public double Progress { get; set; } + [Reactive] public ReactiveCommand Clear { get; set; } + [Reactive] public ReactiveCommand UpdateParams { get; set; } + [Reactive] public ReactiveCommand StopUpdateParams { get; set; } + [Reactive] public ReactiveCommand RemoveAllPins { get; set; } + public Subject> FilterPipe { get; } = new(); + [Reactive] public ReadOnlyObservableCollection Params { get; set; } + public ReadOnlyObservableCollection ViewedParams => _viewedParams; + [Reactive] public string DeviceName { get; set; } + [Reactive] public string SearchText { get; set; } + [Reactive] public int Total { get; set; } + [Reactive] public int Loaded { get; set; } + + public ParamItemViewModel SelectedItem + { + get => _selectedItem; + set + { + var itemsToDelete = _viewedParamsList.Items.Where(_ => _.IsPinned == false).ToArray(); + _viewedParamsList.RemoveMany(itemsToDelete); + this.RaiseAndSetIfChanged(ref _selectedItem, value); + if (value != null) + { + if (_viewedParamsList.Items.Contains(value) == false) + { + _viewedParamsList.Add(value); + } + } + } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleView.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleView.axaml new file mode 100644 index 00000000..293646c4 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleView.axaml @@ -0,0 +1,8 @@ + + Welcome to Avalonia! + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleView.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleView.axaml.cs new file mode 100644 index 00000000..46c378e0 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleView.axaml.cs @@ -0,0 +1,14 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Asv.Drones.Gui.Api; + +[ExportView(typeof(TreePageExampleViewModel))] +public partial class TreePageExampleView : UserControl +{ + public TreePageExampleView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleViewModel.cs new file mode 100644 index 00000000..5a251665 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExampleViewModel.cs @@ -0,0 +1,69 @@ +using System.Collections.ObjectModel; +using Avalonia.Input; +using Material.Icons; +using ReactiveUI; + +namespace Asv.Drones.Gui.Api; + +public class TreePageExampleViewModel : TreePageViewModel +{ + private static int _instanceCounter = 0; + + public TreePageExampleViewModel() : base(WellKnownUri.UndefinedUri) + { + } + + public TreePageExampleViewModel(ITreePageContext treePageContext, string id) : base(id) + { + var collection = new ObservableCollection + { + new MenuItem("asv:1") + { + Header = "Action 1", + Icon = MaterialIconKind.AccessPoint, + Command = ReactiveCommand.Create(() => { }), + Order = 1 + }, + + new MenuItem("asv:2") + { + Header = "Action 2", + Icon = MaterialIconKind.AccessPoint, + Command = ReactiveCommand.Create(() => { }), + Order = 2, + Items = new ReadOnlyObservableCollection(new ObservableCollection + { + new MenuItem("asv:2.1") + { + Header = "Action 2.1", + Icon = MaterialIconKind.AccessPoint, + Command = ReactiveCommand.Create(() => { }), + Order = 2, + HotKey = new KeyGesture(Key.A, KeyModifiers.Alt) + }, + new MenuItem("asv:2.2") + { + Header = "Action 2.2", + Icon = MaterialIconKind.Create, + Command = ReactiveCommand.Create(() => { }), + Order = 2, + HotKey = new KeyGesture(Key.A, KeyModifiers.Alt), + }, + }) + }, + }; + _instanceCounter++; + for (int i = 0; i < Math.Min(_instanceCounter, 3); i++) + { + collection.Add(new MenuItem($"asv:{3 + i}") + { + Header = $"Action {3 + i}", + Icon = (MaterialIconKind)i, + Command = ReactiveCommand.Create(() => { }), + Order = i + }); + } + + Actions = new ReadOnlyObservableCollection(collection); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExplorerDesignTime.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExplorerDesignTime.cs new file mode 100644 index 00000000..b27bccfc --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/DesignTime/TreePageExplorerDesignTime.cs @@ -0,0 +1,47 @@ +using DynamicData; +using Material.Icons; + +namespace Asv.Drones.Gui.Api; + +public class TreePageExplorerDesignTime : ViewModelProviderBase, ITreePageContext +{ + public static TreePageExplorerDesignTime Instance { get; } = new(); + public static TreePageExplorerDesignTime[] Instances { get; } = [Instance]; + + public BreadCrumbItem[] BreadCrumbs { get; } + + private TreePageExplorerDesignTime() + { + const int rootCnt = 10; + const int subRootCnt = 10; + var maxIconIndex = Enum.GetValues().Length; + var icons = Enum.GetValues(); + for (var i = 0; i < rootCnt; i++) + { + var root = new TreePageCallbackMenuItem($"asv:{i}", + $"Settings {i}", + icons[Random.Shared.Next(0, maxIconIndex)], + $"Settings {i} description", + rootCnt - i) + { + Status = i % 3 == 0 ? null : i.ToString() + }; + Source.AddOrUpdate(root); + for (var j = 0; j < subRootCnt; j++) + { + Source.AddOrUpdate(new TreePageCallbackMenuItem($"asv:{i}{j}", + $"Settings {i}", + icons[Random.Shared.Next(0, maxIconIndex)], + $"Settings {i} {j} description", + rootCnt - i, + root.Id, x => new TreePageExampleViewModel(x, $"asv:{i}{j}")) + { + Status = i % 3 == 0 ? null : i.ToString() + }); + } + } + + BreadCrumbs = Source.Items.Take(2).Select((x, i) => new BreadCrumbItem(i == 0, x)).ToArray(); + } + +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePage.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePage.cs new file mode 100644 index 00000000..8d0fc63d --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePage.cs @@ -0,0 +1,45 @@ +using System.Collections.ObjectModel; + +namespace Asv.Drones.Gui.Api; + +public interface ITreePage : IViewModel +{ + ReadOnlyObservableCollection? Actions { get; } + Task TryClose(); + +} + +public class TreePageViewModel : ViewModelBase, ITreePage +{ + protected TreePageViewModel(Uri id) : base(id) + { + } + + protected TreePageViewModel(string id) : base(id) + { + } + + public ReadOnlyObservableCollection? Actions { get; set; } + public virtual Task TryClose() + { + return Task.FromResult(true); + } +} + +public class TreePageWithValidationViewModel : ViewModelBaseWithValidation, ITreePage +{ + protected TreePageWithValidationViewModel(Uri id) : base(id) + { + } + + protected TreePageWithValidationViewModel(string id) : base(id) + { + } + + public ReadOnlyObservableCollection? Actions { get; set; } + + public virtual Task TryClose() + { + return Task.FromResult(true); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageContext.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageContext.cs new file mode 100644 index 00000000..892d9bbd --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageContext.cs @@ -0,0 +1,6 @@ +namespace Asv.Drones.Gui.Api; + +public interface ITreePageContext +{ + +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageExplorer.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageExplorer.cs new file mode 100644 index 00000000..a5dee62e --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageExplorer.cs @@ -0,0 +1,9 @@ +namespace Asv.Drones.Gui.Api; + +public interface ITreePageExplorer +{ + Task GoTo(Uri pageId); + ITreePageMenuItem? SelectedMenu { get; } + ITreePage? CurrentPage { get; } + bool IsCompactMode { get; set; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageMenuItem.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageMenuItem.cs new file mode 100644 index 00000000..c3316f98 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/ITreePageMenuItem.cs @@ -0,0 +1,68 @@ +using Material.Icons; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api; + +public interface ITreePageMenuItem : IViewModel +{ + Uri ParentId { get; } + string? Name { get; } + string? Description { get; } + MaterialIconKind Icon { get; } + int Order { get; } + public string? Status { get; } + ITreePage? CreatePage(ITreePageContext context); +} + +public abstract class TreePageMenuItem : ViewModelBase, ITreePageMenuItem +{ + public abstract Uri ParentId { get; } + public abstract string? Name { get; } + public abstract string? Description { get; } + public abstract MaterialIconKind Icon { get; } + public abstract int Order { get; } + [Reactive] public string? Status { get; set; } + + public abstract ITreePage? CreatePage(ITreePageContext context); + + protected TreePageMenuItem(Uri id) : base(id) + { + } + + protected TreePageMenuItem(string id) : base(id) + { + } +} + +public class TreePageCallbackMenuItem : TreePageMenuItem +{ + private readonly Func? _factory; + + public TreePageCallbackMenuItem(Uri id, string name, MaterialIconKind icon, string? desc = null, int order = 0, + Uri? parentId = null, Func? factory = null) : base(id) + { + ParentId = parentId ?? WellKnownUri.UndefinedUri; + Name = name; + Description = desc; + Icon = icon; + Order = order; + _factory = factory; + } + + public TreePageCallbackMenuItem(string id, string name, MaterialIconKind icon, string? desc = null, int order = 0, + Uri? parentId = null, Func? factory = null) : this(new Uri(id), name, icon, desc, + order, parentId, factory) + { + } + + public override Uri ParentId { get; } + public override string? Name { get; } + public override string? Description { get; } + public override MaterialIconKind Icon { get; } + public override int Order { get; } + + public override ITreePage? CreatePage(ITreePageContext context) + { + return _factory?.Invoke(context); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupView.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupView.axaml new file mode 100644 index 00000000..3821f95f --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupView.axaml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupView.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupView.axaml.cs new file mode 100644 index 00000000..0c5a0974 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupView.axaml.cs @@ -0,0 +1,12 @@ +using Avalonia.Controls; + +namespace Asv.Drones.Gui.Api; + +[ExportView(typeof(TreeGroupViewModel))] +public partial class TreeGroupView : UserControl +{ + public TreeGroupView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupViewModel.cs new file mode 100644 index 00000000..f6880e53 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreeGroupViewModel.cs @@ -0,0 +1,53 @@ +using System.Collections.ObjectModel; +using System.Reactive; +using Asv.Common; +using DynamicData; +using ReactiveUI; + +namespace Asv.Drones.Gui.Api; + +public class TreeGroupViewModel : ViewModelBase, ITreePage +{ + private readonly Func> _navigate; + + public TreeGroupViewModel() : base(TreePageExplorerDesignTime.Instance.BreadCrumbs.First().Item.Id) + { + var item = TreePageExplorerDesignTime.Instance.BreadCrumbs.First().Item; + var node = new Node(item, WellKnownUri.UndefinedUri); + + Items = new ReadOnlyObservableCollection( + new ObservableCollection( + new[] + { + new TreePartMenuItemContainer(new Node(item, WellKnownUri.UndefinedUri)), + new TreePartMenuItemContainer(new Node(item, WellKnownUri.UndefinedUri)) + })); + + + Item = new TreePartMenuItemContainer(node); + } + + public TreeGroupViewModel(TreePartMenuItemContainer menu, Func> navigate) : + base(menu.Base.Id) + { + _navigate = navigate; + Item = menu; + Items = menu.Items; + NavigateCommand = ReactiveCommand.Create(Navigate).DisposeItWith(Disposable); + } + + private Unit Navigate(TreePartMenuItemContainer arg) + { + _navigate(arg); + return Unit.Default; + } + + public TreePartMenuItemContainer Item { get; } + public ReadOnlyObservableCollection Items { get; } + public ReactiveCommand NavigateCommand { get; } + public ReadOnlyObservableCollection? Actions { get; } = null; + public virtual Task TryClose() + { + return Task.FromResult(true); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerView.axaml b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerView.axaml new file mode 100644 index 00000000..433e742b --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerView.axaml @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerView.axaml.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerView.axaml.cs new file mode 100644 index 00000000..e6346111 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerView.axaml.cs @@ -0,0 +1,59 @@ +using System.Diagnostics; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Layout; +using Avalonia.ReactiveUI; +using DynamicData.Binding; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api; + +public partial class TreePageExplorerView : ReactiveUserControl +{ + private IDisposable? _subscribe; + private double? _lastWidth = null; + + public TreePageExplorerView() + { + InitializeComponent(); + this.WhenValueChanged(x => x.ViewModel).Subscribe(OnViewModel); + } + + private void OnViewModel(TreePageExplorerViewModel? vm) + { + if (vm == null) return; + _subscribe?.Dispose(); + _subscribe = vm.WhenValueChanged(x => x.IsCompactMode, false) + .Subscribe(OnIsCompactModeChanged); + } + + private void OnIsCompactModeChanged(bool compactMode) + { + var column = PART_Grid.ColumnDefinitions.FirstOrDefault(); + if (compactMode && column != null) + { + column.Width = new GridLength(0, GridUnitType.Auto); + } + } + + private void Layoutable_OnEffectiveViewportChanged(object? sender, EffectiveViewportChangedEventArgs e) + { + if (_lastWidth == null) + { + if (PART_TitleGrid.ColumnDefinitions[2].ActualWidth < 8) + { + if (ViewModel != null) ViewModel.IsTitleCompactMode = true; + // replace large control + _lastWidth = PART_TitleGrid.Bounds.Width; + } + } + else + { + if (PART_TitleGrid.Bounds.Width > _lastWidth) + { + if (ViewModel != null) ViewModel.IsTitleCompactMode = false; + _lastWidth = null; + } + } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerViewModel.cs new file mode 100644 index 00000000..4d0ffa74 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/TreePage/TreePageExplorerViewModel.cs @@ -0,0 +1,269 @@ +using System.Collections.ObjectModel; +using System.Composition; +using System.Reactive; +using System.Reactive.Linq; +using System.Reflection; +using System.Windows.Input; +using Asv.Common; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Threading; +using DynamicData; +using DynamicData.Binding; +using FluentAvalonia.UI.Controls; +using Material.Icons; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; + +namespace Asv.Drones.Gui.Api; + +public class TreePageExplorerViewModel : DisposableReactiveObject,ITreePageExplorer +{ + private readonly ITreePageContext _context; + private readonly ILogService _log; + private readonly ReadOnlyObservableCollection _tree; + private readonly CircularBuffer2 _backwardHistory = new(10); + private readonly CircularBuffer2 _forwardHistory = new(10); + private bool _addToHistory = true; + private TreePartMenuItemContainer? _lastNavigationItem; + private int _isNavigationInProgress; + + public TreePageExplorerViewModel() : this(TreePageExplorerDesignTime.Instances, TreePageExplorerDesignTime.Instance, + NullLogService.Instance) + { + DesignTime.ThrowIfNotDesignMode(); + Title = "Tree view"; + GoBack = ReactiveCommand.Create(() => { }); + GoForward = ReactiveCommand.Create(() => { }); + BreadCrumb.AddRange(TreePageExplorerDesignTime.Instance.BreadCrumbs); + } + + + public TreePageExplorerViewModel(IEnumerable> items, ITreePageContext context, + ILogService log) + { + _context = context; + _log = log; + items.Select(x => x.Items) + .MergeChangeSets() + .TransformToTree(x => x.ParentId) + .Transform(x => new TreePartMenuItemContainer(x)) + .SortBy(x => x.Base.Order) + .Bind(out _tree) + .DisposeMany() + .Subscribe() + .DisposeItWith(Disposable); + + + this.WhenValueChanged(x => x.SelectedMenuContainer, notifyOnInitialValue:false) + .Where(x=>x != null) + .Do(AddToHistory) + .Do(x=>SelectedMenu = x?.Base) + .Subscribe(x=>Navigate(x).Wait()) + .DisposeItWith(Disposable); + + Disposable.AddAction(() => + { + if (CurrentPage != null && CurrentPage.GetType().GetCustomAttribute() == null) + { + CurrentPage.Dispose(); + } + }); + + GoForward = ReactiveCommand.Create(GoForwardImpl, this.WhenAnyValue(x => x.CanGoForward)) + .DisposeItWith(Disposable); + GoBack = ReactiveCommand.Create(GoBackImpl, this.WhenAnyValue(x => x.CanGoBack)).DisposeItWith(Disposable); + BreadCrumb.CollectionChanged += (sender, args) => + { + + }; + } + + [Reactive] public bool IsCompactMode { get; set; } + [Reactive] public bool IsTitleCompactMode { get; set; } + + public Task GoTo(Uri pageId) + { + ArgumentNullException.ThrowIfNull(pageId); + if (pageId.Scheme.Equals(WellKnownUri.UriScheme) == false) + { + _log.Error(Title, $"Unknown uri scheme. Want {WellKnownUri.UriScheme}. Got:{pageId.Scheme}"); + return Task.FromResult(false); + } + + return Navigate(Find(pageId)); + } + + [Reactive] + public ITreePageMenuItem? SelectedMenu { get; set; } + + private TreePartMenuItemContainer? Find(Uri pageId, TreePartMenuItemContainer? root = null) + { + if (root != null) + { + if (root.Id == pageId) return root; + } + var items = root?.Items ?? _tree; + foreach (var item in items) + { + var result = Find(pageId, item); + if (result != null) return result; + } + return null; + } + + private async Task Navigate(TreePartMenuItemContainer? menu) + { + if (menu == null) return false; + if (Interlocked.CompareExchange(ref _isNavigationInProgress, 1, 0) != 0) + { + // recursive or fast change navigation will be ignored + return false; + } + + try + { + var currentPage = CurrentPage; + if (currentPage != null) + { + var canClose = await currentPage.TryClose(); + if (canClose == false) return false; // can't close, it's busy now + if (currentPage.GetType().GetCustomAttribute() == null) + { + currentPage.Dispose(); + } + } + + var part = menu.Base.CreatePage(_context) ?? new TreeGroupViewModel(menu, Navigate); + + + CurrentPage = part; + + var stack = new Stack(); + stack.Push(menu.Base); + var current = menu.Node.Parent; + while (current.HasValue) + { + stack.Push(current.Value.Item); + current = current.Value.Parent; + } + + BreadCrumb.Clear(); + while (stack.Count > 0) + { + var item = stack.Pop(); + BreadCrumb.Add(new BreadCrumbItem(BreadCrumb.Count == 0, item)); + } + + menu.IsSelected = true; + return true; + } + catch (Exception e) + { + _log.Error(Title, $"Can't create page {menu.Base.Name}:{e.Message}", e); + return false; + } + finally + { + Interlocked.Exchange(ref _isNavigationInProgress, 0); + } + } + + [Reactive] public string Title { get; set; } + [Reactive] public MaterialIconKind Icon { get; set; } + + [Reactive] public TreePartMenuItemContainer? SelectedMenuContainer { get; set; } + + [Reactive] public ITreePage? CurrentPage { get; set; } + + public ReadOnlyObservableCollection Items => _tree; + + public ObservableCollectionExtended BreadCrumb { get; } = []; + + #region Navigation + + private void AddToHistory(TreePartMenuItemContainer? menu) + { + if (_addToHistory && _lastNavigationItem != null) + { + _backwardHistory.PushFront(_lastNavigationItem); + _forwardHistory.Clear(); + CanGoForward = false; + CanGoBack = true; + } + + _lastNavigationItem = menu; + } + + [Reactive] public bool CanGoForward { get; set; } + public ReactiveCommand GoForward { get; } + + private async void GoForwardImpl() + { + if (_forwardHistory.IsEmpty) return; + var item = _forwardHistory[0]; + _forwardHistory.PopFront(); + CanGoForward = _forwardHistory.IsEmpty == false; + _addToHistory = false; + await Navigate(item); + _addToHistory = true; + } + + [Reactive] public bool CanGoBack { get; set; } + public ReactiveCommand GoBack { get; } + + + private async void GoBackImpl() + { + if (_backwardHistory.IsEmpty) return; + var item = _backwardHistory[0]; + _backwardHistory.PopFront(); + CanGoBack = _backwardHistory.IsEmpty == false; + if (SelectedMenuContainer != null) + { + _forwardHistory.PushFront(SelectedMenuContainer); + } + + CanGoForward = true; + _addToHistory = false; + await Navigate(item); + _addToHistory = true; + } + + #endregion +} + +public class BreadCrumbItem(bool isFirst, ITreePageMenuItem item) +{ + public bool IsFirst { get; } = isFirst; + public ITreePageMenuItem Item { get; } = item; +} + +public class TreePartMenuItemContainer : ViewModelBase +{ + private readonly ReadOnlyObservableCollection _items; + + public TreePartMenuItemContainer(Node node) : base(node.Item.Id) + { + Node = node; + node.Children.Connect() + .Transform(x => new TreePartMenuItemContainer(x)) + .SortBy(x => x.Base.Order) + .Bind(out _items) + .DisposeMany() + .Subscribe() + .DisposeItWith(Disposable); + + Base = node.Item; + } + + public Node Node { get; } + + public ITreePageMenuItem Base { get; set; } + + public ReadOnlyObservableCollection Items => _items; + + [Reactive] public bool IsExpanded { get; set; } = true; + + [Reactive] public bool IsSelected { get; set; } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/AddDoubleConverter.cs b/src/Asv.Drones.Gui.Api/Tools/Converters/AddDoubleConverter.cs similarity index 89% rename from src/Asv.Drones.Gui.Core/Controls/AddDoubleConverter.cs rename to src/Asv.Drones.Gui.Api/Tools/Converters/AddDoubleConverter.cs index 39ce2d67..3daf0d45 100644 --- a/src/Asv.Drones.Gui.Core/Controls/AddDoubleConverter.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Converters/AddDoubleConverter.cs @@ -1,18 +1,19 @@ using System.Globalization; using Avalonia.Data.Converters; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { - public class AddDoubleConverter:IValueConverter + public class AddDoubleConverter : IValueConverter { public static IValueConverter Instance { get; } = new AddDoubleConverter(); - + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (parameter is string p && double.TryParse(p, out var add) && value is double v) { return add + v; } + return value; } diff --git "a/src/Asv.Drones.Gui.Core/Controls/AddPer\321\201entDoubleConverter.cs" "b/src/Asv.Drones.Gui.Api/Tools/Converters/AddPer\321\201entDoubleConverter.cs" similarity index 89% rename from "src/Asv.Drones.Gui.Core/Controls/AddPer\321\201entDoubleConverter.cs" rename to "src/Asv.Drones.Gui.Api/Tools/Converters/AddPer\321\201entDoubleConverter.cs" index 8f074bba..b552bdc1 100644 --- "a/src/Asv.Drones.Gui.Core/Controls/AddPer\321\201entDoubleConverter.cs" +++ "b/src/Asv.Drones.Gui.Api/Tools/Converters/AddPer\321\201entDoubleConverter.cs" @@ -1,18 +1,19 @@ using System.Globalization; using Avalonia.Data.Converters; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { - public class AddPerÑentDoubleConverter:IValueConverter + public class AddPerÑentDoubleConverter : IValueConverter { public static IValueConverter Instance { get; } = new AddPerÑentDoubleConverter(); - + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (parameter is string p && double.TryParse(p, out var add) && value is double v) { return v + v * add / 100; } + return value; } diff --git a/src/Asv.Drones.Gui.Core/Controls/Converters/EnumToBooleanConverter.cs b/src/Asv.Drones.Gui.Api/Tools/Converters/EnumToBooleanConverter.cs similarity index 93% rename from src/Asv.Drones.Gui.Core/Controls/Converters/EnumToBooleanConverter.cs rename to src/Asv.Drones.Gui.Api/Tools/Converters/EnumToBooleanConverter.cs index 46285887..7ab3538e 100644 --- a/src/Asv.Drones.Gui.Core/Controls/Converters/EnumToBooleanConverter.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Converters/EnumToBooleanConverter.cs @@ -2,7 +2,7 @@ using Avalonia.Data; using Avalonia.Data.Converters; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; public class EnumToBooleanConverter : IValueConverter { @@ -15,5 +15,4 @@ public class EnumToBooleanConverter : IValueConverter { return value?.Equals(true) == true ? parameter : BindingOperations.DoNothing; } -} - +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/MaterialIconConverter.cs b/src/Asv.Drones.Gui.Api/Tools/Converters/MaterialIconConverter.cs similarity index 90% rename from src/Asv.Drones.Gui.Core/Controls/MaterialIconConverter.cs rename to src/Asv.Drones.Gui.Api/Tools/Converters/MaterialIconConverter.cs index 845aee24..233c5f0b 100644 --- a/src/Asv.Drones.Gui.Core/Controls/MaterialIconConverter.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Converters/MaterialIconConverter.cs @@ -3,12 +3,12 @@ using Material.Icons; using Material.Icons.Avalonia; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { public class MaterialIconConverter : IValueConverter { public static IValueConverter Instance { get; } = new MaterialIconConverter(); - + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is MaterialIconKind kind) @@ -21,7 +21,7 @@ public class MaterialIconConverter : IValueConverter if (value is string str) { - if (Enum.TryParse(str,true, out kind)) + if (Enum.TryParse(str, true, out kind)) { return new MaterialIcon { @@ -29,11 +29,12 @@ public class MaterialIconConverter : IValueConverter }; } } + return new MaterialIcon(); } public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - { + { return value; } } diff --git a/src/Asv.Drones.Gui.Api/Tools/Converters/MultipleIsNotNullConverter.cs b/src/Asv.Drones.Gui.Api/Tools/Converters/MultipleIsNotNullConverter.cs new file mode 100644 index 00000000..82a311f1 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/Converters/MultipleIsNotNullConverter.cs @@ -0,0 +1,19 @@ +using System.Globalization; +using Avalonia.Data.Converters; + +namespace Asv.Drones.Gui.Api; + +public class MultipleIsNotNullConverter : IMultiValueConverter +{ + public static IMultiValueConverter Instance { get; } = new MultipleIsNotNullConverter(); + + public object Convert(IList values, Type targetType, object? parameter, CultureInfo culture) + { + return values.All(value => value != null); + } + + public object ConvertBack(IList values, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/DesignTime.cs b/src/Asv.Drones.Gui.Api/Tools/DesignTime.cs new file mode 100644 index 00000000..3817ca55 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/DesignTime.cs @@ -0,0 +1,14 @@ +using Avalonia.Controls; + +namespace Asv.Drones.Gui.Api; + +public static class DesignTime +{ + public static void ThrowIfNotDesignMode() + { + if (Design.IsDesignMode == false) + throw new InvalidOperationException("This method is for design mode only"); + } + + public static ILogService Log => NullLogService.Instance; +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/ExportViewAttribute.cs b/src/Asv.Drones.Gui.Api/Tools/ExportViewAttribute.cs new file mode 100644 index 00000000..e082493a --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/ExportViewAttribute.cs @@ -0,0 +1,28 @@ +using System.Composition; +using Avalonia.Controls; + +namespace Asv.Drones.Gui.Api +{ + /// + /// This attribute is used to find a matching View for the ViewModel in ViewLocator + /// + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class ExportViewAttribute : ExportAttribute, IViewMetadata + { + public ExportViewAttribute(Type viewModelType) + : base(null, typeof(Control)) + { + if (viewModelType.IsSubclassOf(typeof(Control))) + throw new ArgumentException("ViewModelType cannot be a View type", nameof(viewModelType)); + this.ViewModelType = viewModelType; + } + + public Type ViewModelType { get; } + } + + public interface IViewMetadata + { + Type ViewModelType { get; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/ProgressMessage.cs b/src/Asv.Drones.Gui.Api/Tools/ProgressMessage.cs new file mode 100644 index 00000000..5a584840 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/ProgressMessage.cs @@ -0,0 +1,7 @@ +namespace Asv.Drones.Gui.Api; + +public class ProgressMessage(double progress, string message) +{ + public string Message => message; + public double Progress => progress; +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/PropertyComparer.cs b/src/Asv.Drones.Gui.Api/Tools/PropertyComparer.cs new file mode 100644 index 00000000..f49eb6fc --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/PropertyComparer.cs @@ -0,0 +1,20 @@ +namespace Asv.Drones.Gui.Api; + +public class PropertyComparer : IComparer + where TField : IComparable +{ + private readonly Func _callback; + + public PropertyComparer(Func callback) + { + _callback = callback; + } + + public int Compare(T? x, T? y) + { + if (ReferenceEquals(x, y)) return 0; + if (ReferenceEquals(null, y)) return 1; + if (ReferenceEquals(null, x)) return -1; + return _callback(x).CompareTo(_callback(y)); + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Tools/DisposableReactiveObject.cs b/src/Asv.Drones.Gui.Api/Tools/ViewModel/DisposableReactiveObject.cs similarity index 95% rename from src/Asv.Drones.Gui.Core/Tools/DisposableReactiveObject.cs rename to src/Asv.Drones.Gui.Api/Tools/ViewModel/DisposableReactiveObject.cs index 08a92045..17cee270 100644 --- a/src/Asv.Drones.Gui.Core/Tools/DisposableReactiveObject.cs +++ b/src/Asv.Drones.Gui.Api/Tools/ViewModel/DisposableReactiveObject.cs @@ -1,9 +1,9 @@ using System.Reactive.Disposables; using ReactiveUI; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { - public class DisposableReactiveObject : ReactiveObject,IDisposable + public class DisposableReactiveObject : ReactiveObject, IDisposable { private const int Disposed = 1; private const int NotDisposed = 0; @@ -37,10 +37,10 @@ protected CancellationToken DisposeCancel { return IsDisposed ? CancellationToken.None : _cancel.Token; } + _cancel = new(); return _cancel.Token; } - } } @@ -73,4 +73,4 @@ public void Dispose() GC.SuppressFinalize(this); } } -} +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Tools/DisposableReactiveObjectWithValidation.cs b/src/Asv.Drones.Gui.Api/Tools/ViewModel/DisposableReactiveObjectWithValidation.cs similarity index 97% rename from src/Asv.Drones.Gui.Core/Tools/DisposableReactiveObjectWithValidation.cs rename to src/Asv.Drones.Gui.Api/Tools/ViewModel/DisposableReactiveObjectWithValidation.cs index 1858cc70..d81e8f0d 100644 --- a/src/Asv.Drones.Gui.Core/Tools/DisposableReactiveObjectWithValidation.cs +++ b/src/Asv.Drones.Gui.Api/Tools/ViewModel/DisposableReactiveObjectWithValidation.cs @@ -1,9 +1,9 @@ using System.Reactive.Disposables; using ReactiveUI.Validation.Helpers; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { - public class DisposableReactiveObjectWithValidation : ReactiveValidationObject,IDisposable + public class DisposableReactiveObjectWithValidation : ReactiveValidationObject, IDisposable { private const int Disposed = 1; private const int NotDisposed = 0; @@ -37,10 +37,10 @@ protected CancellationToken DisposeCancel { return IsDisposed ? CancellationToken.None : _cancel.Token; } + _cancel = new(); return _cancel.Token; } - } } diff --git a/src/Asv.Drones.Gui.Api/Tools/ViewModel/IViewModelProvider.cs b/src/Asv.Drones.Gui.Api/Tools/ViewModel/IViewModelProvider.cs new file mode 100644 index 00000000..d5699d21 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/Tools/ViewModel/IViewModelProvider.cs @@ -0,0 +1,60 @@ +using Asv.Common; +using DynamicData; +using ReactiveUI; + +namespace Asv.Drones.Gui.Api +{ + public interface IViewModelProvider : IDisposable + { + IObservable> Items { get; } + } + + public abstract class ViewModelProviderBase : DisposableOnceWithCancel, IViewModelProvider + where TView : IViewModel + { + private readonly SourceCache _sourceCache; + + protected ViewModelProviderBase() + { + _sourceCache = new SourceCache(model => model.Id) + .DisposeItWith(Disposable); + } + + protected ISourceCache Source => _sourceCache; + public virtual IObservable> Items => Source.Connect().DisposeMany(); + } + + + public interface IViewModel : IReactiveObject, IDisposable + { + Uri Id { get; } + } + + public class ViewModelBase : DisposableReactiveObject, IViewModel + { + protected ViewModelBase(Uri id) + { + Id = id; + } + + protected ViewModelBase(string id) : this(new Uri(id)) + { + } + + public Uri Id { get; } + } + + public class ViewModelBaseWithValidation : DisposableReactiveObjectWithValidation, IViewModel + { + protected ViewModelBaseWithValidation(Uri id) + { + Id = id; + } + + protected ViewModelBaseWithValidation(string id) : this(new Uri(id)) + { + } + + public Uri Id { get; } + } +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/RemoteLogMessageProxy.cs b/src/Asv.Drones.Gui.Api/Tools/ViewModel/RemoteLogMessageProxy.cs similarity index 92% rename from src/Asv.Drones.Gui.Core/Shell/Pages/Logs/RemoteLogMessageProxy.cs rename to src/Asv.Drones.Gui.Api/Tools/ViewModel/RemoteLogMessageProxy.cs index c4df4787..c4310382 100644 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/RemoteLogMessageProxy.cs +++ b/src/Asv.Drones.Gui.Api/Tools/ViewModel/RemoteLogMessageProxy.cs @@ -1,6 +1,6 @@ using Material.Icons; -namespace Asv.Drones.Gui.Core; +namespace Asv.Drones.Gui.Api; public class RemoteLogMessageProxy { @@ -12,17 +12,17 @@ public RemoteLogMessageProxy(LogMessage textMessage) IsInfo = true; Icon = MaterialIconKind.InformationCircle; break; - + case LogMessageType.Warning: IsWarning = true; Icon = MaterialIconKind.Warning; break; - + case LogMessageType.Error: IsError = true; Icon = MaterialIconKind.Warning; break; - + case LogMessageType.Trace: IsTrace = true; Icon = MaterialIconKind.Exclamation; @@ -33,7 +33,7 @@ public RemoteLogMessageProxy(LogMessage textMessage) Sender = textMessage.Source; Message = textMessage.Message; } - + public bool IsError { get; } public bool IsWarning { get; } public bool IsTrace { get; } diff --git a/src/Asv.Drones.Gui.Core/Controls/WindowHelper.cs b/src/Asv.Drones.Gui.Api/Tools/WindowHelper.cs similarity index 93% rename from src/Asv.Drones.Gui.Core/Controls/WindowHelper.cs rename to src/Asv.Drones.Gui.Api/Tools/WindowHelper.cs index 2b09303c..30464db6 100644 --- a/src/Asv.Drones.Gui.Core/Controls/WindowHelper.cs +++ b/src/Asv.Drones.Gui.Api/Tools/WindowHelper.cs @@ -4,16 +4,18 @@ using Avalonia.Interactivity; using Avalonia.VisualTree; -namespace Asv.Drones.Gui.Core +namespace Asv.Drones.Gui.Api { - public class WindowHelper { - public static readonly AttachedProperty EnableDragProperty = AvaloniaProperty.RegisterAttached("EnableDrag"); + public static readonly AttachedProperty EnableDragProperty = + AvaloniaProperty.RegisterAttached("EnableDrag"); - public static readonly AttachedProperty DoubleTappedWindowStateProperty = AvaloniaProperty.RegisterAttached("DoubleTappedWindowState"); + public static readonly AttachedProperty DoubleTappedWindowStateProperty = + AvaloniaProperty.RegisterAttached("DoubleTappedWindowState"); - public static readonly AttachedProperty IgnoreDragProperty = AvaloniaProperty.RegisterAttached("IgnoreDrag"); + public static readonly AttachedProperty IgnoreDragProperty = + AvaloniaProperty.RegisterAttached("IgnoreDrag"); static WindowHelper() { @@ -27,6 +29,7 @@ public static void SetIgnoreDrag(AvaloniaObject element, bool commandValue) { element.SetValue(IgnoreDragProperty, commandValue); } + public static bool GetIgnoreDrag(AvaloniaObject element) { return element.GetValue(IgnoreDragProperty); @@ -58,12 +61,12 @@ private static void DoubleTappedHandler(object? sender, RoutedEventArgs e) { if (GetIgnoreDrag(avalonia)) return; } + var parent = uiElement; var avoidInfiniteLoop = 0; // Search up the visual tree to find the first parent window. while (parent is Window == false) { - parent = parent.GetVisualParent(); avoidInfiniteLoop++; if (avoidInfiniteLoop == 1000) @@ -72,6 +75,7 @@ private static void DoubleTappedHandler(object? sender, RoutedEventArgs e) return; } } + var window = parent as Window; window.WindowState = window.WindowState switch { @@ -86,6 +90,7 @@ public static void SetDoubleTappedWindowState(AvaloniaObject element, bool comma { element.SetValue(DoubleTappedWindowStateProperty, commandValue); } + public static bool GetDoubleTappedWindowState(AvaloniaObject element) { return element.GetValue(DoubleTappedWindowStateProperty); @@ -118,7 +123,6 @@ private static void MouseDownHandler(object sender, PointerPressedEventArgs e) // Search up the visual tree to find the first parent window. while (parent is Window == false) { - parent = parent.GetVisualParent(); avoidInfiniteLoop++; if (avoidInfiniteLoop == 1000) @@ -127,6 +131,7 @@ private static void MouseDownHandler(object sender, PointerPressedEventArgs e) return; } } + var window = parent as Window; window.BeginMoveDrag(e); } @@ -149,4 +154,4 @@ public static bool GetEnableDrag(AvaloniaObject element) #endregion } -} +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/WellKnownUri.cs b/src/Asv.Drones.Gui.Api/WellKnownUri.cs new file mode 100644 index 00000000..8bb51d87 --- /dev/null +++ b/src/Asv.Drones.Gui.Api/WellKnownUri.cs @@ -0,0 +1,158 @@ +using Avalonia.Controls; + +namespace Asv.Drones.Gui.Api; + +public static class WellKnownUri +{ + /// + /// This is Scheme for URI in this application + /// + public const string UriScheme = "asv"; + + /// + /// This simple non empty URI + /// + public const string Undefined = $"{UriScheme}:null"; + + public static readonly Uri UndefinedUri = new(Undefined); + + /// + /// This is base URI for all shell controls + /// + public const string Shell = $"{UriScheme}:shell"; + + /// + /// This base URI for left menu tms with shell pages SHELL=>MENU controls + /// + public const string ShellMenu = $"{Shell}.menu"; + + /// + /// This base URI for SHELL=>HEADER controls + /// + public const string ShellHeader = $"{Shell}.header"; + + /// + /// This is base uri for SHELL=>HEADER=>MENU + /// + public const string ShellHeaderMenu = $"{ShellHeader}.menu"; + + /// + /// This is base URI for SHELL=>STATUS controls + /// + public const string ShellStatus = $"{Shell}.status"; + + /// + /// This is base URI for SHELL=>PAGES + /// + public const string ShellPage = $"{Shell}.page"; + + + public const string ShellStatusTextMessage = $"{ShellStatus}.text-message"; + public const string ShellStatusMapCache = $"{ShellStatus}.map-cache"; + public const string ShellStatusPorts = $"{ShellStatus}.ports"; + + + public const string ShellMenuMapFlight = $"{ShellMenu}.flight"; + public static readonly Uri ShellMenuMapFlightUri = new(ShellMenuMapFlight); + public const string ShellPageMapFlight = $"{ShellPage}.flight"; + public static readonly Uri ShellPageMapFlightUri = new(ShellPageMapFlight); + public const string ShellPageMapFlightAction = $"{ShellPageMapFlight}.action"; + public const string ShellPageMapFlightActionZoom = $"{ShellPageMapFlightAction}.zoom"; + public const string ShellPageMapFlightActionRuler = $"{ShellPageMapFlightAction}.ruler"; + public const string ShellPageMapFlightActionMover = $"{ShellPageMapFlightAction}.mover"; + public const string ShellPageMapFlightWidget = $"{ShellPageMapFlight}.widget"; + public const string ShellPageMapFlightWidgetAnchorEditor = $"{ShellPageMapFlightWidget}.editor"; + public const string ShellPageMapFlightWidgetUav = $"{ShellPageMapFlightWidget}.uav"; + public const string ShellPageMapFlightWidgetLogger = $"{ShellPageMapFlightWidget}.logger"; + public const string ShellPageMapFlightAnchor = $"{ShellPageMapFlight}.layer"; + + + public const string ShellMenuMapPlaning = $"{ShellMenu}.planing"; + public static readonly Uri ShellMenuMapPlaningUri = new(ShellMenuMapPlaning); + public const string ShellPageMapPlaning = $"{ShellPage}.planing"; + public static readonly Uri ShellPageMapPlaningUri = new(ShellPageMapPlaning); + public const string ShellPageMapPlaningAction = $"{ShellPageMapPlaning}.action"; + public const string ShellPageMapPlaningActionZoom = $"{ShellPageMapPlaningAction}.zoom"; + public const string ShellPageMapPlaningActionRuler = $"{ShellPageMapPlaningAction}.ruler"; + public const string ShellPageMapPlaningActionMover = $"{ShellPageMapPlaningAction}.mover"; + public const string ShellPageMapPlaningMissionBrowser = $"{ShellPageMapPlaning}.browser"; + public static readonly Uri ShellPageMapPlaningMissionBrowserUri = new(ShellPageMapPlaningMissionBrowser); + public const string ShellPageMapPlaningWidget = $"{ShellPageMapPlaning}.widget"; + public const string ShellPageMapPlaningWidgetAnchorEditor = $"{ShellPageMapPlaningWidget}.editor"; + public const string ShellPageMapPlaningWidgetEditor = $"{ShellPageMapPlaningWidget}.mission-editor"; + public const string ShellPageMapPlaningWidgetItemEditor = $"{ShellPageMapPlaningWidget}.item-editor"; + + public const string ShellPageMapPlaningWidgetEditorUploadMissionDialog = + $"{ShellPageMapPlaningWidgetEditor}.upload-mission-dialog"; + + public const string ShellPageMapPlaningWidgetEditorDownloadMissionDialog = + $"{ShellPageMapPlaningWidgetEditor}.download-mission-dialog"; + + public const string ShellPagePacketViewer = $"{ShellPage}.packets"; + public static readonly Uri ShellPagePacketViewerUri = new(ShellPagePacketViewer); + public const string ShellMenuPacketViewer = $"{ShellMenu}.packets"; + + + public const string ShellMenuSettings = $"{ShellMenu}.settings"; + public static readonly Uri ShellMenuSettingsUri = new(ShellPageSettings); + public const string ShellPageSettings = $"{ShellPage}.settings"; + public static readonly Uri ShellPageSettingsUri = new(ShellPageSettings); + + public const string ShellPageSettingsConnections = $"{ShellPageSettings}.connection"; + public static readonly Uri ShellPageSettingsConnectionsUri = new(ShellPageSettingsConnections); + + public const string ShellPageSettingsConnectionsIdentify = $"{ShellPageSettingsConnections}.id"; + public static readonly Uri ShellPageSettingsConnectionsIdentifyUri = new(ShellPageSettingsConnectionsIdentify); + + public const string ShellPageSettingsConnectionsDevices = $"{ShellPageSettingsConnections}.devices"; + public static readonly Uri ShellPageSettingsConnectionsDevicesUri = new(ShellPageSettingsConnectionsDevices); + + public const string ShellPageSettingsConnectionsPorts = $"{ShellPageSettingsConnections}.ports"; + public static readonly Uri ShellPageSettingsConnectionsPortsUri = new(ShellPageSettingsConnectionsPorts); + + public const string ShellPageSettingsAppearance = $"{ShellPageSettings}.appearance"; + public static readonly Uri ShellPageSettingsAppearanceUri = new Uri(ShellPageSettingsAppearance); + + public const string ShellPageSettingsMeasure = $"{ShellPageSettings}.measure"; + public static readonly Uri ShellPageSettingsMeasureUri = new(ShellPageSettingsMeasure); + + public const string ShellPageSettingsPlugins = $"{ShellPageSettings}.plugins"; + public static readonly Uri ShellPageSettingsPluginsUri = new(ShellPageSettingsPlugins); + + public const string ShellPageSettingsPluginsMarket = $"{ShellPageSettingsPlugins}.market"; + public static readonly Uri ShellPageSettingsPluginsMarketUri = new(ShellPageSettingsPluginsMarket); + + public const string ShellPageSettingsPluginsLocal = $"{ShellPageSettingsPlugins}.local"; + public static readonly Uri ShellPageSettingsPluginsLocalUri = new(ShellPageSettingsPluginsLocal); + + public const string ShellPageSettingsPluginsSource = $"{ShellPageSettingsPlugins}.source"; + public static readonly Uri ShellPageSettingsPluginsSourceUri = new(ShellPageSettingsPluginsSource); + + public const string ShellMenuParamsVehicle = $"{ShellMenu}.params-vehicle"; + public const string ShellPageParamsVehicle = $"{ShellPage}.params-vehicle"; + + public const string ShellMenuQuickParamsVehicle = $"{ShellMenu}.quick-params-vehicle"; + + public const string ShellPageQuickParams = $"{ShellPage}.quick-params"; + + public const string ShellPageQuickParamsArduCopterVehicle = $"{ShellPageQuickParams}.ardu-copter"; + + public const string ShellPageQuickParamsArduPlaneVehicle = $"{ShellPageQuickParams}.ardu-plane"; + + public const string ShellPageQuickParamsPx4CopterVehicle = $"{ShellPageQuickParams}.px-4-copter"; + + public const string ShellPageQuickParamsPx4PlaneVehicle = $"{ShellPageQuickParams}.px-4-plane"; + + public const string ShellPageQuickParamsArduCopterVehicleStandard = $"{ShellPageQuickParamsArduCopterVehicle}.standard-params"; + + public const string ShellPageQuickParamsArduPlaneVehicleStandard = $"{ShellPageQuickParamsArduPlaneVehicle}.standard-params"; + + public const string ShellPageQuickParamsPx4CopterVehicleStandard = $"{ShellPageQuickParamsPx4CopterVehicle}.standard-params"; + + public const string ShellPageQuickParamsPx4PlaneVehicleStandard = $"{ShellPageQuickParamsPx4PlaneVehicle}.standard-params"; + + public const string ShellMenuLogViewer = $"{ShellMenu}.log-viewer"; + public static readonly Uri ShellMenuLogViewerUri = new(ShellMenuLogViewer); + public const string ShellPageLogViewer = $"{ShellPage}.log-viewer"; + public static readonly Uri ShellPageLogViewerUri = new(ShellPageLogViewer); +} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/App.axaml b/src/Asv.Drones.Gui.Core/App.axaml deleted file mode 100644 index b4a6d832..00000000 --- a/src/Asv.Drones.Gui.Core/App.axaml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Asv.Drones.Gui.Core.csproj b/src/Asv.Drones.Gui.Core/Asv.Drones.Gui.Core.csproj deleted file mode 100644 index a0a50234..00000000 --- a/src/Asv.Drones.Gui.Core/Asv.Drones.Gui.Core.csproj +++ /dev/null @@ -1,101 +0,0 @@ - - - ../Asv.Drones.Gui.Custom.props - $(SolutionDir)Asv.Drones.Gui.Custom.props - - - - net7.0 - enable - enable - $(ProductStrongVersion) - $(ProductExtendedVersion) - Debug;Release - AnyCPU - - - - - - - - - - - - - - - - - - - - - - - PublicResXFileCodeGenerator - RS.Designer.cs - - - - - - True - True - RS.resx - - - MapZoomActionView.axaml - Code - - - MapZoomActionView.axaml - Code - - - HeaderCoordinatesCalculatorDialog.axaml - Code - - - ParamItemView.axaml - Code - - - ParamPageView.axaml - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Asv.Drones.Gui.Core.csproj.DotSettings b/src/Asv.Drones.Gui.Core/Asv.Drones.Gui.Core.csproj.DotSettings deleted file mode 100644 index abd4f59e..00000000 --- a/src/Asv.Drones.Gui.Core/Asv.Drones.Gui.Core.csproj.DotSettings +++ /dev/null @@ -1,71 +0,0 @@ - - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/BatteryIndicator.axaml b/src/Asv.Drones.Gui.Core/Controls/BatteryIndicator.axaml deleted file mode 100644 index 3967859e..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/BatteryIndicator.axaml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Controls/ConnectionQuality.axaml b/src/Asv.Drones.Gui.Core/Controls/ConnectionQuality.axaml deleted file mode 100644 index 709c53b6..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/ConnectionQuality.axaml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Controls/ConnectionQuality.axaml.cs b/src/Asv.Drones.Gui.Core/Controls/ConnectionQuality.axaml.cs deleted file mode 100644 index 8d27afbc..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/ConnectionQuality.axaml.cs +++ /dev/null @@ -1,135 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Metadata; -using Avalonia.Media; -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -[PseudoClasses(":critical", ":warning", ":normal", ":unknown")] -public class ConnectionQuality : IndicatorBase -{ - #region Brushes - - public static readonly StyledProperty UnknownBrushProperty = AvaloniaProperty.Register( - "UnknownBrush"); - - public Brush UnknownBrush - { - get => GetValue(UnknownBrushProperty); - set => SetValue(UnknownBrushProperty, value); - } - - public static readonly StyledProperty CriticalBrushProperty = AvaloniaProperty.Register( - "CriticalBrush"); - - public Brush CriticalBrush - { - get => GetValue(CriticalBrushProperty); - set => SetValue(CriticalBrushProperty, value); - } - public static readonly StyledProperty WarningBrushProperty = AvaloniaProperty.Register( - "WarningBrush"); - - public Brush WarningBrush - { - get => GetValue(WarningBrushProperty); - set => SetValue(WarningBrushProperty, value); - } - public static readonly StyledProperty NormalBrushProperty = AvaloniaProperty.Register( - "NormalBrush"); - - public Brush NormalBrush - { - get => GetValue(NormalBrushProperty); - set => SetValue(NormalBrushProperty, value); - } - - #endregion - - #region Styled Props - - public static readonly StyledProperty CriticalValueProperty = AvaloniaProperty.Register( - nameof(CriticalValue), 0.2); - - public double CriticalValue - { - get => GetValue(CriticalValueProperty); - set => SetValue(CriticalValueProperty, value); - } - - public static readonly StyledProperty WarningValueProperty = AvaloniaProperty.Register( - nameof(WarningValue),0.5); - - public double WarningValue - { - get => GetValue(WarningValueProperty); - set => SetValue(WarningValueProperty, value); - } - - public static readonly StyledProperty MaxValueProperty = AvaloniaProperty.Register( - nameof(MaxValue), 1); - - public double MaxValue - { - get => GetValue(MaxValueProperty); - set => SetValue(MaxValueProperty, value); - } - - public static readonly StyledProperty ValueProperty = AvaloniaProperty.Register( - nameof(Value), default(double?)); - - public double? Value - { - get => GetValue(ValueProperty); - set => SetValue(ValueProperty, value); - } - - public static readonly StyledProperty IconKindProperty = AvaloniaProperty.Register( - nameof(IconKind), MaterialIconKind.WifiStrengthAlertOutline); - - public MaterialIconKind IconKind - { - get => GetValue(IconKindProperty); - set => SetValue(IconKindProperty, value); - } - - #endregion - - public ConnectionQuality() - { - - } - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - if (change.Property == ValueProperty) - { - var value = Value; - PseudoClasses.Set(":unknown", value == null || double.IsFinite(value.Value) == false || value > MaxValue); - PseudoClasses.Set(":critical", value <= CriticalValue); - PseudoClasses.Set(":warning", value > CriticalValue & value <= WarningValue); - PseudoClasses.Set(":normal", value > WarningValue & value <= MaxValue); - IconKind = GetIcon(Value/MaxValue); - } - } - - - private static MaterialIconKind GetIcon(double? normalizedValue) - { - return (normalizedValue ?? double.NaN) switch - { - (< 0 or > 1 - or double.NegativeInfinity - or double.PositiveInfinity - or double.NaN) => MaterialIconKind.WifiStrengthAlertOutline, - (0) => MaterialIconKind.WifiStrength0, - (> 0 and <= 0.2) => MaterialIconKind.WifiStrength0, - (> 0.2 and <= 0.4) => MaterialIconKind.WifiStrength1, - (> 0.4 and <= 0.6) => MaterialIconKind.WifiStrength2, - (> 0.6 and <= 0.8) => MaterialIconKind.WifiStrength3, - (> 0.8 and <= 1.0) => MaterialIconKind.WifiStrength4, - }; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/DigitIndicator.axaml b/src/Asv.Drones.Gui.Core/Controls/DigitIndicator.axaml deleted file mode 100644 index 716dc63c..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/DigitIndicator.axaml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Controls/DigitIndicator.axaml.cs b/src/Asv.Drones.Gui.Core/Controls/DigitIndicator.axaml.cs deleted file mode 100644 index a72cf43f..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/DigitIndicator.axaml.cs +++ /dev/null @@ -1,110 +0,0 @@ -using Avalonia; - -namespace Asv.Drones.Gui.Core; - -public class DigitIndicator : IndicatorBase -{ - #region Direct properties - private string _title; - - public static readonly DirectProperty TitleProperty = AvaloniaProperty.RegisterDirect( - nameof(Title), o => o.Title, (o, v) => o.Title = v); - - public string Title - { - get => _title; - set => SetAndRaise(TitleProperty, ref _title, value); - } - - private string _units; - - public static readonly DirectProperty UnitsProperty = AvaloniaProperty.RegisterDirect( - nameof(Units), o => o.Units, (o, v) => o.Units = v); - - public string Units - { - get => _units; - set => SetAndRaise(UnitsProperty, ref _units, value); - } - - private double _value; - - public static readonly DirectProperty ValueProperty = AvaloniaProperty.RegisterDirect( - nameof(Value), o => o.Value, (o, v) => o.Value = v); - - public double Value - { - get => _value; - set - { - if (Math.Abs(value - _value) < double.Epsilon) - { - IsDecreased = false; - IsIncreased = false; - } - else if (value > _value) - { - IsDecreased = false; - IsIncreased = true; - } - else if (value < _value) - { - IsDecreased = true; - IsIncreased = false; - } - - SetAndRaise(ValueProperty, ref _value, value); - FormatedValue = Value.ToString(FormatString); - } - } - - private string _formatString; - - public static readonly DirectProperty FormatStringProperty = AvaloniaProperty.RegisterDirect( - nameof(FormatString), o => o.FormatString, (o, v) => o.FormatString = v); - - public string FormatString - { - get => _formatString; - set => SetAndRaise(FormatStringProperty, ref _formatString, value); - } - - private bool _isIncreased; - - public static readonly DirectProperty IsIncreasedProperty = AvaloniaProperty.RegisterDirect( - nameof(IsIncreased), o => o.IsIncreased, (o, v) => o.IsIncreased = v); - - public bool IsIncreased - { - get => _isIncreased; - set => SetAndRaise(IsIncreasedProperty, ref _isIncreased, value); - } - - private bool _isDecreased; - - public static readonly DirectProperty IsDecreasedProperty = AvaloniaProperty.RegisterDirect( - nameof(IsDecreased), o => o.IsDecreased, (o, v) => o.IsDecreased = v); - - public bool IsDecreased - { - get => _isDecreased; - set => SetAndRaise(IsDecreasedProperty, ref _isDecreased, value); - } - #endregion - - private string _formatedValue; - - public static readonly DirectProperty FormatedValueProperty = AvaloniaProperty.RegisterDirect( - nameof(FormatedValue), o => o.FormatedValue, (o, v) => o.FormatedValue = v); - - public string FormatedValue - { - get => _formatedValue; - set => SetAndRaise(FormatedValueProperty, ref _formatedValue, value); - } - - public DigitIndicator() - { - FormatString = ""; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/GpsStatusIndicator.axaml b/src/Asv.Drones.Gui.Core/Controls/GpsStatusIndicator.axaml deleted file mode 100644 index 5c12b989..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/GpsStatusIndicator.axaml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreEntryTagViewModel.cs b/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreEntryTagViewModel.cs deleted file mode 100644 index 413ca4a1..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreEntryTagViewModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Windows.Input; -using Avalonia.Media; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -public class HierarchicalStoreEntryTagViewModel:ReactiveObject -{ - public MaterialIconKind Icon { get; set; } = MaterialIconKind.Tag; - public IBrush Color { get; set; } - public string Name { get; set; } - public ICommand? Remove { get; set; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreView.axaml b/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreView.axaml deleted file mode 100644 index 468a94ec..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreView.axaml +++ /dev/null @@ -1,244 +0,0 @@ - - - - - - 18 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs b/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs deleted file mode 100644 index ba74232c..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs +++ /dev/null @@ -1,376 +0,0 @@ -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Globalization; -using System.Reactive; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Asv.Mavlink; -using Asv.Common; -using Avalonia.Controls; -using Avalonia.Media; -using DynamicData; -using DynamicData.Binding; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - - -public class HierarchicalStoreViewModel : ViewModelBase -{ - - protected HierarchicalStoreViewModel(Uri id) : base(id) - { - CreateNewFile = ReactiveCommand.Create(CreateNewFileImpl) - .DisposeItWith(Disposable); - CreateNewFile.ThrownExceptions - .Subscribe(ex => OnError( HierarchicalStoreAction.CreateFile,ex)) - .DisposeItWith(Disposable); - - CreateNewFolder = ReactiveCommand.Create(CreateNewFolderImpl) - .DisposeItWith(Disposable); - CreateNewFolder.ThrownExceptions - .Subscribe(ex => OnError( HierarchicalStoreAction.CreateFolder,ex)) - .DisposeItWith(Disposable); - - Refresh = ReactiveCommand.Create(()=> - { - var selectedId = SelectedItem?.Id; - var selectedParentId = SelectedItem?.ParentId; - RefreshImpl(); - if (TrySelect(selectedId) == false) - { - TrySelect(selectedParentId); - } - }) - .DisposeItWith(Disposable); - Refresh.ThrownExceptions - .Subscribe(ex => OnError( HierarchicalStoreAction.Refresh,ex)) - .DisposeItWith(Disposable); - } - - - - public HierarchicalStoreViewModel():this(new($"asv:{Guid.NewGuid()}")) - { - if (Design.IsDesignMode == false) - { - Debug.Assert(false,"Only for debug mode"); - Debugger.Break(); - } - if (Design.IsDesignMode) - { - Items = new ReadOnlyObservableCollection( - new ObservableCollection(new List - { - new() - { - Id = Guid.NewGuid(), - Name = "Record1", - Tags = new ReadOnlyObservableCollection(new ObservableCollection(new List - { - new() - { - Color = Brushes.CornflowerBlue, - Name = "Latitude: 55.1234567", - }, - new() - { - Color = Brushes.DarkOrange, - Name = "Short", - }, - new() - { - Color = new SolidColorBrush(Color.Parse("#FBC02D")), - Name = "Longitude: 66.1234567", - }, - new() - { - Color = new SolidColorBrush(Color.Parse("#FE8256")), - Name = "Longitude: 66.1234567", - }, - new() - { - Color = new SolidColorBrush(Color.Parse("#ACC865")), - Name = "ACC865:66.1234567", - }, - new() - { - Color = new SolidColorBrush(Color.Parse("#CD91B6")), - Name = "ShortShort", - }, - - - })), - IsFile = true, - }, - new() - { - Id = Guid.NewGuid(), - Name = "Folder", - IsFolder = true, - Items = new ReadOnlyObservableCollection(new ObservableCollection(new List - { - new() - { - Id = Guid.NewGuid(), - Name = "Record 2", - IsFile = true, - }, - })) - }, - - })); - FolderItems = new ReadOnlyObservableCollection( - new ObservableCollection(new List - { - new() - { - Id = Guid.NewGuid(), - Name = "Folder", - IsFolder = true, - Items = new ReadOnlyObservableCollection(new ObservableCollection(new List - { - new() - { - Id = Guid.NewGuid(), - Name = "Folder 2", - IsFolder = true, - }, - })) - }, - })); - } - } - - [Reactive] - public string SearchText { get; set; } - [Reactive] - public string DisplayName { get; set; } - public virtual ReadOnlyObservableCollection Items { get; } - public virtual ReadOnlyObservableCollection FolderItems { get; } - [Reactive] - public HierarchicalStoreEntryViewModel? SelectedItem { get; set; } - public ReactiveCommand CreateNewFolder { get; set; } - public ReactiveCommand CreateNewFile { get; set; } - public ReactiveCommand Refresh { get; set; } - public bool IsHeaderVisible { get; set; } = true; - - public bool TrySelect(object? selectedId) - { - if (selectedId == null) return false; - foreach (var item in Items) - { - var find = item.FindAndSelect(selectedId); - if (find == null) continue; - find.IsSelected = true; - return true; - } - return false; - } - protected virtual void RefreshImpl() - { - - } - protected virtual void CreateNewFileImpl() - { - - } - protected virtual void CreateNewFolderImpl() - { - - } - protected virtual void OnError(HierarchicalStoreAction action, Exception ex) - { - - } - - [Reactive] - public bool IsCreateFolderAvailable { get; set; } = true; - [Reactive] - public bool IsCreateFileAvailable { get; set; } = true; - - [Reactive] - public HierarchicalStoreEntryViewModel? SelectedItemMoveTo { get; set; } - - -} - - - -public abstract class HierarchicalStoreViewModel:HierarchicalStoreViewModel - where TFile : IDisposable where TKey : notnull -{ - private readonly IHierarchicalStore _store; - private readonly ILogService _log; - private readonly SourceCache,TKey> _source; - private readonly ReadOnlyObservableCollection _tree; - private readonly ReadOnlyObservableCollection _treeFolder; - - - public HierarchicalStoreViewModel():base(new Uri($"asv:{Guid.NewGuid()}")) - { - - } - public HierarchicalStoreViewModel(Uri id,IHierarchicalStore store, ILogService log):base(id) - { - _store = store; - _log = log; - _source = new SourceCache, TKey>(x => x.Id) - .DisposeItWith(Disposable); - var filterPipe = new Subject, bool>>() - .DisposeItWith(Disposable); - this.WhenValueChanged(x => x.SearchText) - .Throttle(TimeSpan.FromMilliseconds(500), RxApp.MainThreadScheduler) - .Subscribe(search => filterPipe.OnNext(item => search.IsNullOrWhiteSpace() || item.Name.Contains(search))) - .DisposeItWith(Disposable); - - _source - .Connect() - .Filter(filterPipe) - .TransformToTree(x=>x.ParentId) - .Transform(x=>(HierarchicalStoreEntryViewModel)new HierarchicalStoreEntryViewModel(x,this,log)) - .DisposeMany() - .Bind(out _tree) - .Subscribe() - .DisposeItWith(Disposable); - - _source - .Connect() - .Filter(x=>x.Type == FolderStoreEntryType.Folder) - .TransformToTree(x=>x.ParentId) - .Transform(x=>(HierarchicalStoreEntryViewModel)new HierarchicalStoreEntryViewModel(x,this,log)) - .DisposeMany() - .Bind(out _treeFolder) - .Subscribe() - .DisposeItWith(Disposable); - - this.WhenValueChanged(x => x.SelectedItem) - .Subscribe(x=>x?.Refresh()).DisposeItWith(Disposable); - } - - protected override void OnError(HierarchicalStoreAction action, Exception ex) - { - _log.Error( DisplayName,$"Error to '{action:G}'",ex); - } - - protected override void CreateNewFolderImpl() - { - TKey parentId; - if (SelectedItem != null) - { - parentId = (TKey)(SelectedItem.Type == FolderStoreEntryType.Folder ? SelectedItem.Id : SelectedItem.ParentId); - } - else - { - parentId = _store.RootFolderId; - } - - var attempt = 0; - start: - var name = $"New folder {++attempt}"; - try - { - _store.CreateFolder(GenerateNewId(), name, parentId); - } - catch (HierarchicalStoreFolderAlreadyExistException) - { - goto start; - } - - Refresh.Execute().Subscribe(_ => { }); - } - protected abstract TKey GenerateNewId(); - protected override void CreateNewFileImpl() - { - TKey parentId; - if (SelectedItem != null) - { - parentId = (TKey)(SelectedItem.Type == FolderStoreEntryType.Folder ? SelectedItem.Id : SelectedItem.ParentId); - } - else - { - parentId = _store.RootFolderId; - } - - var attempt = 0; - start: - var name = $"New file {++attempt}"; - try - { - using var file = _store.CreateFile(GenerateNewId(), name, parentId); - } - catch (HierarchicalStoreFolderAlreadyExistException) - { - goto start; - } - Refresh.Execute().Subscribe(_ => { }); - } - - protected override void RefreshImpl() - { - _source.Clear(); - _source.AddOrUpdate(_store.GetEntries()); - } - - - - public override ReadOnlyObservableCollection Items => _tree; - public override ReadOnlyObservableCollection FolderItems => _treeFolder; - public void DeleteEntryImpl(TKey itemId) - { - _store.DeleteEntry(itemId); - Refresh.Execute().Subscribe(); - } - public void RenameEntryImpl(TKey itemId, string name) - { - _store.RenameEntry(itemId, name); - Refresh.Execute().Subscribe(); - } - - public void MoveEntryImpl(TKey id, TKey parentId) - { - _store.MoveEntry(id,parentId); - Refresh.Execute().Subscribe(); - } - - public IReadOnlyCollection GetEntryTags(TKey id) - { - var item = _source.Lookup(id); - return !item.HasValue ? ArraySegment.Empty : InternalGetEntryTags(item.Value); - } - - protected virtual IReadOnlyCollection InternalGetEntryTags(IHierarchicalStoreEntry itemValue) - { - return ArraySegment.Empty; - } - - - public virtual string GetEntryDescription(IHierarchicalStoreEntry nodeItem) - { - var entry = nodeItem as FileSystemHierarchicalStoreEntry; - - if (entry == null) return string.Empty; - - if (nodeItem.Type == FolderStoreEntryType.Folder) - { - var info = new DirectoryInfo(entry.FullPath); - return info.CreationTime.ToString(CultureInfo.CurrentCulture); - } - - if(nodeItem.Type == FolderStoreEntryType.File) - { - var info = new FileInfo(entry.FullPath); - return info.CreationTime.ToString(CultureInfo.CurrentCulture); - } - - return string.Empty; - } -} - -public enum HierarchicalStoreAction -{ - Refresh, - CreateFile, - CreateFolder -} diff --git a/src/Asv.Drones.Gui.Core/Controls/IndicatorBase.cs b/src/Asv.Drones.Gui.Core/Controls/IndicatorBase.cs deleted file mode 100644 index 8365b853..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/IndicatorBase.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Avalonia; -using Avalonia.Controls.Primitives; -using Avalonia.Media; -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public abstract class IndicatorBase : TemplatedControl -{ - #region Brushes - - public static readonly StyledProperty UnknownBrushProperty = AvaloniaProperty.Register( - "UnknownBrush"); - - public Brush UnknownBrush - { - get => GetValue(UnknownBrushProperty); - set => SetValue(UnknownBrushProperty, value); - } - - public static readonly StyledProperty CriticalBrushProperty = AvaloniaProperty.Register( - "CriticalBrush"); - - public Brush CriticalBrush - { - get => GetValue(CriticalBrushProperty); - set => SetValue(CriticalBrushProperty, value); - } - public static readonly StyledProperty WarningBrushProperty = AvaloniaProperty.Register( - "WarningBrush"); - - public Brush WarningBrush - { - get => GetValue(WarningBrushProperty); - set => SetValue(WarningBrushProperty, value); - } - public static readonly StyledProperty NormalBrushProperty = AvaloniaProperty.Register( - "NormalBrush"); - - public Brush NormalBrush - { - get => GetValue(NormalBrushProperty); - set => SetValue(NormalBrushProperty, value); - } - - #endregion - - public static readonly StyledProperty IconKindProperty = AvaloniaProperty.Register( - nameof(IconKind), MaterialIconKind.BatteryUnknown); - - public MaterialIconKind IconKind - { - get => GetValue(IconKindProperty); - set => SetValue(IconKindProperty, value); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/LevelIndicator.axaml b/src/Asv.Drones.Gui.Core/Controls/LevelIndicator.axaml deleted file mode 100644 index 47f8e9b3..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/LevelIndicator.axaml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Controls/LostFocusUpdateBindingBehavior.cs b/src/Asv.Drones.Gui.Core/Controls/LostFocusUpdateBindingBehavior.cs deleted file mode 100644 index bcec921c..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/LostFocusUpdateBindingBehavior.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Data; -using Avalonia.Input; -using Avalonia.Interactivity; -using Avalonia.Xaml.Interactivity; - -namespace Asv.Drones.Gui.Core; - -public class LostFocusUpdateBindingBehavior : Behavior - { - static LostFocusUpdateBindingBehavior () - { - TextProperty.Changed.Subscribe(e => - { - ((LostFocusUpdateBindingBehavior ) e.Sender).OnBindingValueChanged(); - }); - } - - protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error) - { - base.UpdateDataValidation(property, state, error); - if (property == TextProperty && AssociatedObject != null) - { - if (error != null) - { - DataValidationErrors.SetError(AssociatedObject, error); - } - else - { - DataValidationErrors.ClearErrors(AssociatedObject); - } - - } - - } - - - protected override void OnAttached() - { - if (AssociatedObject != null) - { - AssociatedObject.LostFocus += OnLostFocus; - AssociatedObject.KeyDown += OnKeyDown; - } - - base.OnAttached(); - } - - protected override void OnDetaching() - { - if (AssociatedObject != null) - { - AssociatedObject.LostFocus -= OnLostFocus; - AssociatedObject.KeyDown -= OnKeyDown; - } - - base.OnDetaching(); - } - - private void OnKeyDown(object sender, KeyEventArgs e) - { - if (AssociatedObject != null && e.Key == Key.Enter) - { - Text = AssociatedObject.Text; - } - } - - private void OnLostFocus(object sender, RoutedEventArgs e) - { - if (AssociatedObject != null) - Text = AssociatedObject.Text; - } - - private void OnBindingValueChanged() - { - if (AssociatedObject != null) - AssociatedObject.Text = Text; - } - - public static readonly DirectProperty TextProperty - = AvaloniaProperty.RegisterDirect(nameof(Text), o => o.Text, - (o, v) => o.Text = v, null, BindingMode.TwoWay, true); - - private string _text; - - public string Text - { - get { return _text; } - set { this.SetAndRaise(TextProperty, ref _text, value); } - } - } \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Controls/OptionsDisplayItem/OptionsDisplayItemStyles.axaml b/src/Asv.Drones.Gui.Core/Controls/OptionsDisplayItem/OptionsDisplayItemStyles.axaml deleted file mode 100644 index 23995aa0..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/OptionsDisplayItem/OptionsDisplayItemStyles.axaml +++ /dev/null @@ -1,282 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Controls/StringIndicator.axaml b/src/Asv.Drones.Gui.Core/Controls/StringIndicator.axaml deleted file mode 100644 index 14dd75db..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/StringIndicator.axaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Controls/StringIndicator.axaml.cs b/src/Asv.Drones.Gui.Core/Controls/StringIndicator.axaml.cs deleted file mode 100644 index fd5d468e..00000000 --- a/src/Asv.Drones.Gui.Core/Controls/StringIndicator.axaml.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Avalonia; - -namespace Asv.Drones.Gui.Core; - -public class StringIndicator : IndicatorBase -{ - #region Directed properties - private string _title; - - public static readonly DirectProperty TitleProperty = AvaloniaProperty.RegisterDirect( - nameof(Title), o => o.Title, (o, v) => o.Title = v); - - public string Title - { - get => _title; - set => SetAndRaise(TitleProperty, ref _title, value); - } - - private string _value; - - public static readonly DirectProperty ValueProperty = AvaloniaProperty.RegisterDirect( - nameof(Value), o => o.Value, (o, v) => o.Value = v); - - public string Value - { - get => _value; - set => SetAndRaise(ValueProperty, ref _value, value); - } - #endregion -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/CorePlugin.cs b/src/Asv.Drones.Gui.Core/CorePlugin.cs deleted file mode 100644 index f3748f65..00000000 --- a/src/Asv.Drones.Gui.Core/CorePlugin.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.ComponentModel.Composition; -using System.ComponentModel.Composition.Hosting; -using System.Reflection; -using Asv.Cfg; -using Asv.Cfg.Json; -using Avalonia; -using Avalonia.Controls.Templates; - -namespace Asv.Drones.Gui.Core; - -[PluginEntryPoint(Name)] -[PartCreationPolicy(CreationPolicy.Shared)] -public class CorePlugin: IPluginEntryPoint -{ - private readonly IDataTemplateHost _applicationDataTemplateHost; - private readonly ViewLocator _defaultViewLocator; - public const string Name = "Core"; - - [ImportingConstructor] - public CorePlugin(CompositionContainer container, IDataTemplateHost applicationDataTemplateHost) - { - _applicationDataTemplateHost = applicationDataTemplateHost; - var batch = new CompositionBatch(); - var path = GetAppPathInfo(); - var config = new JsonOneFileConfiguration(path.ConfigFilePath, true, TimeSpan.FromSeconds(1)); - batch.AddExportedValue(path); - batch.AddExportedValue(config); - batch.AddExportedValue(_defaultViewLocator = new ViewLocator(container)); - batch.AddExportedValue(GetAppInfo()); - batch.AddExportedValue(new LocalizationServiceBase(config)); - container.Compose(batch); - } - public void Initialize() - { - _applicationDataTemplateHost.DataTemplates.Add(_defaultViewLocator ?? throw new InvalidOperationException()); - } - - public void OnFrameworkInitializationCompleted() - { - - } - - public void OnShutdownRequested() - { - - } - - private IAppPathInfo GetAppPathInfo() - { -#if DEBUG - var baseDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); // Path.GetDirectoryName(Environment.ProcessPath) ?? Environment.CurrentDirectory; -#else - var baseDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); -#endif - var appData = Path.Combine(baseDirectory, "asv-data-folder"); - var configPath = Path.Combine(appData, "config.json"); - var storeFilePath = Path.Combine(appData, "data.asv"); - return new AppPathInfo(appData,configPath,storeFilePath); - } - - - - private IAppInfo GetAppInfo() - { - var assm = _applicationDataTemplateHost.GetType().Assembly.GetName(); // hack - to get application assembly - var version = assm.Version != null ? $"{assm.Version.Major}.{assm.Version.Minor}.{assm.Version.Build}" : "0.0.0"; - var name = assm.Name ?? "Asv.Drones"; - const string author = "https://asv.me/"; - const string appUrl = "https://docs.asv.me/"; - const string licence = "MIT License"; - var avaloniaVersion = typeof(AppBuilder).Assembly.GetName().Version?.ToString() ?? "0.0.0"; // hack to get Avalonia version - return new AppInfo(name, version,author, appUrl, licence, avaloniaVersion); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/CoreServicePlugin.cs b/src/Asv.Drones.Gui.Core/CoreServicePlugin.cs deleted file mode 100644 index 16b12dbb..00000000 --- a/src/Asv.Drones.Gui.Core/CoreServicePlugin.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Asv.Cfg; -using System.ComponentModel.Composition; -using System.ComponentModel.Composition.Hosting; -using System.Diagnostics; -using System.Reactive.Concurrency; -using Asv.Drones.Gui.Uav; -using NLog; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - /// - /// This module only imports all core services to be created by IoC container - /// - [PluginEntryPoint(Name, CorePlugin.Name)] - [PartCreationPolicy(CreationPolicy.Shared)] - public class CoreServicePlugin:IPluginEntryPoint, IObserver - { - public const string Name = "CoreServices"; - private readonly CompositionContainer _container; - private ILogService? _log; - private static Logger Logger = LogManager.GetCurrentClassLogger(); - - [ImportingConstructor] - public CoreServicePlugin(CompositionContainer container) - { - _container = container; - } - - public void Initialize() - { - - } - - public void OnFrameworkInitializationCompleted() - { - // We need the plugin to ask the container to create services to make them work - var svc1 = _container.GetExportedValue(); - var svc2 = _container.GetExportedValue(); - var svc3 = _container.GetExportedValue(); - var svc4 = _container.GetExportedValue(); - var svc5 = _container.GetExportedValue(); - var svc6 = _container.GetExportedValue(); - var svc7 = _container.GetExportedValue(); - _log = _container.GetExportedValue(); - RxApp.DefaultExceptionHandler = this; - } - - public void OnShutdownRequested() - { - - } - - public void OnCompleted() - { - if (Debugger.IsAttached) Debugger.Break(); - RxApp.MainThreadScheduler.Schedule(() => throw new NotImplementedException()); - } - - public void OnError(Exception error) - { - Logger.Error(error,$"Unhandled task exception {error.Message}"); - if (Debugger.IsAttached) Debugger.Break(); - RxApp.MainThreadScheduler.Schedule(() => throw error); - } - - public void OnNext(Exception value) - { - if (Debugger.IsAttached) Debugger.Break(); - Logger.Error(value,$"Unhandled RxApp exception {value.Message}"); - _log?.Error("Core",$"Unhandled RxApp exception:{value.Message}",value); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/FodyWeavers.xsd b/src/Asv.Drones.Gui.Core/FodyWeavers.xsd deleted file mode 100644 index f3ac4762..00000000 --- a/src/Asv.Drones.Gui.Core/FodyWeavers.xsd +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. - - - - - A comma-separated list of error codes that can be safely ignored in assembly verification. - - - - - 'false' to turn off automatic generation of the XML Schema file. - - - - - \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/RS.Designer.cs b/src/Asv.Drones.Gui.Core/RS.Designer.cs deleted file mode 100644 index 829aa51d..00000000 --- a/src/Asv.Drones.Gui.Core/RS.Designer.cs +++ /dev/null @@ -1,3356 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Asv.Drones.Gui.Core { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class RS { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal RS() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Asv.Drones.Gui.Core.RS", typeof(RS).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Accuracy. - /// - public static string AddNewMapPointView_Accuracy_Name { - get { - return ResourceManager.GetString("AddNewMapPointView_Accuracy_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Altitude. - /// - public static string AddNewMapPointView_Altitude_Name { - get { - return ResourceManager.GetString("AddNewMapPointView_Altitude_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Latitude. - /// - public static string AddNewMapPointView_Latitude_Name { - get { - return ResourceManager.GetString("AddNewMapPointView_Latitude_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Longitude. - /// - public static string AddNewMapPointView_Longitude_Name { - get { - return ResourceManager.GetString("AddNewMapPointView_Longitude_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Name. - /// - public static string AddNewMapPointView_Point_Name { - get { - return ResourceManager.GetString("AddNewMapPointView_Point_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accuracy must be greater or equal {0}.. - /// - public static string AddNewMapPointViewModel_Accuracy_ValidValue { - get { - return ResourceManager.GetString("AddNewMapPointViewModel_Accuracy_ValidValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Name can not be empty. - /// - public static string AddNewMapPointViewModel_Name_ValidValue { - get { - return ResourceManager.GetString("AddNewMapPointViewModel_Name_ValidValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Altitude measure units. - /// - public static string Altitude_Description { - get { - return ResourceManager.GetString("Altitude_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Feets. - /// - public static string Altitude_Feet_Title { - get { - return ResourceManager.GetString("Altitude_Feet_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ft. - /// - public static string Altitude_Feet_Unit { - get { - return ResourceManager.GetString("Altitude_Feet_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Meters. - /// - public static string Altitude_Meter_Title { - get { - return ResourceManager.GetString("Altitude_Meter_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to m. - /// - public static string Altitude_Meter_Unit { - get { - return ResourceManager.GetString("Altitude_Meter_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Altitude. - /// - public static string Altitude_Title { - get { - return ResourceManager.GetString("Altitude_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Amplitude modulation measure units. - /// - public static string AmplitudeModulation_Description { - get { - return ResourceManager.GetString("AmplitudeModulation_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In parts. - /// - public static string AmplitudeModulation_InParts_Unit { - get { - return ResourceManager.GetString("AmplitudeModulation_InParts_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Percents. - /// - public static string AmplitudeModulation_Percent_Title { - get { - return ResourceManager.GetString("AmplitudeModulation_Percent_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to AM. - /// - public static string AmplitudeModulation_Title { - get { - return ResourceManager.GetString("AmplitudeModulation_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move anchors. - /// - public static string AnchorMoverActionView_Title { - get { - return ResourceManager.GetString("AnchorMoverActionView_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Altitude. - /// - public static string AnchorsEditorView_TextBlock_Altitude_Text { - get { - return ResourceManager.GetString("AnchorsEditorView_TextBlock_Altitude_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Latitude. - /// - public static string AnchorsEditorView_TextBlock_Latitude_Text { - get { - return ResourceManager.GetString("AnchorsEditorView_TextBlock_Latitude_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Longitude. - /// - public static string AnchorsEditorView_TextBlock_Longitude_Text { - get { - return ResourceManager.GetString("AnchorsEditorView_TextBlock_Longitude_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Bearing measure units. - /// - public static string Bearing_Description { - get { - return ResourceManager.GetString("Bearing_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Bearing. - /// - public static string Bearing_Title { - get { - return ResourceManager.GetString("Bearing_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Degrees. - /// - public static string BearingDegreeTitle { - get { - return ResourceManager.GetString("BearingDegreeTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to B. - /// - public static string ByteSize_BytesUnit { - get { - return ResourceManager.GetString("ByteSize_BytesUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to GB. - /// - public static string ByteSize_GigabytesUnit { - get { - return ResourceManager.GetString("ByteSize_GigabytesUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to KB. - /// - public static string ByteSize_KilobytesUnit { - get { - return ResourceManager.GetString("ByteSize_KilobytesUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MB. - /// - public static string ByteSize_MegabytesUnit { - get { - return ResourceManager.GetString("ByteSize_MegabytesUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to B/s. - /// - public static string BytesRate_BytesPerSecondUnit { - get { - return ResourceManager.GetString("BytesRate_BytesPerSecondUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to GB/s. - /// - public static string BytesRate_GigaBytesPerSecondUnit { - get { - return ResourceManager.GetString("BytesRate_GigaBytesPerSecondUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to KB/s. - /// - public static string BytesRate_KiloBytesPerSecondUnit { - get { - return ResourceManager.GetString("BytesRate_KiloBytesPerSecondUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MB/s. - /// - public static string BytesRate_MegaBytesPerSecondUnit { - get { - return ResourceManager.GetString("BytesRate_MegaBytesPerSecondUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to N/A. - /// - public static string Common_NotAvailable { - get { - return ResourceManager.GetString("Common_NotAvailable", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The rate at which the HEARTBEAT message must be transmitted to announce the existence of the system on the MAVLink network. - /// - public static string ConnectionsIdentificationView_HeartbeatRate_Description { - get { - return ResourceManager.GetString("ConnectionsIdentificationView_HeartbeatRate_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Heartbeat rate. - /// - public static string ConnectionsIdentificationView_HeartbeatRate_Header { - get { - return ResourceManager.GetString("ConnectionsIdentificationView_HeartbeatRate_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to After that timeout of Heartbeat packet deviceService will be removed from deviceService list. - /// - public static string ConnectionsIdentificationView_HeartbeatTimeout_Description { - get { - return ResourceManager.GetString("ConnectionsIdentificationView_HeartbeatTimeout_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Heartbeat timeout. - /// - public static string ConnectionsIdentificationView_HeartbeatTimeout_Header { - get { - return ResourceManager.GetString("ConnectionsIdentificationView_HeartbeatTimeout_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Each system has a network-unique system id, and each component has a system-unique component id that can be used for addressing/routing. - /// - public static string ConnectionsIdentificationView_SystemComponentId_Description { - get { - return ResourceManager.GetString("ConnectionsIdentificationView_SystemComponentId_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to System \ Component ID. - /// - public static string ConnectionsIdentificationView_SystemComponentId_Header { - get { - return ResourceManager.GetString("ConnectionsIdentificationView_SystemComponentId_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Timeout must be from {0} to {1}. - /// - public static string ConnectionsIdentificationViewModel_DeviceTimeout { - get { - return ResourceManager.GetString("ConnectionsIdentificationViewModel_DeviceTimeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Hz. - /// - public static string ConnectionsIdentificationViewModel_ToString { - get { - return ResourceManager.GetString("ConnectionsIdentificationViewModel_ToString", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add Serial. - /// - public static string ConnectionsPortsView_AddSerialCommand_Title { - get { - return ResourceManager.GetString("ConnectionsPortsView_AddSerialCommand_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add TCP. - /// - public static string ConnectionsPortsView_AddTcpCommand_Title { - get { - return ResourceManager.GetString("ConnectionsPortsView_AddTcpCommand_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add UDP. - /// - public static string ConnectionsPortsView_AddUdpCommand_Title { - get { - return ResourceManager.GetString("ConnectionsPortsView_AddUdpCommand_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Point of entry that allows it to communicate with other devices in Mavlink network.. - /// - public static string ConnectionsPortsView_Header_Description { - get { - return ResourceManager.GetString("ConnectionsPortsView_Header_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connections ports. - /// - public static string ConnectionsPortsView_Header_Title { - get { - return ResourceManager.GetString("ConnectionsPortsView_Header_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connections. - /// - public static string ConnectionsShellMenuItem_Name { - get { - return ResourceManager.GetString("ConnectionsShellMenuItem_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This page allows you to configure the basic settings on the Mavlink network. - /// - public static string ConnectionsView_Header_Description { - get { - return ResourceManager.GetString("ConnectionsView_Header_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Mavlink network. - /// - public static string ConnectionsView_Header_Title { - get { - return ResourceManager.GetString("ConnectionsView_Header_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add. - /// - public static string ConnectionsViewModel_AddDialogPort_Add { - get { - return ResourceManager.GetString("ConnectionsViewModel_AddDialogPort_Add", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string ConnectionsViewModel_AddDialogPort_Cancel { - get { - return ResourceManager.GetString("ConnectionsViewModel_AddDialogPort_Cancel", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add new Mavlink serial port. - /// - public static string ConnectionsViewModel_AddSerialPortDialog_Title { - get { - return ResourceManager.GetString("ConnectionsViewModel_AddSerialPortDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add new Mavlink TCP port. - /// - public static string ConnectionsViewModel_AddTcpPortDialog_Title { - get { - return ResourceManager.GetString("ConnectionsViewModel_AddTcpPortDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add new Mavlink UDP port. - /// - public static string ConnectionsViewModel_AddUdpPortDialog_Title { - get { - return ResourceManager.GetString("ConnectionsViewModel_AddUdpPortDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accept. - /// - public static string ConnectionsViewModel_EditDialogPort_Accept { - get { - return ResourceManager.GetString("ConnectionsViewModel_EditDialogPort_Accept", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string ConnectionsViewModel_EditDialogPort_Cancel { - get { - return ResourceManager.GetString("ConnectionsViewModel_EditDialogPort_Cancel", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Edit selected Mavlink serial port. - /// - public static string ConnectionsViewModel_EditSerialPortDialog_Title { - get { - return ResourceManager.GetString("ConnectionsViewModel_EditSerialPortDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Edit selected Mavlink TCP port. - /// - public static string ConnectionsViewModel_EditTcpPortDialog_Title { - get { - return ResourceManager.GetString("ConnectionsViewModel_EditTcpPortDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Edit selected Mavlink UDP port. - /// - public static string ConnectionsViewModel_EditUdpPortDialog_Title { - get { - return ResourceManager.GetString("ConnectionsViewModel_EditUdpPortDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Close. - /// - public static string CoordinatesCalculatorDialog_CloseButton { - get { - return ResourceManager.GetString("CoordinatesCalculatorDialog_CloseButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Coordinates calculator. - /// - public static string CoordinatesCalculatorDialog_Title { - get { - return ResourceManager.GetString("CoordinatesCalculatorDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to From altitude. - /// - public static string CoordinatesCalculatorView_FromAltitude { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_FromAltitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to From altitude units. - /// - public static string CoordinatesCalculatorView_FromAltUnit { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_FromAltUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to From latitude. - /// - public static string CoordinatesCalculatorView_FromLatitude { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_FromLatitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to From lat/long units. - /// - public static string CoordinatesCalculatorView_FromLatLonUnit { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_FromLatLonUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to From longitude. - /// - public static string CoordinatesCalculatorView_FromLongitude { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_FromLongitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to From standard. - /// - public static string CoordinatesCalculatorView_FromStandard { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_FromStandard", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to To altitude. - /// - public static string CoordinatesCalculatorView_ToAltitude { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_ToAltitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to To altitude units. - /// - public static string CoordinatesCalculatorView_ToAltUnit { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_ToAltUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to To latitude. - /// - public static string CoordinatesCalculatorView_ToLatitude { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_ToLatitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to To lat/long units. - /// - public static string CoordinatesCalculatorView_ToLatLonUnit { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_ToLatLonUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to To longitude. - /// - public static string CoordinatesCalculatorView_ToLongitude { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_ToLongitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to To standard. - /// - public static string CoordinatesCalculatorView_ToStandard { - get { - return ResourceManager.GetString("CoordinatesCalculatorView_ToStandard", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In parts. - /// - public static string Ddm_InParts_Title { - get { - return ResourceManager.GetString("Ddm_InParts_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Microamp. - /// - public static string Ddm_Microamp_Title { - get { - return ResourceManager.GetString("Ddm_Microamp_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Microamp (Rus). - /// - public static string Ddm_MicroampRus_Title { - get { - return ResourceManager.GetString("Ddm_MicroampRus_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Percent. - /// - public static string Ddm_Percent_Title { - get { - return ResourceManager.GetString("Ddm_Percent_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to µA. - /// - public static string Ddm_µA_Unit { - get { - return ResourceManager.GetString("Ddm_µA_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Difference depth of modulation measure units. - /// - public static string DdmGp_Description { - get { - return ResourceManager.GetString("DdmGp_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to DDM (Gp). - /// - public static string DdmGp_Title { - get { - return ResourceManager.GetString("DdmGp_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Difference depth of modulation measure units. - /// - public static string DdmLlz_Description { - get { - return ResourceManager.GetString("DdmLlz_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to DDM (Llz). - /// - public static string DdmLlz_Title { - get { - return ResourceManager.GetString("DdmLlz_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [D]°. - /// - public static string Degrees_Degree_Title { - get { - return ResourceManager.GetString("Degrees_Degree_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Angle measure units. - /// - public static string Degrees_Description { - get { - return ResourceManager.GetString("Degrees_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [D]°[M]′. - /// - public static string Degrees_DM_Title { - get { - return ResourceManager.GetString("Degrees_DM_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [D]°[M]′[S]′′. - /// - public static string Degrees_DMS_Title { - get { - return ResourceManager.GetString("Degrees_DMS_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Angle. - /// - public static string Degrees_Title { - get { - return ResourceManager.GetString("Degrees_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In this section you can see all found devices on the network. - /// - public static string DeviceBrowserView_Description { - get { - return ResourceManager.GetString("DeviceBrowserView_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Device list. - /// - public static string DeviceBrowserView_Header { - get { - return ResourceManager.GetString("DeviceBrowserView_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Distance measure units. - /// - public static string Distance_Description { - get { - return ResourceManager.GetString("Distance_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Meters. - /// - public static string Distance_Meters_Title { - get { - return ResourceManager.GetString("Distance_Meters_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to m. - /// - public static string Distance_Meters_Unit { - get { - return ResourceManager.GetString("Distance_Meters_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Nautical miles. - /// - public static string Distance_NauticalMiles_Title { - get { - return ResourceManager.GetString("Distance_NauticalMiles_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to NM. - /// - public static string Distance_NauticalMiles_Unit { - get { - return ResourceManager.GetString("Distance_NauticalMiles_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Distance. - /// - public static string Distance_Title { - get { - return ResourceManager.GetString("Distance_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Field strength measure units. - /// - public static string FieldStrength_Description { - get { - return ResourceManager.GetString("FieldStrength_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to µV/m. - /// - public static string FieldStrength_MicroVoltsPerMeter_Unit { - get { - return ResourceManager.GetString("FieldStrength_MicroVoltsPerMeter_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Field strength. - /// - public static string FieldStrength_Title { - get { - return ResourceManager.GetString("FieldStrength_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Flight mode. - /// - public static string FlightShellMenuItem_Name { - get { - return ResourceManager.GetString("FlightShellMenuItem_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Frequency measure units. - /// - public static string Frequency_Description { - get { - return ResourceManager.GetString("Frequency_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Gigahertz. - /// - public static string Frequency_Gigahertz_Title { - get { - return ResourceManager.GetString("Frequency_Gigahertz_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to GHz. - /// - public static string Frequency_Gigahertz_Unit { - get { - return ResourceManager.GetString("Frequency_Gigahertz_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Hertz. - /// - public static string Frequency_Hertz_Title { - get { - return ResourceManager.GetString("Frequency_Hertz_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Hz. - /// - public static string Frequency_Hertz_Unit { - get { - return ResourceManager.GetString("Frequency_Hertz_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Kilohertz. - /// - public static string Frequency_Kilohertz_Title { - get { - return ResourceManager.GetString("Frequency_Kilohertz_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to kHz. - /// - public static string Frequency_Kilohertz_Unit { - get { - return ResourceManager.GetString("Frequency_Kilohertz_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Megahertz. - /// - public static string Frequency_Megahertz_Title { - get { - return ResourceManager.GetString("Frequency_Megahertz_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MHz. - /// - public static string Frequency_Megahertz_Unit { - get { - return ResourceManager.GetString("Frequency_Megahertz_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Frequency. - /// - public static string Frequency_Title { - get { - return ResourceManager.GetString("Frequency_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Open store file. - /// - public static string GlobalCommands_OpenStoreDialogTitle { - get { - return ResourceManager.GetString("GlobalCommands_OpenStoreDialogTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Anchors. - /// - public static string HeaderAnchorsMenu_Title { - get { - return ResourceManager.GetString("HeaderAnchorsMenu_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Coordinates calculator. - /// - public static string HeaderCoordinatesCalculatorMenu_Header { - get { - return ResourceManager.GetString("HeaderCoordinatesCalculatorMenu_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete. - /// - public static string HeaderPlaningFileDeleteMenuItem_Title { - get { - return ResourceManager.GetString("HeaderPlaningFileDeleteMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Download. - /// - public static string HeaderPlaningFileDownloadMenuItem_Title { - get { - return ResourceManager.GetString("HeaderPlaningFileDownloadMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to File. - /// - public static string HeaderPlaningFileMenuItem_Title { - get { - return ResourceManager.GetString("HeaderPlaningFileMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Open. - /// - public static string HeaderPlaningFileOpenMenuItem_Title { - get { - return ResourceManager.GetString("HeaderPlaningFileOpenMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save. - /// - public static string HeaderPlaningFileSaveMenuItem_Title { - get { - return ResourceManager.GetString("HeaderPlaningFileSaveMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Upload. - /// - public static string HeaderPlaningFileUploadMenuItem_Title { - get { - return ResourceManager.GetString("HeaderPlaningFileUploadMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Templater. - /// - public static string HeaderTemplaterMenu_Header { - get { - return ResourceManager.GetString("HeaderTemplaterMenu_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tools. - /// - public static string HeaderToolsMenu_Header { - get { - return ResourceManager.GetString("HeaderToolsMenu_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string HierarchicalStoreView_TextBlock_Text_Cancel { - get { - return ResourceManager.GetString("HierarchicalStoreView_TextBlock_Text_Cancel", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move Folder. - /// - public static string HierarchicalStoreView_TextBlock_Text_MoveFolder { - get { - return ResourceManager.GetString("HierarchicalStoreView_TextBlock_Text_MoveFolder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move Here. - /// - public static string HierarchicalStoreView_TextBlock_Text_MoveHere { - get { - return ResourceManager.GetString("HierarchicalStoreView_TextBlock_Text_MoveHere", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search. - /// - public static string HierarhicalStoreView_Search_Textbox_Watermark { - get { - return ResourceManager.GetString("HierarhicalStoreView_Search_Textbox_Watermark", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to GHz. - /// - public static string ItemsRate_GigaHerzUnit { - get { - return ResourceManager.GetString("ItemsRate_GigaHerzUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Hz. - /// - public static string ItemsRate_HerzUnit { - get { - return ResourceManager.GetString("ItemsRate_HerzUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete. - /// - public static string HierarchicalStoreView_Button_DeleteFile { - get { - return ResourceManager.GetString("HierarchicalStoreView_Button_DeleteFile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Rename. - /// - public static string HierarchicalStoreView_Button_EditFileName { - get { - return ResourceManager.GetString("HierarchicalStoreView_Button_EditFileName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move To Folder. - /// - public static string HierarchicalStoreView_Button_MovefileToFolder { - get { - return ResourceManager.GetString("HierarchicalStoreView_Button_MovefileToFolder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create New File. - /// - public static string HierarchicalStoreView_Button_ToolTip_CreateNewFile { - get { - return ResourceManager.GetString("HierarchicalStoreView_Button_ToolTip_CreateNewFile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create New Folder. - /// - public static string HierarchicalStoreView_Button_ToolTip_CreateNewFolder { - get { - return ResourceManager.GetString("HierarchicalStoreView_Button_ToolTip_CreateNewFolder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Refresh . - /// - public static string HierarchicalStoreView_Button_ToolTip_Refresh { - get { - return ResourceManager.GetString("HierarchicalStoreView_Button_ToolTip_Refresh", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete File. - /// - public static string HierarchicalStoreView_File_Button_DeleteFile { - get { - return ResourceManager.GetString("HierarchicalStoreView_File_Button_DeleteFile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Rename File. - /// - public static string HierarchicalStoreView_File_Button_EditeFileName { - get { - return ResourceManager.GetString("HierarchicalStoreView_File_Button_EditeFileName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move File. - /// - public static string HierarchicalStoreView_File_Button_MoveFile { - get { - return ResourceManager.GetString("HierarchicalStoreView_File_Button_MoveFile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete Folder. - /// - public static string HierarchicalStoreView_Folder_Button_DeleteFolder { - get { - return ResourceManager.GetString("HierarchicalStoreView_Folder_Button_DeleteFolder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Rename Folder. - /// - public static string HierarchicalStoreView_Folder_Button_EditFolderName { - get { - return ResourceManager.GetString("HierarchicalStoreView_Folder_Button_EditFolderName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move Folder. - /// - public static string HierarchicalStoreView_Folder_Button_MoveFolderToFolder { - get { - return ResourceManager.GetString("HierarchicalStoreView_Folder_Button_MoveFolderToFolder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to KHz. - /// - public static string ItemsRate_KiloHerzUnit { - get { - return ResourceManager.GetString("ItemsRate_KiloHerzUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MHz. - /// - public static string ItemsRate_MegaHerzUnit { - get { - return ResourceManager.GetString("ItemsRate_MegaHerzUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [D]°. - /// - public static string Latitude_Degree_Title { - get { - return ResourceManager.GetString("Latitude_Degree_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Latitude measure units. - /// - public static string Latitude_Description { - get { - return ResourceManager.GetString("Latitude_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [D]°[M]′[S]′′. - /// - public static string Latitude_DMS_Title { - get { - return ResourceManager.GetString("Latitude_DMS_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Latitude. - /// - public static string Latitude_Title { - get { - return ResourceManager.GetString("Latitude_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Clear. - /// - public static string LoggerView_Clear_Name { - get { - return ResourceManager.GetString("LoggerView_Clear_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error. - /// - public static string LoggerView_ErrorFilter_Name { - get { - return ResourceManager.GetString("LoggerView_ErrorFilter_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Info. - /// - public static string LoggerView_InfoFilter_Name { - get { - return ResourceManager.GetString("LoggerView_InfoFilter_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Trace. - /// - public static string LoggerView_TraceFilter_Name { - get { - return ResourceManager.GetString("LoggerView_TraceFilter_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Warning. - /// - public static string LoggerView_WarningFilter_Name { - get { - return ResourceManager.GetString("LoggerView_WarningFilter_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to by . - /// - public static string LogMessagesPageView_By { - get { - return ResourceManager.GetString("LogMessagesPageView_By", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Number of elements on one page . - /// - public static string LogMessagesPageView_By_ToolTip { - get { - return ResourceManager.GetString("LogMessagesPageView_By_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Clear all logs. - /// - public static string LogMessagesPageView_ClearAllButton_ToolTip { - get { - return ResourceManager.GetString("LogMessagesPageView_ClearAllButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Filtered: {0}. - /// - public static string LogMessagesPageView_Filtered { - get { - return ResourceManager.GetString("LogMessagesPageView_Filtered", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to From {0}. - /// - public static string LogMessagesPageView_From { - get { - return ResourceManager.GetString("LogMessagesPageView_From", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to next page. - /// - public static string LogMessagesPageView_NextButton_ToolTip { - get { - return ResourceManager.GetString("LogMessagesPageView_NextButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to previous page. - /// - public static string LogMessagesPageView_PrevButton_ToolTip { - get { - return ResourceManager.GetString("LogMessagesPageView_PrevButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Refresh all elements. - /// - public static string LogMessagesPageView_RefreshButton_ToolTip { - get { - return ResourceManager.GetString("LogMessagesPageView_RefreshButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search. - /// - public static string LogMessagesPageView_SearchWatermark { - get { - return ResourceManager.GetString("LogMessagesPageView_SearchWatermark", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to to {0}. - /// - public static string LogMessagesPageView_To { - get { - return ResourceManager.GetString("LogMessagesPageView_To", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Total: {0}. - /// - public static string LogMessagesPageView_Total { - get { - return ResourceManager.GetString("LogMessagesPageView_Total", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Clear all log messages. - /// - public static string LogMessagesPageViewModel_ClearAllMessage { - get { - return ResourceManager.GetString("LogMessagesPageViewModel_ClearAllMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to LogMessages. - /// - public static string LogMessagesPageViewModel_LogName { - get { - return ResourceManager.GetString("LogMessagesPageViewModel_LogName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error to refresh items. - /// - public static string LogMessagesPageViewModel_RefreshErrorMessage { - get { - return ResourceManager.GetString("LogMessagesPageViewModel_RefreshErrorMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Log messages. - /// - public static string LogMessagesShellMenuItem_Name { - get { - return ResourceManager.GetString("LogMessagesShellMenuItem_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error. - /// - public static string LogMessageTypeHelper_GetDisplayName_Error { - get { - return ResourceManager.GetString("LogMessageTypeHelper_GetDisplayName_Error", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Info. - /// - public static string LogMessageTypeHelper_GetDisplayName_Info { - get { - return ResourceManager.GetString("LogMessageTypeHelper_GetDisplayName_Info", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Warning. - /// - public static string LogMessageTypeHelper_GetDisplayName_Warning { - get { - return ResourceManager.GetString("LogMessageTypeHelper_GetDisplayName_Warning", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [D]°. - /// - public static string Longitude_Degree_Title { - get { - return ResourceManager.GetString("Longitude_Degree_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Longitude measure units. - /// - public static string Longitude_Description { - get { - return ResourceManager.GetString("Longitude_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [D]°[M]′[S]′′. - /// - public static string Longitude_DMS_Title { - get { - return ResourceManager.GetString("Longitude_DMS_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Longitude. - /// - public static string Longitude_Title { - get { - return ResourceManager.GetString("Longitude_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select ruler starting point. - /// - public static string MapPageViewModel_RulerStartPoint_Description { - get { - return ResourceManager.GetString("MapPageViewModel_RulerStartPoint_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select ruler end point. - /// - public static string MapPageViewModel_RulerStopPoint_Description { - get { - return ResourceManager.GetString("MapPageViewModel_RulerStopPoint_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change current map provider for application. - /// - public static string MapSettingsView_MapProvider_Description { - get { - return ResourceManager.GetString("MapSettingsView_MapProvider_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Map Provider. - /// - public static string MapSettingsView_MapProvider_Header { - get { - return ResourceManager.GetString("MapSettingsView_MapProvider_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change current map settings. - /// - public static string MapSettingsView_MapSettings_Description { - get { - return ResourceManager.GetString("MapSettingsView_MapSettings_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Map settings. - /// - public static string MapSettingsView_MapSettings_Header { - get { - return ResourceManager.GetString("MapSettingsView_MapSettings_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Clear storage. - /// - public static string MapSettingsView_MapsInfo_ButtonTitle { - get { - return ResourceManager.GetString("MapSettingsView_MapsInfo_ButtonTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Current map storage is located at {0} and has a size of {1}. - /// - public static string MapSettingsView_MapsInfo_Description { - get { - return ResourceManager.GetString("MapSettingsView_MapsInfo_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Map storage. - /// - public static string MapSettingsView_MapsInfo_Header { - get { - return ResourceManager.GetString("MapSettingsView_MapsInfo_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Maps. - /// - public static string MapSettingsViewModel_MapDialogTitle { - get { - return ResourceManager.GetString("MapSettingsViewModel_MapDialogTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Custom mode. - /// - public static string MavlinkDeviceView_Mode_Name { - get { - return ResourceManager.GetString("MavlinkDeviceView_Mode_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Heartbeat rate. - /// - public static string MavlinkDeviceView_Rate_Name { - get { - return ResourceManager.GetString("MavlinkDeviceView_Rate_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to System status. - /// - public static string MavlinkDeviceView_Status_Name { - get { - return ResourceManager.GetString("MavlinkDeviceView_Status_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Fixed wing. - /// - public static string MavlinkHelper_GetTypeName_FixedWing { - get { - return ResourceManager.GetString("MavlinkHelper_GetTypeName_FixedWing", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Helicopter. - /// - public static string MavlinkHelper_GetTypeName_Helicopter { - get { - return ResourceManager.GetString("MavlinkHelper_GetTypeName_Helicopter", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Hexarotor. - /// - public static string MavlinkHelper_GetTypeName_HexaRotor { - get { - return ResourceManager.GetString("MavlinkHelper_GetTypeName_HexaRotor", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Octorotor. - /// - public static string MavlinkHelper_GetTypeName_OctoRotor { - get { - return ResourceManager.GetString("MavlinkHelper_GetTypeName_OctoRotor", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Quadrotor. - /// - public static string MavlinkHelper_GetTypeName_QuadRotor { - get { - return ResourceManager.GetString("MavlinkHelper_GetTypeName_QuadRotor", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tricopter. - /// - public static string MavlinkHelper_GetTypeName_TriCopter { - get { - return ResourceManager.GetString("MavlinkHelper_GetTypeName_TriCopter", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unknown type. - /// - public static string MavlinkHelper_GetTypeName_UnknownType { - get { - return ResourceManager.GetString("MavlinkHelper_GetTypeName_UnknownType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value must be a number. - /// - public static string MeasureUnitBase_ErrorMessage_NotANumber { - get { - return ResourceManager.GetString("MeasureUnitBase_ErrorMessage_NotANumber", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value can't be null or white space. - /// - public static string MeasureUnitBase_ErrorMessage_NullOrWhiteSpace { - get { - return ResourceManager.GetString("MeasureUnitBase_ErrorMessage_NullOrWhiteSpace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value must be greater than {0} ({1}). - /// - public static string MeasureUnitExtensions_ErrorMessage_GreaterValue { - get { - return ResourceManager.GetString("MeasureUnitExtensions_ErrorMessage_GreaterValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value must be less than {0} ({1}). - /// - public static string MeasureUnitExtensions_ErrorMessage_LesserValue { - get { - return ResourceManager.GetString("MeasureUnitExtensions_ErrorMessage_LesserValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Altitude. - /// - public static string MeasureUnitsSettingsViewModel_Altitude { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_Altitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of altitude.. - /// - public static string MeasureUnitsSettingsViewModel_AltitudeDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_AltitudeDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to DDM Llz. - /// - public static string MeasureUnitsSettingsViewModel_DdmLlz { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_DdmLlz", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of DDM Llz.. - /// - public static string MeasureUnitsSettingsViewModel_DdmLlzDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_DdmLlzDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Distance. - /// - public static string MeasureUnitsSettingsViewModel_Distance { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_Distance", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of distance.. - /// - public static string MeasureUnitsSettingsViewModel_DistanceDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_DistanceDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Nautical miles. - /// - public static string MeasureUnitsSettingsViewModel_DistanceInternationalNauticalMiles { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_DistanceInternationalNauticalMiles", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Meters. - /// - public static string MeasureUnitsSettingsViewModel_DistanceMeters { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_DistanceMeters", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Latitude. - /// - public static string MeasureUnitsSettingsViewModel_Latitude { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_Latitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of latitude & longitude.. - /// - public static string MeasureUnitsSettingsViewModel_LatitudeLongitudeDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_LatitudeLongitudeDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Degrees. - /// - public static string MeasureUnitsSettingsViewModel_LatitudeLongtitudeDegrees { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_LatitudeLongtitudeDegrees", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Degrees, minutes, seconds. - /// - public static string MeasureUnitsSettingsViewModel_LatitudeLongtitudeDegreesMinutesSeconds { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_LatitudeLongtitudeDegreesMinutesSeconds", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Longitude. - /// - public static string MeasureUnitsSettingsViewModel_Longitude { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_Longitude", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In this section you can specialize measurement units for various parameters.. - /// - public static string MeasureUnitsSettingsViewModel_MeasurementUnits_Header_Description { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_MeasurementUnits_Header_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Measurement units. - /// - public static string MeasureUnitsSettingsViewModel_MeasurementUnits_Header_Title { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_MeasurementUnits_Header_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Velocity. - /// - public static string MeasureUnitsSettingsViewModel_Velocity { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_Velocity", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of velocity.. - /// - public static string MeasureUnitsSettingsViewModel_VelocityDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModel_VelocityDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Angle. - /// - public static string MeasureUnitsSettingsViewModelAngle { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModelAngle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of angle.. - /// - public static string MeasureUnitsSettingsViewModelAngleDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModelAngleDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Bearing. - /// - public static string MeasureUnitsSettingsViewModelBearing { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModelBearing", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of bearing.. - /// - public static string MeasureUnitsSettingsViewModelBearingDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModelBearingDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to DDM GP. - /// - public static string MeasureUnitsSettingsViewModelDdmGp { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModelDdmGp", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of DDM GP. - /// - public static string MeasureUnitsSettingsViewModelDdmGpDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModelDdmGpDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Temperature. - /// - public static string MeasureUnitsSettingsViewModelTemperature { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModelTemperature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current measure units of temperature.. - /// - public static string MeasureUnitsSettingsViewModelTemperatureDescription { - get { - return ResourceManager.GetString("MeasureUnitsSettingsViewModelTemperatureDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Mission points. - /// - public static string MissionEditorView_Points_Title { - get { - return ResourceManager.GetString("MissionEditorView_Points_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Message sources. - /// - public static string PacketViewer_Expander_MessageSources { - get { - return ResourceManager.GetString("PacketViewer_Expander_MessageSources", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Message types. - /// - public static string PacketViewer_Expander_MessageTypes { - get { - return ResourceManager.GetString("PacketViewer_Expander_MessageTypes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Packet Viewer. - /// - public static string PacketViewerShellMenuItem_Name { - get { - return ResourceManager.GetString("PacketViewerShellMenuItem_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Check/Uncheck All. - /// - public static string PacketViewerView_CheckAll { - get { - return ResourceManager.GetString("PacketViewerView_CheckAll", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Clear all packets. - /// - public static string PacketViewerView_ClearAll { - get { - return ResourceManager.GetString("PacketViewerView_ClearAll", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Play/Pause. - /// - public static string PacketViewerView_PlayPause { - get { - return ResourceManager.GetString("PacketViewerView_PlayPause", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save as CSV. - /// - public static string PacketViewerView_Save { - get { - return ResourceManager.GetString("PacketViewerView_Save", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Packet Viewer. - /// - public static string PacketViewerViewDockPanelText { - get { - return ResourceManager.GetString("PacketViewerViewDockPanelText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Coma [ , ]. - /// - public static string PacketViewerViewModel_SeparatorDialog_Coma { - get { - return ResourceManager.GetString("PacketViewerViewModel_SeparatorDialog_Coma", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select. - /// - public static string PacketViewerViewModel_SeparatorDialog_DialogPrimaryButton { - get { - return ResourceManager.GetString("PacketViewerViewModel_SeparatorDialog_DialogPrimaryButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string PacketViewerViewModel_SeparatorDialog_DialogSecondaryButton { - get { - return ResourceManager.GetString("PacketViewerViewModel_SeparatorDialog_DialogSecondaryButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Semicolon [ ; ]. - /// - public static string PacketViewerViewModel_SeparatorDialog_Semicolon { - get { - return ResourceManager.GetString("PacketViewerViewModel_SeparatorDialog_Semicolon", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Horizontal tabulation [ Tab ]. - /// - public static string PacketViewerViewModel_SeparatorDialog_Tab { - get { - return ResourceManager.GetString("PacketViewerViewModel_SeparatorDialog_Tab", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select the separator. - /// - public static string PacketViewerViewModel_SeparatorDialog_Title { - get { - return ResourceManager.GetString("PacketViewerViewModel_SeparatorDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remove all pinned parameters. - /// - public static string ParametersEditorPageView_PinsOffButton_ToolTip { - get { - return ResourceManager.GetString("ParametersEditorPageView_PinsOffButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Star this parameter. - /// - public static string ParametersEditorPageView_StarButton_ToolTip { - get { - return ResourceManager.GetString("ParametersEditorPageView_StarButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show only starred parameters. - /// - public static string ParametersEditorPageView_StarsToggleButton_ToolTip { - get { - return ResourceManager.GetString("ParametersEditorPageView_StarsToggleButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Update all parameters. - /// - public static string ParametersEditorPageView_UpdateButton_ToolTip { - get { - return ResourceManager.GetString("ParametersEditorPageView_UpdateButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Loaded: {0}. - /// - public static string ParametersEditorPageViewModel_Loaded { - get { - return ResourceManager.GetString("ParametersEditorPageViewModel_Loaded", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search. - /// - public static string ParametersEditorPageViewModel_Search { - get { - return ResourceManager.GetString("ParametersEditorPageViewModel_Search", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Parameters editor [{0}]. - /// - public static string ParametersEditorPageViewModel_Title { - get { - return ResourceManager.GetString("ParametersEditorPageViewModel_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Total: {0}. - /// - public static string ParametersEditorPageViewModel_Total { - get { - return ResourceManager.GetString("ParametersEditorPageViewModel_Total", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to On/off pin for this parameter. - /// - public static string ParametersEditorParameterView_PinToggleButton_ToolTip { - get { - return ResourceManager.GetString("ParametersEditorParameterView_PinToggleButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Reboot required. - /// - public static string ParametersEditorParameterView_RebootRequired { - get { - return ResourceManager.GetString("ParametersEditorParameterView_RebootRequired", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Update. - /// - public static string ParametersEditorParameterView_UpdateButton { - get { - return ResourceManager.GetString("ParametersEditorParameterView_UpdateButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Update this parameter from UAV. - /// - public static string ParametersEditorParameterView_UpdateButton_ToolTip { - get { - return ResourceManager.GetString("ParametersEditorParameterView_UpdateButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Write. - /// - public static string ParametersEditorParameterView_WriteButton { - get { - return ResourceManager.GetString("ParametersEditorParameterView_WriteButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Write this parameter to UAV. - /// - public static string ParametersEditorParameterView_WriteButton_ToolTip { - get { - return ResourceManager.GetString("ParametersEditorParameterView_WriteButton_ToolTip", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string ParamPageViewModel_DataLossDialog_CloseButtonText { - get { - return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_CloseButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You're trying to open another menu folder, but you have unsaved changes in the current one. Do you want to save them?. - /// - public static string ParamPageViewModel_DataLossDialog_Content { - get { - return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_Content", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save. - /// - public static string ParamPageViewModel_DataLossDialog_PrimaryButtonText { - get { - return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_PrimaryButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Don't save. - /// - public static string ParamPageViewModel_DataLossDialog_SecondaryButtonText { - get { - return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_SecondaryButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Potential data loss warning. - /// - public static string ParamPageViewModel_DataLossDialog_Title { - get { - return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Degrees. - /// - public static string Phase_Degree_Title { - get { - return ResourceManager.GetString("Phase_Degree_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Phase measure units. - /// - public static string Phase_Description { - get { - return ResourceManager.GetString("Phase_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Radian. - /// - public static string Phase_Radian_Title { - get { - return ResourceManager.GetString("Phase_Radian_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Rad. - /// - public static string Phase_Radian_Unit { - get { - return ResourceManager.GetString("Phase_Radian_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Phase. - /// - public static string Phase_Title { - get { - return ResourceManager.GetString("Phase_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add. - /// - public static string PlaningMissionEditorViewModel_AddPointFlyoutMenuItem_Title { - get { - return ResourceManager.GetString("PlaningMissionEditorViewModel_AddPointFlyoutMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Do land. - /// - public static string PlaningMissionEditorViewModel_DoLandMenuItem_Title { - get { - return ResourceManager.GetString("PlaningMissionEditorViewModel_DoLandMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace. - /// - public static string PlaningMissionEditorViewModel_ReplacePointFlyoutMenuItem { - get { - return ResourceManager.GetString("PlaningMissionEditorViewModel_ReplacePointFlyoutMenuItem", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ROI. - /// - public static string PlaningMissionEditorViewModel_RoiMenuItem_Title { - get { - return ResourceManager.GetString("PlaningMissionEditorViewModel_RoiMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Take off. - /// - public static string PlaningMissionEditorViewModel_TakeOffMenuItem_Title { - get { - return ResourceManager.GetString("PlaningMissionEditorViewModel_TakeOffMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Waypoint. - /// - public static string PlaningMissionEditorViewModel_WaypointMenuItem_Title { - get { - return ResourceManager.GetString("PlaningMissionEditorViewModel_WaypointMenuItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Name must be not empty. - /// - public static string PlaningMissionViewModel_NameMustBeNotEmpty { - get { - return ResourceManager.GetString("PlaningMissionViewModel_NameMustBeNotEmpty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select target point location. - /// - public static string PlaningMissionViewModel_SelectTargetLocation { - get { - return ResourceManager.GetString("PlaningMissionViewModel_SelectTargetLocation", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string PlaningPageViewModel_DataLossDialog_CloseButtonText { - get { - return ResourceManager.GetString("PlaningPageViewModel_DataLossDialog_CloseButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You're trying to open another menu folder, but you have unsaved changes in the current one. Do you want to save them?. - /// - public static string PlaningPageViewModel_DataLossDialog_Content { - get { - return ResourceManager.GetString("PlaningPageViewModel_DataLossDialog_Content", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save. - /// - public static string PlaningPageViewModel_DataLossDialog_PrimaryButtonText { - get { - return ResourceManager.GetString("PlaningPageViewModel_DataLossDialog_PrimaryButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Don't save. - /// - public static string PlaningPageViewModel_DataLossDialog_SecondaryButtonText { - get { - return ResourceManager.GetString("PlaningPageViewModel_DataLossDialog_SecondaryButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Potential data loss warning. - /// - public static string PlaningPageViewModel_DataLossDialog_Title { - get { - return ResourceManager.GetString("PlaningPageViewModel_DataLossDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Mission planing. - /// - public static string PlaningShellMenuItem_Name { - get { - return ResourceManager.GetString("PlaningShellMenuItem_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Open. - /// - public static string PlanningPageViewModel_MissionBrowserDialog_PrimaryButton { - get { - return ResourceManager.GetString("PlanningPageViewModel_MissionBrowserDialog_PrimaryButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string PlanningPageViewModel_MissionBrowserDialog_SecondaryButton { - get { - return ResourceManager.GetString("PlanningPageViewModel_MissionBrowserDialog_SecondaryButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select mission file. - /// - public static string PlanningPageViewModel_MissionBrowserDialog_Title { - get { - return ResourceManager.GetString("PlanningPageViewModel_MissionBrowserDialog_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Mission uploaded!. - /// - public static string PlanningPageViewModel_MissionUploaded { - get { - return ResourceManager.GetString("PlanningPageViewModel_MissionUploaded", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Disabled. - /// - public static string PortView_ToggleButton_Disabled { - get { - return ResourceManager.GetString("PortView_ToggleButton_Disabled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enabled. - /// - public static string PortView_ToggleButton_Enabled { - get { - return ResourceManager.GetString("PortView_ToggleButton_Enabled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to error. - /// - public static string PortViewModel_SkippedUnitTest { - get { - return ResourceManager.GetString("PortViewModel_SkippedUnitTest", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Decibel to 1 milliwatt. - /// - public static string Power_Dbm_Title { - get { - return ResourceManager.GetString("Power_Dbm_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to dBm. - /// - public static string Power_Dbm_Unit { - get { - return ResourceManager.GetString("Power_Dbm_Unit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Power measure units. - /// - public static string Power_Description { - get { - return ResourceManager.GetString("Power_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Power. - /// - public static string Power_Title { - get { - return ResourceManager.GetString("Power_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ms. - /// - public static string RelativeTime_MillisecondsUnit { - get { - return ResourceManager.GetString("RelativeTime_MillisecondsUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to s. - /// - public static string RelativeTime_SecondsUnit { - get { - return ResourceManager.GetString("RelativeTime_SecondsUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accuracy. - /// - public static string RemoveMapPointView_Accuracy_Name { - get { - return ResourceManager.GetString("RemoveMapPointView_Accuracy_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Altitude. - /// - public static string RemoveMapPointView_Altitude_Name { - get { - return ResourceManager.GetString("RemoveMapPointView_Altitude_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Are you sure you want to delete this map point?. - /// - public static string RemoveMapPointView_ConfirmationText { - get { - return ResourceManager.GetString("RemoveMapPointView_ConfirmationText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Latitude. - /// - public static string RemoveMapPointView_Latitude_Name { - get { - return ResourceManager.GetString("RemoveMapPointView_Latitude_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Longitude. - /// - public static string RemoveMapPointView_Longitude_Name { - get { - return ResourceManager.GetString("RemoveMapPointView_Longitude_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Name. - /// - public static string RemoveMapPointView_Point_Name { - get { - return ResourceManager.GetString("RemoveMapPointView_Point_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add New. - /// - public static string SavedCoordsView_AddNewButton_Name { - get { - return ResourceManager.GetString("SavedCoordsView_AddNewButton_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to in this section you can view and save new map coordinates for GBS Fixed Mode. - /// - public static string SavedCoordsView_Description { - get { - return ResourceManager.GetString("SavedCoordsView_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Saved Coordinates. - /// - public static string SavedCoordsView_Header { - get { - return ResourceManager.GetString("SavedCoordsView_Header", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remove. - /// - public static string SavedCoordsView_RemoveButton_Name { - get { - return ResourceManager.GetString("SavedCoordsView_RemoveButton_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string SavedCoordsViewModel_AddNewItem_CloseButtonText { - get { - return ResourceManager.GetString("SavedCoordsViewModel_AddNewItem_CloseButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add. - /// - public static string SavedCoordsViewModel_AddNewItem_PrimaryButtonText { - get { - return ResourceManager.GetString("SavedCoordsViewModel_AddNewItem_PrimaryButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add new map coordinate. - /// - public static string SavedCoordsViewModel_AddNewItem_Title { - get { - return ResourceManager.GetString("SavedCoordsViewModel_AddNewItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string SavedCoordsViewModel_RemoveItem_CloseButtonText { - get { - return ResourceManager.GetString("SavedCoordsViewModel_RemoveItem_CloseButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remove. - /// - public static string SavedCoordsViewModel_RemoveItem_PrimaryButtonText { - get { - return ResourceManager.GetString("SavedCoordsViewModel_RemoveItem_PrimaryButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remove Map Point. - /// - public static string SavedCoordsViewModel_RemoveItem_Title { - get { - return ResourceManager.GetString("SavedCoordsViewModel_RemoveItem_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sum depth of modulation measure units. - /// - public static string Sdm_Description { - get { - return ResourceManager.GetString("Sdm_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SDM. - /// - public static string Sdm_Title { - get { - return ResourceManager.GetString("Sdm_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Baud rate. - /// - public static string SerialPortView_BaudRate { - get { - return ResourceManager.GetString("SerialPortView_BaudRate", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Port name. - /// - public static string SerialPortView_PortName { - get { - return ResourceManager.GetString("SerialPortView_PortName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Port title. - /// - public static string SerialPortView_Title { - get { - return ResourceManager.GetString("SerialPortView_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Baud rate must be value from {0} to {1}. - /// - public static string SerialPortViewModel_SerialPortViewModel_BaudRateValid { - get { - return ResourceManager.GetString("SerialPortViewModel_SerialPortViewModel_BaudRateValid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to New serial {0}. - /// - public static string SerialPortViewModel_SerialPortViewModel_NewSerial { - get { - return ResourceManager.GetString("SerialPortViewModel_SerialPortViewModel_NewSerial", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must specify a valid serial port name. - /// - public static string SerialPortViewModel_SerialPortViewModel_ValidSerialPort { - get { - return ResourceManager.GetString("SerialPortViewModel_SerialPortViewModel_ValidSerialPort", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must specify a valid name. - /// - public static string SerialPortViewModel_SerialPortViewModel_You_must_specify_a_valid_name { - get { - return ResourceManager.GetString("SerialPortViewModel_SerialPortViewModel_You_must_specify_a_valid_name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Settings. - /// - public static string SettingsShellMenuProvider_SettingsShellMenuProvider_Settings { - get { - return ResourceManager.GetString("SettingsShellMenuProvider_SettingsShellMenuProvider_Settings", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current application theme.. - /// - public static string SettingsThemeViewModel_ChangeThemeDescription { - get { - return ResourceManager.GetString("SettingsThemeViewModel_ChangeThemeDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Language. - /// - public static string SettingsThemeViewModel_CurrentLanguage { - get { - return ResourceManager.GetString("SettingsThemeViewModel_CurrentLanguage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current application language. The changes will be applied after a restart.. - /// - public static string SettingsThemeViewModel_CurrentLanguageDescription { - get { - return ResourceManager.GetString("SettingsThemeViewModel_CurrentLanguageDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Theme. - /// - public static string SettingsThemeViewModel_CurrentTheme { - get { - return ResourceManager.GetString("SettingsThemeViewModel_CurrentTheme", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Flow direction. - /// - public static string SettingsThemeViewModel_FlowDirection { - get { - return ResourceManager.GetString("SettingsThemeViewModel_FlowDirection", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change the current application flow direction.. - /// - public static string SettingsThemeViewModel_FlowDirectionDescription { - get { - return ResourceManager.GetString("SettingsThemeViewModel_FlowDirectionDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must reload the program to apply the changes.. - /// - public static string SettingsView_RebootRequiredDescription { - get { - return ResourceManager.GetString("SettingsView_RebootRequiredDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Reboot required. - /// - public static string SettingsView_RebootRequiredTitle { - get { - return ResourceManager.GetString("SettingsView_RebootRequiredTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Port title. - /// - public static string TcpPortView_PortTitle { - get { - return ResourceManager.GetString("TcpPortView_PortTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to IP address. - /// - public static string TcpPortView_TcpIpAddress { - get { - return ResourceManager.GetString("TcpPortView_TcpIpAddress", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Port number. - /// - public static string TcpPortView_TcpIpPort { - get { - return ResourceManager.GetString("TcpPortView_TcpIpPort", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error to create port. - /// - public static string TcpPortViewModel_LogService_Error { - get { - return ResourceManager.GetString("TcpPortViewModel_LogService_Error", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to New TCP. - /// - public static string TcpPortViewModel_Title { - get { - return ResourceManager.GetString("TcpPortViewModel_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must insert a valid ip address. - /// - public static string TcpPortViewModel_ValidIpAddress { - get { - return ResourceManager.GetString("TcpPortViewModel_ValidIpAddress", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Port number must be value from 1 to 65535. - /// - public static string TcpPortViewModel_ValidPort { - get { - return ResourceManager.GetString("TcpPortViewModel_ValidPort", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must specify a valid name. - /// - public static string TcpPortViewModel_ValidTitle { - get { - return ResourceManager.GetString("TcpPortViewModel_ValidTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Celsius. - /// - public static string Temperature_Celsius_Title { - get { - return ResourceManager.GetString("Temperature_Celsius_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Farenheit. - /// - public static string Temperature_Farenheit_Title { - get { - return ResourceManager.GetString("Temperature_Farenheit_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Kelvin. - /// - public static string Temperature_Kelvin_Title { - get { - return ResourceManager.GetString("Temperature_Kelvin_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value must be a number. - /// - public static string TemperatureCelsius_ErrorMessage_NaN { - get { - return ResourceManager.GetString("TemperatureCelsius_ErrorMessage_NaN", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value can't be null or white space. - /// - public static string TemperatureCelsius_ErrorMessage_NullOrWhiteSpace { - get { - return ResourceManager.GetString("TemperatureCelsius_ErrorMessage_NullOrWhiteSpace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value must be a number. - /// - public static string TemperatureFarenheit_ErrorMessage_NaN { - get { - return ResourceManager.GetString("TemperatureFarenheit_ErrorMessage_NaN", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value can't be null or white space. - /// - public static string TemperatureFarenheit_ErrorMessage_NullOrWhiteSpace { - get { - return ResourceManager.GetString("TemperatureFarenheit_ErrorMessage_NullOrWhiteSpace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Close. - /// - public static string TemplaterDialog_CloseButton { - get { - return ResourceManager.GetString("TemplaterDialog_CloseButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save. - /// - public static string TemplaterDialog_SaveButton { - get { - return ResourceManager.GetString("TemplaterDialog_SaveButton", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add image tag. - /// - public static string TemplaterView_AddImageTag { - get { - return ResourceManager.GetString("TemplaterView_AddImageTag", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add new tag. - /// - public static string TemplaterView_AddNewTag { - get { - return ResourceManager.GetString("TemplaterView_AddNewTag", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add string tag. - /// - public static string TemplaterView_AddStringTag { - get { - return ResourceManager.GetString("TemplaterView_AddStringTag", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Clear tags list. - /// - public static string TemplaterView_ClearTagsList { - get { - return ResourceManager.GetString("TemplaterView_ClearTagsList", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to File path:. - /// - public static string TemplaterView_ResultPath { - get { - return ResourceManager.GetString("TemplaterView_ResultPath", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Template path:. - /// - public static string TemplaterView_TemplatePath { - get { - return ResourceManager.GetString("TemplaterView_TemplatePath", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to LeftToRight. - /// - public static string ThemeService_FlowDirections_LeftToRight { - get { - return ResourceManager.GetString("ThemeService_FlowDirections_LeftToRight", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to RightToLeft. - /// - public static string ThemeService_FlowDirections_RightToLeft { - get { - return ResourceManager.GetString("ThemeService_FlowDirections_RightToLeft", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Contrast. - /// - public static string ThemeService_Themes_Contrast { - get { - return ResourceManager.GetString("ThemeService_Themes_Contrast", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Dark. - /// - public static string ThemeService_Themes_Dark { - get { - return ResourceManager.GetString("ThemeService_Themes_Dark", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Light. - /// - public static string ThemeService_Themes_Light { - get { - return ResourceManager.GetString("ThemeService_Themes_Light", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to IP Address. - /// - public static string UdpPortView_LocalIpAddress { - get { - return ResourceManager.GetString("UdpPortView_LocalIpAddress", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Port Number. - /// - public static string UdpPortView_LocalPortName { - get { - return ResourceManager.GetString("UdpPortView_LocalPortName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Title. - /// - public static string UdpPortView_PortTitle { - get { - return ResourceManager.GetString("UdpPortView_PortTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remote IP Address. - /// - public static string UdpPortView_RemoteIpAddress { - get { - return ResourceManager.GetString("UdpPortView_RemoteIpAddress", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remote port number. - /// - public static string UdpPortView_RemotePortName { - get { - return ResourceManager.GetString("UdpPortView_RemotePortName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Specify remote host. - /// - public static string UdpPortView_ToggleName { - get { - return ResourceManager.GetString("UdpPortView_ToggleName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to New UDP. - /// - public static string UdpPortViewModel_Title { - get { - return ResourceManager.GetString("UdpPortViewModel_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must enter a valid IP address. - /// - public static string UdpPortViewModel_ValidLocalIpAddress { - get { - return ResourceManager.GetString("UdpPortViewModel_ValidLocalIpAddress", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Port number must be a value between 1 and 65535. - /// - public static string UdpPortViewModel_ValidLocalPort { - get { - return ResourceManager.GetString("UdpPortViewModel_ValidLocalPort", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must enter a valid IP address. - /// - public static string UdpPortViewModel_ValidRemoteIpAddress { - get { - return ResourceManager.GetString("UdpPortViewModel_ValidRemoteIpAddress", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Port number must be a value between 1 and 65535. - /// - public static string UdpPortViewModel_ValidRemotePort { - get { - return ResourceManager.GetString("UdpPortViewModel_ValidRemotePort", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must specify a valid name. - /// - public static string UdpPortViewModel_ValidTitle { - get { - return ResourceManager.GetString("UdpPortViewModel_ValidTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Velocity measure units. - /// - public static string Velocity_Description { - get { - return ResourceManager.GetString("Velocity_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to km/h. - /// - public static string Velocity_KilometersPerHourUnit { - get { - return ResourceManager.GetString("Velocity_KilometersPerHourUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to m/s. - /// - public static string Velocity_MetersPerSecondUnit { - get { - return ResourceManager.GetString("Velocity_MetersPerSecondUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to mi/h. - /// - public static string Velocity_MilesPerHourUnit { - get { - return ResourceManager.GetString("Velocity_MilesPerHourUnit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Velocity. - /// - public static string Velocity_Title { - get { - return ResourceManager.GetString("Velocity_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to V. - /// - public static string Voltage_Unit { - get { - return ResourceManager.GetString("Voltage_Unit", resourceCulture); - } - } - } -} diff --git a/src/Asv.Drones.Gui.Core/RS.resx b/src/Asv.Drones.Gui.Core/RS.resx deleted file mode 100644 index c3c1a0e1..00000000 --- a/src/Asv.Drones.Gui.Core/RS.resx +++ /dev/null @@ -1,1225 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Settings - - - Flight mode - - - Contrast - - - Light - - - Dark - - - LeftToRight - - - RightToLeft - - - Theme - - - Change the current application theme. - - - Language - - - Change the current application language. The changes will be applied after a restart. - - - Flow direction - - - Change the current application flow direction. - - - Mission planing - - - B - - - KB - - - MB - - - GB - - - N/A - - - B/s - - - KB/s - - - MB/s - - - GB/s - - - Hz - - - KHz - - - MHz - - - GHz - - - - Reboot required - - - You must reload the program to apply the changes. - - - Distance - - - Change the current measure units of distance. - - - Altitude - - - Change the current measure units of altitude. - - - Latitude - - - Longitude - - - Change the current measure units of latitude & longitude. - - - Meters - - - Nautical miles - - - Meters - - - Feets - - - Degrees - - - Degrees, minutes, seconds - - - ft - - - m - - - m - - - NM - - - - m/s - - - km/h - - - mi/h - - - ms - - - s - - - Measurement units - - - In this section you can specialize measurement units for various parameters. - - - Velocity - - - Change the current measure units of velocity. - - - Tools - - - Coordinates calculator - - - Open store file - - - Change current map provider for application - - - Map Provider - - - Clear storage - - - Current map storage is located at {0} and has a size of {1} - - - Map storage - - - Maps - - - Meters - - - Nautical miles - - - Log messages - - - by - - - Search - - - From {0} - - - to {0} - - - Filtered: {0} - - - Total: {0} - - - LogMessages - - - Error to refresh items - - - Clear all log messages - - - You must specify a valid name - - - You must specify a valid serial port name - - - Baud rate must be value from {0} to {1} - - - New serial {0} - - - Port title - - - Port name - - - Baud rate - - - Connections - - - Add - - - Cancel - - - Add new Mavlink serial port - - - Add new Mavlink TCP port - - - Add new Mavlink UDP port - - - Enabled - - - Disabled - - - Add Serial - - - Add TCP - - - Add UDP - - - Connections ports - - - This page allows you to configure the basic settings on the Mavlink network - - - Mavlink network - - - Point of entry that allows it to communicate with other devices in Mavlink network. - - - In this section you can see all found devices on the network - - - Device list - - - The rate at which the HEARTBEAT message must be transmitted to announce the existence of the system on the MAVLink network - - - Heartbeat rate - - - After that timeout of Heartbeat packet deviceService will be removed from deviceService list - - - Heartbeat timeout - - - Each system has a network-unique system id, and each component has a system-unique component id that can be used for addressing/routing - - - System \ Component ID - - - Custom mode - - - Heartbeat rate - - - System status - - - IP address - - - Port title - - - Port number - - - IP Address - - - Port Number - - - Title - - - Remote IP Address - - - Remote port number - - - Specify remote host - - - Timeout must be from {0} to {1} - - - Hz - - - error - - - - New TCP - - - You must specify a valid name - - - Port number must be value from 1 to 65535 - - - You must insert a valid ip address - - - Error to create port - - - You must specify a valid name - - - You must enter a valid IP address - - - Port number must be a value between 1 and 65535 - - - Port number must be a value between 1 and 65535 - - - You must enter a valid IP address - - - New UDP - - - Packet Viewer - - - Info - - - Warning - - - Error - - - Check/Uncheck All - - - Play/Pause - - - Clear all packets - - - Save as CSV - - - V - - - Accept - - - Edit selected Mavlink serial port - - - Edit selected Mavlink TCP port - - - Edit selected Mavlink UDP port - - - Cancel - - - Number of elements on one page - - - Clear all logs - - - Move to previous page - - - Move to next page - - - Refresh all elements - - - Error - - - Info - - - Warning - - - Trace - - - Saved Coordinates - - - in this section you can view and save new map coordinates for GBS Fixed Mode - - - Add New - - - Remove - - - Add new map coordinate - - - Add - - - Cancel - - - Latitude - - - Longitude - - - Altitude - - - Accuracy - - - Remove Map Point - - - Remove - - - Cancel - - - Are you sure you want to delete this map point? - - - Name - - - Latitude - - - Longitude - - - Altitude - - - Accuracy - - - Name - - - Accuracy must be greater or equal {0}. - - - Name can not be empty - - - Clear - - - Select the separator - - - Select - - - Cancel - - - Coma [ , ] - - - Semicolon [ ; ] - - - Horizontal tabulation [ Tab ] - - - Select ruler starting point - - - Select ruler end point - - - In parts - - - Percent - - - Microamp - - - µA - - - Microamp (Rus) - - - DDM Llz - - - Change the current measure units of DDM Llz. - - - Decibel to 1 milliwatt - - - dBm - - - Percents - - - In parts - - - Hertz - - - Kilohertz - - - Megahertz - - - Gigahertz - - - Hz - - - kHz - - - MHz - - - GHz - - - Degrees - - - Radian - - - Rad - - - Map settings - - - Change current map settings - - - DDM GP - - - Change the current measure units of DDM GP - - - Degrees - - - Celsius - - - Farenheit - - - Kelvin - - - Temperature - - - Change the current measure units of temperature. - - - - Move anchors - - - Angle - - - Change the current measure units of angle. - - - [D]° - - - [D]°[M]′[S]′′ - - - [D]° - - - [D]°[M]′[S]′′ - - - [D]° - - - [D]°[M]′[S]′′ - - - Coordinates calculator - - - Close - - - To standard - - - To longitude - - - To lat/long units - - - To latitude - - - To altitude units - - - To altitude - - - From standard - - - From longitude - - - From lat/long units - - - From latitude - - - From altitude units - - - From altitude - - - Value must be greater than {0} ({1}) - - - Value must be less than {0} ({1}) - - - Altitude - - - Altitude measure units - - - AM - - - Amplitude modulation measure units - - - Bearing - - - Bearing measure units - - - Angle - - - Angle measure units - - - Distance - - - Distance measure units - - - Frequency - - - Frequency measure units - - - Latitude - - - Latitude measure units - - - Longitude - - - Longitude measure units - - - Value can't be null or white space - - - Value must be a number - - - Phase - - - Phase measure units - - - Power - - - Power measure units - - - Value can't be null or white space - - - Value must be a number - - - Value can't be null or white space - - - Value must be a number - - - Velocity - - - Velocity measure units - - - DDM (Gp) - - - Difference depth of modulation measure units - - - DDM (Llz) - - - Difference depth of modulation measure units - - - SDM - - - Sum depth of modulation measure units - - - Templater - - - Close - - - Save - - - Template path: - - - File path: - - - Add new tag - - - Add string tag - - - Add image tag - - - Clear tags list - - - Field strength - - - Field strength measure units - - - µV/m - - - - [D]°[M]′ - - - Bearing - - - Change the current measure units of bearing. - - - - On/off pin for this parameter - - - Update this parameter from UAV - - - Write this parameter to UAV - - - Reboot required - - - Update - - - Write - - - Potential data loss warning - - - You're trying to open another menu folder, but you have unsaved changes in the current one. Do you want to save them? - - - Save - - - Don't save - - - Cancel - - - Show only starred parameters - - - Update all parameters - - - Remove all pinned parameters - - - Parameters editor [{0}] - - - Search - - - Total: {0} - - - Star this parameter - - - Mission points - - - File - - - Open - - - Select mission file - - - Open - - - Cancel - - - Upload - - - Download - - - Delete - - - Name must be not empty - - - Save - - - Mission uploaded! - - - Select target point location - - - Anchors - - - Search - - - Packet Viewer - - - Message sources - - - Message types - - - Move Folder - - - Move Here - - - Cancel - - - Latitude - - - Altitude - - - Longitude - - - Fixed wing - - - Quadrotor - - - Hexarotor - - - Octorotor - - - Helicopter - - - Tricopter - - - Unknown type - - - Take off - - - Do land - - - Waypoint - - - ROI - - - Replace - - - Add - - - Potential data loss warning - - - You're trying to open another menu folder, but you have unsaved changes in the current one. Do you want to save them? - - - Save - - - Don't save - - - Cancel - - - Loaded: {0} - - - Refresh - - - Create New Folder - - - Create New File - - - Rename Folder - - - Move Folder - - - Delete Folder - - - Delete File - - - Delete - - - Rename - - - Move To Folder - - - Rename File - - - Move File - - \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/RS.ru.resx b/src/Asv.Drones.Gui.Core/RS.ru.resx deleted file mode 100644 index af7c6fbc..00000000 --- a/src/Asv.Drones.Gui.Core/RS.ru.resx +++ /dev/null @@ -1,1249 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ÐаÑтройки - - - Режим полета - - - КонтраÑÑ‚Ð½Ð°Ñ - - - Ð¢ÐµÐ¼Ð½Ð°Ñ - - - Ð¡Ð²ÐµÑ‚Ð»Ð°Ñ - - - СлеваÐаПраво - - - СправаÐаЛево - - - Тема - - - Измените текущую тему приложениÑ. - - - Язык Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ - - - Измените текущий Ñзык приложениÑ. Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ применены поÑле перезапуÑка приложениÑ. - - - Ðаправление Ñ‡Ñ‚ÐµÐ½Ð¸Ñ - - - Измените направление чтениÑ. - - - Планирование полета - - - Б - - - КБ - - - МБ - - - ГБ - - - Ð/Д - - - Б/Ñ - - - ГБ/Ñ - - - КБ/Ñ - - - МБ/Ñ - - - ГГц - - - Гц - - - КГц - - - МГц - - - - ТребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° - - - Ð’Ñ‹ должны перезагрузить программу, чтобы применить изменениÑ. - - - РаÑÑтоÑние - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ñ€Ð°ÑÑтоÑниÑ. - - - Ð’Ñ‹Ñота - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñоты. - - - Широта - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ñ‹ и долготы. - - - Метры - - - МорÑкие мили - - - Метры - - - Футы - - - ГрадуÑÑ‹ - - - ГрадуÑÑ‹, минуты, Ñекунды - - - фут - - - м - - - м - - - NM - - - - м/Ñ - - - км/ч - - - миль/ч - - - Ð¼Ñ - - - Ñ - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ - - - Ð’ Ñтом разделе можно наÑтроить единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… параметров. - - - СкороÑÑ‚ÑŒ - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ ÑкороÑти. - - - ИнÑтрументы - - - КалькулÑтор координат - - - - ÐаÑтройки - - - Режим полета - - - КонтраÑÑ‚Ð½Ð°Ñ - - - Ð¢ÐµÐ¼Ð½Ð°Ñ - - - Ð¡Ð²ÐµÑ‚Ð»Ð°Ñ - - - СлеваÐаПраво - - - СправаÐаЛево - - - Тема - - - Измените текущую тему приложениÑ. - - - Язык Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ - - - Измените текущий Ñзык приложениÑ. Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ применены поÑле перезапуÑка приложениÑ. - - - Ðаправление Ñ‡Ñ‚ÐµÐ½Ð¸Ñ - - - Измените направление чтениÑ. - - - Планирование полета - - - Выбрать провайдер карт - - - Провайдер карт - - - ОчиÑтить хранилище - - - Текущее хранилище карт находитÑÑ {0} и занимает {1} - - - Хранилище карт - - - Карты - - - Метры - - - Открыть файл - - - МорÑкие мили - - - Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð»Ð¾Ð³Ð° - - - по - - - Ðайти - - - От {0} - - - до {0} - - - Фильтрованных: {0} - - - Ð’Ñего: {0} - - - СообщениÑЛога - - - Ошибка при обновлении Ñлементов - - - ОчиÑтить вÑе ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð»Ð¾Ð³Ð° - - - Ð’Ñ‹ должны указать допуÑтимое Ð¸Ð¼Ñ - - - Ð’Ñ‹ должны указать дейÑтвительное Ð¸Ð¼Ñ Ð¿Ð¾Ñледовательного порта - - - СкороÑÑ‚ÑŒ передачи данных должна быть значением от {0} до {1} - - - Ðовый поÑледовательный порт {0} - - - Ðазвание - - - Порт - - - СкороÑÑ‚ÑŒ порта - - - ÐŸÐ¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ - - - Добавить - - - Отмена - - - Ðовый поÑледовательный порт - - - Ðовый TCP порт - - - Ðовый порт UDP - - - Включен - - - Выключен - - - Ðовый COM - - - Ðовый TCP - - - Ðовый UDP - - - Порты Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ - - - Эта Ñтраница позволÑет наÑтроить оÑновные параметры Ñети Mavlink - - - Точка входа, позволÑÑŽÑ‰Ð°Ñ ÐµÐ¼Ñƒ общатьÑÑ Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ уÑтройÑтвами в Ñети Mavlink. - - - Сеть Mavlink - - - Ð’ Ñтом разделе можно поÑмотреть вÑе найденные уÑтройÑтва в Ñети - - - СпиÑок найденных уÑтройÑтв - - - ЧаÑтота, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð¹ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ HEARTBEAT должны передаватьÑÑ, чтобы объÑвить о ÑущеÑтвовании ÑиÑтемы в Ñети MAVLink - - - ЧаÑтота Heartbeat - - - По иÑтечении таймаута пакета Heartbeat уÑтройÑтво будет удалено из ÑпиÑка уÑтройÑтв - - - Таймаут Heartbeat - - - ÐšÐ°Ð¶Ð´Ð°Ñ ÑиÑтема имеет идентификатор, и каждый компонент имеет идентификатор компонента ÑиÑтемы, который можно иÑпользовать Ð´Ð»Ñ Ð°Ð´Ñ€ÐµÑации/маршрутизации - - - ID СиÑтемы \ Компонента - - - ПользовательÑкий режим - - - ЧаÑтота Heartbeat - - - Ð¡Ñ‚Ð°Ñ‚ÑƒÑ ÑиÑтемы - - - IP Ð°Ð´Ñ€ÐµÑ - - - Ðазвание - - - Ðомер порта - - - IP Ð°Ð´Ñ€ÐµÑ - - - Порт - - - Ðазвание - - - Удаленный IP Ð°Ð´Ñ€ÐµÑ - - - Удаленный порт - - - Указать удаленный хоÑÑ‚ - - - Таймаут должен быть от {0} до {1} - - - Гц - - - ошибка - - - - Ðовый TCP - - - Ð’Ñ‹ должны указать дейÑтвительное Ð¸Ð¼Ñ - - - Ðомер порта должен иметь значение от 1 до 65535 - - - Ð’Ñ‹ должны ввеÑти дейÑтвительный IP-Ð°Ð´Ñ€ÐµÑ - - - Ошибка при Ñоздании порта - - - Ð’Ñ‹ должны указать дейÑтвительное Ð¸Ð¼Ñ - - - Ð’Ñ‹ должны ввеÑти дейÑтвительный IP-Ð°Ð´Ñ€ÐµÑ - - - Ðомер порта должен иметь значение от 1 до 65535 - - - Ðомер порта должен иметь значение от 1 до 65535 - - - Ð’Ñ‹ должны ввеÑти дейÑтвительный IP-Ð°Ð´Ñ€ÐµÑ - - - Ðовый UDP - - - ПроÑмотр пакетов - - - Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ - - - Предупреждение - - - Ошибка - - - Показать/Скрыть вÑе - - - Возобновить/ОÑтановить - - - ОчиÑтить ÑпиÑок пакетов - - - Сохранить как CSV - - - Ð’ - - - Долгота - - - ПринÑÑ‚ÑŒ - - - Редактировать выбранный поÑледовательный порт - - - Редактировать выбранный TCP порт - - - Редактировать выбранный порт UDP - - - Отмена - - - Ошибка - - - Инфо - - - Отладка - - - Предупреждение - - - ЧиÑло Ñлементов на одной Ñтранице - - - ОчиÑтить логи - - - Перейти к предыдущей Ñтранице - - - Перейти к Ñледующей Ñтранице - - - Обновить вÑе Ñлементы - - - Сохраненные координаты - - - Ð’ Ñтом разделе вы можете проÑматривать и добавлÑÑ‚ÑŒ новые точки координат Ð´Ð»Ñ Fixed режима базовой Ñтанции - - - Добавить - - - Удалить - - - Отмена - - - Добавить - - - Добавить новую точку на карте - - - ТочноÑÑ‚ÑŒ - - - Ð’Ñ‹Ñота - - - Широта - - - Долгота - - - Удалить точку - - - Отмена - - - Удалить - - - Уверены что хотите удалить Ñту точку? - - - ТочноÑÑ‚ÑŒ - - - Ð’Ñ‹Ñота - - - Широта - - - Долгота - - - Ð˜Ð¼Ñ - - - Ð˜Ð¼Ñ - - - ТочноÑÑ‚ÑŒ должна быть больше или равна {0}. - - - Ð˜Ð¼Ñ Ð½Ðµ может быть пуÑтым - - - ОчиÑтить - - - Выберите разделитель - - - Выбрать - - - Отмена - - - Ð“Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ñ‚Ð°Ð±ÑƒÐ»ÑÑ†Ð¸Ñ [ Tab ] - - - Точка Ñ Ð·Ð°Ð¿Ñтой [ ; ] - - - ЗапÑÑ‚Ð°Ñ [ , ] - - - Укажите начальную точку линейки - - - Укажите конечную точку линейки - - - Ð’ чаÑÑ‚ÑÑ… - - - Процент - - - Микроампер - - - мкР- - - Микроампер (РуÑ) - - - РГМ (КурÑ) - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð Ð“Ðœ (КурÑ). - - - Децибел по отношению к 1 милливатт - - - дБм - - - Проценты - - - Ð’ чаÑÑ‚ÑÑ… - - - Герц - - - Килогерц - - - Мегагерц - - - Гигагерц - - - Гц - - - кГц - - - МГц - - - ГГц - - - ГрадуÑÑ‹ - - - Радианы - - - Рад - - - ÐаÑтройки карты - - - Изменить текущие наÑтройки карты - - - РГМ (ГлиÑÑада) - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð Ð“Ðœ (ГлиÑÑада). - - - ГрадуÑÑ‹ - - - ЦельÑий - - - Фаренгейт - - - Кельвин - - - Температура - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ñ‹. - - - - ПеремеÑтить ÑÐºÐ¾Ñ€Ñ - - - Угол - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ ÑƒÐ³Ð»Ð°. - - - [Г]° - - - [Г]°[Ðœ]′[С]′′ - - - [Г]° - - - [Г]°[Ðœ]′[С]′′ - - - [Г]°[Ðœ]′[С]′′ - - - [Г]° - - - КалькулÑтор координат - - - Закрыть - - - Ð’ Ñтандарт - - - Ð’ долготу - - - Ð’ единицы шир/долг - - - Ð’ широту - - - Ð’ единицы выÑоты - - - Ð’ выÑоту - - - Из Ñтандарта - - - Из долготы - - - Из единиц шир/долг - - - Из широты - - - Из единиц выÑоты - - - Из выÑоты - - - Значение должно быть больше чем {0} ({1}) - - - Значение должно быть меньше чем {0} ({1}) - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñоты - - - Ð’Ñ‹Ñота - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð°Ð¼Ð¿Ð»Ð¸Ñ‚ÑƒÐ´Ð½Ð¾Ð¹ модулÑции - - - ÐÐœ - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð½ÐµÑущей - - - ÐеÑÑƒÑ‰Ð°Ñ - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ ÑƒÐ³Ð»Ð° - - - Угол - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ñ€Ð°ÑÑтоÑÐ½Ð¸Ñ - - - РаÑÑтоÑние - - - ЧаÑтота - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ñ‡Ð°Ñтоты - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ñ‹ - - - Широта - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ñ‹ - - - Долгота - - - Значение не должно быть пуÑтым или пробелом - - - Значение должно быть чиÑлом - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ñ„Ð°Ð·Ñ‹ - - - Фаза - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð¼Ð¾Ñ‰Ð½Ð¾Ñти - - - МощноÑÑ‚ÑŒ - - - Значение должно быть чиÑлом - - - Значение должно быть чиÑлом - - - Значение не должно быть пуÑтым или пробелом - - - Значение не должно быть пуÑтым или пробелом - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ ÑкороÑти - - - СкороÑÑ‚ÑŒ - - - РГМ (Gp) - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ñ Ñ€Ð°Ð·Ð½Ð¸Ñ†Ñ‹ в глубине модулÑции - - - РГМ (Llz) - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ñ Ñ€Ð°Ð·Ð½Ð¸Ñ†Ñ‹ в глубине модулÑции - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ñуммы глубины модулÑции - - - Шаблонизатор - - - Закрыть - - - Сохранить - - - Путь к шаблону: - - - Путь к файлу: - - - Добавить новый тег - - - Добавить тег картинки - - - Добавить Ñтроковый тег - - - ОчиÑтить ÑпиÑок тегов - - - СГМ - - - ÐапрÑжённоÑÑ‚ÑŒ Ð¿Ð¾Ð»Ñ - - - Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð½Ð°Ð¿Ñ€ÑжённоÑти Ð¿Ð¾Ð»Ñ - - - мкВ/м - - - - [Г]°[Ðœ]′ - - - Ðзимут - - - Измените текущие единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð°Ð·Ð¸Ð¼ÑƒÑ‚Ð°. - - - Якори - - - - Включить/выключить закрепление Ñтого параметра - - - Обновить Ñтот парметр из БПЛР- - - ЗапиÑать Ñтот парметр в БПЛР- - - ТребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° - - - Обновить - - - ЗапиÑать - - - Отмена - - - Ð’Ñ‹ пытаетеÑÑŒ открыть другой пункт меню, но в текущем у Ð²Ð°Ñ ÐµÑÑ‚ÑŒ неÑохраненные изменениÑ. Хотите Ñохранить их? - - - Сохранить - - - Ðе ÑохранÑÑ‚ÑŒ - - - Предупреждение о возможной потере данных - - - Показать только избранные параметры - - - Обновить вÑе параметры - - - Убрать вÑе прикреплённые параметры - - - - Добавить параметр в избранные - - - Редактор параметров [{0}] - - - Ðайти - - - Ð’Ñего: {0} - - - Точки миÑÑии - - - Файл - - - Открыть - - - Выберите файл миÑÑии - - - Открыть - - - Отмена - - - Удалить - - - Скачать - - - Загрузить - - - Ð˜Ð¼Ñ Ð½Ðµ должно быть пуÑтым - - - Сохранить - - - МиÑÑÐ¸Ñ Ð·Ð°Ð³Ñ€ÑƒÐ¶ÐµÐ½Ð°! - - - Укажите меÑтоположение точки - - - ПоиÑк - - - ПроÑмотр пакетов - - - ИÑточники Ñообщений - - - Типы Ñообщений - - - ПеремеÑтить папку - - - ПеремеÑтить Ñюда - - - Отмена - - - Широта - - - Ð’Ñ‹Ñота - - - Долгота - - - Ðеподвижное крыло - - - Вертолёт - - - ГекÑакоптер - - - Октокоптер - - - Квадрокоптер - - - Трикоптер - - - ÐеизвеÑтный тип - - - ÐŸÑƒÑ‚ÐµÐ²Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° - - - Взлёт - - - Регион интереÑов - - - ПоÑадка - - - Заменить - - - Добавить - - - Сохранить - - - Ðе ÑохранÑÑ‚ÑŒ - - - Отмена - - - Предупреждение о возможной потере данных - - - Ð’Ñ‹ пытаетеÑÑŒ открыть другой пункт меню, но в текущем у Ð²Ð°Ñ ÐµÑÑ‚ÑŒ неÑохраненные изменениÑ. Хотите Ñохранить их? - - - Получено: {0} - - - Создать новый файл - - - Создать новую папку - - - Обновить - - - Удалить Файл - - - Переименовать - - - ПеремеÑтить - - - ПеремеÑтить папку - - - Переименовать папку - - - Удалить файл - - - Переименовать файл - - - ПеремеÑтить файл - - - Удалить папку - - \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/App/AppService.cs b/src/Asv.Drones.Gui.Core/Services/App/AppService.cs deleted file mode 100644 index bf415d5b..00000000 --- a/src/Asv.Drones.Gui.Core/Services/App/AppService.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.ComponentModel.Composition; -using Asv.Cfg; -using Asv.Common; -using Asv.Drones.Core; -using LiteDB; -using NLog; - -namespace Asv.Drones.Gui.Core -{ - public class AppServiceConfig - { - - } - - [Export(typeof(IAppService))] - [PartCreationPolicy(CreationPolicy.Shared)] - public class AppService :ServiceWithConfigBase, IAppService - { - private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); - private readonly LiteDbAppStore _store; - - [ImportingConstructor] - public AppService(IConfiguration cfg, IAppPathInfo path, IAppInfo info):base(cfg) - { - Paths = path; - Info = info; - - BsonMapper.Global.RegisterType - ( - serialize: (uri) => uri.AbsoluteUri, - deserialize: (bson) => new Uri(bson.AsString) - ); - BsonMapper.Global.RegisterType - ( - serialize: (point) => new BsonDocument - { - ["lat"] = point.Latitude, - ["lon"] = point.Longitude, - ["alt"] = point.Altitude, - }, - deserialize: (bson) => new GeoPoint(bson["lat"].AsDouble, bson["lon"].AsDouble, bson["alt"].AsDouble) - ); - - _store = new LiteDbAppStore(new LiteDatabase(new ConnectionString(path.StoreFilePath) - { - Connection = ConnectionType.Direct, - }), path.StoreFilePath).DisposeItWith(Disposable); - } - - public IAppInfo Info { get; } - public IAppPathInfo Paths { get; } - public IAppStore Store => _store; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/App/IAppInfo.cs b/src/Asv.Drones.Gui.Core/Services/App/IAppInfo.cs deleted file mode 100644 index 722a3e52..00000000 --- a/src/Asv.Drones.Gui.Core/Services/App/IAppInfo.cs +++ /dev/null @@ -1,118 +0,0 @@ -namespace Asv.Drones.Gui.Core; - -/// -/// Represents an interface for retrieving information about an application. -/// -public interface IAppInfo -{ - /// - /// Gets the name of the property. - /// - /// - /// The name. - /// - string Name { get; } - - /// - /// Gets the version of the property. - /// - /// - /// A string representing the version of the property. - /// - string Version { get; } - - /// - /// Gets the name of the author of the code. - /// - /// A string representing the name of the author. - string Author { get; } - - /// - /// Gets the URL of the application. - /// - /// - /// This property is used to retrieve the URL of the application. - /// - /// - /// The URL of the application. - /// - string AppUrl { get; } - - /// - /// Gets the license information of the application. - /// - /// - /// The license string of the application. - /// - string AppLicense { get; } - - /// - /// Gets the current version of Avalonia. - /// - /// The current version of Avalonia. - string CurrentAvaloniaVersion { get; } -} - -/// -/// Represents information about an application. -/// -public class AppInfo : IAppInfo -{ - /// - /// Represents information about an application. - /// - public AppInfo(string name, string version, string author, string appUrl, string appLicense, string avaloniaVersion) - { - Name = name; - Version = version; - Author = author; - AppUrl = appUrl; - AppLicense = appLicense; - CurrentAvaloniaVersion = avaloniaVersion; - } - - /// - /// Gets the name of an object. - /// - /// - /// The name. - /// - public string Name { get; } - - /// - /// Gets the version of the property. - /// - /// The version of the property as a string. - public string Version { get; } - - /// - /// Gets the author of the property. - /// - /// - /// The author of the property. - /// - public string Author { get; } - - /// - /// Gets the URL of the property app. - /// - /// The URL of the property app. - public string AppUrl { get; } - - /// - /// Gets the license information of the application. - /// - /// - /// A string representing the license of the application. - /// - public string AppLicense { get; } - - /// - /// Gets the current version of Avalonia. - /// - /// - /// A string representing the current version of Avalonia. - /// - public string CurrentAvaloniaVersion { get; } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/App/IAppPathInfo.cs b/src/Asv.Drones.Gui.Core/Services/App/IAppPathInfo.cs deleted file mode 100644 index d641dcf7..00000000 --- a/src/Asv.Drones.Gui.Core/Services/App/IAppPathInfo.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Asv.Drones.Gui.Core; - -/// -/// Represents an interface for retrieving application path information. -/// -public interface IAppPathInfo -{ - /// - /// Gets the path of the data folder. - /// - /// - /// The path of the data folder. - /// - string DataFolder { get; } - - /// - /// Gets the file path to the configuration file. - /// - /// A string representing the file path to the configuration file. - string ConfigFilePath { get; } - - /// - /// Gets the file path of the store. - /// - /// - /// The file path of the store. - /// - string StoreFilePath { get; } -} - -/// -/// Represents the information related to the application paths. -/// -public class AppPathInfo : IAppPathInfo -{ - /// - /// Represents the information about the application paths. - /// - public AppPathInfo(string dataFolder, string configFilePath, string storeFilePath) - { - DataFolder = dataFolder; - ConfigFilePath = configFilePath; - StoreFilePath = storeFilePath; - } - - /// - /// Gets the path of the data folder. - /// - /// - /// A string representing the path of the data folder. - /// - public string DataFolder { get; } - - /// - /// Gets the path to the configuration file. - /// - /// - /// The path to the configuration file. - /// - public string ConfigFilePath { get; } - - /// - /// Gets the file path of the store. - /// - /// - /// The store file path represents the location of the store file. - /// - /// - /// The file path of the store. - /// - public string StoreFilePath { get; } -} diff --git a/src/Asv.Drones.Gui.Core/Services/App/IAppService.cs b/src/Asv.Drones.Gui.Core/Services/App/IAppService.cs deleted file mode 100644 index 74b51492..00000000 --- a/src/Asv.Drones.Gui.Core/Services/App/IAppService.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Asv.Drones.Core; - -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents an application service that provides information, paths, and a store for the application. - /// - public interface IAppService - { - /// - /// Gets the name, version, and other information about the application. - /// - IAppInfo Info { get; } - - /// - /// Gets the default application paths. - /// - /// - /// The default application paths. - /// - IAppPathInfo Paths { get; } - - /// - /// Gets the application store database, where all modules and plugins can store data. - /// - IAppStore Store { get; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/App/Store/IAppStore.cs b/src/Asv.Drones.Gui.Core/Services/App/Store/IAppStore.cs deleted file mode 100644 index 1ac0ee7b..00000000 --- a/src/Asv.Drones.Gui.Core/Services/App/Store/IAppStore.cs +++ /dev/null @@ -1,37 +0,0 @@ -using LiteDB; - -namespace Asv.Drones.Core -{ - /// - /// Represents an interface for an app store. - /// - public interface IAppStore:IDisposable - { - /// - /// Retrieves the file size in bytes. - /// - /// The file size in bytes. - int GetFileSizeInBytes(); - - /// - /// Gets the instance of the LiteDatabase for the property. - /// - /// - /// The LiteDatabase is responsible for managing the connection to the database and provides methods for executing database operations. - /// - /// - /// An instance of the LiteDatabase. - /// - ILiteDatabase Db { get; } - - /// - /// Gets the name of the source. - /// - /// - /// The name of the source. - /// - string SourceName { get; } - } - - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/App/Store/LiteDbAppStore.cs b/src/Asv.Drones.Gui.Core/Services/App/Store/LiteDbAppStore.cs deleted file mode 100644 index deaf23be..00000000 --- a/src/Asv.Drones.Gui.Core/Services/App/Store/LiteDbAppStore.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Asv.Common; -using LiteDB; - -namespace Asv.Drones.Core -{ - - public class LiteDbAppStore : DisposableOnceWithCancel, IAppStore - { - private readonly LiteDatabase _db; - - public LiteDbAppStore(LiteDatabase db, string sourceName) - { - SourceName = sourceName; - _db = db.DisposeItWith(Disposable); - } - - public int GetFileSizeInBytes() - { - var result = _db.GetCollection("$dump") - .Query() - .Select("{used: SUM(*.usedBytes)}") - .ToList(); - - return result[0]["used"].AsInt32; - } - - public ILiteDatabase Db => _db; - public string SourceName { get; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Commands/GlobalCommands.cs b/src/Asv.Drones.Gui.Core/Services/Commands/GlobalCommands.cs deleted file mode 100644 index 22b023be..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Commands/GlobalCommands.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents a service that provides global commands functionality. - /// - public interface IGlobalCommandsService - { - - } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/ILocalizationService.cs b/src/Asv.Drones.Gui.Core/Services/Localization/ILocalizationService.cs deleted file mode 100644 index 60292910..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/ILocalizationService.cs +++ /dev/null @@ -1,322 +0,0 @@ -using Asv.Common; -using System.Globalization; - -namespace Asv.Drones.Gui.Core -{ - /// - /// Initializes a new instance of the class. - /// - /// The identifier of the language. - /// The display name of the language. - /// The function to retrieve the object for the language. - /// Thrown when id or displayName is null, empty, or whitespace. - /// Thrown when getCulture is null. - public class LanguageInfo - { - /// - /// The culture information used for formatting and parsing values. - /// - /// - /// This variable holds an instance of which provides information about - /// a specific culture, including the language, writing system, calendar, and cultural conventions. - /// The value can be null if no specific culture is set. - /// - private CultureInfo? _culture; - - /// - /// Gets the culture information. - /// - /// - /// The culture information. - /// - /// - /// This is a delegate that should return the culture information. - /// - private readonly Func _getCulture; - - /// - /// Represents information about a language. - /// - public LanguageInfo(string id, string displayName, Func getCulture) - { - if (string.IsNullOrWhiteSpace(id)) - throw new ArgumentException("Value cannot be null or whitespace.", nameof(id)); - if (string.IsNullOrWhiteSpace(displayName)) - throw new ArgumentException("Value cannot be null or whitespace.", nameof(displayName)); - Id = id; - DisplayName = displayName; - _getCulture = getCulture ?? throw new ArgumentNullException(nameof(getCulture)); - } - - /// - /// Gets the unique identifier for the property. - /// - /// - /// The unique identifier for the property. - /// - public string Id { get; } - - /// - /// Gets the display name of the object. - /// - /// - /// The display name represents the name or title that is shown to the user for identification - /// or labeling purposes. It does not necessarily have to be unique within a system. - /// - /// - /// A string representing the display name of the object. - /// - public string DisplayName { get; } - - /// - /// Gets the CultureInfo of the property. - /// - /// - /// This property returns the CultureInfo associated with the current instance. - /// If the CultureInfo is not set, it will be lazily initialized using the private _getCulture() method. - /// - /// - /// The CultureInfo of the property. - /// - public CultureInfo Culture => _culture ??= _getCulture(); - } - - /// - /// Represents a localization service for handling language and unit conversions. - /// - public interface ILocalizationService - { - /// - /// Gets or sets the current application language. - /// - /// - /// This property allows you to select or get the current application language. - /// - /// - /// An instance of representing the current language. - /// - IRxEditableValue CurrentLanguage { get; } - - /// - /// Gets the list of available languages. - /// - /// - /// An enumerable collection of LanguageInfo objects representing the available languages. - /// - IEnumerable AvailableLanguages { get; } - - #region Units - - /// - /// Gets the byte rate as a short localized string. - /// - /// - /// Use this property to convert the byte rate to a string representation with the appropriate unit. - /// For example: 1024 => "1 KB/s" - /// - /// - /// An object implementing the interface, where T is double. - /// - IReadOnlyMeasureUnit ByteRate { get; } - - /// - /// Gets the items rate as a short localized string. - /// For example: 1000 => 1 KHz - /// - /// A read-only measure unit with a double value representing the items rate. - IReadOnlyMeasureUnit ItemsRate { get; } - - /// - /// Gets the measure unit for byte sizes, represented as a short localized string. - /// For example, 1024 bytes would be represented as "1 KB". - /// - /// The measure unit for byte sizes. - IReadOnlyMeasureUnit ByteSize { get; } - - /// - /// Gets the read-only measure unit for relative time. - /// - /// - /// The read-only measure unit for relative time. - /// - IReadOnlyMeasureUnit RelativeTime { get; } - - /// - /// Gets the voltage. - /// - /// - /// The voltage. - /// - IReadOnlyMeasureUnit Voltage { get; } - - /// - /// Gets the current measurement unit. - /// - /// - /// The current measurement unit. - /// - IReadOnlyMeasureUnit Current { get; } - - /// - /// Gets the altitude value with its associated units. - /// - /// - /// The altitude value with its associated units. - /// - IMeasureUnit Altitude { get; } - - /// - /// Gets the distance measurement. - /// - /// - /// The distance measurement. - /// - IMeasureUnit Distance { get; } - - /// - /// Gets the latitude as a measurement with a specified unit of measure. - /// - /// The latitude measurement. - IMeasureUnit Latitude { get; } - - /// - /// Gets the longitude measurement unit. - /// - /// - /// The longitude measurement unit. - /// - IMeasureUnit Longitude { get; } - - /// - /// Gets the velocity value with its associated measurement unit. - /// - /// - /// The velocity value with its associated measurement unit. - /// - IMeasureUnit Velocity { get; } - - /// - /// Gets the measurement unit for DdmLlz property. - /// - /// - /// The measurement unit for DdmLlz property. - /// - IMeasureUnit DdmLlz { get; } - - /// - /// Gets the measurement unit for DdmGp. - /// - /// The measurement unit. - IMeasureUnit DdmGp { get; } - - /// Gets or sets the measurement unit for the Sdm property. - /// - /// - /// The measurement unit for the Sdm property. - /// - IMeasureUnit Sdm { get; } - - /// - /// Represents the power property. - /// - /// - /// The power property as an instance of IMeasureUnit. - /// - IMeasureUnit Power { get; } - - /// - /// Gets the amplitude modulation measurement. - /// - /// - /// The amplitude modulation measurement. - /// - IMeasureUnit AmplitudeModulation { get; } - - /// - /// Represents the property for frequency measurements. - /// - /// - /// The property for frequency measurements. - /// - IMeasureUnit Frequency { get; } - - /// - /// Gets the phase measurement. - /// - /// - /// The property represents a measurement of phase. - /// - /// - /// The phase measurement. - /// - IMeasureUnit Phase { get; } - - /// - /// Property that represents a bearing. - /// - /// - /// An object of type where T is - /// and U is . - /// - /// - /// The bearing is a measurement of the horizontal direction of an object, relative to a reference point. - /// It is usually represented in degrees or radians. - /// - IMeasureUnit Bearing { get; } - - /// - /// Represents a property that represents temperature measurement. - /// - /// - /// The temperature measurement represented using the interface. - /// - IMeasureUnit Temperature { get; } - - /// - /// Represents a measurement in degrees. - /// - /// - IMeasureUnit Degree { get; } - - /// - /// Gets the field strength value. - /// - /// - /// The field strength value. - /// - /// - /// The field strength is measured in units of FieldStrengthUnits. - /// - IMeasureUnit FieldStrength { get; } - - #endregion - - /// - /// Converts the latitude, longitude, and altitude values to a GeoPoint object in - /// the International System of Units. - /// - /// The latitude value in degrees or DMS format. - /// If the latitude is invalid, it defaults to double.NaN. - /// The longitude value in degrees or DMS format. - /// If the longitude is invalid, it defaults to double.NaN. - /// The altitude value in meters or feet. - /// If the altitude is invalid, it defaults to double.NaN. - /// A GeoPoint object representing the converted latitude, longitude, and altitude - /// values in the International System of Units. - public GeoPoint ToSiGeoPoint(string? latitude, string? longitude, string? altitude) - { - var lat = Latitude.IsValid(latitude) ? Latitude.ConvertToSi(latitude) : double.NaN; - var lon = Longitude.IsValid(longitude) ? Longitude.ConvertToSi(longitude) : double.NaN; - var alt = Altitude.IsValid(altitude) ? Altitude.ConvertToSi(altitude) : double.NaN; - return new GeoPoint(lat,lon,alt); - } - } - - - - - - - - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/LocalizationServiceBase.cs b/src/Asv.Drones.Gui.Core/Services/Localization/LocalizationServiceBase.cs deleted file mode 100644 index a95f8358..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/LocalizationServiceBase.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System.ComponentModel.Composition; -using System.Globalization; -using Asv.Cfg; -using Asv.Common; - -namespace Asv.Drones.Gui.Core -{ - public class LocalizationServiceConfig - { - public string? CurrentLanguage { get; set; } - } - - public class LocalizationServiceBase : ServiceWithConfigBase, ILocalizationService - { - private readonly List _languages = new() - { - new LanguageInfo("en","English (EN)", ()=>CultureInfo.GetCultureInfo("en") ), - new LanguageInfo("ru","РуÑÑкий (RU)", ()=>CultureInfo.GetCultureInfo("ru") ), - }; - - [ImportingConstructor] - public LocalizationServiceBase(IConfiguration cfgSvc):base(cfgSvc) - { - #region CurrentLanguageInit - - var selectedLang = default(LanguageInfo); - var langFromConfig = InternalGetConfig(_ => _.CurrentLanguage); - if (string.IsNullOrWhiteSpace(langFromConfig) == false) - { - selectedLang = _languages.FirstOrDefault(_ => _.Id.Equals(langFromConfig)); - } - - selectedLang ??= _languages.First(); - CurrentLanguage = new RxValue(selectedLang).DisposeItWith(Disposable); - CurrentLanguage.Subscribe(SetLanguage).DisposeItWith(Disposable); - - #endregion - - Altitude = new Altitude(cfgSvc, nameof(Altitude)).DisposeItWith(Disposable); - Velocity = new Velocity(cfgSvc, nameof(Velocity)).DisposeItWith(Disposable); - Distance = new Distance(cfgSvc, nameof(Distance)).DisposeItWith(Disposable); - Latitude = new Latitude(cfgSvc, nameof(Latitude)).DisposeItWith(Disposable); - Longitude = new Longitude(cfgSvc, nameof(Longitude)).DisposeItWith(Disposable); - - DdmLlz = new DdmLlz(cfgSvc, nameof(DdmLlz)).DisposeItWith(Disposable); - DdmGp = new DdmGp(cfgSvc, nameof(DdmLlz)).DisposeItWith(Disposable); - Sdm = new Sdm(cfgSvc, nameof(Sdm)).DisposeItWith(Disposable); - Power = new Power(cfgSvc, nameof(Power)).DisposeItWith(Disposable); - AmplitudeModulation = new AmplitudeModulation(cfgSvc, nameof(AmplitudeModulation)).DisposeItWith(Disposable); - Frequency = new Frequency(cfgSvc, nameof(Frequency)).DisposeItWith(Disposable); - Phase = new Phase(cfgSvc, nameof(Phase)).DisposeItWith(Disposable); - Bearing = new Bearing(cfgSvc, nameof(Bearing)).DisposeItWith(Disposable); - Temperature = new Temperature(cfgSvc, nameof(Temperature)).DisposeItWith(Disposable); - Degree = new Degrees(cfgSvc, nameof(Degree)).DisposeItWith(Disposable); - FieldStrength = new FieldStrength(cfgSvc, nameof(FieldStrength)).DisposeItWith(Disposable); - } - - public IRxEditableValue CurrentLanguage { get; } - public IEnumerable AvailableLanguages => _languages; - - private void SetLanguage(LanguageInfo lang) - { - if (lang == null) throw new ArgumentNullException(nameof(lang)); - var culture = lang.Culture; - CultureInfo.CurrentUICulture = culture; - CultureInfo.DefaultThreadCurrentUICulture = culture; - Thread.CurrentThread.CurrentUICulture = culture; - InternalSaveConfig(_ => _.CurrentLanguage = lang.Id); - } - - #region Units - - public IReadOnlyMeasureUnit ByteRate { get; } = new BytesRate(); - public IReadOnlyMeasureUnit ItemsRate { get; } = new ItemsRate(); - public IReadOnlyMeasureUnit ByteSize { get; } = new ByteSize(); - public IReadOnlyMeasureUnit RelativeTime { get; } = new RelativeTime(); - public IReadOnlyMeasureUnit Voltage { get; } = new Voltage(); - public IReadOnlyMeasureUnit Current { get; } = new Current(); - - public IMeasureUnit Altitude { get; } - public IMeasureUnit Distance { get; } - public IMeasureUnit Latitude { get; } - public IMeasureUnit Longitude { get; } - public IMeasureUnit Velocity { get; } - public IMeasureUnit DdmLlz { get; } - public IMeasureUnit DdmGp { get; } - public IMeasureUnit Sdm { get; } - public IMeasureUnit Power { get; } - public IMeasureUnit AmplitudeModulation { get; } - public IMeasureUnit Frequency { get; } - public IMeasureUnit Phase { get; } - public IMeasureUnit Bearing { get; } - public IMeasureUnit Temperature { get; } - public IMeasureUnit Degree { get; } - public IMeasureUnit FieldStrength { get; } - #endregion - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Altitude.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Altitude.cs deleted file mode 100644 index be7ece47..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Altitude.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - - -public enum AltitudeUnits -{ - Meters, - Feets -} - -public class Altitude : MeasureUnitBase -{ - private const double MetersInFeet = 0.3048; - - private static readonly IMeasureUnitItem[] _units = { - new DoubleMeasureUnitItem(AltitudeUnits.Meters,RS.Altitude_Meter_Title,RS.Altitude_Meter_Unit,true, "F2",1), - new DoubleMeasureUnitItem(AltitudeUnits.Feets,RS.Altitude_Feet_Title,RS.Altitude_Feet_Unit,false,"F2",MetersInFeet), - }; - public Altitude(IConfiguration cfgSvc, string cfgKey) : base(cfgSvc, cfgKey,_units) - { - - } - - public override string Title => RS.Altitude_Title; - public override string Description => RS.Altitude_Description; -} diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/AmplitudeModulation.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/AmplitudeModulation.cs deleted file mode 100644 index dade7d60..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/AmplitudeModulation.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public enum AmplitudeModulationUnits -{ - Percent, - InParts -} -public class AmplitudeModulation : MeasureUnitBase -{ - private const double PercentInParts = 0.01; - - private static readonly IMeasureUnitItem[] _units = { - new DoubleMeasureUnitItem(AmplitudeModulationUnits.Percent,RS.AmplitudeModulation_Percent_Title,"%",true,"F2",PercentInParts), - new DoubleMeasureUnitItem(AmplitudeModulationUnits.InParts,RS.AmplitudeModulation_InParts_Unit,"1",true,"F4",1), - }; - - public AmplitudeModulation(IConfiguration cfgSvc, string cfgKey) : base(cfgSvc, cfgKey, _units) - { - } - - public override string Title => RS.AmplitudeModulation_Title; - - public override string Description => RS.AmplitudeModulation_Description; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/DdmGp.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/DdmGp.cs deleted file mode 100644 index cd6a6949..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/DdmGp.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public class DdmGp : MeasureUnitBase -{ - private const double AbsoluteInPercent = 0.01; - private const double AbsoluteInMicroAmp = 0.175 / 150; - private const double AbsoluteInMicroAmpRu = 0.175 / 250; - - private static readonly IMeasureUnitItem[] _units = { - new DoubleMeasureUnitItem(DdmUnits.InParts,RS.Ddm_InParts_Title,"1",true, "F4",1), - new DoubleMeasureUnitItem(DdmUnits.Percent,RS.Ddm_Percent_Title,"%",false,"F2",AbsoluteInPercent), - new DoubleMeasureUnitItem(DdmUnits.MicroAmp,RS.Ddm_Microamp_Title,RS.Ddm_µA_Unit,false,"F1",AbsoluteInMicroAmp), - new DoubleMeasureUnitItem(DdmUnits.MicroAmpRu,RS.Ddm_MicroampRus_Title,RS.Ddm_µA_Unit,false,"F1",AbsoluteInMicroAmpRu) - }; - - public DdmGp(IConfiguration cfgSvc, string cfgKey) : base(cfgSvc, cfgKey, _units) - { - } - - public override string Title => RS.DdmGp_Title; - - public override string Description => RS.DdmGp_Description; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/DdmLlz.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/DdmLlz.cs deleted file mode 100644 index cfbee08f..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/DdmLlz.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public enum DdmUnits -{ - InParts, - Percent, - MicroAmp, - MicroAmpRu -} - -public class DdmLlz : MeasureUnitBase -{ - private const double AbsoluteInPercent = 0.01; - private const double AbsoluteInMicroAmp = 0.155 / 150; - private const double AbsoluteInMicroAmpRu = 0.155 / 250; - - private static readonly IMeasureUnitItem[] _units = { - new DoubleMeasureUnitItem(DdmUnits.InParts,RS.Ddm_InParts_Title,"1",true, "F4",1), - new DoubleMeasureUnitItem(DdmUnits.Percent,RS.Ddm_Percent_Title,"%",false,"F2",AbsoluteInPercent), - new DoubleMeasureUnitItem(DdmUnits.MicroAmp,RS.Ddm_Microamp_Title,RS.Ddm_µA_Unit,false,"F1",AbsoluteInMicroAmp), - new DoubleMeasureUnitItem(DdmUnits.MicroAmpRu,RS.Ddm_MicroampRus_Title,RS.Ddm_µA_Unit,false,"F1",AbsoluteInMicroAmpRu) - }; - - public DdmLlz(IConfiguration cfgSvc, string cfgKey) : base(cfgSvc, cfgKey, _units) - { - } - - public override string Title => RS.DdmLlz_Title; - - public override string Description => RS.DdmLlz_Description; -} diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Distance.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Distance.cs deleted file mode 100644 index 5b9f835f..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Distance.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public enum DistanceUnits -{ - Meters, - NauticalMiles -} -public class Distance : MeasureUnitBase -{ - private const double MetersInInternationalNauticalMile = 1852; - private static readonly IMeasureUnitItem[] _units = { - new DoubleMeasureUnitItem(DistanceUnits.Meters,RS.Distance_Meters_Title,RS.Distance_Meters_Unit,true,"F1",1), - new DoubleMeasureUnitItem(DistanceUnits.NauticalMiles,RS.Distance_NauticalMiles_Title,RS.Distance_NauticalMiles_Unit,false,"F4",MetersInInternationalNauticalMile), - }; - public Distance(IConfiguration cfgSvc,string cfgKey):base(cfgSvc,cfgKey,_units) - { - - } - public override string Title => RS.Distance_Title; - public override string Description => RS.Distance_Description; - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Frequency.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Frequency.cs deleted file mode 100644 index 83d9df5e..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Frequency.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public enum FrequencyUnits -{ - Hz, - KHz, - MHz, - GHz -} -public class Frequency : MeasureUnitBase -{ - - private const double HzInKHz = 1000; - private const double HzInMHz = 1000000; - private const double HzInGHz = 1000000000; - - public static readonly IMeasureUnitItem[] Units = { - new DoubleMeasureUnitItem(FrequencyUnits.Hz,RS.Frequency_Hertz_Title,RS.Frequency_Hertz_Unit,true, "F0",1), - new DoubleMeasureUnitItem(FrequencyUnits.KHz,RS.Frequency_Kilohertz_Title,RS.Frequency_Kilohertz_Unit,false,"F3",HzInKHz), - new DoubleMeasureUnitItem(FrequencyUnits.MHz,RS.Frequency_Megahertz_Title,RS.Frequency_Megahertz_Unit,false,"F3",HzInMHz), - new DoubleMeasureUnitItem(FrequencyUnits.GHz,RS.Frequency_Gigahertz_Title,RS.Frequency_Gigahertz_Unit,false,"F3",HzInGHz) - }; - - public Frequency(IConfiguration cfgSvc, string cfgKey) : base(cfgSvc, cfgKey, Units) - { - } - - public override string Title => RS.Frequency_Title; - - public override string Description => RS.Frequency_Description; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/IMeasureUnit.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/IMeasureUnit.cs deleted file mode 100644 index 85c77d96..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/IMeasureUnit.cs +++ /dev/null @@ -1,379 +0,0 @@ -#nullable enable -using System.Globalization; -using Asv.Common; -using Avalonia; -using Avalonia.Data.Converters; - -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents a measure unit item. - /// - /// The type of value for the measure unit item. - public interface IMeasureUnitItem - { - /// - /// Gets the title of the property. - /// - /// - /// The title is a read-only property that represents the title of the object. - /// - /// - /// A string value representing the title of the object. - /// - public string Title { get; } - - /// - /// Gets the unit of the property. - /// - /// The unit of the property. - /// - /// This property represents the unit associated with a specific property. The unit can be used to indicate the measurement type - /// of the property's value. For example, if the property represents a length, the unit can be "m" for meters or "ft" for feet. - /// - public string Unit { get; } - - /// - /// Gets a value indicating whether the property represents an SI unit. - /// - /// true if the property is an SI unit; otherwise, false. - public bool IsSiUnit { get; } - public TValue ConvertFromSi(TValue siValue); - - /// - /// Converts the specified value to SI units. - /// - /// The type of the value to convert. - /// The value to convert. - /// The converted value in SI units. - public TValue ConvertToSi(TValue value); - - /// - /// Parses the specified string value and converts it to a value of type TValue. - /// - /// The string value to parse. - /// The parsed value of type TValue. - /// - /// This method converts the string value to the specified type using the default parsing mechanism of the type. - /// If the value is null, it returns the default value of type TValue. - /// - /// The type to which the value should be converted. - /// The parsed value of type TValue. - public TValue Parse(string? value); - - /// - /// Checks if the given value is valid. - /// - /// The value to be checked. - /// True if the value is valid, otherwise false. - bool IsValid(string? value); - - /// - /// Retrieves the error message associated with the specified value. - /// - /// The value to retrieve the error message for. - /// The error message associated with the specified value. - /// - /// If the value is null, the method returns null as well. - /// - string? GetErrorMessage(string? value); - - /// - /// Prints the value of the given type. - /// - /// The type of value. - /// The value to print. - /// The printed value as a string. - string Print(TValue value); - - /// - /// Prints the given value with units. - /// - /// The value to be printed. - /// The formatted value with units as a string. - string PrintWithUnits(TValue value); - - /// - /// Converts the given value to the SI unit representation. - /// - /// The value to convert. - /// The value converted to the SI unit representation. - public TValue ConvertToSi(string? value) - { - return ConvertToSi(Parse(value)); - } - - /// - /// Converts the specified value from SI units to string representation. - /// - /// The type of the value to convert. - /// The value to convert from SI units. - /// The string representation of the converted value. - public string FromSiToString(TValue value) - { - return Print(ConvertFromSi(value)); - } - - /// - /// Converts the given value from SI units to a formatted string with units. - /// - /// The value to convert. - /// A string representation of the converted value with units. - public string FromSiToStringWithUnits(TValue value) - { - return PrintWithUnits(ConvertFromSi(value)); - } - } - - /// - /// Represents a measure unit item with a specific identifier. - /// - /// The type of the value associated with the measure unit item. - /// The type of the enum identifier associated with the measure unit item. - public interface IMeasureUnitItem:IMeasureUnitItem - { - /// - /// Gets the value of the property Id. - /// - /// The enum type of the Id. - /// The value of the property Id. - /// - /// Example usage: - /// - /// Console.WriteLine(property.Id); - /// - /// - public TEnum Id { get; } - - } - - /// - /// Interface for representing a measure unit. - /// - /// The type of the value associated with the unit. - /// The enum type representing the available units. - public interface IMeasureUnit - { - /// - /// Gets the title of the property. - /// - /// - /// The title of the property. - /// - string Title { get; } - - /// - /// Gets the description of the property. - /// - /// - /// A string representing the description of the property. - /// - string Description { get; } - - /// - /// Gets the collection of available units for the property. - /// - /// - /// An of representing the available units. - /// - /// The type of value associated with the units. - /// The type of enum used to represent the units. - IEnumerable> AvailableUnits { get; } - - /// - /// Gets the current unit for the editable value. - /// - /// The type of the value. - /// The enumeration type representing the units. - /// The current unit for the editable value. - IRxEditableValue> CurrentUnit { get; } - - /// Gets or sets the SI unit for the property. - /// @remarks - /// The SI unit determines the standard unit of measurement for the property value. - /// @typeParam TValue - The type of the property value. - /// @typeParam TEnum - The enum type representing the available measurement units. - /// @returns The SI unit for the property. - /// / - IMeasureUnitItem SiUnit { get; } - - /// - /// Converts the given value from SI units to a string representation with units. - /// - /// The value to convert. - /// The string representation of the converted value with units. - public string FromSiToStringWithUnits(TValue value) - { - return CurrentUnit.Value.FromSiToStringWithUnits(value); - } - - /// - /// Converts the value from the SI unit to a string representation. - /// - /// The type of the value. - /// The value to convert. - /// A string representation of the converted value. - public string FromSiToString(TValue value) - { - return CurrentUnit.Value.FromSiToString(value); - } - - /// - /// Converts a value from the SI unit of the current unit to the unit's native value. - /// - /// The type of the value to convert. - /// The value to convert. - /// The converted value. - public TValue ConvertFromSi(TValue value) - { - return CurrentUnit.Value.ConvertFromSi(value); - } - - /// - /// Converts the given value to the SI unit. - /// - /// The value to be converted. - /// The converted value in SI unit. - /// The type of the value to be converted. - public TValue ConvertToSi(TValue value) - { - return CurrentUnit.Value.ConvertToSi(value); - } - - /// - /// Converts the given value to the equivalent value in the International System of Units (SI). - /// - /// The value to be converted as a string. - /// The converted value of type TValue. - public TValue ConvertToSi(string? value) - { - return CurrentUnit.Value.ConvertToSi(value); - } - - /// - /// Checks if the given value is valid. - /// - /// The value to be checked. - /// True if the value is valid, false otherwise. - public bool IsValid(string? value) - { - return CurrentUnit.Value.IsValid(value); - } - } - - public static class MeasureUnitExtensions - { - /// - /// Checks if the provided value is valid within the given range. - /// - /// The enum type representing the measure unit. - /// The instance of an object implementing the IMeasureUnit interface. - /// The minimum valid value in the SI unit. - /// The maximum valid value in the SI unit. - /// The value to be checked. - /// - /// True if the value is valid within the provided range; otherwise, false. - /// - public static bool IsValid(this IMeasureUnit src, double minSiValue, double maxSiValue, string value) - { - if (src.CurrentUnit.Value.IsValid(value) == false) return false; - if (src.CurrentUnit.Value.ConvertToSi(value) < minSiValue) return false; - if (src.CurrentUnit.Value.ConvertToSi(value) > maxSiValue) return false; - return true; - } - - /// - /// Retrieves the error message for the given value. - /// - /// The type of the value. - /// The type of the enum. - /// The object. - /// The input value. - /// The error message for the given value. - public static string? GetErrorMessage(this IMeasureUnit src, string? value) - { - return src.CurrentUnit.Value.GetErrorMessage(value); - } - - /// - /// Get the error message based on the provided values. - /// - /// The enum type representing the measure unit. - /// The source IMeasureUnit instance. - /// The minimum SI value. - /// The maximum SI value. - /// The value to check against the minimum and maximum SI values. - /// The error message if value is out of range, or null if value is within the range. - public static string? GetErrorMessage(this IMeasureUnit src,double minSiValue, double maxSiValue, string? value) - { - var msg = src.CurrentUnit.Value.GetErrorMessage(value); - if (string.IsNullOrWhiteSpace(msg) == false) return msg; - var siValue = src.CurrentUnit.Value.ConvertToSi(value); - if ( siValue< minSiValue) return string.Format(RS.MeasureUnitExtensions_ErrorMessage_GreaterValue, src.CurrentUnit.Value.FromSiToStringWithUnits(minSiValue), src.SiUnit.FromSiToStringWithUnits(siValue)); - if (siValue > maxSiValue) return string.Format(RS.MeasureUnitExtensions_ErrorMessage_LesserValue, src.CurrentUnit.Value.FromSiToStringWithUnits(minSiValue), src.SiUnit.FromSiToStringWithUnits(siValue)); - return null; - } - - } - - - /// - /// Represents a class that provides conversion between different units of measure. - /// - public static class MeasureUnitConverter - { - /// - /// This class represents a MeasureUnitConverter that can convert between different measure units. - /// - static MeasureUnitConverter() - { - DoubleInstance = new MeasureUnitConverter(); - UlongInstance = new MeasureUnitConverter(); - } - - /// - /// Gets or sets the instance of for values. - /// - /// - /// The instance of for values. - /// - public static MeasureUnitConverter UlongInstance { get; set; } - - /// - /// Gets the instance of MeasureUnitConverter class. - /// - /// - /// The instance of MeasureUnitConverter class. - /// - public static MeasureUnitConverter DoubleInstance { get; } - } - - - /// - /// A class that represents a measure unit converter. - /// - /// The type of value to convert. - public class MeasureUnitConverter : IMultiValueConverter - { - /// - /// Converts a list of values to the specified target type using the specified culture information. - /// - /// The list of values to convert. - /// The target type to convert the values to. - /// An optional parameter to use during the conversion process. - /// The culture information to use for the conversion. - /// The converted value as an . If the conversion fails, is returned. - public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) - { - if (values.Count == 1) - return System.Convert.ChangeType(values[0], targetType, culture); - if (values is [_, IMeasureUnitItem measureUnit, ..]) - { - var value = (TValue)System.Convert.ChangeType(values[0], typeof(TValue), culture)!; - return measureUnit.Print(value); - } - - return AvaloniaProperty.UnsetValue; - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Phase.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Phase.cs deleted file mode 100644 index 1c833259..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Phase.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public enum PhaseUnits -{ - Degree, - Radian -} -public class Phase : MeasureUnitBase -{ - private const double DegreeInRadian = 180.0 / Math.PI; - - private static readonly IMeasureUnitItem[] _units = { - new DoubleMeasureUnitItem(PhaseUnits.Degree,RS.Phase_Degree_Title,"°",true,"F2",1), - new DoubleMeasureUnitItem(PhaseUnits.Radian,RS.Phase_Radian_Title,RS.Phase_Radian_Unit,false, "F2",DegreeInRadian) - }; - - public Phase(IConfiguration cfgSvc, string cfgKey) : base(cfgSvc, cfgKey, _units) - { - } - - public override string Title => RS.Phase_Title; - - public override string Description => RS.Phase_Description; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Power.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Power.cs deleted file mode 100644 index 027365e2..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Power.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public enum PowerUnits -{ - Dbm -} -public class Power : MeasureUnitBase -{ - public static readonly IMeasureUnitItem[] Units = { - new DoubleMeasureUnitItem(PowerUnits.Dbm,RS.Power_Dbm_Title,RS.Power_Dbm_Unit,true,"F2",1), - }; - - public Power(IConfiguration cfgSvc, string cfgKey) : base(cfgSvc, cfgKey, Units) - { - } - - public override string Title => RS.Power_Title; - - public override string Description => RS.Power_Description; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Sdm.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Sdm.cs deleted file mode 100644 index 0e6036be..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Sdm.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public enum SdmUnits -{ - Percent -} -public class Sdm : MeasureUnitBase -{ - private const double PercentInParts = 0.01; - - private static readonly IMeasureUnitItem[] _units = { - new DoubleMeasureUnitItem(SdmUnits.Percent,RS.Ddm_Percent_Title,"%",true,"F2",PercentInParts) - }; - - public Sdm(IConfiguration cfgSvc, string cfgKey) : base(cfgSvc, cfgKey, _units) - { - } - - public override string Title => RS.Sdm_Title; - - public override string Description => RS.Sdm_Description; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Velocity.cs b/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Velocity.cs deleted file mode 100644 index d4cbd0a9..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/MeasureUnits/Velocity.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Asv.Cfg; - -namespace Asv.Drones.Gui.Core; - -public enum VelocityUnits -{ - MetersPerSecond, - KilometersPerHour, - MilesPerHour -} - -public class Velocity : MeasureUnitBase -{ - private const double MetersPerSecondInKilometersPerHour = 3.6; - - private const double MetersPerSecondInMilesPerHour = 2.236936; - - private static readonly IMeasureUnitItem[] Units = { - new DoubleMeasureUnitItem(VelocityUnits.MetersPerSecond,RS.Velocity_MetersPerSecondUnit,RS.Velocity_MetersPerSecondUnit,true,"F0",1), - new DoubleMeasureUnitItem(VelocityUnits.KilometersPerHour,RS.Velocity_KilometersPerHourUnit,RS.Velocity_KilometersPerHourUnit,false,"F0",MetersPerSecondInKilometersPerHour), - new DoubleMeasureUnitItem(VelocityUnits.MilesPerHour,RS.Velocity_MilesPerHourUnit,RS.Velocity_MilesPerHourUnit,false,"F0",MetersPerSecondInMilesPerHour), - }; - - public Velocity(IConfiguration cfgSvc,string cfgKey):base(cfgSvc,cfgKey,Units) - { - - } - - public override string Title => RS.Velocity_Title; - public override string Description => RS.Velocity_Description; - - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Localization/ReadOnlyMeasures/IReadOnlyMeasureUnit.cs b/src/Asv.Drones.Gui.Core/Services/Localization/ReadOnlyMeasures/IReadOnlyMeasureUnit.cs deleted file mode 100644 index 07933528..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Localization/ReadOnlyMeasures/IReadOnlyMeasureUnit.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Asv.Drones.Gui.Core; - -/// -/// Represents an interface for read-only measure units. -/// -/// The type of value that the measure units can be applied to. -public interface IReadOnlyMeasureUnit -{ - /// - /// Retrieves the unit associated with the given value. - /// - /// The type of the value. - /// The value for which to retrieve the unit. - /// The unit associated with the given value, or null if no unit is found. - string? GetUnit(TValue value); - - /// - /// Converts the given value to a string representation. - /// - /// The type of the value. - /// The value to convert. - /// The string representation of the value. - string ConvertToString(TValue value); - -} - -/// -/// Extension methods for the readonly measure unit. -/// -public static class ReadOnlyMeasureUnitExtensions -{ - /// - /// Converts the value to a string representation with units using the provided measure unit. - /// - /// The type of the value. - /// The measure unit used for conversion. - /// The value to be converted. - /// The string representation of the value with units. - public static string ConvertToStringWithUnits(this IReadOnlyMeasureUnit src, TValue value) - { - return src.ConvertToString(value) + src.GetUnit(value); - } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/LogService/ILogService.cs b/src/Asv.Drones.Gui.Core/Services/LogService/ILogService.cs deleted file mode 100644 index 6bfc4ef5..00000000 --- a/src/Asv.Drones.Gui.Core/Services/LogService/ILogService.cs +++ /dev/null @@ -1,269 +0,0 @@ -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents a logging service. - /// - public interface ILogService - { - /// - /// Saves a log message. - /// - /// The log message to be saved. - void SaveMessage(LogMessage message); - - /// - /// Gets the observable sequence of objects. - /// - /// - /// The observable sequence of objects. - /// - IObservable OnMessage { get; } - - /// - /// Clears all the data stored in the current object. - /// This method is used to remove all data from the object and reset it to its initial state. - /// / - void ClearAll(); - - /// - /// Returns the count of items. - /// - /// The count of items. - int Count(); - - /// - /// Finds log messages based on the specified query. - /// - /// The query used to filter the log messages. - /// An IEnumerable of LogMessage objects that match the query. - /// - /// The Find method searches for log messages based on the specified query. - /// The query can include various filter criteria such as date range, log level, - /// log source, log message content, etc. By applying the query, only the log messages - /// that satisfy the specified criteria will be returned. - /// - /// - /// - IEnumerable Find(LogQuery query); - - /// - /// Returns the number of logs that match the given query. - /// - /// The query used to filter the logs. - /// The number of logs that match the query. - int Count(LogQuery query); - } - - /// - /// Represents a query to filter log records. - /// - public class LogQuery - { - /// - /// Gets or sets the number of elements to take from a collection. - /// - /// - /// The number of elements to take. - /// - public int Take { get; set; } - - /// - /// Gets or sets the number of elements to skip. - /// - /// - /// The number of elements to skip. - /// - public int Skip { get; set; } - - /// - /// Gets or sets the search text. - /// - /// - /// The search text entered by the user. - /// - public string Search { get; set; } - } - - /// - /// The LogServiceHelper class provides extension methods to simplify logging operations. - /// - public static class LogServiceHelper - { - /// - /// Logs an error message with optional exception information using the specified log service. - /// - /// The to use for logging. - /// The sender of the error message. - /// The error message to be logged. - /// The optional containing additional information about the error. - /// - /// This method saves a new with the current timestamp, the type of , - /// the specified sender, the given error message, and the exception message (if provided) using the specified log service. - /// - /// Thrown when , , or is null. - /// - /// - /// ILogService logService = new LogService(); - /// logService.Error("MySender", "An error occurred"); - /// logService.Error("MySender", "An error occurred", new Exception("Sample exception message")); - /// - /// - public static void Error(this ILogService src, string sender, string message, - Exception ex = default) - { - src.SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Error, sender, message, ex?.Message)); - } - - /// - /// Logs an informational message. - /// - /// The instance of the logging service. - /// The sender of the message. - /// The message content. - public static void Info(this ILogService src, string sender, string message) - { - src.SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Info, sender, message, default)); - } - - /// - /// Logs a warning message using the provided log service. - /// - /// The log service used to save the warning message. - /// The sender of the warning message. - /// The warning message to be logged. - public static void Warning(this ILogService src, string sender, string message) - { - src.SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Warning, sender, message, default)); - } - - /// - /// Logs a trace message using the specified log service. - /// - /// The log service. - /// The sender of the message. - /// The message to be logged. - public static void Trace(this ILogService src, string sender, string message) - { - src.SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Trace, sender, message, default)); - } - } - - /// - /// Defines the types of log messages. - /// - public enum LogMessageType - { - /// - /// Represents a log message type of 'Info'. - /// - Info, - - /// - /// Represents an error message type in the log system. - /// - Error, - - /// - /// Represents a warning message in the log. - /// - /// - /// This enum member is used to identify a warning message in the log. - /// - /// - /// The following example demonstrates the usage of the enum member. - /// - /// LogMessageType messageType = LogMessageType.Warning; - /// - /// - Warning, - - /// - /// Represents the severity level of a log message as "Trace". - /// - /// - /// Trace log messages are used to provide detailed information for debugging and troubleshooting purposes. - /// - /// - /// This example demonstrates how to use the severity level: - /// - /// Logger.Log(LogMessageType.Trace, "Trace log message"); - /// - /// - Trace, - } - - /// - /// Represents a log message with various properties such as date and time, log message type, source, message, and description. - /// - public class LogMessage - { - /// - /// Represents a log message. - /// - /// The date and time when the log message occurred. - /// The type of log message. - /// The source of the log message. - /// The message text. - /// Additional description of the log message. - public LogMessage(DateTime dateTime, LogMessageType type, string source, string message, string description) - { - Type = type; - Source = source; - Message = message; - Description = description; - DateTime = dateTime; - } - - /// - /// Gets the current date and time. - /// - /// - /// The current date and time. - /// - public DateTime DateTime { get; } - - /// - /// Gets the type of the log message. - /// - /// - /// The type of the log message. - /// - public LogMessageType Type { get; } - - /// - /// Gets or sets the source of the property. - /// - /// - /// The source of the property. - /// - public string Source { get; internal set; } - - /// - /// Gets the message. - /// - /// - /// This property represents the message associated with an object. - /// - /// - /// A string that represents the message. - /// - public string Message { get; } - - /// - /// Gets the description of the property. - /// - /// - /// The description of the property. - /// - public string Description { get; } - - /// - /// Override of the ToString() method. - /// - /// A string representation of the object. - public override string ToString() - { - return $"{Type} {Message}"; - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/LogService/LogService.cs b/src/Asv.Drones.Gui.Core/Services/LogService/LogService.cs deleted file mode 100644 index a9753d57..00000000 --- a/src/Asv.Drones.Gui.Core/Services/LogService/LogService.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Collections.Immutable; -using System.ComponentModel.Composition; -using System.Reactive.Subjects; -using Asv.Cfg; -using Asv.Common; -using LiteDB; - -namespace Asv.Drones.Gui.Core -{ - public class LogServiceConfig - { - - } - - [Export(typeof(ILogService))] - [PartCreationPolicy(CreationPolicy.Shared)] - public class LogService : ServiceWithConfigBase, ILogService - { - private readonly Subject _onMessage; - private readonly string _hostName; - private ILiteCollection _coll; - private const string StoreTextCollectionName = "log"; - - [ImportingConstructor] - public LogService(IConfiguration cfgService,IAppService app) : base(cfgService) - { - _onMessage = new Subject().DisposeItWith(Disposable); - _hostName = $"{Environment.MachineName}.{Environment.UserName}"; - _onMessage.Subscribe(SaveToStore,DisposeCancel); - _coll = app.Store.Db.GetCollection(StoreTextCollectionName); - _coll.EnsureIndex(x => x.Type); - _coll.EnsureIndex(x => x.DateTime); - _coll.EnsureIndex(x => x.Source); - _coll.EnsureIndex(x => x.Message); - } - - private void SaveToStore(LogMessage logMessage) - { - logMessage.Source = GetSourceName(logMessage.Source); - _coll.Insert(logMessage); - } - - private string GetSourceName(string rootSource) - { - return rootSource; - return $"{_hostName}.{rootSource}"; - } - - public IObservable OnMessage => _onMessage; - public void ClearAll() - { - _coll.DeleteAll(); - this.Info(nameof(LogService),"User clear all messages"); - } - - public int Count() - { - return _coll.Count(); - } - - public IEnumerable Find(LogQuery query) - { - return _coll.Find(Convert(query), query.Skip, query.Take).ToImmutableList(); - } - - public int Count(LogQuery query) - { - return _coll.Count(Convert(query)); - } - public void SaveMessage(LogMessage message) - { - _onMessage.OnNext(message); - } - private static Query Convert(LogQuery query) - { - var q = Query.All(nameof(LogMessage.DateTime)); - - if (!query.Search.IsNullOrWhiteSpace()) - { - q.Where.Add(Query.Contains(nameof(LogMessage.Message), query.Search)); - } - - return q; - } - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/MapService/IMapService.cs b/src/Asv.Drones.Gui.Core/Services/MapService/IMapService.cs deleted file mode 100644 index cdd9abaf..00000000 --- a/src/Asv.Drones.Gui.Core/Services/MapService/IMapService.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Asv.Avalonia.Map; -using Asv.Common; - -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents the configuration settings for a map service. - /// - public class MapServiceConfig - { - /// - /// Gets or sets the name of the map provider. - /// - /// - /// This property represents the name of the map provider used for displaying maps. - /// It can be used to identify the specific map provider being used, for example, "Google Maps" or "Bing Maps". - /// - /// - /// The name of the map provider. - /// - public string? MapProviderName { get; set; } - } - - /// - /// Represents a map service that can calculate map cache size, set map cache directory, and provide information about the current map provider and available providers. - /// - public interface IMapService - { - /// - /// Calculates the size of the map cache. - /// - /// - /// The size of the map cache in bytes. - /// - long CalculateMapCacheSize(); - - /// - /// Sets the directory where map cache will be stored. - /// - /// The path to the directory. - void SetMapCacheDirectory(string path); - - /// - /// Gets the directory path where the cache for the map is stored. - /// - /// The directory path where the cache for the map is stored. - string MapCacheDirectory { get; } - - /// - /// Gets or sets the current map provider that is used for displaying the map. - /// - /// - /// The property represents an interface - /// for the selected map provider. It allows getting or setting the currently used , - /// which is responsible for rendering the map. - /// - /// - /// An implementation of the interface with the underlying type . - /// - IRxEditableValue CurrentMapProvider { get; } - - /// - /// Gets the available providers for GMap. - /// - /// - /// An enumerable collection of GMapProvider objects representing the available providers for GMap. - /// - IEnumerable AvailableProviders { get; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/MapService/MapService.cs b/src/Asv.Drones.Gui.Core/Services/MapService/MapService.cs deleted file mode 100644 index 2aba5445..00000000 --- a/src/Asv.Drones.Gui.Core/Services/MapService/MapService.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.ComponentModel.Composition; -using System.Reactive.Linq; -using Asv.Avalonia.Map; -using Asv.Cfg; -using Asv.Common; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IMapService))] - [PartCreationPolicy(CreationPolicy.Shared)] - public class MapService: ServiceWithConfigBase, IMapService - { - private readonly IRxEditableValue _currentMapProvider; - private string _mapCacheDirectory; - - [ImportingConstructor] - public MapService(IConfiguration cfgService,IAppPathInfo paths) : base(cfgService) - { - if (cfgService == null) throw new ArgumentNullException(nameof(cfgService)); - - // this is for store map tiles - Cache.CacheFolder = Path.Combine(paths.DataFolder, "map"); - if (Directory.Exists(Cache.CacheFolder) == false) - { - Directory.CreateDirectory(Cache.CacheFolder); - } - - var providerName = InternalGetConfig(_ => _.MapProviderName); - if (providerName.IsNullOrWhiteSpace()) - { - InternalSaveConfig(_=>_.MapProviderName = BingHybridMapProvider.Instance.Name); - providerName = BingHybridMapProvider.Instance.Name; - } - var provider = GMapProviders.List.FirstOrDefault(_ => _.Name == providerName); - if (provider == null) - { - InternalSaveConfig(_ => _.MapProviderName = BingHybridMapProvider.Instance.Name); - provider = BingHybridMapProvider.Instance; - } - _currentMapProvider = new RxValue(provider).DisposeItWith(Disposable); - _currentMapProvider - .DistinctUntilChanged() - .Skip(1) - .Subscribe(_ => InternalSaveConfig(cfg => cfg.MapProviderName = _.Name)) - .DisposeItWith(Disposable); - - _mapCacheDirectory = Cache.CacheFolder; - } - - public long CalculateMapCacheSize() - { - return DirSize(new DirectoryInfo(_mapCacheDirectory)); - } - - private static long DirSize(DirectoryInfo d) - { - // if folder not exist return zero size - if (d.Exists == false) return 0; - // Add file sizes. - var fis = d.GetFiles(); - var size = fis.Sum(fi => fi.Length); - // Add subdirectory sizes. - var dis = d.GetDirectories(); - size += dis.Sum(DirSize); - return size; - } - - public void SetMapCacheDirectory(string directory) - { - _mapCacheDirectory = directory; - } - - public string MapCacheDirectory => _mapCacheDirectory; - - public IRxEditableValue CurrentMapProvider => _currentMapProvider; - - public IEnumerable AvailableProviders => GMapProviders.List; - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/MavlinkDevices/GlobalMavlinkPacketSequenceCalculator.cs b/src/Asv.Drones.Gui.Core/Services/MavlinkDevices/GlobalMavlinkPacketSequenceCalculator.cs deleted file mode 100644 index 2088fa3f..00000000 --- a/src/Asv.Drones.Gui.Core/Services/MavlinkDevices/GlobalMavlinkPacketSequenceCalculator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Asv.Mavlink; - -namespace Asv.Drones.Gui.Uav -{ - /// - /// Packet sequence calculator for all sent mavlink packet form app to devices - /// - [Export(typeof(IPacketSequenceCalculator))] - [PartCreationPolicy(CreationPolicy.Shared)] - public class GlobalMavlinkPacketSequenceCalculator : PacketSequenceCalculator - { - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/MavlinkDevices/IMavlinkDevicesService.cs b/src/Asv.Drones.Gui.Core/Services/MavlinkDevices/IMavlinkDevicesService.cs deleted file mode 100644 index 1593fdc3..00000000 --- a/src/Asv.Drones.Gui.Core/Services/MavlinkDevices/IMavlinkDevicesService.cs +++ /dev/null @@ -1,138 +0,0 @@ -using Asv.Common; -using Asv.Mavlink; -using DynamicData; - -namespace Asv.Drones.Gui.Uav -{ - /// - /// Represents a service for managing MAVlink devices. - /// - public interface IMavlinkDevicesService - { - /// - /// Collection with all devices in the network. - /// - /// - /// The Devices property is an IObservable collection that contains all the devices in the network. - /// - /// - /// An IObservable collection of IChangeSet of IMavlinkDevice objects that represents all the devices in the network. - /// - IObservable> Devices { get; } - - /// - /// Gets or sets the timeout for device connection. - /// - /// - /// If the device does not respond within this time, it will be removed from the collection. - /// - /// - /// The timeout value, in TimeSpan format. - /// - IRxEditableValue DeviceTimeout { get; } - - /// - /// Gets or sets the Mavlink router. - /// - IMavlinkRouter Router { get; } - - /// - /// Gets a value indicating whether the application needs to be reloaded in order to apply the new config. - /// - /// - /// true if the application needs to be reloaded; otherwise, false. - /// - IRxValue NeedReloadToApplyConfig { get; } - - /// - /// ComponentId identifier of this app in mavlink network - /// - /// The ComponentId - IRxEditableValue ComponentId { get; } - - /// - /// SystemId identifier of this app in mavlink network - /// - IRxEditableValue SystemId { get; } - - /// - /// Rate of heartbeat packets for sending to network. - /// - /// - /// This property represents the rate at which heartbeat packets are sent to the network. - /// Heartbeat packets are used to maintain a connection between devices and ensure that they are still active. - /// The value of this property is an object that allows the rate to be modified. - /// - IRxEditableValue HeartbeatRate { get; } - - /// - /// Gets the list of all founded vehicles in the network. - /// - /// - /// The vehicles are observed using the interface. - /// The sequence contains changes to the vehicles along with the reason for the change represented by the interface. - /// Each vehicle is represented by an instance of interface. - /// - IObservable> Vehicles { get; } - - /// - /// Gets a vehicle by its id. - /// - /// The id of the vehicle to be searched. - /// Returns the vehicle object representing the found vehicle. Returns null if no vehicle with the specified id is found. - public IVehicleClient? GetVehicleByFullId(ushort id); - - /// - /// Gets the base stations. - /// - /// - /// The base stations. - /// - IObservable> BaseStations { get; } - - /// - /// Retrieves the GbsClientDevice object associated with the specified full ID. - /// - /// The full ID of the GbsClientDevice to retrieve. - /// - /// The GbsClientDevice object associated with the specified full ID, or null if no device was found. - /// - public IGbsClientDevice? GetGbsByFullId(ushort id); - - /// - /// Gets the observable sequence of payloads. - /// - /// - /// The payloads are represented by which contains a collection of change sets. - /// Each change set represents the changes made to the collection of objects. - /// - /// - /// The observable sequence of payloads. - /// - IObservable> Payloads { get; } - - /// - /// Retrieves the payloads associated with the specified full ID. - /// - /// The full ID of the payloads to retrieve. - /// An instance of ISdrClientDevice representing the payloads associated with the specified full ID, or null if no payloads found. - public ISdrClientDevice? GetPayloadsByFullId(ushort id); - - /// - /// Gets an observable sequence of changes to the collection of AdsbClientDevice objects. - /// - /// - /// An observable sequence of changes that occurred on the collection of AdsbClientDevice objects. - /// - public IObservable> AdsbDevices { get; } - - /// - /// Retrieves an AdsbClientDevice object based on the provided full ID. - /// - /// The full ID of the AdsbClientDevice. - /// An instance of the AdsbClientDevice class representing the requested vehicle, or null if not found. - public IAdsbClientDevice? GetAdsbVehicleByFullId(ushort id); - } - - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMission.cs b/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMission.cs deleted file mode 100644 index fd6382e0..00000000 --- a/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMission.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.ComponentModel.Composition; -using Asv.Common; -using Asv.Mavlink; - -namespace Asv.Drones.Gui.Core; - -[Export(typeof(IPlaningMission))] -[PartCreationPolicy(CreationPolicy.Shared)] -public class PlaningMission : DisposableOnceWithCancel, IPlaningMission -{ - public const string MissionDataFolder = "missions"; - - [ImportingConstructor] - public PlaningMission(IAppService appService) - { - var missionPath = Path.Combine(appService.Paths.DataFolder, MissionDataFolder); - if (Directory.Exists(missionPath) == false) - { - Directory.CreateDirectory(missionPath); - } - MissionStore = new FileSystemHierarchicalStore(missionPath, - PlaningMissionStoreFormat.Instance, TimeSpan.Zero); - } - - public IHierarchicalStore MissionStore { get; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMissionFile.cs b/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMissionFile.cs deleted file mode 100644 index 6f6c568a..00000000 --- a/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMissionFile.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Asv.Cfg; -using Asv.Cfg.Json; -using Asv.Common; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionFile : ZipJsonVersionedFile -{ - public static readonly SemVersion Version1_0_0 = new(1,0,0); - public static readonly SemVersion LastVersion = Version1_0_0; - private const string FileType = "AsvDronesMission"; - - - public PlaningMissionFile(Stream stream, Guid id, string name) : base(stream,LastVersion,FileType,true) - { - - } - - public PlaningMissionFile(Stream stream) : base(stream,LastVersion,FileType,false) - { - - } - - public PlaningMissionModel Load() - { - return this.Get(); - } - - public void Save(PlaningMissionModel model) - { - this.Set(model); - } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMissionModel.cs b/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMissionModel.cs deleted file mode 100644 index 1076fe08..00000000 --- a/src/Asv.Drones.Gui.Core/Services/MissionPlaning/PlaningMissionModel.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Asv.Common; -using Newtonsoft.Json.Linq; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -public record PlaningMissionModel -{ - public List Points { get; set; } = new(); -} - -public enum PlaningMissionPointType -{ - // !!! DON'T CHANGE ORDER. ONLY ADD ITEMS !!! - TakeOff, - DoLand, - Waypoint, - Roi - // !!! DON'T CHANGE ORDER. ONLY ADD ITEMS !!! -} - -public class PlaningMissionPointModel -{ - [Reactive] - public int Index { get; set; } - [Reactive] - public PlaningMissionPointType Type { get; set; } - [Reactive] - public GeoPoint Location { get; set; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Navigation/INavigationService.cs b/src/Asv.Drones.Gui.Core/Services/Navigation/INavigationService.cs deleted file mode 100644 index 2583bdc3..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Navigation/INavigationService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Avalonia.Platform.Storage; - -namespace Asv.Drones.Gui.Core -{ - /// - /// This class provides helper methods for navigation in the application. - /// - public class NavigationServiceHelper - { - } - - /// - /// An interface for navigating between pages in an application. - /// - public interface INavigationService - { - /// - /// Initializes the storage provider for the given window. - /// - /// The storage provider to be initialized. - void InitStorageProvider(IStorageProvider windowStorageProvider); - - /// - /// Initializes the application with the specified shell. The shell object used for initializing the application. void - /// / - void Init(IShell shell); - - /// - /// Navigates to the specified URI. - /// - /// The URI to navigate to. - /// A task representing the asynchronous operation. The task result represents whether the navigation was successful or not. - Task GoTo(Uri uri); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Navigation/NavigationService.cs b/src/Asv.Drones.Gui.Core/Services/Navigation/NavigationService.cs deleted file mode 100644 index f1a5b14e..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Navigation/NavigationService.cs +++ /dev/null @@ -1,75 +0,0 @@ -#nullable enable -using System.ComponentModel.Composition; -using System.ComponentModel.Composition.Hosting; -using System.Reflection; -using Asv.Cfg; -using Avalonia.Platform.Storage; - -namespace Asv.Drones.Gui.Core -{ - - public class NavigationServiceConfig - { - - } - - - [Export(typeof(INavigationService))] - [PartCreationPolicy(CreationPolicy.Shared)] - public class NavigationService: ServiceWithConfigBase, INavigationService - { - public const string UriScheme = "asv"; - private readonly CompositionContainer _container; - private IShell? _shell; - private IStorageProvider? _windowStorageProvider; - - [ImportingConstructor] - public NavigationService(CompositionContainer container, IConfiguration cfgSvc):base(cfgSvc) - { - _container = container; - } - - public void InitStorageProvider(IStorageProvider windowStorageProvider) - { - _windowStorageProvider = windowStorageProvider ?? throw new ArgumentNullException(nameof(windowStorageProvider)); - } - - public void Init(IShell shellPage) - { - _shell = shellPage ?? throw new ArgumentNullException(nameof(shellPage)); - } - - public async Task GoTo(Uri link) - { - if (_shell == null) - { - throw new Exception( - $"The order of loading services was broken. At this point the variable {nameof(_shell)} must be initialized."); - } - if (link == null) throw new ArgumentNullException(nameof(link)); - if (link.Scheme.Equals(UriScheme) == false) - { - throw new Exception($"Unknown uri scheme. Want {UriScheme}. Got:{link.Scheme}"); - } - - var current = _shell.CurrentPage; - if (current != null) - { - var canClose = await current.TryClose(); - if (canClose == false) return false; - - if (current.GetType().GetCustomAttribute()!.CreationPolicy == CreationPolicy.NonShared) - { - current.Dispose(); - } - } - - var viewModel = _container.GetExportedValue(link.AbsolutePath); - - viewModel?.SetArgs(link); - _shell.CurrentPage = viewModel; - return true; - } - } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/SoundNotificationService/ISoundNotificationService.cs b/src/Asv.Drones.Gui.Core/Services/SoundNotificationService/ISoundNotificationService.cs deleted file mode 100644 index 016fb708..00000000 --- a/src/Asv.Drones.Gui.Core/Services/SoundNotificationService/ISoundNotificationService.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Asv.Drones.Gui.Core; - -/// -/// Interface for a sound notification service. -/// -public interface ISoundNotificationService -{ - /// - /// Sends a notification to the intended recipients. - /// - /// - /// This method is used to notify the intended recipients about a particular event or occurrence. - /// - /// - /// - /// // Example usage: - /// Notify(); - /// - /// - public void Notify(); -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Theme/IThemeService.cs b/src/Asv.Drones.Gui.Core/Services/Theme/IThemeService.cs deleted file mode 100644 index 6892584e..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Theme/IThemeService.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Asv.Common; -using Avalonia.Styling; - -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents a theme item. - /// - public class ThemeItem - { - /// - /// Represents a theme item, which includes an id, name, and theme variant. - /// - /// The unique identifier for the theme item. - /// The name of the theme item. - /// The theme variant for the item. - public ThemeItem(string id, string name,ThemeVariant theme) - { - Id = id; - Name = name; - Theme = theme; - } - - /// - /// Gets the identifier of the property. - /// - /// - /// The identifier of the property. - /// - public string Id { get; } - - /// - /// Gets the name of the property. - /// - /// - /// The name of the property. - /// - public string Name { get; } - - /// - /// Gets the theme variant of the application. - /// - /// - /// The theme variant of the application. - /// - public ThemeVariant Theme { get; } - } - - - /// - /// Represents a service for managing themes. - /// - public interface IThemeService - { - /// - /// Gets an enumerable collection of theme items. - /// - /// - /// An enumerable collection of theme items. - /// - IEnumerable Themes { get; } - - /// Gets the current theme of the application. - /// - /// - /// This property returns an instance of which represents the current theme. - /// - /// - /// An instance representing the current theme of the application. - /// - IRxEditableValue CurrentTheme { get; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Services/Theme/ThemeService.cs b/src/Asv.Drones.Gui.Core/Services/Theme/ThemeService.cs deleted file mode 100644 index ce1dc4c5..00000000 --- a/src/Asv.Drones.Gui.Core/Services/Theme/ThemeService.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.ComponentModel.Composition; -using Asv.Cfg; -using Asv.Common; -using Avalonia; -using Avalonia.Styling; -using FluentAvalonia.Styling; - -namespace Asv.Drones.Gui.Core -{ - public class ThemeServiceConfig - { - public string? Theme { get; set; } - } - - [Export(typeof(IThemeService))] - [PartCreationPolicy(CreationPolicy.Shared)] - public class ThemeService : ServiceWithConfigBase, IThemeService - { - private readonly ThemeItem[] _themes = { - new(FluentAvaloniaTheme.DarkModeString, RS.ThemeService_Themes_Dark, ThemeVariant.Dark), - new(FluentAvaloniaTheme.LightModeString, RS.ThemeService_Themes_Light, ThemeVariant.Light), - }; - - [ImportingConstructor] - public ThemeService(IConfiguration cfgSvc):base(cfgSvc) - { - Application.Current.RequestedThemeVariant = ThemeVariant.Default; - var selectedTheme = default(ThemeItem); - - var themeFromConfig = InternalGetConfig(_ => _.Theme); - if (string.IsNullOrWhiteSpace(themeFromConfig) == false) - { - selectedTheme = _themes.FirstOrDefault(_ => _.Id.Equals(themeFromConfig)); - } - - selectedTheme ??= _themes.First(); - CurrentTheme = new RxValue(selectedTheme).DisposeItWith(Disposable); - CurrentTheme.Subscribe(SetTheme).DisposeItWith(Disposable); - } - - public IEnumerable Themes =>_themes; - public IRxEditableValue CurrentTheme { get; } - - private void SetTheme(ThemeItem theme) - { - if (theme == null) throw new ArgumentNullException(nameof(theme)); - Application.Current.RequestedThemeVariant = theme.Theme; - - InternalSaveConfig(_ => _.Theme = theme.Id); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Default/DefaultHeaderFileMenuProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Default/DefaultHeaderFileMenuProvider.cs deleted file mode 100644 index bcd85170..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Default/DefaultHeaderFileMenuProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core -{ - [Export(HeaderMenuItem.UriString + "/file",typeof(IViewModelProvider))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class DefaultHeaderFileMenuProvider : ViewModelProviderBase - { - [ImportingConstructor] - public DefaultHeaderFileMenuProvider([ImportMany(HeaderMenuItem.UriString + "/file")]IEnumerable exportedMenuItems) - { - Source.AddOrUpdate(exportedMenuItems); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/DefaultHeaderMenuProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/DefaultHeaderMenuProvider.cs deleted file mode 100644 index ac8cb53a..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/DefaultHeaderMenuProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core -{ - [Export(HeaderMenuItem.UriString,typeof(IViewModelProvider))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class DefaultHeaderMenuProvider : ViewModelProviderBase - { - [ImportingConstructor] - public DefaultHeaderMenuProvider([ImportMany(HeaderMenuItem.UriString)]IEnumerable exportedMenuItems) - { - Source.AddOrUpdate(exportedMenuItems); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/HeaderMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/HeaderMenuItem.cs deleted file mode 100644 index 43cb8cf3..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/HeaderMenuItem.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Collections.ObjectModel; -using System.Windows.Input; -using Avalonia.Input; -using Material.Icons; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core -{ - public class HeaderMenuItem : ViewModelBase, IHeaderMenuItem - { - public const string? UriString = "asv:shell.header.menu"; - - public HeaderMenuItem(Uri id) : base(id) - { - - } - public HeaderMenuItem(string id) : base(id) - { - - } - - [Reactive] - public int Order { get; set; } - [Reactive] - public MaterialIconKind Icon { get; set; } - [Reactive] - public string Header { get; set; } - [Reactive] - public ICommand Command { get; set; } - [Reactive] - public object? CommandParameter { get; set; } - [Reactive] - public bool IsVisible { get; set; } = true; - [Reactive] - public bool StaysOpenOnClick { get; set; } - [Reactive] - public bool IsEnabled { get; set; } = true; - public virtual ReadOnlyObservableCollection? Items { get; set; } - [Reactive] - public KeyGesture? HotKey { get; set; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/IHeaderMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/IHeaderMenuItem.cs deleted file mode 100644 index e735c7d5..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/IHeaderMenuItem.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections.ObjectModel; -using System.Windows.Input; -using Avalonia.Input; -using Material.Icons; - -namespace Asv.Drones.Gui.Core -{ - /// - /// This interface represents each Menu Item that is present in the user interface header bar. - /// - public interface IHeaderMenuItem : IViewModel - { - /// - /// This property holds the sequence order of the menu item - /// - int Order { get; } - - /// - /// Icon property that holds the icon of the header menu item - /// - MaterialIconKind Icon { get; } - - /// - /// Text associated with the menu item in the header - /// - string Header { get; } - - /// - /// ICommand that will be associated with the activity of the particular header menu item - /// - ICommand Command { get; } - - /// - /// Any additional parameter to pass to the command associated with the menu item - /// - object? CommandParameter { get; } - - /// - /// Property to set the visibility of the menu item in the header - /// - bool IsVisible { get; } - - /// - /// Determines whether the menu item remains open post a click - /// - bool StaysOpenOnClick { get; } - - /// - /// Collection of all child items (menu item) if any for the particular header menu item - /// - ReadOnlyObservableCollection? Items { get; set; } - - /// - /// Property to enable or disable the header menu item - /// - public bool IsEnabled { get; } - - /// - /// Typically would be the shortcut for the menu item in the header - /// - public KeyGesture? HotKey { get; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/DefaultHeaderToolsMenuProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/DefaultHeaderToolsMenuProvider.cs deleted file mode 100644 index 34e23418..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/DefaultHeaderToolsMenuProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core; - -[Export(HeaderMenuItem.UriString + "/tools",typeof(IViewModelProvider))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class DefaultHeaderToolsMenuProvider : ViewModelProviderBase -{ - [ImportingConstructor] - public DefaultHeaderToolsMenuProvider([ImportMany(HeaderMenuItem.UriString + "/tools")]IEnumerable exportedMenuItems) - { - Source.AddOrUpdate(exportedMenuItems); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorView.axaml b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorView.axaml deleted file mode 100644 index 3c5f4a03..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorView.axaml +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorView.axaml.cs deleted file mode 100644 index 4d9f872f..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorView.axaml.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(CoordinatesCalculatorViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class CoordinatesCalculatorView : ReactiveUserControl -{ - public CoordinatesCalculatorView() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorViewModel.cs deleted file mode 100644 index ce6a3033..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/Dialog/CoordinatesCalculatorViewModel.cs +++ /dev/null @@ -1,328 +0,0 @@ -using System.ComponentModel.Composition; -using System.Windows.Input; -using Asv.Cfg; -using Asv.Common; -using Asv.Mavlink.Vehicle; -using DynamicData.Binding; -using FluentAvalonia.UI.Controls; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Validation.Extensions; - -namespace Asv.Drones.Gui.Core; - -public class CoordinatesCalculatorViewModelConfig -{ - public int SelectedFromAltUnitIndex { get; set; } - public int SelectedToAltUnitIndex { get; set; } - public int SelectedFromLatLongUnitIndex { get; set; } - public int SelectedToLatLongUnitIndex { get; set; } - public int SelectedFromStandardIndex { get; set; } - public int SelectedToStandardIndex { get; set; } - public string Latitude { get; set; } - public string Longitude { get; set; } - public string Altitude { get; set; } -} - -[ExportShellPage(UriString)] -[PartCreationPolicy(CreationPolicy.Shared)] -public class CoordinatesCalculatorViewModel : ViewModelBaseWithValidation -{ - private readonly IConfiguration _cfg; - private readonly ILocalizationService _loc; - - public const string UriString = ShellViewModel.UriString + "/tools/coordinates-calculator"; - public static readonly Uri Uri = new(UriString); - private readonly CoordinatesCalculatorViewModelConfig _config; - - [ImportingConstructor] - public CoordinatesCalculatorViewModel(IConfiguration cfg, ILocalizationService loc) : this() - { - _cfg = cfg; - _loc = loc; - _config = cfg.Get(); - - SelectedFromLatLongUnitIndex = _config.SelectedFromLatLongUnitIndex; - SelectedToLatLongUnitIndex = _config.SelectedToLatLongUnitIndex; - SelectedFromStandardIndex = _config.SelectedFromStandardIndex; - SelectedToStandardIndex = _config.SelectedToStandardIndex; - SelectedFromAltUnitIndex = _config.SelectedFromAltUnitIndex; - SelectedToAltUnitIndex = _config.SelectedToAltUnitIndex; - FromLatitude = _config.Latitude; - FromLongitude = _config.Longitude; - FromAltitude = _config.Altitude; - - this.WhenPropertyChanged(_ => _.SelectedFromLatLongUnitIndex) - .Subscribe(_ => - { - SelectedFromLatLongUnit = LatLongUnits[_.Value].Unit; - _config.SelectedFromLatLongUnitIndex = _.Value; - cfg.Set(_config); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.SelectedToLatLongUnitIndex) - .Subscribe(_ => - { - SelectedToLatLongUnit = LatLongUnits[_.Value].Unit; - _config.SelectedToLatLongUnitIndex = _.Value; - cfg.Set(_config); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.SelectedFromStandardIndex) - .Subscribe(_ => - { - _config.SelectedFromStandardIndex = _.Value; - cfg.Set(_config); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.SelectedToStandardIndex) - .Subscribe(_ => - { - _config.SelectedToStandardIndex = _.Value; - cfg.Set(_config); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.SelectedFromAltUnitIndex) - .Subscribe(_ => - { - SelectedFromAltUnit = AltUnits[_.Value].Unit; - _config.SelectedFromAltUnitIndex = _.Value; - cfg.Set(_config); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.SelectedToAltUnitIndex) - .Subscribe(_ => - { - SelectedToAltUnit = AltUnits[_.Value].Unit; - _config.SelectedToAltUnitIndex = _.Value; - cfg.Set(_config); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.FromLatitude) - .Subscribe(_ => - { - UpdateLatitude(_.Value); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.FromLongitude) - .Subscribe(_ => - { - UpdateLongitude(_.Value); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.FromAltitude) - .Subscribe(_ => - { - UpdateAltitude(_.Value); - }) - .DisposeItWith(Disposable); - - this.WhenAnyPropertyChanged(nameof(SelectedFromLatLongUnitIndex), - nameof(SelectedToLatLongUnitIndex), - nameof(SelectedFromStandardIndex), - nameof(SelectedToStandardIndex), - nameof(SelectedFromAltUnitIndex), - nameof(SelectedToAltUnitIndex)) - .Subscribe(_ => - { - UpdateLatitude(FromLatitude); - UpdateLongitude(FromLongitude); - UpdateAltitude(FromAltitude); - }) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.FromLatitude, - _ => _loc.Latitude.IsValid(_), - _ => _loc.Latitude.GetErrorMessage(_)) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.FromLongitude, - _ => _loc.Longitude.IsValid(_), - _ => _loc.Longitude.GetErrorMessage(_)) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.FromAltitude, - _ => _loc.Altitude.IsValid(_), - _ => _loc.Altitude.GetErrorMessage(_)) - .DisposeItWith(Disposable); - - SwapLatLongUnits = ReactiveCommand.Create(SwapLatLongUnitsImpl).DisposeItWith(Disposable); - SwapStandards = ReactiveCommand.Create(SwapStandardsImpl).DisposeItWith(Disposable); - SwapAltUnits = ReactiveCommand.Create(SwapAltUnitsImpl).DisposeItWith(Disposable); - } - - public CoordinatesCalculatorViewModel() : base(Uri) - { - - } - - public void ApplyDialog(ContentDialog dialog) - { - if (dialog == null) throw new ArgumentNullException(nameof(dialog)); - } - - private void SwapStandardsImpl() - { - (SelectedToStandardIndex, SelectedFromStandardIndex) = - (SelectedFromStandardIndex, SelectedToStandardIndex); - } - - private void SwapLatLongUnitsImpl() - { - (SelectedToLatLongUnitIndex, SelectedFromLatLongUnitIndex) = - (SelectedFromLatLongUnitIndex, SelectedToLatLongUnitIndex); - } - - private void SwapAltUnitsImpl() - { - (SelectedToAltUnitIndex, SelectedFromAltUnitIndex) = - (SelectedFromAltUnitIndex, SelectedToAltUnitIndex); - } - - private void UpdateLatitude(string latitude) - { - if (!string.IsNullOrWhiteSpace(latitude) && - GeoPointLatitude.TryParse(latitude, out var latResult)) - { - var currentSiValue = - _loc.Latitude.AvailableUnits - .Single(u => u.Unit == SelectedFromLatLongUnit) - .ConvertToSi(latResult); - - var point = GetCorrectedGeoPoint(new GeoPoint(currentSiValue, 0, 0)); - - ToLatitude = _loc.Latitude.AvailableUnits - .Single(u => u.Unit == SelectedToLatLongUnit) - .FromSiToString(point.Latitude); - - _config.Latitude = latitude; - _cfg.Set(_config); - } - } - - private void UpdateLongitude(string longitude) - { - if (!string.IsNullOrWhiteSpace(longitude) && - GeoPointLongitude.TryParse(longitude, out var longResult)) - { - var currentSiValue = - _loc.Longitude.AvailableUnits - .Single(u => u.Unit == SelectedFromLatLongUnit) - .ConvertToSi(longResult); - - var point = GetCorrectedGeoPoint(new GeoPoint(0, currentSiValue, 0)); - - ToLongitude = _loc.Longitude.AvailableUnits - .Single(u => u.Unit == SelectedToLatLongUnit) - .FromSiToString(point.Longitude); - - _config.Longitude = longitude; - _cfg.Set(_config); - } - } - - private void UpdateAltitude(string altitude) - { - if (!string.IsNullOrWhiteSpace(altitude) && - double.TryParse(altitude, out var altResult)) - { - var currentSiValue = - _loc.Altitude.AvailableUnits - .Single(u => u.Unit == SelectedFromAltUnit) - .ConvertToSi(altResult); - - var point = GetCorrectedGeoPoint(new GeoPoint(0, 0, currentSiValue)); - - ToAltitude = _loc.Altitude.AvailableUnits - .Single(u => u.Unit == SelectedToAltUnit) - .FromSiToString(point.Altitude); - - _config.Altitude = altitude; - _cfg.Set(_config); - } - } - - private GeoPoint GetCorrectedGeoPoint(GeoPoint point) - { - // WGS 84 -> PZ 90 - if (SelectedFromStandardIndex == 0 & SelectedToStandardIndex == 1) return point.WGS84_PZ90(); - // PZ 90 -> WGS 84 - if (SelectedFromStandardIndex == 1 & SelectedToStandardIndex == 0) return point.PZ90_WGS84(); - return point; - } - - [Reactive] - public ICommand SwapStandards { get; set; } - - [Reactive] - public ICommand SwapLatLongUnits { get; set; } - - [Reactive] - public ICommand SwapAltUnits { get; set; } - - [Reactive] - public int SelectedFromStandardIndex { get; set; } - - [Reactive] - public int SelectedToStandardIndex { get; set; } - - [Reactive] - public int SelectedFromLatLongUnitIndex { get; set; } - - [Reactive] - public int SelectedToLatLongUnitIndex { get; set; } - - [Reactive] - public string SelectedFromLatLongUnit { get; set; } - - [Reactive] - public string SelectedToLatLongUnit { get; set; } - - [Reactive] - public int SelectedFromAltUnitIndex { get; set; } - - [Reactive] - public int SelectedToAltUnitIndex { get; set; } - - [Reactive] - public string SelectedFromAltUnit { get; set; } - - [Reactive] - public string SelectedToAltUnit { get; set; } - - [Reactive] - public string FromLatitude { get; set; } - - [Reactive] - public string ToLatitude { get; set; } - - [Reactive] - public string FromLongitude { get; set; } - - [Reactive] - public string ToLongitude { get; set; } - - [Reactive] - public string FromAltitude { get; set; } - - [Reactive] - public string ToAltitude { get; set; } - - public IMeasureUnitItem[] LatLongUnits => _loc.Degree.AvailableUnits.ToArray(); - - public IMeasureUnitItem[] AltUnits => _loc.Altitude.AvailableUnits.ToArray(); - - public string[] Standards => new[] - { - "WSG 84", - "ПЗ 90" - }; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/HeaderCoordinatesCalculatorMenu.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/HeaderCoordinatesCalculatorMenu.cs deleted file mode 100644 index 830e9383..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/CoordinatesCalculator/HeaderCoordinatesCalculatorMenu.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.ComponentModel.Composition; -using Asv.Cfg; -using Avalonia.Input; -using FluentAvalonia.UI.Controls; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[Export(HeaderMenuItem.UriString + "/tools", typeof(IHeaderMenuItem))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class HeaderCoordinatesCalculatorMenu : HeaderMenuItem -{ - public const string UriString = HeaderMenuItem.UriString + "tools/coord-calc"; - public static readonly Uri Uri = new(UriString); - private readonly ILocalizationService _loc; - private readonly IConfiguration _cfg; - - [ImportingConstructor] - public HeaderCoordinatesCalculatorMenu(ILocalizationService loc, IConfiguration cfg):base(Uri) - { - _loc = loc ?? throw new ArgumentNullException(nameof(loc)); - _cfg = cfg ?? throw new ArgumentNullException(nameof(cfg)); - Header = RS.HeaderCoordinatesCalculatorMenu_Header; - Icon = MaterialIconKind.DatabaseOutline; - Order = 0; - //Command = cmd.OpenStore; - HotKey = KeyGesture.Parse("Alt+C"); - Command = ReactiveCommand.CreateFromTask(ExecuteImpl); - } - - private async Task ExecuteImpl(CancellationToken cancel) - { - var dialog = new ContentDialog - { - Title = RS.CoordinatesCalculatorDialog_Title, - CloseButtonText = RS.CoordinatesCalculatorDialog_CloseButton, - IsPrimaryButtonEnabled = false, - IsSecondaryButtonEnabled = false, - FullSizeDesired = true - }; - - using var viewModel = new CoordinatesCalculatorViewModel(_cfg, _loc); - viewModel.ApplyDialog(dialog); - dialog.Content = viewModel; - - var result = await dialog.ShowAsync(); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterView.axaml b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterView.axaml deleted file mode 100644 index bf6fb77f..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterView.axaml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterView.axaml.cs deleted file mode 100644 index d1ef0b7c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterView.axaml.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(TemplaterViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class TemplaterView : ReactiveUserControl -{ - public TemplaterView() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterViewModel.cs deleted file mode 100644 index 266ea201..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/Dialog/TemplaterViewModel.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Windows.Input; -using Asv.Cfg; -using Asv.Common; -using DynamicData; -using DynamicData.Binding; -using FluentAvalonia.UI.Controls; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -public class TemplaterViewModelConfig -{ - public string TemplatePath { get; set; } - public string ResultPath { get; set; } -} - -public class TemplaterViewModel : ViewModelBaseWithValidation -{ - private readonly IConfiguration _cfg; - private readonly ILocalizationService _loc; - private readonly TemplaterViewModelConfig _config; - - private ReadOnlyObservableCollection _tags; - private ObservableAsPropertyHelper _isRefreshing; - private readonly SourceList _tagsList; - - public const string UriString = ShellViewModel.UriString + "/tools/templater"; - public static readonly Uri Uri = new(UriString); - - public TemplaterViewModel() : base(Uri) - { - - ClearTagsList = ReactiveCommand.Create(ClearTagsListImpl); - AddEmptyStringTag = ReactiveCommand.Create(() => AddStringTag()); - AddEmptyImageTag = ReactiveCommand.Create(() => AddImageTag()); - } - - [ImportingConstructor] - public TemplaterViewModel(IConfiguration cfg) : this() - { - _cfg = cfg; - _config = _cfg.Get(); - - TemplatePath = _config.TemplatePath; - ResultPath = _config.ResultPath; - - _tagsList = new SourceList().DisposeItWith(Disposable); - _tagsList.Connect() - .Bind(out _tags) - .Subscribe() - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.TemplatePath, false) - .Subscribe(_ => - { - _config.TemplatePath = TemplatePath; - _cfg.Set(_config); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.ResultPath, false) - .Subscribe(_ => - { - _config.ResultPath = ResultPath; - _cfg.Set(_config); - }) - .DisposeItWith(Disposable); - } - - [Reactive] - public ICommand ClearTagsList { get; set; } - - [Reactive] - public ICommand AddEmptyStringTag { get; set; } - - [Reactive] - public ICommand AddEmptyImageTag { get; set; } - - [Reactive] - public string TemplatePath { get; set; } - - [Reactive] - public string ResultPath { get; set; } - - [Reactive] - public bool IsReportPrint { get; set; } - - public ReadOnlyObservableCollection Tags => _tags; - - public void AddImageTag(string tag = "", string path = "") - { - var currentGuid = Guid.NewGuid(); - _tagsList.Add(new ImageTagElement(currentGuid, ReactiveCommand.Create(() => - { - _tagsList.Remove(_tags.FirstOrDefault(_ => _.Id == currentGuid)); - })){Tag = tag, Path = path}); - } - - public void AddStringTag(string tag = "", string value = "") - { - var currentGuid = Guid.NewGuid(); - _tagsList.Add(new StringTagElement(currentGuid, ReactiveCommand.Create(() => - { - _tagsList.Remove(_tags.FirstOrDefault(_ => _.Id == currentGuid)); - })){Tag = tag, Value = value}); - } - - private void ClearTagsListImpl() - { - _tagsList.Clear(); - } - - private void SaveDocImpl() - { - if(!File.Exists(TemplatePath)) return; - - var template = new DocxTemplate(TemplatePath); - - foreach (var tag in Tags) - { - if (tag is StringTagElement strTag) - { - template.Tag(strTag.Tag, strTag.Value); - } - else if (tag is ImageTagElement imgTag) - { - template.Image(imgTag.Tag, imgTag.Path); - } - } - - template.Save(ResultPath); - } - - public void ApplyDialog(ContentDialog dialog) - { - if (dialog == null) throw new ArgumentNullException(nameof(dialog)); - - dialog.PrimaryButtonCommand = ReactiveCommand.Create(SaveDocImpl).DisposeItWith(Disposable); - } -} - -public abstract class TagElement -{ - public Guid Id { get; protected set; } - public string Tag { get; set; } - internal ICommand Remove { get; set; } -} - -public class StringTagElement : TagElement -{ - public StringTagElement(Guid id, ICommand remove) - { - Id = id; - Remove = remove; - } - - public string Value { get; set; } -} - -public class ImageTagElement : TagElement -{ - public ImageTagElement(Guid id, ICommand remove) - { - Id = id; - Remove = remove; - } - - public string Path { get; set; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/DocxTemplate.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/DocxTemplate.cs deleted file mode 100644 index ff0a2b69..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/DocxTemplate.cs +++ /dev/null @@ -1,783 +0,0 @@ -using System.Text; -using System.Text.RegularExpressions; -using DocumentFormat.OpenXml; -using DocumentFormat.OpenXml.Drawing; -using DocumentFormat.OpenXml.Office2010.Word.DrawingShape; -using DocumentFormat.OpenXml.Packaging; -using DocumentFormat.OpenXml.Vml; -using DocumentFormat.OpenXml.Wordprocessing; -using SkiaSharp; -using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing; -using PIC = DocumentFormat.OpenXml.Drawing.Pictures; - -using Path = System.IO.Path; -using Paragraph = DocumentFormat.OpenXml.Wordprocessing.Paragraph; -using Run = DocumentFormat.OpenXml.Wordprocessing.Run; -using RunProperties = DocumentFormat.OpenXml.Wordprocessing.RunProperties; -using Table = DocumentFormat.OpenXml.Wordprocessing.Table; -using TableCell = DocumentFormat.OpenXml.Wordprocessing.TableCell; -using TableRow = DocumentFormat.OpenXml.Wordprocessing.TableRow; -using Text = DocumentFormat.OpenXml.Wordprocessing.Text; -using Anchor = DocumentFormat.OpenXml.Drawing.Wordprocessing.Anchor; -using Picture = DocumentFormat.OpenXml.Wordprocessing.Picture; -using Shape = DocumentFormat.OpenXml.Vml.Shape; - -namespace Asv.Drones.Gui.Core; - -public class DocxTemplate : IDocxTemplate -{ - private WordprocessingDocument _document; - private readonly string _tmpFilePath; - - /// - /// Initializes a DocxTemplate object with a Stream - /// - /// - public DocxTemplate(Stream stream) - { - _tmpFilePath = Path.GetTempFileName(); - try - { - if (stream.Length != 0) - using (var fileStream = File.Create(_tmpFilePath, (int)stream.Length)) - { - //Allocates an array with a total size equal to the size of the stream - //May have difficulty allocating memory for large volumes - byte[] data = new byte[stream.Length]; - _ = stream.Read(data, 0, data.Length); - fileStream.Write(data, 0, data.Length); - } - _document = WordprocessingDocument.Open(_tmpFilePath, true); - } - catch - { - _document = null; - } - } - - /// - /// Initializes a DocxTemplate object with a file path - /// - /// - public DocxTemplate(string filePath) - { - try - { - _tmpFilePath = Path.GetTempFileName(); - File.Copy(filePath, _tmpFilePath, true); - _document = WordprocessingDocument.Open(_tmpFilePath, true); - } - catch - { - _document = null; - } - } - - /// - /// Insert an image referenced either by a file path or a memory stream - /// at a location marked by a tag in the document. - /// - /// - /// path to image - /// - /// - public void Image(string tag, string imgFileName) - { - var mainPart = _document.MainDocumentPart; - var imagePart = mainPart.AddImagePart(ImagePartType.Png); - - using (var stream = new FileStream(imgFileName, FileMode.Open)) - { - imagePart.FeedData(stream); - } - using(var stream = new FileStream(imgFileName, FileMode.Open)) - using (SKManagedStream skStream = new SKManagedStream(stream)) - using (SKBitmap skBitmap = SKBitmap.Decode(skStream)) - { - AddImageToBody(_document, mainPart.GetIdOfPart(imagePart), tag, ImagePartType.Png, skBitmap.Width, skBitmap.Height); - } - - } - - /// - /// Insert an image referenced either by a file path or a memory stream - /// at a location marked by a tag in the document. - /// - /// - /// image stream - /// - /// - public void Image(string tag, MemoryStream imageStream) - { - var mainPart = _document.MainDocumentPart; - var imagePart = mainPart.AddImagePart(ImagePartType.Png); - imagePart.FeedData(imageStream); - using (SKManagedStream skStream = new SKManagedStream(imageStream)) - using (SKBitmap skBitmap = SKBitmap.Decode(skStream)) - { - AddImageToBody(_document, mainPart.GetIdOfPart(imagePart), tag, ImagePartType.Png, skBitmap.Width, skBitmap.Height); - } - } - - /// - /// This method is used to replace a specific tag - /// with a provided text in headers, footers, and the document body. - /// This could be useful for things like template placeholders. - /// - /// what to replace - /// replace string - /// Returns replacement result. - public bool Tag(string tagName, string toString) - { - if (_document == null) return false; - - //Finding (and replacing) the tag in the headers - var headerParts = _document.MainDocumentPart.HeaderParts; - - foreach (var headerPart in headerParts) - { - foreach (var paragraph in headerPart.Header.ChildElements.OfType()) - ReplaceTagInFooterParagraph(paragraph, tagName, toString); - - foreach (var table in headerPart.Header.ChildElements.OfType()) - foreach (var tableRow in table.Elements()) - foreach (var tableCell in tableRow.Elements()) - { - if (!CheckIsMarkedColumn(tableCell, tagName)) continue; - foreach (var element in tableCell.Elements()) - ReplaceTagInParagraph(element, tagName, toString); - } - - foreach (var sdtBlock in headerPart.Header.ChildElements.OfType()) - foreach (var paragraph in sdtBlock.SdtContentBlock.ChildElements.OfType()) - ReplaceTagInFooterParagraph(paragraph, tagName, toString); - } - - //Finding (and replacing) the tag in the footers - var footerParts = _document.MainDocumentPart.FooterParts; - foreach (var footerPart in footerParts) - { - if (footerPart.Footer.Elements().Any()) - foreach (var sdtBlock in footerPart.Footer.Elements()) - foreach (var paragraph in sdtBlock.SdtContentBlock.ChildElements.OfType()) - ReplaceTagInFooterParagraph(paragraph, tagName, toString); - else - foreach (var paragraph in footerPart.Footer.ChildElements.OfType()) - ReplaceTagInParagraphMod(paragraph, tagName, toString); - } - - //Finding (and replacing) a tag in the document body - var body = _document.MainDocumentPart.Document.Body; - foreach (var paragraph in body.Elements()) - ReplaceTagInParagraph(paragraph, tagName, toString); - - //Finding (and replacing) the tag in the document body tables - InsertTagToTable(_document, tagName, toString); - return true; - } - - /// - /// This method tries to insert the data into the existing table. - /// - /// - /// - public void FixedTable(string column, IEnumerable data) - { - InsertDataToTable(column, data, false); - } - - /// - /// This method can expand the table if the data size exceeds the table size. - /// - /// - /// - public void DynamicTable(string column, IEnumerable data) - { - InsertDataToTable(column, data, true); - } - - /// - /// This method saves any modifications to the document. - /// - /// - public void Save(string filePath) - { - if (_document == null) return; - _document.MainDocumentPart.Document.Save(); - _document.Dispose(); - CreateDirectory(filePath); - - File.Copy(_tmpFilePath, filePath, true); - _document = WordprocessingDocument.Open(_tmpFilePath, true); - } - - /// - /// This method disposes of the document - /// and deletes any temporary files created during operations. - /// - public void Dispose() - { - if (_document == null) return; - _document.Dispose(); - File.Delete(_tmpFilePath); - } - - /// - /// This method inserts an image into the body of the document - /// at the location marked by a tag. - /// - /// - /// - /// - /// - /// - /// - private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId, string tag, ImagePartType imageType, double width, double height) - { - var picName = $"{tag}.{(imageType == ImagePartType.Jpeg ? "jpg" : $"{imageType:G}".ToLower())}"; - //Define the reference of the image. - var element = - new Drawing( - new DW.Inline( - new DW.Extent { Cx = width.Inches(), Cy = height.Inches() }, //Width and Height of the image in inches. 1" = 1000000L - new DW.EffectExtent - { - LeftEdge = 0L, - TopEdge = 0L, - RightEdge = 0L, - BottomEdge = 0L - }, - new DW.DocProperties - { - Id = 1U, - Name = tag //Make sure all of the images have a different name - }, - new DW.NonVisualGraphicFrameDrawingProperties( - new GraphicFrameLocks { NoChangeAspect = true }), - new Graphic( - new GraphicData( - new PIC.Picture( - new PIC.NonVisualPictureProperties( - new PIC.NonVisualDrawingProperties - { - Id = (UInt32Value)0U, - Name = picName //Make sure all of the images have a different name - }, - new PIC.NonVisualPictureDrawingProperties()), - new PIC.BlipFill( - new Blip( - new BlipExtensionList( - new BlipExtension - { - Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}" - }) - ) - { - Embed = relationshipId, - CompressionState = BlipCompressionValues.Print - }, - new Stretch( - new FillRectangle())), - new PIC.ShapeProperties( - new Transform2D( - new Offset { X = 0L, Y = 0L }, - new Extents { Cx = width.Inches(), Cy = height.Inches() }), //Width and Height of the image in inches. 1" = 1000000L - new PresetGeometry( - new AdjustValueList() - ) - { Preset = ShapeTypeValues.Rectangle })) - ) - { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }) - ) - { - DistanceFromTop = 0U, - DistanceFromBottom = 0U, - DistanceFromLeft = 0U, - DistanceFromRight = 0U, - EditId = "50D07946" - }); - - //Append the reference to the specific paragraph that contains the 'tag'. - - var paragraphs = wordDoc.MainDocumentPart.Document.Body.Elements() - .Where(f => f.InnerText.Contains('$' + tag + '$')); - var tables = wordDoc.MainDocumentPart.Document.Body.Elements
(); - paragraphs = tables.Aggregate(paragraphs, (current2, table) => table.Elements().Aggregate(current2, (current1, row) => row.Elements().Aggregate(current1, (current, cell) => current.Concat(cell.Elements().Where(_ => _.InnerText.Contains('$' + tag + '$')))))); - - foreach (var paragraph in paragraphs) - ReplaceImageTagInParagraph(paragraph, element); - } - - /// - /// This method used to replace a specified tag with text in different parts - /// of the paragraph. It's essential for the Tag method which - /// provides the functionality of replacing tags in the document. - /// - /// - /// - /// - private static void ReplaceTagInParagraphMod(Paragraph paragraph, string tag, string tagValue) - { - if (paragraph == null || string.IsNullOrEmpty(tag)) return; - - RemoveProofErrorFromParagraph(paragraph); - - var strBld = new StringBuilder(""); - - var strPattern = $@"\${tag}\$"; - - var startIndex = -1; - var elements = paragraph.Elements().ToList(); - for (var i = 0; i < elements.Count; i++) - { - int count; - if (elements[i] is Run) - { - if (elements[i].Elements().Any(_ => _ is Text) && !string.IsNullOrWhiteSpace(elements[i].InnerText)) - { - if (startIndex == -1) startIndex = i; - foreach (var element in elements[i].Elements()) - { - strBld.Append(element.InnerText); - } - } - else - { - count = startIndex != -1 ? i - startIndex : 0; - - if (Regex.Match(strBld.ToString(), strPattern, RegexOptions.IgnoreCase) != Match.Empty) - { - var str = Regex.Replace(strBld.ToString(), strPattern, tagValue, RegexOptions.IgnoreCase); - ModifyParagraph(paragraph, str, startIndex, count); - } - strBld.Clear(); - startIndex = -1; - } - } - else - { - count = startIndex != -1 ? i - startIndex : 0; - if (Regex.Match(strBld.ToString(), strPattern, RegexOptions.IgnoreCase) != Match.Empty) - { - var str = Regex.Replace(strBld.ToString(), strPattern, tagValue, RegexOptions.IgnoreCase); - ModifyParagraph(paragraph, str, startIndex, count); - } - strBld.Clear(); - startIndex = -1; - } - } - } - - /// - /// This method used to replace a specified tag with image in different parts - /// of the paragraph. It's essential for the Tag method which - /// provides the functionality of replacing tags in the document. - /// - /// - /// - private static void ReplaceImageTagInParagraph(Paragraph paragraph, OpenXmlElement img) - { - paragraph.RemoveAllChildren(); - - if (img != null) paragraph.AppendChild(new Run(img)); - } - - /// - /// This method used to replace a specified tag with text in different parts - /// of the paragraph. It's essential for the Tag method which - /// provides the functionality of replacing tags in the document. - /// - /// - /// - /// - private static void ReplaceTagInParagraph(Paragraph paragraph, string tag, string tagValue) - { - var strBld = new StringBuilder(""); - - foreach (var run in paragraph.ChildElements.OfType()) - { - foreach (var element in run.ChildElements) - { - if (element is TabChar) - strBld.Append('\t'); - else - strBld.Append(element.InnerText); - } - } - - var strPattern = $@"\${tag}\$"; - - if (Regex.Match(strBld.ToString(), strPattern, RegexOptions.IgnoreCase).Length == 0) return; - var str = Regex.Replace(strBld.ToString(), strPattern, tagValue, RegexOptions.IgnoreCase); - ModifyParagraph(paragraph, str); - } - - /// - /// This method used to replace a specified tag with text in different parts - /// of the paragraph. It's essential for the Tag method which - /// provides the functionality of replacing tags in the document. - /// - /// - /// - /// - private static void ReplaceTagInFooterParagraph(Paragraph paragraph, string tagName, string toString) - { - foreach (var run in paragraph.ChildElements.OfType()) - { - if (!run.InnerText.Contains(tagName)) continue; - - var choice = run.GetFirstChild()?.GetFirstChild(); - //ReSharper disable once PossibleNullReferenceException - if (choice != null) - foreach (var par in choice.GetFirstChild().GetFirstChild().GetFirstChild().GraphicData.GetFirstChild().GetFirstChild().TextBoxContent.ChildElements.OfType()) - { - ReplaceTagInParagraph(par, tagName, toString); - } - - var fallback = run.GetFirstChild()?.GetFirstChild(); - - if (fallback != null) - foreach (var par in fallback.GetFirstChild().GetFirstChild().GetFirstChild().GetFirstChild().ChildElements.OfType()) - { - ReplaceTagInParagraph(par, tagName, toString); - } - - ReplaceTagInParagraphMod(paragraph, tagName, toString); - } - } - - /// - /// This method changes the text within a paragraph to the suggested one. - /// It is used by other methods to replace the text corresponding to the - /// tag with the given text. - /// - /// - /// - /// paragraph must be not null - private static void ModifyParagraph(Paragraph paragraph, string str) - { - if (paragraph == null) throw new ArgumentNullException(nameof(paragraph)); - if (str == null) return; - var run = new Run(); - var text = new Text { Text = str }; - - var runProperties = paragraph.ChildElements.OfType() - ?.FirstOrDefault(_ => _.ChildElements.OfType().Any()) - ?.GetFirstChild(); - if (runProperties != null) run.Append(runProperties.CloneNode(true)); - - run.Append(text); - if (paragraph.Elements().Any()) paragraph.RemoveAllChildren(); - paragraph.Append(run); - } - - /// - /// This method changes the text within a paragraph to the suggested one. - /// It is used by other methods to replace the text corresponding to the - /// tag with the given text. - /// - /// - /// - /// - /// - /// paragraph must be not null - private static void ModifyParagraph(Paragraph paragraph, string str, int startIndex, int count) - { - if (paragraph == null) throw new ArgumentNullException(nameof(paragraph)); - if (str == null) return; - - if (count == 0) return; - - - var elements = paragraph.Elements().Skip(startIndex).Take(count).ToList(); - var properties = elements.FirstOrDefault(_ => _.ChildElements.OfType().Any())?.ChildElements.OfType().FirstOrDefault()?.CloneNode(true); - - var run = new Run(); - var text = new Text { Text = str }; - if (properties != null) - run.Append(properties); - run.Append(text); - - foreach (var element in elements) - { - paragraph.RemoveChild(element); - } - paragraph.InsertAt(run, startIndex); - } - - /// - /// This method is used to insert data into a table in the document. - /// - /// - /// - /// - private void InsertDataToTable(string column, IEnumerable data, bool isDynamic) - { - if (_document == null) return; - var body = _document.MainDocumentPart.Document.Body; - IEnumerable strings = data as string[] ?? data.ToArray(); - foreach (var table in body.Elements
()) - { - var rowNumber = 0; - - foreach (var tableRow in table.Elements()) - { - foreach (var tableCell in tableRow.Elements()) - { - if (!CheckIsMarkedColumn(tableCell, column)) continue; - - //cellNumber is returned given the GridSpan - var cellNumber = GetCellNumber(tableRow.Elements(), tableCell); - InsertDataToTableBeginningWith(table, rowNumber, cellNumber, strings, isDynamic); - - } - rowNumber++; - } - } - } - - /// - /// This method is used to insert data into a table in the document. - /// - /// - /// - /// - private static void InsertDataToTableBeginningWith(Table table, int rowNumber, int cellNumber, IEnumerable data, bool isDynamicTable) - { - IEnumerable strings = data as string[] ?? data.ToArray(); - - var deltaRowNumber = 0; //A variable is needed to shift the row number if the FIXED table has vertically merged cells - - var tableRowCount = table.Elements().Count(); - var emplyRow = table.Elements().ElementAt(rowNumber).Clone() as TableRow; - var cells = emplyRow?.Elements(); - ClearTextInCells(cells); - var emplyLastRow = table.Elements().ElementAt(tableRowCount - 1).Clone() as TableRow; - cells = emplyLastRow?.Elements(); - ClearTextInCells(cells); - - for (var i = 0; i < strings.Count(); i++) - { - if (i + rowNumber + deltaRowNumber >= table.Elements().Count()) - { - if (isDynamicTable) - { - if (i == strings.Count() - 1) - table.Append(emplyLastRow.Clone() as TableRow); - else - table.Append(emplyRow.Clone() as TableRow); - } - else break; - } - else if (i + rowNumber + deltaRowNumber == tableRowCount - 1) - //Last row of the table - { - if (i < strings.Count() - 1 && rowNumber != tableRowCount - 1 && isDynamicTable) - //Not the last line of data - { - //The last row is replaced by an intermediate empty row - table.ReplaceChild(emplyRow.Clone() as TableRow, - table.Elements().ElementAt(i + rowNumber + deltaRowNumber)); - } - - } - //In fixed tables, we can insert data into merged cells - - var cell = GetCell( - table.Elements().ElementAt(i + rowNumber + deltaRowNumber).Elements(), - cellNumber); - - var mergeCount = 0; - if (!isDynamicTable) - { - //Check if the cell is a continuation of the combined cell - if (cell.TableCellProperties.VerticalMerge != null && - (cell.TableCellProperties.VerticalMerge.Val?.Value == MergedCellValues.Continue || - cell.TableCellProperties.VerticalMerge.Val?.Value == MergedCellValues.Restart)) - { - while (i + rowNumber + deltaRowNumber + mergeCount + 1 < tableRowCount) - { - cell = GetCell( - table.Elements().ElementAt(i + rowNumber + deltaRowNumber + mergeCount + 1) - .Elements(), cellNumber); - if (cell.TableCellProperties.VerticalMerge != null && - (cell.TableCellProperties.VerticalMerge.Val?.Value == MergedCellValues.Continue || - cell.TableCellProperties.VerticalMerge.Val == null)) - mergeCount++; - else break; - } - } - } - - CopyRunToParagraph(table, rowNumber + i + deltaRowNumber, cellNumber, rowNumber); - ModifyParagraph( - GetCell(table.Elements().ElementAt(i + rowNumber + deltaRowNumber).Elements(), - cellNumber) - .GetFirstChild(), strings.ElementAt(i)); - - deltaRowNumber += mergeCount; - } - } - - /// - /// This method performs the insertion of a specified tag into the table - /// of a document. - /// - /// - /// - /// - private static void InsertTagToTable(WordprocessingDocument document, string tag, string value) - { - if (document == null) return; - - var tables = document.MainDocumentPart.Document.Body.Elements
(); - - IEnumerable paragraphs = new List(); - paragraphs = tables.Aggregate(paragraphs, (current2, table) => table.Elements() - .Aggregate(current2, (current1, tableRow) => tableRow.Elements() - .Aggregate(current1, (current, tableCell) => current.Concat(tableCell.Elements() - .Where(_ => _.InnerText.Contains('$' + tag + '$')))))); - - foreach (var paragraph in paragraphs) - { - ReplaceTagInParagraph(paragraph, tag, value); - } - } - - /// - /// This method is used to clear the text in the cells of a table - /// and a run, respectively. - /// - /// - private static void ClearTextInCells(IEnumerable cells) - { - foreach (var cell in cells) - foreach (var paragpaph in cell.Elements()) - foreach (var run in paragpaph.Elements()) - ClearTextInRun(run); - } - - /// - /// This method is used to clear the text in the cells of a table - /// and a run, respectively. - /// - /// - private static void ClearTextInRun(Run run) - { - if (run.Elements().Any()) - run.RemoveAllChildren(); - var text = new Text { Text = "" }; - run.Append(text); - } - - /// - /// This is helper method used for dealing with tables. - /// - /// - /// - /// It returns the cell number and a reference to a cell. - private static int GetCellNumber(IEnumerable cells, TableCell cell) - { - var cellNumber = 0; - - foreach (var c in cells) - { - if (c == cell) break; - - if (c.TableCellProperties.GridSpan?.Val != null) - cellNumber += c.TableCellProperties.GridSpan.Val.Value; - else - cellNumber++; - } - - return cellNumber; - } - - /// - /// This is helper method used for dealing with tables. - /// - /// - /// - /// It returns a reference to a cell. - private static TableCell GetCell(IEnumerable cells, int cellNum) - { - var index = 0; - foreach (var cell in cells) - { - if (index == cellNum) - return cell; - - if (cell.TableCellProperties.GridSpan?.Val != null) - index += cell.TableCellProperties.GridSpan.Val.Value; - else - index++; - } - return null; - } - - /// - /// This method creates directories in the specified path if - /// they don't exist yet. - /// - /// - private static void CreateDirectory(string templFilePath) - { - //If there are folders in the template path (in templFilePath), then when unloading, we also create folders - var directoryName = Path.GetDirectoryName(templFilePath); - - if (!string.IsNullOrWhiteSpace(directoryName) && Directory.Exists(directoryName) == false) - Directory.CreateDirectory(directoryName); - } - - /// - /// This method copies a run (a block of text) from an old location - /// to a new one. - /// - /// - /// - /// - /// - private static void CopyRunToParagraph(Table table, int newRowNumber, int cellNumber, int oldRowNumber) - { - var cell = GetCell(table.Elements().ElementAt(newRowNumber).Elements(), cellNumber); - - if (cell.GetFirstChild().Elements().Any()) return; - - var oldCell = GetCell(table.Elements().ElementAt(oldRowNumber).Elements(), cellNumber); - - cell.GetFirstChild().Append(oldCell.GetFirstChild().GetFirstChild().Clone() as Run); - - ClearTextInRun(cell.GetFirstChild().GetFirstChild()); - } - - /// - /// This method checks whether the specified table cell contains - /// the specified tag. - /// - /// - /// - /// Returns true if contains. - private static bool CheckIsMarkedColumn(TableCell tableCell, string column) - { - var strBld = new StringBuilder(""); - var strPattern = $@"\${column}\$"; - foreach (var paragraph in tableCell.Elements()) - foreach (var run in paragraph.Elements()) - strBld.Append(run.InnerText); - - return Regex.Match(strBld.ToString(), strPattern, RegexOptions.IgnoreCase).Length != 0; - } - - /// - /// Removes ProofError elements from a paragraph. - /// - /// - private static void RemoveProofErrorFromParagraph(OpenXmlElement paragraph) - { - var error = paragraph.ChildElements.OfType().ToList(); - foreach (var er in error) - { - paragraph.RemoveChild(er); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/DocxTemplateHelper.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/DocxTemplateHelper.cs deleted file mode 100644 index e08e380b..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/DocxTemplateHelper.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Asv.Drones.Gui.Core; - -internal static class DocxTemplateHelper -{ - public static long Inches(this double size) - { - return (long)(size * 5000); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/HeaderTemplaterMenu.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/HeaderTemplaterMenu.cs deleted file mode 100644 index 81d8313a..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/HeaderTemplaterMenu.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.ComponentModel.Composition; -using Asv.Cfg; -using Avalonia.Input; -using FluentAvalonia.UI.Controls; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[Export(HeaderMenuItem.UriString + "/tools", typeof(IHeaderMenuItem))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class HeaderTemplaterMenu : HeaderMenuItem -{ - public const string UriString = HeaderMenuItem.UriString + "tools/templater"; - public static readonly Uri Uri = new(UriString); - private readonly IConfiguration _cfg; - - [ImportingConstructor] - public HeaderTemplaterMenu(IConfiguration cfg):base(Uri) - { - _cfg = cfg; - Header = RS.HeaderTemplaterMenu_Header; - Icon = MaterialIconKind.CalendarBlank; - Order = 1; - HotKey = KeyGesture.Parse("Alt+T"); - Command = ReactiveCommand.CreateFromTask(ExecuteImpl); - } - - private async Task ExecuteImpl(CancellationToken cancel) - { - var dialog = new ContentDialog - { - Title = RS.HeaderTemplaterMenu_Header, - CloseButtonText = RS.TemplaterDialog_CloseButton, - PrimaryButtonText = RS.TemplaterDialog_SaveButton - }; - using var viewModel = new TemplaterViewModel(_cfg); - viewModel.ApplyDialog(dialog); - dialog.Content = viewModel; - var result = await dialog.ShowAsync(); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/IDocxTemplate.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/IDocxTemplate.cs deleted file mode 100644 index 02105421..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/Items/Templater/IDocxTemplate.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace Asv.Drones.Gui.Core; - -public interface IDocxTemplate : IDisposable -{ - /// - /// Insert an image referenced either by a file path or a memory stream - /// at a location marked by a tag in the document. - /// - /// - /// path to image - /// - /// - void Image(string tag, string path); - - /// - /// Insert an image referenced either by a file path or a memory stream - /// at a location marked by a tag in the document. - /// - /// - /// image stream - /// - /// - void Image(string tag, MemoryStream imageStream); - - /// - /// This method is used to replace a specific tag - /// with a provided text in headers, footers, and the document body. - /// This could be useful for things like template placeholders. - /// - /// what to replace - /// replace string - /// Returns replacement result. - bool Tag(string tagName, string value); - - /// - /// This method saves any modifications to the document. - /// - /// - void Save(string filePath); - - /// - /// This method tries to insert the data into the existing table. - /// - /// - /// - void FixedTable(string column, IEnumerable data); - - /// - /// This method can expand the table if the data size exceeds the table size. - /// - /// - /// - void DynamicTable(string column, IEnumerable data); -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/ToolsMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/ToolsMenuItem.cs deleted file mode 100644 index 4a104cf2..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Header/TopMenu/Tools/ToolsMenuItem.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Reactive.Linq; -using Asv.Common; -using Asv.Drones.Gui.Core; -using DynamicData; -using Material.Icons; - -[Export(HeaderMenuItem.UriString, typeof(IHeaderMenuItem))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class HeaderToolsMenu : HeaderMenuItem -{ - public const string UriString = HeaderMenuItem.UriString + "/tools"; - public static readonly Uri Uri = new(UriString); - private readonly ReadOnlyObservableCollection _items; - - [ImportingConstructor] - public HeaderToolsMenu([ImportMany(UriString)]IEnumerable> fileItemProviders) : base(Uri) - { - fileItemProviders - .Select(_ => _.Items) - .Merge() - .SortBy(_ => _.Order) - .Bind(out _items) - .Subscribe() - .DisposeItWith(Disposable); - - Header = RS.HeaderToolsMenu_Header; - Icon = MaterialIconKind.Tools; - Order = ushort.MaxValue; - } - - public override ReadOnlyObservableCollection? Items => _items; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/IShell.cs b/src/Asv.Drones.Gui.Core/Shell/IShell.cs deleted file mode 100644 index 61a45149..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/IShell.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents the main view interface of the application. - /// - public interface IShell - { - /// - /// Gets or sets the currently active shell page. - /// - /// - /// The currently active shell page. Can be null if no shell page is currently active. - /// - IShellPage? CurrentPage { get; set; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Menu/DefaultShellMenuProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Menu/DefaultShellMenuProvider.cs deleted file mode 100644 index 8fbd19c0..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Menu/DefaultShellMenuProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IViewModelProvider))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class DefaultShellMenuProvider : ViewModelProviderBase - { - [ImportingConstructor] - public DefaultShellMenuProvider([ImportMany]IEnumerable exportedMenuItems) - { - Source.AddOrUpdate(exportedMenuItems); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Menu/IShellMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Menu/IShellMenuItem.cs deleted file mode 100644 index 736d54c8..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Menu/IShellMenuItem.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Collections.ObjectModel; -using FluentAvalonia.UI.Controls; - -namespace Asv.Drones.Gui.Core -{ - /// - /// Interface for the ShellMenuItem. - /// - public interface IShellMenuItem : IViewModel - { - /// - /// Information badge displayed next to the menu item. - /// - InfoBadge InfoBadge { get; set; } - - /// - /// Parent menu item of the current menu item. - /// - IShellMenuItem? Parent { get; set; } - - /// - /// Name of the menu item. - /// - string Name { get; set; } - - /// - /// Navigation target URI of the menu item. - /// - Uri NavigateTo { get; set; } - - /// - /// Icon of the menu item. - /// - string Icon { get; } - - /// - /// Position of the menu item in the shell menu. - /// - ShellMenuPosition Position { get; } - - /// - /// Type of the menu item. - /// - ShellMenuItemType Type { get; } - - /// - /// Order of the menu item in the shell menu. - /// - int Order { get; } - - /// - /// Child menu items of the current menu item. - /// - ReadOnlyObservableCollection? Items { get; } - - /// - /// indicates if the menu item is currently selected. - /// - bool IsSelected { get; set; } - - /// - /// indicates if the menu item is currently visible. - /// - bool IsVisible { get; set; } - } - - /// - /// Enum for the position of the ShellMenu item. - /// - public enum ShellMenuPosition - { - Top, - Bottom, - } - - /// - /// Enum for the type of the ShellMenu item. - /// - public enum ShellMenuItemType - { - Header, - Group, - PageNavigation - } - - /// - /// Interface for the ShellMenuItem with a target. - /// - public interface IShellMenuItem:IShellMenuItem - { - /// - /// Method to Initialize a ShellMenuItem with a target. - /// - IShellMenuItem Init(TTarget target); - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsShellMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsShellMenuItem.cs deleted file mode 100644 index 14c42ffb..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsShellMenuItem.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.ComponentModel.Composition; -using Material.Icons; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IShellMenuItem))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class ConnectionsShellMenuItem : ShellMenuItem - { - public ConnectionsShellMenuItem():base("asv:shell.menu.connections") - { - Name = RS.ConnectionsShellMenuItem_Name; - NavigateTo = ConnectionsViewModel.BaseUri; - Icon = MaterialIconDataProvider.GetData(MaterialIconKind.Lan); - Position = ShellMenuPosition.Bottom; - Type = ShellMenuItemType.PageNavigation; - Order = -1; - } - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsView.axaml deleted file mode 100644 index 1c537935..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsView.axaml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsView.axaml.cs deleted file mode 100644 index 7fd1c3b8..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(ConnectionsViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class ConnectionsView : ReactiveUserControl - { - public ConnectionsView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsViewModel.cs deleted file mode 100644 index 6c9a816d..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/ConnectionsViewModel.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Reactive.Linq; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Avalonia.Controls; -using DynamicData; -using DynamicData.Binding; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportShellPage(BaseUriString)] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class ConnectionsViewModel: ShellPage - { - public const string BaseUriString = "asv:shell.connections"; - public static readonly Uri BaseUri = new(BaseUriString); - private readonly ReadOnlyObservableCollection _items; - private readonly ObservableAsPropertyHelper _isReloadRequired; - - - public ConnectionsViewModel() : base(BaseUri) - { - Title = RS.ConnectionsShellMenuItem_Name; - if (Design.IsDesignMode) - { - _isReloadRequired = Observable.Return(true).ToProperty(this, _ => _.IsReloadRequired); - _items = new ReadOnlyObservableCollection(new ObservableCollection( - new IConnectionPart[] - { - new ConnectionsIdentificationViewModel(), - new ConnectionsPortsViewModel() - })); - } - } - - [ImportingConstructor] - public ConnectionsViewModel([ImportMany]IEnumerable> partProviders, IMavlinkDevicesService svc) : this() - { - partProviders.Select(_ => _.Items) - .Merge() - .SortBy(_ => _.Order) - .Bind(out _items) - .DisposeMany() - .Subscribe() - .DisposeItWith(Disposable); - - // this is for ReloadRequired showing - _items.ToObservableChangeSet() - .AutoRefresh(_ => _.IsRebootRequired) // update collection when any part require reboot - .ToCollection() - .Select(parts => parts.Any(part => part.IsRebootRequired)) // check if any part require reboot - .ToProperty(this, _ => _.IsReloadRequired, out _isReloadRequired) - .DisposeItWith(Disposable); - } - - public ReadOnlyObservableCollection Items => _items; - - public bool IsReloadRequired => _isReloadRequired.Value; - - public void SetArgs(Uri link) - { - - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DefaultSettingsPartProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DefaultSettingsPartProvider.cs deleted file mode 100644 index 8a62ec2b..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DefaultSettingsPartProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IViewModelProvider))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class DefaultConnectionSettingsPartProvider : ViewModelProviderBase - { - [ImportingConstructor] - public DefaultConnectionSettingsPartProvider([ImportMany] IEnumerable exportedMenuItems) - { - Source.AddOrUpdate(exportedMenuItems); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserView.axaml deleted file mode 100644 index de4dfb6c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserView.axaml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserView.axaml.cs deleted file mode 100644 index 8c3dd7df..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(DeviceBrowserViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class DeviceBrowserView : ReactiveUserControl - { - public DeviceBrowserView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserViewModel.cs deleted file mode 100644 index 31377792..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/DeviceBrowserViewModel.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Reactive.Linq; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Avalonia.Controls; -using DynamicData; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IConnectionPart))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class DeviceBrowserViewModel : ViewModelBase,IConnectionPart - { - public const string BaseUriString = $"{ConnectionsViewModel.BaseUriString}.devices"; - public static readonly Uri BaseUri = new(BaseUriString); - - private readonly ReadOnlyObservableCollection _items; - - public DeviceBrowserViewModel() : base(BaseUri) - { - if (Design.IsDesignMode) - { - var portList = new List - { - new() { }, - new() { }, - new() { }, - }; - _items = new ReadOnlyObservableCollection(new ObservableCollection(portList)); - - - - } - } - - [ImportingConstructor] - public DeviceBrowserViewModel(IMavlinkDevicesService svc):this() - { - svc.Devices - .Do(_ => { }) - .Transform(_=>new MavlinkDeviceViewModel(_)) - .Bind(out _items) - .DisposeMany() - .Subscribe() - .DisposeItWith(Disposable); - Disposable.AddAction(() => { }); - } - - public bool IsRebootRequired { get; private set; } - - public int Order => 255; - - public ReadOnlyObservableCollection Items => _items; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceView.axaml deleted file mode 100644 index 08bf4ccb..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceView.axaml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceView.axaml.cs deleted file mode 100644 index ffb66dc4..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(MavlinkDeviceViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class MavlinkDeviceView : ReactiveUserControl - { - public MavlinkDeviceView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceViewModel.cs deleted file mode 100644 index 5860b9c2..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/DeviceBrowser/MavlinkDeviceViewModel.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System.Reactive.Linq; -using Asv.Common; -using Asv.Mavlink; -using Avalonia.Controls; -using Material.Icons; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core -{ - public class MavlinkDeviceViewModel : ViewModelBase - { - private uint _rate; - private DateTime _lastUpdate; - private uint _lastRate; - - public MavlinkDeviceViewModel():base(new Uri(DeviceBrowserViewModel.BaseUri,"item")) - { - if (Design.IsDesignMode) - { - Icon = MaterialIconKind.Quadcopter; - Name = "Quadcopter [1:1]"; - Description = "Type:Quadcopter, System ID:1, Component ID:{1}, Mavlink version:3"; - BaseModeText = "Mode:UnInit"; - CustomModeText = "10"; - SystemStatusText = "Ready"; - RateText = "0.5 Hz"; - DeviceFullId = UInt16.MinValue; - } - } - - public MavlinkDeviceViewModel(IMavlinkDevice info) : base(new Uri(DeviceBrowserViewModel.BaseUri, $"{info.FullId}")) - { - DeviceFullId = info.FullId; - Icon = MavlinkHelper.GetIcon(info.Type); - Name = $"{MavlinkHelper.GetTypeName(info.Type):G} [{info.SystemId}:{info.ComponentId}]"; - Description = $"Type: {info.Type.ToString("G").Replace("MavType","")}, System ID: {info.SystemId}, Component ID: {info.ComponentId}, Mavlink Version: {info.MavlinkVersion}"; - - Observable.Timer(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(3),RxApp.MainThreadScheduler).Subscribe(_ => - { - var now = DateTime.Now; - var rate = (((double)_rate - _lastRate) / (now - _lastUpdate).TotalSeconds); - RateText = $"{rate:F1} Hz"; - _lastUpdate = now; - _lastRate = _rate; - }).DisposeItWith(Disposable); - - info.Ping.Sample(TimeSpan.FromSeconds(2),RxApp.MainThreadScheduler) - .Subscribe(_ => - { - ToggleLinkPing = false; - ToggleLinkPing = true; - }).DisposeItWith(Disposable); - - info.Ping.Subscribe(_=>Interlocked.Increment(ref _rate)).DisposeItWith(Disposable); - - info.BaseMode.Subscribe(_ => BaseModeText = $"Mode: {_.ToString("F").Replace("MavModeFlag","")}").DisposeItWith(Disposable); - info.SystemStatus.Subscribe(_ => SystemStatusText = _.ToString("G").Replace("MavState","")).DisposeItWith(Disposable); - info.CustomMode.Subscribe(_ => CustomModeText = _.ToString()).DisposeItWith(Disposable); - } - - - - - public ushort DeviceFullId { get; } - - public MaterialIconKind Icon { get; set; } - - public string Description { get; set; } - - public string Name { get; set; } - - [Reactive] - public bool ToggleLinkPing { get; set; } - - [Reactive] - public string BaseModeText { get; set; } - [Reactive] - public string CustomModeText { get; set; } - [Reactive] - public string SystemStatusText { get; set; } - [Reactive] - public string RateText { get; set; } - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/IConnectionPart.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/IConnectionPart.cs deleted file mode 100644 index cccb2cb7..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/IConnectionPart.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Asv.Drones.Gui.Core -{ - - /// - /// All parts of the connection settings must implement this interface to be displayed in the application - /// - public interface IConnectionPart : IViewModel - { - /// - /// Part of the connection settings can set it to true to force the application to restart - /// - bool IsRebootRequired { get; } - /// - /// Display order of the part - /// - int Order { get; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationView.axaml deleted file mode 100644 index 260214da..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationView.axaml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationView.axaml.cs deleted file mode 100644 index 045384de..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(ConnectionsIdentificationViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class ConnectionsIdentificationView : ReactiveUserControl - { - public ConnectionsIdentificationView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationViewModel.cs deleted file mode 100644 index 48fb8e8a..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Identification/ConnectionsIdentificationViewModel.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System.ComponentModel.Composition; -using System.Reactive.Linq; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Avalonia.Controls; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Validation.Extensions; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IConnectionPart))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class ConnectionsIdentificationViewModel:ViewModelBaseWithValidation,IConnectionPart - { - public const uint DeviceTimeoutMin = 1; // 1 second - public const uint DeviceTimeoutMax = 15 * 60; // 15 minute - - public ConnectionsIdentificationViewModel() : base(new Uri(ConnectionsViewModel.BaseUri,"id")) - { - this.ValidationRule(_ => _.DeviceTimeout, _ => _ is >= DeviceTimeoutMin and <= DeviceTimeoutMax, _ => string.Format(RS.ConnectionsIdentificationViewModel_DeviceTimeout, DeviceTimeoutMin, DeviceTimeoutMax)) - .DisposeItWith(Disposable); - - - if (Design.IsDesignMode) - { - SystemId = 254; - ComponentId = 254; - SelectedRate = Rates.First(); - DeviceTimeout = 30; - } - } - - [ImportingConstructor] - public ConnectionsIdentificationViewModel(IMavlinkDevicesService svc):this() - { - svc.NeedReloadToApplyConfig - .Subscribe(_ => IsRebootRequired = _) - .DisposeItWith(Disposable); - - svc.SystemId - .Subscribe(_ => SystemId = _) - .DisposeItWith(Disposable); - this.WhenAnyValue(_ => _.SystemId) - .Skip(1) - .DistinctUntilChanged() - .Subscribe(svc.SystemId) - .DisposeItWith(Disposable); - - svc.ComponentId - .Subscribe(_ => ComponentId = _) - .DisposeItWith(Disposable); - this.WhenAnyValue(_ => _.ComponentId) - .Skip(1) - .DistinctUntilChanged() - .Subscribe(svc.ComponentId) - .DisposeItWith(Disposable); - - svc.HeartbeatRate - .Subscribe(_ => SelectedRate = new RateItem(_)) - .DisposeItWith(Disposable); - this.WhenAnyValue(_ => _.SelectedRate) - .Skip(1) - .DistinctUntilChanged() - .Subscribe(_ => svc.HeartbeatRate.OnNext(_.Time)).DisposeItWith(Disposable); - - svc.DeviceTimeout - .Subscribe(_ => DeviceTimeout = (uint)_.TotalSeconds) - .DisposeItWith(Disposable); - this.WhenAnyValue(_ => _.DeviceTimeout) - .Skip(1) - .Where(_=> HasErrors == false) - .DistinctUntilChanged() - .Subscribe(_ => svc.DeviceTimeout.OnNext(TimeSpan.FromSeconds(_))) - .DisposeItWith(Disposable); - } - - [Reactive] - public bool IsRebootRequired { get; private set; } - - public int Order => -1; - - public byte[] Ids { get; } = Enumerable.Range(1,254).Select(_=>(byte)_).ToArray(); - - public RateItem[] Rates { get; } = - { - new(TimeSpan.FromMilliseconds(2000)), - new(TimeSpan.FromMilliseconds(1000)), - new(TimeSpan.FromMilliseconds(500)), - new(TimeSpan.FromMilliseconds(200)), - new(TimeSpan.FromMilliseconds(100)), - }; - - - [Reactive] - public RateItem SelectedRate { get; set; } - - [Reactive] - public byte SystemId { get; set; } - - [Reactive] - public byte ComponentId { get; set; } - - [Reactive] public uint DeviceTimeout { get; set; } - - } - - public struct RateItem - { - public RateItem(TimeSpan time) - { - Time = time; - } - - public TimeSpan Time { get; } - - public override string ToString() - { - return string.Format($"{(1.0 / Time.TotalSeconds):F1}", RS.ConnectionsIdentificationViewModel_ToString); - } - } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortView.axaml deleted file mode 100644 index 4e50c00b..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortView.axaml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortView.axaml.cs deleted file mode 100644 index 51e737be..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(ConnectionsPortsViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class ConnectionsPortView : ReactiveUserControl - { - public ConnectionsPortView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortsViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortsViewModel.cs deleted file mode 100644 index 8eccfdce..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/ConnectionsPortsViewModel.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Windows.Input; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Avalonia.Controls; -using DynamicData; -using FluentAvalonia.UI.Controls; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IConnectionPart))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class ConnectionsPortsViewModel:ViewModelBase,IConnectionPart - { - private readonly IMavlinkDevicesService _deviceSvc; - private readonly ILogService _logService; - private readonly ReadOnlyObservableCollection _items; - - public ConnectionsPortsViewModel() : base(new Uri(ConnectionsViewModel.BaseUri,"ports")) - { - if (Design.IsDesignMode) - { - var portList = new List - { - new() { Name = "TCP port" }, - new() { Name = "UDP port" }, - new() { Name = "Serial port" }, - }; - _items = new ReadOnlyObservableCollection(new ObservableCollection(portList)); - } - } - - [ImportingConstructor] - public ConnectionsPortsViewModel(IMavlinkDevicesService deviceSvc, ILogService logService,ILocalizationService localization):this() - { - _deviceSvc = deviceSvc ?? throw new ArgumentNullException(nameof(deviceSvc)); - _logService = logService ?? throw new ArgumentNullException(nameof(logService)); - var cache = new SourceCache(_ => _.PortId).DisposeItWith(Disposable); - cache.Connect() - .Bind(out _items) - .DisposeMany() - .Subscribe() - .DisposeItWith(Disposable); - deviceSvc.Router - .GetPorts() - .ForEach(_ => cache.AddOrUpdate(new PortViewModel(deviceSvc, localization, _logService,_))); - deviceSvc.Router - .OnAddPort - .Subscribe(_ => cache.AddOrUpdate(new PortViewModel(deviceSvc, localization, _logService,_))) - .DisposeItWith(Disposable); - deviceSvc.Router - .OnRemovePort - .Subscribe(_ => cache.Remove(_)).DisposeItWith(Disposable); - - AddSerialPortCommand = ReactiveCommand.CreateFromTask(AddSerialPort).DisposeItWith(Disposable); - AddTcpPortCommand = ReactiveCommand.CreateFromTask(AddTcpPort).DisposeItWith(Disposable); - AddUdpPortCommand = ReactiveCommand.CreateFromTask(AddUdpPort).DisposeItWith(Disposable); - } - - private async Task AddSerialPort(CancellationToken cancel) - { - var dialog = new ContentDialog() - { - Title = RS.ConnectionsViewModel_AddSerialPortDialog_Title, - PrimaryButtonText = RS.ConnectionsViewModel_AddDialogPort_Add, - IsSecondaryButtonEnabled = true, - CloseButtonText = RS.ConnectionsViewModel_AddDialogPort_Cancel - }; - using var viewModel = new SerialPortViewModel(_deviceSvc, _logService); - viewModel.ApplyDialog(dialog); - dialog.Content = viewModel; - var result = await dialog.ShowAsync(); - } - - private async Task AddTcpPort(CancellationToken cancel) - { - var dialog = new ContentDialog() - { - Title = RS.ConnectionsViewModel_AddTcpPortDialog_Title, - PrimaryButtonText = RS.ConnectionsViewModel_AddDialogPort_Add, - IsSecondaryButtonEnabled = true, - CloseButtonText = RS.ConnectionsViewModel_AddDialogPort_Cancel - }; - using var viewModel = new TcpPortViewModel(_deviceSvc,_logService); - viewModel.ApplyDialog(dialog); - dialog.Content = viewModel; - var result = await dialog.ShowAsync(); - } - - private async Task AddUdpPort(CancellationToken cancel) - { - var dialog = new ContentDialog() - { - Title = RS.ConnectionsViewModel_AddUdpPortDialog_Title, - PrimaryButtonText = RS.ConnectionsViewModel_AddDialogPort_Add, - IsSecondaryButtonEnabled = true, - CloseButtonText = RS.ConnectionsViewModel_AddDialogPort_Cancel - }; - using var viewModel = new UdpPortViewModel(_deviceSvc); - viewModel.ApplyDialog(dialog); - dialog.Content = viewModel; - var result = await dialog.ShowAsync(); - } - - public ReadOnlyObservableCollection Items => _items; - - public ICommand AddSerialPortCommand { get; } - public ICommand AddTcpPortCommand { get; } - public ICommand AddUdpPortCommand { get; } - - public bool IsRebootRequired { get; private set; } - - public int Order => 0; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortView.axaml deleted file mode 100644 index a4827843..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortView.axaml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortView.axaml.cs deleted file mode 100644 index 43c811d4..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(SerialPortViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class SerialPortView : ReactiveUserControl - { - public SerialPortView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortViewModel.cs deleted file mode 100644 index a713019b..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/SerialPortViewModel.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.IO.Ports; -using System.Reactive.Linq; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Asv.Mavlink; -using DynamicData; -using FluentAvalonia.UI.Controls; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Validation.Extensions; - -namespace Asv.Drones.Gui.Core -{ - [Export] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class SerialPortViewModel: ViewModelBaseWithValidation - { - private readonly IMavlinkDevicesService? _device; - private readonly ILogService _logService; - private int _requestNotComplete; - private readonly ReadOnlyObservableCollection _ports; - private readonly SourceList _myCache; - public const int MinBaudRate = 75; - public const int MaxBaudRate = 921_600; - - public SerialPortViewModel() : base(new Uri(ConnectionsViewModel.BaseUri,"ports.serial")) - { - - this.ValidationRule(x => x.Title, _ => !string.IsNullOrWhiteSpace(_), RS.SerialPortViewModel_SerialPortViewModel_You_must_specify_a_valid_name) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.SelectedPort, _ => !string.IsNullOrWhiteSpace(_), RS.SerialPortViewModel_SerialPortViewModel_ValidSerialPort) - .DisposeItWith(Disposable); - - this - .ValidationRule(x => x.SelectedBaudRate, _ => _ is >= MinBaudRate and <= MaxBaudRate, string.Format(RS.SerialPortViewModel_SerialPortViewModel_BaudRateValid, MinBaudRate, MaxBaudRate)) - .DisposeItWith(Disposable); - - _myCache = new SourceList() - .DisposeItWith(Disposable); - _myCache.Connect() - .ObserveOn(RxApp.MainThreadScheduler) - .Bind(out _ports) - .Subscribe(_ => SelectedPort ??= _ports.FirstOrDefault()) - .DisposeItWith(Disposable); - Observable - .Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1)) - .Subscribe(UpdateSerialPorts) - .DisposeItWith(Disposable); - } - - [ImportingConstructor] - public SerialPortViewModel(IMavlinkDevicesService device,ILogService logService):this() - { - _device = device ?? throw new ArgumentNullException(nameof(device)); - _logService = logService; - Title = string.Format(RS.SerialPortViewModel_SerialPortViewModel_NewSerial, device.Router.GetPorts().Length); - } - - public void ApplyDialog(ContentDialog dialog) - { - if (dialog == null) throw new ArgumentNullException(nameof(dialog)); - dialog.PrimaryButtonCommand = - ReactiveCommand.Create(AddSerialPort, this.IsValid().Do(_ =>dialog.IsPrimaryButtonEnabled = _)).DisposeItWith(Disposable); - } - - private void AddSerialPort() - { - if (_device == null) return; - try - { - _device.Router.AddPort(new MavlinkPortConfig - { - Name = Title, - ConnectionString = $"serial:{SelectedPort}?br={SelectedBaudRate}", - IsEnabled = true - }); - } - catch (Exception e) - { - _logService.Error("",$"Error to create port:{e.Message}",e); - } - } - - private void UpdateSerialPorts(long l) - { - if (Interlocked.CompareExchange(ref _requestNotComplete, 1, 0) != 0) return; - try - { - var value = SerialPort.GetPortNames(); - var exist = _myCache.Items.ToArray(); - var toDelete = exist.Except(value).ToArray(); - var toAdd = value.Except(exist).ToArray(); - _myCache.RemoveMany(toDelete); - _myCache.AddRange(toAdd); - } - catch (Exception) - { - // ignored - } - finally - { - Interlocked.Exchange(ref _requestNotComplete, 0); - } - } - - public ReadOnlyObservableCollection Ports => _ports; - - public ReadOnlyObservableCollection BaudRates { get; } = new( - new ObservableCollection(new[] { 9600, 14400, 19200, 38400, 56000, 57600, 115200, 128000, 256000 })); - - [Reactive] - public string Title { get; set; } - - [Reactive] public int SelectedBaudRate { get; set; } = 115_200; - - [Reactive] - public string SelectedPort { get; set; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortView.axaml deleted file mode 100644 index 88a1fb55..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortView.axaml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortView.axaml.cs deleted file mode 100644 index a4552b30..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(TcpPortViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class TcpPortView : ReactiveUserControl - { - public TcpPortView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortViewModel.cs deleted file mode 100644 index 88cb9b05..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/TcpPortViewModel.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System.ComponentModel.Composition; -using System.Net; -using System.Reactive.Linq; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Asv.Mavlink; -using FluentAvalonia.UI.Controls; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Validation.Extensions; - -namespace Asv.Drones.Gui.Core -{ - public class TcpPortViewModel:ViewModelBaseWithValidation - { - private readonly IMavlinkDevicesService? _deviceService; - private readonly ILogService _logService; - - public TcpPortViewModel() : base(new Uri(ConnectionsViewModel.BaseUri, "ports.tcp")) - { - - } - - [ImportingConstructor] - public TcpPortViewModel(IMavlinkDevicesService deviceService,ILogService logService) : this() - { - _deviceService = deviceService ?? throw new ArgumentNullException(nameof(deviceService)); - _logService = logService ?? throw new ArgumentNullException(nameof(logService)); - Title = $"{RS.TcpPortViewModel_Title}: {deviceService.Router.GetPorts().Length}"; - Port = 7341; - IpAddress = "172.16.0.1"; - IsTcpIpServer = true; - - this.ValidationRule(x => x.Title, _ => !string.IsNullOrWhiteSpace(_), RS.TcpPortViewModel_ValidTitle) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.Port, _ => _ is > 1 and < 65535, RS.TcpPortViewModel_ValidPort) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.IpAddress, _ => !string.IsNullOrWhiteSpace(_) && IPAddress.TryParse(_, out IPAddress? ip), RS.TcpPortViewModel_ValidIpAddress) - .DisposeItWith(Disposable); - - } - - - public void ApplyDialog(ContentDialog dialog) - { - if (dialog == null) throw new ArgumentNullException(nameof(dialog)); - dialog.PrimaryButtonCommand = - ReactiveCommand.Create(AddTcpPort, this.IsValid().Do(_ => dialog.IsPrimaryButtonEnabled = _)).DisposeItWith(Disposable); - } - - private void AddTcpPort() - { - // this is for design mode - if (_deviceService == null) return; - - try - { - _deviceService.Router.AddPort(new MavlinkPortConfig - { - Name = Title, - ConnectionString = $"tcp://{IpAddress}:{Port}" + (IsTcpIpServer ? "?srv=true":string.Empty), - IsEnabled = true, - }); - - } - catch (Exception e) - { - _logService.Error("", $"{RS.TcpPortViewModel_LogService_Error}:{e.Message}", e); - } - } - - [Reactive] - public string Title { get; set; } - - [Reactive] - public int Port { get; set; } - - [Reactive] - public bool IsTcpIpServer { get; set; } - - [Reactive] - public string IpAddress { get; set; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortView.axaml deleted file mode 100644 index 420e12e2..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortView.axaml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortView.axaml.cs deleted file mode 100644 index 48a9f2e5..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(UdpPortViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class UdpPortView : ReactiveUserControl - { - public UdpPortView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortViewModel.cs deleted file mode 100644 index 150e206d..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/Dialogs/UdpPortViewModel.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System.ComponentModel.Composition; -using System.Net; -using System.Reactive.Linq; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Asv.Mavlink; -using Avalonia.Controls; -using DynamicData.Binding; -using FluentAvalonia.UI.Controls; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Validation.Extensions; - -namespace Asv.Drones.Gui.Core -{ - public class UdpPortViewModel:ViewModelBaseWithValidation - { - private readonly IMavlinkDevicesService? _device; - - - public UdpPortViewModel() : base(new Uri(ConnectionsViewModel.BaseUri, "ports.udp")) - { - if (Design.IsDesignMode) - { - - } - - this.WhenValueChanged(_ => IsRemote).Subscribe(_ => UpdateValidationRules()).DisposeItWith(Disposable); - } - - private void UpdateValidationRules() - { - this.ClearValidationRules(); - - this.ValidationRule(x => x.Title, _ => !string.IsNullOrWhiteSpace(_), RS.UdpPortViewModel_ValidTitle) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.LocalIpAddress, _ => !string.IsNullOrWhiteSpace(_) && IPAddress.TryParse(_, out IPAddress? ip), RS.UdpPortViewModel_ValidLocalIpAddress) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.LocalPort, _ => _ is > 1 and < 65535, RS.UdpPortViewModel_ValidLocalPort) - .DisposeItWith(Disposable); - - if (IsRemote) - { - this.ValidationRule(x => x.RemoteIpAddress, _ => !string.IsNullOrWhiteSpace(_) && IPAddress.TryParse(_, out IPAddress? ip), RS.UdpPortViewModel_ValidRemoteIpAddress) - .DisposeItWith(Disposable); - this.ValidationRule(x => x.RemotePort, _ => _ is > 1 and < 65535, RS.UdpPortViewModel_ValidRemotePort) - .DisposeItWith(Disposable); - - } - } - - [ImportingConstructor] - public UdpPortViewModel(IMavlinkDevicesService device) : this() - { - _device = device ?? throw new ArgumentNullException(nameof(device)); - Title = $"{RS.UdpPortViewModel_Title} {device.Router.GetPorts().Length}"; - } - - public void ApplyDialog(ContentDialog dialog) - { - if (dialog == null) throw new ArgumentNullException(nameof(dialog)); - dialog.PrimaryButtonCommand = - ReactiveCommand.Create(AddUdpPort, this.IsValid().Do(_ => dialog.IsPrimaryButtonEnabled = _)) - .DisposeItWith(Disposable); - } - - private void AddUdpPort() - { - if (_device == null) return; - try - { - _device.Router.AddPort(new MavlinkPortConfig - { - Name = Title, - ConnectionString = $"udp://{LocalIpAddress}:{LocalPort}" + (IsRemote ? $"?rhost={RemoteIpAddress}&rport={RemotePort}":string.Empty), - IsEnabled = true - }); - } - catch (Exception e) - { - } - } - - [Reactive] - public string Title { get; set; } - [Reactive] - public int LocalPort { get; set; } - [Reactive] - public string LocalIpAddress { get; set; } - - [Reactive] - public bool IsRemote { get; set; } - [Reactive] - public string RemoteIpAddress { get; set; } - [Reactive] - public int RemotePort { get; set; } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortView.axaml deleted file mode 100644 index eb770e27..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortView.axaml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortView.axaml.cs deleted file mode 100644 index 7cb857c6..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortView.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(PortViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class PortView : ReactiveUserControl - { - public PortView() - { - InitializeComponent(); - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortViewModel.cs deleted file mode 100644 index e6575445..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Connections/Ports/PortViewModel.cs +++ /dev/null @@ -1,300 +0,0 @@ -using System.Reactive.Linq; -using System.Windows.Input; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Asv.IO; -using Avalonia.Controls; -using FluentAvalonia.UI.Controls; -using Material.Icons; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core -{ - public class PortViewModel:ViewModelBase - { - private readonly IMavlinkDevicesService _svc; - private readonly ILocalizationService _localization; - private readonly Guid _id; - private readonly IncrementalRateCounter _rxByteRate = new(3); - private readonly IncrementalRateCounter _rxPacketRate = new(3); - private readonly IncrementalRateCounter _txByteRate = new(3); - private readonly IncrementalRateCounter _txPacketRate = new(3); - private readonly ILogService _logService; - - - public PortViewModel() : base(new Uri(ConnectionsViewModel.BaseUri, $"port.{Guid.NewGuid()}")) - { - if (Design.IsDesignMode) - { - PortId = Guid.NewGuid(); - Icon = ConvertIcon(PortType.Serial); - RxText = "0.456"; - RxUnitText = "kb/s"; - RxPktText = "156"; - RxPktUnitText = "Hz"; - - - TxText = "0.456"; - TxUnitText = "kb/s"; - TxPktText = "156"; - TxPktUnitText = "Hz"; - - SkippedText = "153"; - SkippedUnitText = "pkt"; - ConnectionString = "tcp://127.0.0.1:7341?srv=true"; - } - - } - - public PortViewModel(Guid id):base(new Uri(ConnectionsViewModel.BaseUri, $"port.{id}")) - { - PortId = id; - - } - - public PortViewModel(IMavlinkDevicesService svc, ILocalizationService localization, ILogService logService, Guid id):this(id) - { - _svc = svc ?? throw new ArgumentNullException(nameof(svc)); - _localization = localization ?? throw new ArgumentNullException(nameof(localization)); - _id = id; - _logService = logService; - Observable.Timer(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(1),RxApp.MainThreadScheduler).Subscribe(Update).DisposeItWith(Disposable); - EnableDisableCommand = ReactiveCommand.Create(() => _svc.Router.SetEnabled(_id, IsPortEnabled)).DisposeItWith(Disposable); - DeletePortCommand = ReactiveCommand.Create(() => _svc.Router.RemovePort(_id)).DisposeItWith(Disposable); - EditPortCommand = ReactiveCommand.CreateFromTask(EditPortImpl).DisposeItWith(Disposable); - } - - public Guid PortId { get; } - - private void Update(long l) - { - var info = _svc.Router.GetInfo(_id); - if (info == null) return; - Name = info.Name; - Icon = ConvertIcon(info.Type); - ConnectionString = info.ConnectionString; - Description = info.Description; - switch (info.State) - { - case PortState.Disabled: - IsDisabled = true; - IsConnected = false; - IsConnecting = false; - IsError = false; - break; - case PortState.Connecting: - IsDisabled = false; - IsConnected = false; - IsConnecting = true; - IsError = false; - break; - case PortState.Error: - IsDisabled = false; - IsConnected = false; - IsConnecting = false; - IsError = true; - break; - case PortState.Connected: - IsDisabled = false; - IsConnected = true; - IsConnecting = false; - IsError = false; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - Error = info.LastException?.Message; - - var rxByteRate = _rxByteRate.Calculate(info.RxBytes); - RxText = _localization.ByteRate.ConvertToString(rxByteRate); - RxUnitText = _localization.ByteRate.GetUnit(rxByteRate); - - var rxPktRate = _rxPacketRate.Calculate(info.RxPackets); - RxPktText = _localization.ItemsRate.ConvertToString(rxPktRate); - RxPktUnitText = _localization.ItemsRate.GetUnit(rxPktRate); - - var txByteRate = _txByteRate.Calculate(info.TxBytes); - TxText = _localization.ByteRate.ConvertToString(txByteRate); - TxUnitText = _localization.ByteRate.GetUnit(txByteRate); - - var txPktRate = _txPacketRate.Calculate(info.TxPackets); - TxPktText = _localization.ItemsRate.ConvertToString(txPktRate); - TxPktUnitText = _localization.ItemsRate.GetUnit(txPktRate); - - IsPortEnabled = info.IsEnabled ?? false; - SkippedText = $"{info.SkipPackets}"; - SkippedUnitText = RS.PortViewModel_SkippedUnitTest; - - } - - private MaterialIconKind ConvertIcon(PortType infoType) - { - return infoType switch - { - PortType.Serial => MaterialIconKind.SerialPort, - PortType.Udp => MaterialIconKind.IpNetworkOutline, - PortType.Tcp => MaterialIconKind.RouterWireless, - _ => throw new ArgumentOutOfRangeException(nameof(infoType), infoType, null) - }; - } - - [Reactive] - public string Name { get; set; } - - [Reactive] - public MaterialIconKind Icon { get; set; } - - [Reactive] - public string? RxText { get; set; } - [Reactive] - public string? RxUnitText { get; set; } - [Reactive] - public string? RxPktUnitText { get; set; } - [Reactive] - public string RxPktText { get; set; } - - - - [Reactive] - public string? TxText { get; set; } - [Reactive] - public string? TxUnitText { get; set; } - [Reactive] - public string? TxPktUnitText { get; set; } - [Reactive] - public string TxPktText { get; set; } - - - [Reactive] - public string ConnectionString { get; set; } - - [Reactive] - public bool IsPortEnabled { get; set; } - - public ICommand? EnableDisableCommand { get; } - - public ICommand? EditPortCommand { get; } - - private async Task EditPortImpl(CancellationToken cancel) - { - var info = _svc.Router.GetInfo(_id); - - var uri = new Uri(info.ConnectionString); - - var dialog = new ContentDialog() - { - PrimaryButtonText = RS.ConnectionsViewModel_EditDialogPort_Accept, - IsSecondaryButtonEnabled = true, - CloseButtonText = RS.ConnectionsViewModel_EditDialogPort_Cancel - }; - - switch (info.Type) - { - case PortType.Serial: - { - dialog.Title = RS.ConnectionsViewModel_EditSerialPortDialog_Title; - - using var viewModel = new SerialPortViewModel(_svc, _logService); - - viewModel.Title = info.Name; - - viewModel.SelectedPort = uri.AbsolutePath; - - var query = uri.Query.Split(new char[] {'?'}); - - int.TryParse(query[1].Replace("br=", ""), out var baudRate); - - viewModel.SelectedBaudRate = baudRate; - - viewModel.ApplyDialog(dialog); - - dialog.Content = viewModel; - } - break; - case PortType.Tcp: - { - dialog.Title = RS.ConnectionsViewModel_EditTcpPortDialog_Title; - - using var viewModel = new TcpPortViewModel(_svc, _logService); - - viewModel.Title = info.Name; - - viewModel.IpAddress = uri.Host; - - viewModel.Port = uri.Port; - - viewModel.IsTcpIpServer = false; - - if (!uri.Query.IsNullOrWhiteSpace()) - { - var query = uri.Query.Split(new char[] {'?'}); - bool.TryParse(query[1].Replace("srv=", ""), out var isTcpIpServer); - viewModel.IsTcpIpServer = isTcpIpServer; - } - - viewModel.ApplyDialog(dialog); - - dialog.Content = viewModel; - } - break; - case PortType.Udp: - { - dialog.Title = RS.ConnectionsViewModel_EditUdpPortDialog_Title; - - using var viewModel = new UdpPortViewModel(_svc); - - viewModel.Title = info.Name; - - viewModel.LocalIpAddress = uri.Host; - - viewModel.LocalPort = uri.Port; - - if (!uri.Query.IsNullOrWhiteSpace()) - { - var query = uri.Query.Split(new char[] {'?','&'}); - viewModel.IsRemote = true; - viewModel.RemoteIpAddress = query[1].Replace("rhost=", ""); - int.TryParse(query[2].Replace("rport=", ""), out var remotePort); - viewModel.RemotePort = remotePort; - } - - viewModel.ApplyDialog(dialog); - - dialog.Content = viewModel; - } - break; - } - - if (await dialog.ShowAsync() == ContentDialogResult.Primary) - { - _svc.Router.RemovePort(_id); - - } - } - - [Reactive] - public bool IsConnected { get; set; } - [Reactive] - public bool IsError { get; set; } - [Reactive] - public bool IsDisabled { get; set; } - [Reactive] - public bool IsConnecting { get; set; } - - public ICommand DeletePortCommand { get; } - - [Reactive] - public string? SkippedText { get; set; } - [Reactive] - public string? SkippedUnitText { get; set; } - - [Reactive] - public string? Description { get; set; } - - [Reactive] - public string? Error { get; set; } - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/IShellPage.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/IShellPage.cs deleted file mode 100644 index 55c91d01..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/IShellPage.cs +++ /dev/null @@ -1,59 +0,0 @@ -using DynamicData; -using Material.Icons; - -namespace Asv.Drones.Gui.Core -{ - /// - /// All pages in the shell must implement this interface. - /// - public interface IShellPage : IViewModel - { - /// - /// Gets the material icon kind for this property. - /// - /// - /// The material icon kind. - /// - MaterialIconKind Icon { get; } - - /// - /// Gets the title of the property. - /// - /// A string representing the title. - string Title { get; } - - /// - /// Gets the observable collection of header menu items along with their corresponding URIs. - /// - /// - /// The observable collection of header menu items and their URIs. - /// - IObservable> HeaderItems { get; } - - /// - /// Gets the collection of status items. - /// - /// - /// This property returns an where T is an instance of . - /// The TObject represents an instance of and TIdentifier is . - /// - /// An IObservable representing the collection of status items. - IObservable> StatusItems { get; } - - /// - /// Sets additional arguments for the page. - /// - /// The URI link specifying the additional arguments. - void SetArgs(Uri link); - - /// - /// Attempts to close the current instance. - /// - /// - /// A representing the asynchronous operation. - /// The will return if the instance was successfully closed; - /// otherwise, it will return . - /// - Task TryClose(); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageView.axaml deleted file mode 100644 index 783807de..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageView.axaml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageView.axaml.cs deleted file mode 100644 index 3eb8222c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageView.axaml.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core -{ - [ExportView(typeof(LogMessagesPageViewModel))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public partial class LogMessagesPageView : ReactiveUserControl - { - public LogMessagesPageView() - { - InitializeComponent(); - } - } -} - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageViewModel.cs deleted file mode 100644 index 06ac90fc..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesPageViewModel.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.ComponentModel.Composition; -using System.Reactive; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Asv.Cfg; -using Asv.Common; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core -{ - [ExportShellPage(UriString)] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class LogMessagesPageViewModel : ShellPage - { - public const string UriString = "asv:shell.page.logs"; - public static readonly Uri Uri = new Uri(UriString); - - public List PageLengths { get; } - - private readonly ILogService _logService; - private readonly IConfiguration _configuration; - private readonly ObservableAsPropertyHelper _isRefreshing; - - public LogMessagesPageViewModel() : base(Uri) - { - Title = RS.FlightShellMenuItem_Name; - Refresh = ReactiveCommand.CreateFromObservable(() => Observable.Start(RefreshItemsImpl).SubscribeOn(RxApp.TaskpoolScheduler).TakeUntil(CancelRefresh)); - Refresh.IsExecuting.ToProperty(this, _ => _.IsRefreshing, out _isRefreshing); - Refresh.ThrownExceptions.Subscribe(OnRefreshError); - CancelRefresh = ReactiveCommand.Create(() => { }, Refresh.IsExecuting); - ClearAll = ReactiveCommand.CreateFromObservable(() => Observable.Start(ClearAllImpl)); - Next = ReactiveCommand.Create(() => - { - Skip += Take; - }, CanNext.ObserveOn(RxApp.MainThreadScheduler)); - Prev = ReactiveCommand.Create(() => - { - Skip -= Take; - }, CanPrev.ObserveOn(RxApp.MainThreadScheduler)); - } - - [ImportingConstructor] - public LogMessagesPageViewModel(ILogService logService, IConfiguration configuration) : this() - { - _logService = logService; - _configuration = configuration; - - PageLengths = new List { 25, 50, 100, 250, 500 }; - Take = _configuration.Get("TakePageLength"); - if (Take == 0) Take = 25; - - this.WhenAnyValue(_ => _.SearchText) - .ObserveOn(RxApp.MainThreadScheduler) - .Throttle(TimeSpan.FromMilliseconds(200),RxApp.MainThreadScheduler) - .Skip(1) - .Subscribe(_ => Refresh.Execute()) - .DisposeItWith(Disposable); - - this.WhenAnyValue(_ => _.Take, _ => _.Skip) - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(_ => Refresh.Execute()) - .DisposeItWith(Disposable); - } - - private void OnRefreshError(Exception ex) - { - _logService.Error(RS.LogMessagesPageViewModel_LogName, RS.LogMessagesPageViewModel_RefreshErrorMessage, ex); - } - - private void RefreshItemsImpl() - { - if (Skip < 0) Skip = 0; - var query = new LogQuery { Take = Take, Skip = Skip, Search = SearchText ?? string.Empty }; - - Messages = _logService.Find(query).Select(_ => new RemoteLogMessageProxy(_)).ToList(); - - Filtered = _logService.Count(query); - - if (Messages?.Count == 0 && Filtered != 0) - { - Skip = 0; - } - - Total = _logService.Count(); - To = Skip + Take; - CanNext.OnNext(To < Filtered); - CanPrev.OnNext(Skip > 0); - _configuration.Set("TakePageLength", Take); - - } - - private void ClearAllImpl() - { - _logService.Warning(RS.LogMessagesPageViewModel_LogName,RS.LogMessagesPageViewModel_ClearAllMessage); - _logService.ClearAll(); - RefreshItemsImpl(); - } - - public bool IsRefreshing => _isRefreshing.Value; - - public ReactiveCommand CancelRefresh { get; } - - public ReactiveCommand Refresh { get; } - - public ReactiveCommand ClearAll { get; set; } - - public ReactiveCommand Next { get; set; } - - public ReactiveCommand Prev { get; set; } - - public Subject CanNext { get; } = new(); - - public Subject CanPrev { get; } = new(); - - [Reactive] - public List Messages { get; set; } - - [Reactive] - public string SearchText { get; set; } - - [Reactive] - public int Skip { get; set; } - - [Reactive] - public int Take { get; set; } - - [Reactive] - public int Filtered { get; set; } - - [Reactive] - public int Total { get; set; } - - [Reactive] - public int To { get; set; } - - } - - -} - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesShellMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesShellMenuItem.cs deleted file mode 100644 index 5b05ecd7..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Logs/LogMessagesShellMenuItem.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.Composition; -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - - -[Export(typeof(IShellMenuItem))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class LogMessagesShellMenuItem : ShellMenuItem -{ - public LogMessagesShellMenuItem() : base("asv:shell.menu.logs") - { - Name = RS.LogMessagesShellMenuItem_Name; - NavigateTo = LogMessagesPageViewModel.Uri; - Icon = MaterialIconDataProvider.GetData(MaterialIconKind.Journal); - Position = ShellMenuPosition.Bottom; - Type = ShellMenuItemType.PageNavigation; - Order = 1; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionView.axaml deleted file mode 100644 index e707d50b..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionView.axaml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionView.axaml.cs deleted file mode 100644 index 08497fca..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionView.axaml.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(AnchorMoverActionViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class AnchorMoverActionView : ReactiveUserControl -{ - [ImportingConstructor] - public AnchorMoverActionView() - { - InitializeComponent(); - HotKeyManager.SetHotKey(editAnchorsToggleButton, new KeyGesture(Key.LeftAlt, KeyModifiers.Alt)); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionViewModel.cs deleted file mode 100644 index bc4c0e67..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/AnchorMover/AnchorMoverActionViewModel.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.Controls; - -namespace Asv.Drones.Gui.Core; - -[Export(FlightPageViewModel.UriString,typeof(IMapAction))] -[Export(PlaningPageViewModel.UriString,typeof(IMapAction))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class AnchorMoverActionViewModel : ViewModelBase, IMapAction -{ - private IMap _map; - - public AnchorMoverActionViewModel() : base("asv:shell.page.map.action.move-anchors") - { - } - - public IMapAction Init(IMap context) - { - _map = context; - return this; - } - - public IMap Map => _map; - public Dock Dock { get; } - public int Order => 0; -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/IMapAction.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/IMapAction.cs deleted file mode 100644 index 2dfcceb1..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/IMapAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Avalonia.Controls; -namespace Asv.Drones.Gui.Core -{ - /// - /// IMapAction provides a contract for a Map Action. - /// It's part of the Asv.Drones.Gui.Core project which uses AvaloniaUI for the User Interface. - /// - public interface IMapAction : IViewModel - { - /// - /// Position on the control where an element/border should be docked. - /// - Dock Dock { get; } - - /// - /// Represents the order or sequence of the map actions. - /// - int Order { get; } - - /// - /// Initializes a map action using the provided context. - /// - /// An instance of IMap to be used for initiation. - /// An instance of IMapAction. - IMapAction Init(IMap context); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionView.axaml deleted file mode 100644 index b7785e3e..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionView.axaml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionView.axaml.cs deleted file mode 100644 index 1ba005e9..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionView.axaml.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(MapRulerActionViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class MapRulerActionView : ReactiveUserControl -{ - public MapRulerActionView() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionViewModel.cs deleted file mode 100644 index a5cebc97..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/MapRulerActionViewModel.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.ComponentModel.Composition; -using Asv.Common; -using DynamicData.Binding; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -[Export(FlightPageViewModel.UriString,typeof(IMapAction))] -[Export(PlaningPageViewModel.UriString,typeof(IMapAction))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class MapRulerActionViewModel:MapActionBase -{ - [ImportingConstructor] - public MapRulerActionViewModel( ILogService log) : base("asv:shell.page.map.action.ruler") - { - this.WhenValueChanged(_ => _.IsRulerEnabled) - .Subscribe(SetUpRuler) - .DisposeItWith(Disposable); - } - - private async void SetUpRuler(bool isEnabled) - { - if (Map == null) return; - var polygon = Map.Markers.FirstOrDefault(x => x is RulerPolygon) as RulerPolygon; - if (polygon == null) return; - - _tokenSource.Cancel(); - _tokenSource = new CancellationTokenSource(); - - if(isEnabled) - { - try - { - var start = await Map.ShowTargetDialog(RS.MapPageViewModel_RulerStartPoint_Description, - _tokenSource.Token); - var stop = await Map.ShowTargetDialog(RS.MapPageViewModel_RulerStopPoint_Description, - _tokenSource.Token); - polygon.Ruler.Value.Start.OnNext(start); - polygon.Ruler.Value.Stop.OnNext(stop); - } - catch (TaskCanceledException) - { - return; - } - } - - polygon.Ruler.Value.IsVisible.OnNext(isEnabled); - } - - private static CancellationTokenSource _tokenSource = new (); - - [Reactive] - public bool IsRulerEnabled { get; set; } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/Ruler.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/Ruler.cs deleted file mode 100644 index 8660b349..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/Ruler.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Reactive.Linq; -using Asv.Common; -using Asv.Mavlink.Vehicle; - -namespace Asv.Drones.Gui.Core; - -public class Ruler : DisposableReactiveObject -{ - public IRxEditableValue Start { get; } - public IRxEditableValue Stop { get; } - public IRxEditableValue Distance { get; } - public IRxEditableValue IsVisible { get; } - - public Ruler() - { - Start = new RxValue(new GeoPoint()).DisposeItWith(Disposable); - Stop = new RxValue(new GeoPoint()).DisposeItWith(Disposable); - Distance = new RxValue().DisposeItWith(Disposable); - IsVisible = new RxValue().DisposeItWith(Disposable); - - Start.Merge(Stop).Subscribe(_ => CalculateDistance()).DisposeItWith(Disposable); - } - - private void CalculateDistance() - { - Distance.OnNext(GeoMath.Distance(Start.Value, Stop.Value)); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerAnchor.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerAnchor.cs deleted file mode 100644 index 43b75375..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerAnchor.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Reactive.Linq; -using Asv.Avalonia.Map; -using Asv.Common; -using Avalonia.Media; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -public enum RulerPosition -{ - Start, - Stop -} - -public class RulerAnchor : MapAnchorBase -{ - public RulerAnchor(string id, Ruler ruler, RulerPosition rulerPosition, ILocalizationService loc) : base(new Uri($"{FlightPageViewModel.UriString}layer/ruler/{id}")) - { - Size = 48; - OffsetX = OffsetXEnum.Center; - OffsetY = OffsetYEnum.Bottom; - StrokeThickness = 1; - IconBrush = Brushes.Indigo; - Stroke = Brushes.White; - IsVisible = false; - Icon = MaterialIconKind.MapMarker; - IsEditable = true; - - ruler.IsVisible.Where(_ => _.HasValue).Subscribe(_ => IsVisible = _.Value).DisposeItWith(Disposable); - - if (rulerPosition == RulerPosition.Stop) - { - ruler.Distance.Subscribe(_ => Title = loc.Distance.FromSiToStringWithUnits(_)); - } - - var isLocationInternalChanged = false; - var point = rulerPosition == RulerPosition.Start ? ruler.Start : ruler.Stop; - - point.Where(_ => _.HasValue) - .Subscribe(_ => - { - isLocationInternalChanged = true; - Location = _.Value; - isLocationInternalChanged = false; - }) - .DisposeItWith(Disposable); - - this.WhenAnyValue(_ => _.Location) - .Where(_ => !isLocationInternalChanged) - .Subscribe(_ => point.OnNext(_)) - .DisposeItWith(Disposable); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerMapLayerProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerMapLayerProvider.cs deleted file mode 100644 index 65f5da66..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerMapLayerProvider.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core; - -[Export(FlightPageViewModel.UriString, typeof(IViewModelProvider))] -[Export(PlaningPageViewModel.UriString, typeof(IViewModelProvider))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class RulerMapLayerProvider : ViewModelProviderBase -{ - [ImportingConstructor] - public RulerMapLayerProvider(ILocalizationService loc) - { - var ruler = new Ruler(); - - Source.AddOrUpdate(new RulerAnchor("1", ruler, RulerPosition.Start, loc)); - Source.AddOrUpdate(new RulerAnchor("2", ruler, RulerPosition.Stop, loc)); - Source.AddOrUpdate(new RulerPolygon(ruler)); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerPolygon.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerPolygon.cs deleted file mode 100644 index e64b4540..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Ruler/RulerPolygon.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Collections.ObjectModel; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using Asv.Common; -using Avalonia.Collections; -using Avalonia.Media; -using DynamicData; - -namespace Asv.Drones.Gui.Core; - -public class RulerPolygon : MapAnchorBase -{ - private readonly ReadOnlyObservableCollection _path; - - public RulerPolygon(Ruler ruler) : base(new Uri(FlightPageViewModel.UriString + "/layer/ruler-polygon")) - { - Ruler = new RxValue().DisposeItWith(Disposable); - - ZOrder = -1000; - OffsetX = 0; - OffsetY = 0; - PathOpacity = 0.6; - StrokeThickness = 5; - Stroke = Brushes.Purple; - IsVisible = false; - StrokeDashArray = new AvaloniaList(2,2); - - var cache = new SourceList().DisposeItWith(Disposable); - cache.Add(new GeoPoint(0, 0, 0)); - cache.Add(new GeoPoint(0, 0, 0)); - - ruler.IsVisible.Where(_ => _.HasValue).Subscribe(_ => IsVisible = _.Value).DisposeItWith(Disposable); - ruler.Start.Where(_ => _.HasValue).Subscribe(_ => cache.ReplaceAt(0, _.Value)).DisposeItWith(Disposable); - ruler.Stop.Where(_ => _.HasValue).Subscribe(_ => cache.ReplaceAt(1, _.Value)).DisposeItWith(Disposable); - - cache.Connect() - .Bind(out _path) - .Subscribe() - .DisposeWith(Disposable); - - Ruler.OnNext(ruler); - } - - public override ReadOnlyObservableCollection Path => _path; - - public IRxEditableValue Ruler { get; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Zoom/MapZoomActionView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Zoom/MapZoomActionView.axaml deleted file mode 100644 index 446bf160..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Actions/Zoom/MapZoomActionView.axaml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerView.axaml.cs deleted file mode 100644 index e77c02da..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerView.axaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(LoggerViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class LoggerView : ReactiveUserControl -{ - public LoggerView() - { - InitializeComponent(); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerViewModel.cs deleted file mode 100644 index 23b0ac0d..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerViewModel.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Windows.Input; -using Asv.Common; -using Avalonia.Controls; -using DynamicData; -using DynamicData.Binding; -using Material.Icons; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -public class LoggerViewModel : FlightWidgetBase -{ - private readonly SourceList _logSource = new(); - private readonly ReadOnlyObservableCollection _logs; - - private readonly Subject> _filterUpdate = new(); - - private const int MaxLogSize = 30; - - public LoggerViewModel() : base(new Uri(UriString + "logger")) - { - if (Design.IsDesignMode) - { - _logs = new ReadOnlyObservableCollection( - new ObservableCollection(new[] - { - new FlightLogMessageViewModel(MaterialIconKind.Error, "ERROR", LogMessageType.Error), - new FlightLogMessageViewModel(MaterialIconKind.InfoCircle, "INFO", LogMessageType.Info), - new FlightLogMessageViewModel(MaterialIconKind.Warning, "WARNING", LogMessageType.Warning), - new FlightLogMessageViewModel(MaterialIconKind.Abacus, "TRACE", LogMessageType.Trace) - })); - } - } - - [ImportingConstructor] - public LoggerViewModel(ILogService log) : this() - { - Location = WidgetLocation.Bottom; - Title = "Logger"; - - _logSource.LimitSizeTo(MaxLogSize).Subscribe().DisposeItWith(Disposable); - _filterUpdate.OnNext(FilterByTypePredicate); - - log.OnMessage - .Select(ConvertLogToMessage) - .Subscribe(_logSource.Add) - .DisposeItWith(Disposable); - - _logSource - .Connect() - .Filter(_filterUpdate) - .Bind(out _logs) - .Subscribe() - .DisposeItWith(Disposable); - - this.WhenValueChanged(_ => _.IsTraceSelected) - .Subscribe(_ => _filterUpdate.OnNext(FilterByTypePredicate)) - .DisposeItWith(Disposable); - this.WhenValueChanged(_ => _.IsErrorSelected) - .Subscribe(_ => _filterUpdate.OnNext(FilterByTypePredicate)) - .DisposeItWith(Disposable); - this.WhenValueChanged(_ => _.IsInfoSelected) - .Subscribe(_ => _filterUpdate.OnNext(FilterByTypePredicate)) - .DisposeItWith(Disposable); - this.WhenValueChanged(_ => _.IsWarningSelected) - .Subscribe(_ => _filterUpdate.OnNext(FilterByTypePredicate)) - .DisposeItWith(Disposable); - - ClearLogs = ReactiveCommand.Create(() => { _logSource.Clear(); }).DisposeItWith(Disposable); - - // #if DEBUG - // log.SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Error, "debug", "Test error", "This is a test log message")); - // log.SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Warning, "debug", "Test warning", "This is a test log message")); - // log.SaveMessage(new LogMessage(DateTime.Now, LogMessageType.Trace, "debug", "Test trace", "This is a test log message")); - // #endif - } - - public ReadOnlyObservableCollection Logs => _logs; - - [Reactive] public bool IsWarningSelected { get; set; } = true; - [Reactive] public bool IsErrorSelected { get; set; } = true; - [Reactive] public bool IsInfoSelected { get; set; } = true; - [Reactive] public bool IsTraceSelected { get; set; } = true; - public ICommand ClearLogs { get; } - - private static FlightLogMessageViewModel ConvertLogToMessage(LogMessage logMessage) - { - return logMessage.Type switch - { - LogMessageType.Info => new FlightLogMessageViewModel(MaterialIconKind.InfoCircle, logMessage.Message, LogMessageType.Info), - LogMessageType.Error => new FlightLogMessageViewModel(MaterialIconKind.Error, logMessage.Message, LogMessageType.Error), - LogMessageType.Warning => new FlightLogMessageViewModel(MaterialIconKind.Warning, logMessage.Message, LogMessageType.Warning), - LogMessageType.Trace => new FlightLogMessageViewModel(MaterialIconKind.Abacus, logMessage.Message, LogMessageType.Trace), - _ => new FlightLogMessageViewModel(MaterialIconKind.InfoCircle, logMessage.Message, LogMessageType.Info) - }; - } - - private bool FilterByTypePredicate(FlightLogMessageViewModel vm) - { - return vm.Type switch - { - LogMessageType.Error => IsErrorSelected, - LogMessageType.Info => IsInfoSelected, - LogMessageType.Warning => IsWarningSelected, - LogMessageType.Trace => IsTraceSelected, - _ => false - }; - } - - protected override void InternalAfterMapInit(IMap context) - { - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerWidgetProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerWidgetProvider.cs deleted file mode 100644 index 0663fdcc..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Flight/Logger/LoggerWidgetProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core; - -[Export(FlightPageViewModel.UriString, typeof(IViewModelProvider))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class LoggerWidgetProvider : ViewModelProviderBase -{ - [ImportingConstructor] - public LoggerWidgetProvider(ILogService log) - { - Source.AddOrUpdate(new LoggerViewModel(log)); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/HeaderAnchorsMenu.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/HeaderAnchorsMenu.cs deleted file mode 100644 index 7e0f655e..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/HeaderAnchorsMenu.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using Asv.Common; -using Material.Icons; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -[Export(HeaderMenuItem.UriString, typeof(IHeaderMenuItem))] -[PartCreationPolicy(CreationPolicy.Shared)] -public class HeaderAnchorsMenu : HeaderMenuItem -{ - public const string UriString = HeaderMenuItem.UriString + "/anchors"; - public static readonly Uri Uri = new(UriString); - - [ImportingConstructor] - public HeaderAnchorsMenu() : base(Uri) - { - Header = RS.HeaderAnchorsMenu_Title; - Icon = MaterialIconKind.Anchor; - Order = short.MinValue; - - this.WhenAnyValue(_ => _.Items) - .Subscribe(_ => IsVisible = _ != null) - .DisposeItWith(Disposable); - } - - [Reactive] - public override ReadOnlyObservableCollection? Items { get; set; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/IMap.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/IMap.cs deleted file mode 100644 index 3c429d88..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/IMap.cs +++ /dev/null @@ -1,126 +0,0 @@ -using Asv.Avalonia.Map; -using Asv.Common; -using System.Collections.ObjectModel; -using System.ComponentModel; -using Material.Icons; - -namespace Asv.Drones.Gui.Core -{ - /// - /// Provides an interface that dictates the structure and behavior of a Map. - /// The Map is designed to be interactive and allows for various manipulations. - /// - public interface IMap: INotifyPropertyChanged - { - /// - /// Gets or sets a boolean value indicating whether the map is currently in dialog mode. - /// - bool IsInDialogMode { get; set; } - - /// - /// Gets or sets the maximum zoom level allowed on the map. - /// - int MaxZoom { get; set; } - - /// - /// Gets or sets the minimum zoom level allowed on the map. - /// - int MinZoom { get; set; } - - /// - /// Gets or sets the current zoom level of the map. - /// - double Zoom { get; set; } - - /// - /// Gets or sets the center point of the map in geographical coordinates. - /// - GeoPoint Center { get; set; } - - /// - /// Gets a read-only collection of markers (points of interest) on the map. - /// - ReadOnlyObservableCollection Markers { get; } - - /// - /// Gets or sets the currently selected item (marker) on the map. - /// - IMapAnchor SelectedItem { get; set; } - - /// - /// Gets or sets the item (marker) to follow on the map. - /// - IMapAnchor? ItemToFollow { get; set; } - - /// - /// Gets or sets a boolean value indicating whether the map is in anchor edit mode. - /// - bool IsInAnchorEditMode { get; set; } - - /// - /// Asynchronously displays a target dialog on the map and waits for user response. - /// - /// The text to display on the target dialog. - /// A cancellation token to cancel the operation. - /// A task that returns a GeoPoint when completed. - Task ShowTargetDialog(string text, CancellationToken cancel); - } - - /// - /// Provides an interface that describes the structure and behavior of a Map Anchor. - /// Map Anchor represents a point of interest on the map. - /// - public interface IMapAnchor : IMapAnchorViewModel, IViewModel - { - /// - /// Initializes the MapAnchor with a reference to a Map it belongs to. - /// - /// The map the anchor is associated with. - /// The initialized MapAnchor. - IMapAnchor Init(IMap map); - } - - /// - /// Enumeration to specify the location of a widget on the map. - /// - public enum WidgetLocation - { - Left, - Right, - Bottom - } - - /// - /// An interface that describes the structure and behavior of a Map Widget. - /// Map Widget represents an interface element on the map. - /// - public interface IMapWidget : IViewModel - { - /// - /// Gets the location of the widget on the map. - /// - WidgetLocation Location { get; } - - /// - /// Gets the title of the widget. - /// - string Title { get; } - - /// - /// Gets the order of the widget. - /// - int Order { get; } - - /// - /// Gets the icon associated with the widget. - /// - MaterialIconKind Icon { get; } - - /// - /// Initializes the Map Widget with a reference to a Map it belongs to. - /// - /// The map the widget is associated with. - /// The initialized MapWidget. - IMapWidget Init(IMap context); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapPageView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapPageView.axaml deleted file mode 100644 index bb8f3d5c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapPageView.axaml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapPageViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapPageViewModel.cs deleted file mode 100644 index 2980add0..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapPageViewModel.cs +++ /dev/null @@ -1,232 +0,0 @@ -using System.Collections.ObjectModel; -using System.Reactive.Linq; -using Asv.Avalonia.Map; -using Asv.Common; -using DynamicData; -using DynamicData.Binding; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core -{ - public class MapPageViewModel:ShellPage,IMap - { - private readonly ReadOnlyObservableCollection _markers; - private readonly ReadOnlyObservableCollection _widgets; - private readonly ReadOnlyObservableCollection _leftWidgets; - private readonly ReadOnlyObservableCollection _rightWidgets; - private readonly ReadOnlyObservableCollection _bottomWidgets; - private ReadOnlyObservableCollection _mapActions; - - private IDisposable _disposableMapUpdate; - - public const string UriString = "asv:shell.page.map"; - - /// - /// This constructor is used for design time - /// - public MapPageViewModel():base("asv:shell.page.map") - { - - } - - public MapPageViewModel(Uri id, IMapService map, - IEnumerable exportedMenuItems, - IEnumerable> markers, - IEnumerable> widgets, - IEnumerable> actions):base(id) - { - Disposable.AddAction(() => - { - markers.ForEach(provider=>provider.Dispose()); - widgets.ForEach(provider=>provider.Dispose()); - }); - - #region Map provider - - map.CurrentMapProvider.Subscribe(_ => MapProvider = _).DisposeItWith(Disposable); - this.WhenAnyValue(_ => _.MapProvider).Subscribe(map.CurrentMapProvider).DisposeItWith(Disposable); - - #endregion - - #region Map anchors - - markers.Select(_ => _.Items) - .IgnoreNulls() - .Merge() - .Transform(_ => _.Init(this)) - .DisposeMany() - .Bind(out _markers) - .Subscribe() - .DisposeItWith(Disposable); - - this.WhenValueChanged(_ => _.IsInAnchorEditMode) - .Subscribe(_ => - { - foreach (var marker in _markers) - { - if (marker.IsEditable) marker.IsInEditMode = _; - } - }) - .DisposeItWith(Disposable); - - #endregion - - #region Widgets - - widgets.Select(_ => _.Items) - .IgnoreNulls() - .Merge() - .Transform(_ => _.Init(this)) - .SortBy(_=>_.Order) - .DisposeMany() - .Bind(out _widgets) - .Subscribe() - .DisposeItWith(Disposable); - - _widgets - .ToObservableChangeSet() - .Filter(_ => _.Location == WidgetLocation.Left) - .AutoRefresh(_ => _.Location) - .Bind(out _leftWidgets) - .Subscribe() - .DisposeItWith(Disposable); - _widgets - .ToObservableChangeSet() - .Filter(_ => _.Location == WidgetLocation.Right) - .AutoRefresh(_ => _.Location) - .Bind(out _rightWidgets) - .Subscribe() - .DisposeItWith(Disposable); - _widgets - .ToObservableChangeSet() - .Filter(_ => _.Location == WidgetLocation.Bottom) - .AutoRefresh(_ => _.Location) - .Bind(out _bottomWidgets) - .Subscribe() - .DisposeItWith(Disposable); - - #endregion - - #region MapActions - - actions.Select(_ => _.Items) - .IgnoreNulls() - .Merge() - .Transform(_ => _.Init(this)) - .SortBy(_=>_.Order) - .Bind(out _mapActions) - .DisposeMany() - .Subscribe() - .DisposeItWith(Disposable); - - #endregion - - this.WhenValueChanged(_ => _.ItemToFollow, false) - .Subscribe(SetUpFollow) - .DisposeItWith(Disposable); - - Markers.ToObservableChangeSet() - .Transform(_ => (IHeaderMenuItem)new HeaderMenuItem(_.Id) - { - Header = _.Id.AbsoluteUri, - Icon = _.Icon, - Command = ReactiveCommand.Create(() => - { - Center = _.Location; - //SelectedItem = _; - }) - }) - .Bind(out var anchorMenuItems) - .Subscribe() - .DisposeItWith(Disposable); - - var menuItem = exportedMenuItems.FirstOrDefault(_ => _ is HeaderAnchorsMenu); - - if (menuItem != null) - { - menuItem.Items = anchorMenuItems; - } - - Disposable.AddAction(() => - { - if (menuItem != null) - menuItem.Items = null; - _disposableMapUpdate?.Dispose(); - }); - } - - private void SetUpFollow(IMapAnchor anchor) - { - _disposableMapUpdate?.Dispose(); - - _disposableMapUpdate = anchor?.WhenAnyValue(_ => _.Location) - .Subscribe(_ => Center = _); - } - - public ReadOnlyObservableCollection Markers => _markers; - public ReadOnlyObservableCollection LeftWidgets => _leftWidgets; - public ReadOnlyObservableCollection RightWidgets => _rightWidgets; - public ReadOnlyObservableCollection BottomWidgets => _bottomWidgets; - - public ReadOnlyObservableCollection MapActions => _mapActions; - - #region Map properties - - [Reactive] - public GMapProvider MapProvider { get; set; } = EmptyProvider.Instance; - - [Reactive] - public int MaxZoom { get; set; } = 20; - [Reactive] - public int MinZoom { get; set; } = 1; - [Reactive] - public double Zoom { get; set; } = 10; - [Reactive] - public GeoPoint Center { get; set; } - [Reactive] - public IMapAnchor SelectedItem { get; set; } - [Reactive] - public IMapAnchor ItemToFollow { get; set; } - [Reactive] - public bool IsInAnchorEditMode { get; set; } - - #endregion - - #region Map dialog - - [Reactive] - public GeoPoint DialogTarget { get; set; } - [Reactive] - public bool IsInDialogMode { get; set; } - [Reactive] - public string DialogText { get; set; } - - public async Task ShowTargetDialog(string text, CancellationToken cancel) - { - var tcs = new TaskCompletionSource(); - DialogText = text; - IsInDialogMode = true; - - await using var c1 = cancel.Register(() => - { - tcs.TrySetCanceled(); - IsInDialogMode = false; - SelectedItem = null; - }); - - this.WhenAnyValue(_ => _.IsInDialogMode).Where(_ => IsInDialogMode == false).Subscribe(_ => - { - if (!tcs.Task.IsCanceled) - { - tcs.TrySetResult(DialogTarget); - } - }, cancel); - - await tcs.Task; - return DialogTarget; - } - - #endregion - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapWidgetBase.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapWidgetBase.cs deleted file mode 100644 index 9c4e0505..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/MapWidgetBase.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Material.Icons; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core -{ - public abstract class MapWidgetBase : ViewModelBaseWithValidation, IMapWidget - { - protected MapWidgetBase(Uri id) : base(id) - { - - } - protected MapWidgetBase(string id) : base(id) - { - - } - - [Reactive] - public WidgetLocation Location { get;set; } - [Reactive] - public string Title { get;set; } - public int Order { get; set; } - [Reactive] - public MaterialIconKind Icon { get; set; } - public IMapWidget Init(IMap context) - { - Map = context; - InternalAfterMapInit(context); - return this; - } - - protected abstract void InternalAfterMapInit(IMap context); - - public IMap Map { get; private set; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/DefaultPlaningMapActionProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/DefaultPlaningMapActionProvider.cs deleted file mode 100644 index d93c8e5c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/DefaultPlaningMapActionProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core; - -[Export(PlaningPageViewModel.UriString,typeof(IViewModelProvider))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class DefaultPlaningMapActionProvider:ViewModelProviderBase -{ - [ImportingConstructor] - public DefaultPlaningMapActionProvider([ImportMany(PlaningPageViewModel.UriString)]IEnumerable items) - { - Source.AddOrUpdate(items); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionAnchor.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionAnchor.cs deleted file mode 100644 index 1eba5c88..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionAnchor.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Asv.Avalonia.Map; -using Asv.Common; -using Avalonia.Media; -using Material.Icons; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionAnchor : MapAnchorBase -{ - public const string UriString = PlaningPageViewModel.UriString + "/layer/{0}"; - - protected PlaningMissionAnchor(PlaningMissionPointModel point) : base(new Uri(UriString.FormatWith($"{point.Index}/{point.Type}"))) - { - Title = $"{point.Type} {point.Index}"; - Location = point.Location; - IsFilled = true; - IsEditable = true; - IsVisible = true; - OffsetX = OffsetXEnum.Center; - OffsetY = OffsetYEnum.Center; - PathOpacity = 0.6; - IconBrush = Brushes.Purple; - } - - [Reactive] - public int Index { get; set; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionDoLandPointAnchor.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionDoLandPointAnchor.cs deleted file mode 100644 index c7b6923c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionDoLandPointAnchor.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionDoLandPointAnchor : PlaningMissionAnchor -{ - public PlaningMissionDoLandPointAnchor(PlaningMissionPointModel point) : base(point) - { - Icon = MaterialIconKind.FlightLand; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionNavigationPointAnchor.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionNavigationPointAnchor.cs deleted file mode 100644 index a221fcf7..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionNavigationPointAnchor.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionNavigationPointAnchor : PlaningMissionAnchor -{ - public PlaningMissionNavigationPointAnchor(PlaningMissionPointModel point) : base(point) - { - Icon = MaterialIconKind.Location; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionRoiPointAnchor.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionRoiPointAnchor.cs deleted file mode 100644 index 9e061536..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionRoiPointAnchor.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionRoiPointAnchor : PlaningMissionAnchor -{ - public PlaningMissionRoiPointAnchor(PlaningMissionPointModel point) : base(point) - { - Icon = MaterialIconKind.ImageFilterCenterFocus; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionTakeOffPointAnchor.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionTakeOffPointAnchor.cs deleted file mode 100644 index d306a8fc..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Anchors/PlaningMissionTakeOffPointAnchor.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionTakeOffPointAnchor : PlaningMissionAnchor -{ - public PlaningMissionTakeOffPointAnchor(PlaningMissionPointModel point) : base(point) - { - Icon = MaterialIconKind.FlightTakeoff; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserView.axaml deleted file mode 100644 index 083b63fa..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserView.axaml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserView.axaml.cs deleted file mode 100644 index c20a3d6b..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserView.axaml.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace Asv.Drones.Gui.Core; - -public partial class PlaningMissionBrowserView : UserControl -{ - public PlaningMissionBrowserView() - { - InitializeComponent(); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserViewModel.cs deleted file mode 100644 index 55789e0c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Browser/PlaningMissionBrowserViewModel.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Collections.Immutable; -using System.ComponentModel.Composition; -using System.Reactive.Linq; -using Asv.Drones.Gui.Core; -using Asv.Mavlink; -using Avalonia.Media; -using DynamicData.Binding; -using FluentAvalonia.UI.Controls; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionBrowserViewModel : HierarchicalStoreViewModel -{ - private readonly IPlaningMission _svc; - - public const string UriString = "asv:shell.page.mission.mission-browser"; - - public PlaningMissionBrowserViewModel() : base() - { - } - - [ImportingConstructor] - public PlaningMissionBrowserViewModel(IPlaningMission svc, ILogService log) : base(new Uri(UriString), svc.MissionStore, log) - { - _svc = svc; - using var a = Refresh.Execute().Subscribe(); - } - - protected override void RefreshImpl() - { - if (_svc.MissionStore is FileSystemHierarchicalStore fileStore) - { - fileStore.UpdateEntries(); - } - base.RefreshImpl(); - } - - public IObservable CanOpen => this.WhenValueChanged(x => x.SelectedItem) - .Select(item => item is { Type: FolderStoreEntryType.File }); - protected override Guid GenerateNewId() => Guid.NewGuid(); - - public void ApplyDialog(ContentDialog dialog) - { - dialog.PrimaryButtonCommand = ReactiveCommand.Create(() => - { - if (SelectedItem != null) DialogResult = (Guid)SelectedItem.Id; - },CanOpen.Do(_=>dialog.IsPrimaryButtonEnabled = _)); - } - - public Guid DialogResult { get; set; } - - protected override IReadOnlyCollection InternalGetEntryTags(IHierarchicalStoreEntry itemValue) - { - switch (itemValue.Type) - { - case FolderStoreEntryType.File: - using (var file = _svc.MissionStore.OpenFile(itemValue.Id)) - { - var item = file.File.Load(); - if (item == null) return ArraySegment.Empty; - return item.Points.Select(x=>x.Type).Distinct().Select(x => ConvertToTag(x)).ToImmutableArray(); - } - case FolderStoreEntryType.Folder: - return base.InternalGetEntryTags(itemValue); - default: - throw new ArgumentOutOfRangeException(); - } - } - - private HierarchicalStoreEntryTagViewModel ConvertToTag(PlaningMissionPointType argType) - { - return new HierarchicalStoreEntryTagViewModel - { - Name = argType.ToString("G"), - Color = Brushes.CornflowerBlue, - Icon = MaterialIconKind.AlphaL, - }; - } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorView.axaml deleted file mode 100644 index 0d79e4dc..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorView.axaml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorView.axaml.cs deleted file mode 100644 index bbb12585..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorView.axaml.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(PlaningMissionEditorViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class PlaningMissionEditorView : ReactiveUserControl -{ - public PlaningMissionEditorView() - { - InitializeComponent(); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorViewModel.cs deleted file mode 100644 index f33c2ecc..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorViewModel.cs +++ /dev/null @@ -1,206 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Reactive; -using System.Windows.Input; -using Asv.Common; -using Avalonia.Controls; -using DynamicData; -using DynamicData.Binding; -using Material.Icons; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -[Export] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class PlaningMissionEditorViewModel : PlaningWidgetBase -{ - private readonly IPlaningMission _svc; - private readonly ILocalizationService _loc; - private readonly MissionPointFlyoutMenuItem _addItems; - private readonly MissionPointFlyoutMenuItem _replaceItems; - private IDisposable _selectedPointDisposable; - - public PlaningMissionEditorViewModel() : base(new Uri("asv:shell.page.mission.mission-editor")) - { - if (Design.IsDesignMode) - { - - } - } - - [ImportingConstructor] - public PlaningMissionEditorViewModel(IPlaningMission svc, ILocalizationService loc) : this() - { - _svc = svc; - _loc = loc; - - _addItems = new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_AddPointFlyoutMenuItem_Title, - Icon = MaterialIconKind.Add, - Items = - { - new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_TakeOffMenuItem_Title, - Type = PlaningMissionPointType.TakeOff, - Icon = MaterialIconKind.FlightTakeoff, - Command = ReactiveCommand.Create(() => - { - Context.Mission.AddPointCmd.Execute(PlaningMissionPointType.TakeOff).Subscribe(); - }) - }, - new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_DoLandMenuItem_Title, - Type = PlaningMissionPointType.DoLand, - Icon = MaterialIconKind.FlightLand, - Command = ReactiveCommand.Create(() => - { - Context.Mission.AddPointCmd.Execute(PlaningMissionPointType.DoLand).Subscribe(); - }) - }, - new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_WaypointMenuItem_Title, - Type = PlaningMissionPointType.Waypoint, - Icon = MaterialIconKind.Location, - Command = ReactiveCommand.Create(() => - { - Context.Mission.AddPointCmd.Execute(PlaningMissionPointType.Waypoint).Subscribe(); - }) - }, - new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_RoiMenuItem_Title, - Type = PlaningMissionPointType.Roi, - Icon = MaterialIconKind.ImageFilterCenterFocus, - Command = ReactiveCommand.Create(() => - { - Context.Mission.AddPointCmd.Execute(PlaningMissionPointType.Roi).Subscribe(); - }) - } - } - }; - - _replaceItems = new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_ReplacePointFlyoutMenuItem, - Icon = MaterialIconKind.FindReplace, - Items = - { - new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_TakeOffMenuItem_Title, - Type = PlaningMissionPointType.TakeOff, - Icon = MaterialIconKind.FlightTakeoff, - Command = ReactiveCommand.Create(() => - { - Context.Mission.ReplacePointCmd.Execute(PlaningMissionPointType.TakeOff).Subscribe(); - }) - }, - new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_DoLandMenuItem_Title, - Type = PlaningMissionPointType.DoLand, - Icon = MaterialIconKind.FlightLand, - Command = ReactiveCommand.Create(() => - { - Context.Mission.ReplacePointCmd.Execute(PlaningMissionPointType.DoLand).Subscribe(); - }) - }, - new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_WaypointMenuItem_Title, - Type = PlaningMissionPointType.Waypoint, - Icon = MaterialIconKind.Location, - Command = ReactiveCommand.Create(() => - { - Context.Mission.ReplacePointCmd.Execute(PlaningMissionPointType.Waypoint).Subscribe(); - }) - }, - new MissionPointFlyoutMenuItem - { - Title = RS.PlaningMissionEditorViewModel_RoiMenuItem_Title, - Type = PlaningMissionPointType.Roi, - Icon = MaterialIconKind.ImageFilterCenterFocus, - Command = ReactiveCommand.Create(() => - { - Context.Mission.ReplacePointCmd.Execute(PlaningMissionPointType.Roi).Subscribe(); - }) - } - } - }; - - AddablePoints.Add(new[] - { - _addItems, - _replaceItems - } - ); - - BeginEditName = ReactiveCommand.Create(() => - { - IsInEditNameMode = true; - }).DisposeItWith(Disposable); - - EndEditName = ReactiveCommand.Create(() => - { - IsInEditNameMode = false; - _svc.MissionStore.RenameFile(Context.Mission.MissionId, Context.Mission.Name); - }).DisposeItWith(Disposable); - - Delete = ReactiveCommand.Create(() => - { - _svc.MissionStore.DeleteFile(Context.Mission.MissionId); - Context.Mission = null; - }).DisposeItWith(Disposable); - } - - protected override void InternalAfterMapInit(IMap context) - { - Context = (IPlaningMissionContext)context; - - Context.WhenAnyValue(_ => _.Mission) - .WhereNotNull() - .Subscribe(_ => - { - if (_selectedPointDisposable != null) - { - _selectedPointDisposable.Dispose(); - _selectedPointDisposable = null; - } - - _selectedPointDisposable = _.WhenAnyValue(_ => _.SelectedPoint) - .Subscribe(_ => - { - _replaceItems.IsEnabled = _ != null; - }); - }).DisposeItWith(Disposable); - } - - [Reactive] - public bool IsInEditNameMode { get; set; } - public ReactiveCommand BeginEditName { get; } - public ReactiveCommand EndEditName { get; } - public ReactiveCommand Delete { get; } - [Reactive] - public IPlaningMissionContext Context { get; set; } - [Reactive] - public string TotalDistance { get; set; } - - public List AddablePoints { get; } = new(); -} - -public class MissionPointFlyoutMenuItem : ReactiveObject -{ - [Reactive] - public bool IsEnabled { get; set; } = true; - public string Title { get; init; } - public MaterialIconKind Icon { get; init; } - public PlaningMissionPointType Type { get; init; } - public ReactiveCommand Command { get; init; } - public List Items { get; } = new(); -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorWidgetProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorWidgetProvider.cs deleted file mode 100644 index bafab2bf..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Editor/PlaningMissionEditorWidgetProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core; - -[Export(PlaningPageViewModel.UriString, typeof(IViewModelProvider))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class PlaningMissionEditorWidgetProvider : ViewModelProviderBase -{ - [ImportingConstructor] - public PlaningMissionEditorWidgetProvider(IPlaningMission svc, ILocalizationService loc) - { - Source.AddOrUpdate(new PlaningMissionEditorViewModel(svc, loc)); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/HeaderPlaningFileMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/HeaderPlaningFileMenuItem.cs deleted file mode 100644 index 540137ea..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/HeaderPlaningFileMenuItem.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Reactive.Linq; -using Asv.Common; -using DynamicData; -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class HeaderPlaningFileMenuItem : HeaderMenuItem -{ - public const string UriString = HeaderMenuItem.UriString + "/planing-file"; - public static readonly Uri Uri = new(UriString); - private readonly ReadOnlyObservableCollection _items; - - [ImportingConstructor] - public HeaderPlaningFileMenuItem() : base(Uri) - { - Header = RS.HeaderPlaningFileMenuItem_Title; - Order = 0; - } - - public override ReadOnlyObservableCollection? Items { get; set; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Delete/HeaderPlaningFileDeleteMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Delete/HeaderPlaningFileDeleteMenuItem.cs deleted file mode 100644 index 4a9c7006..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Delete/HeaderPlaningFileDeleteMenuItem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class HeaderPlaningFileDeleteMenuItem : HeaderMenuItem -{ - public const string UriString = HeaderPlaningFileMenuItem.UriString + "/delete"; - public static readonly Uri Uri = new(UriString); - - public HeaderPlaningFileDeleteMenuItem() : base(Uri) - { - Header = RS.HeaderPlaningFileDeleteMenuItem_Title; - Icon = MaterialIconKind.Delete; - Order = ushort.MaxValue; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Download/HeaderPlaningFileDownloadMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Download/HeaderPlaningFileDownloadMenuItem.cs deleted file mode 100644 index 5e558d3b..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Download/HeaderPlaningFileDownloadMenuItem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class HeaderPlaningFileDownloadMenuItem : HeaderMenuItem -{ - public const string UriString = HeaderPlaningFileMenuItem.UriString + "/download"; - public static readonly Uri Uri = new(UriString); - - public HeaderPlaningFileDownloadMenuItem() : base(Uri) - { - Header = RS.HeaderPlaningFileDownloadMenuItem_Title; - Icon = MaterialIconKind.Download; - Order = ushort.MaxValue; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Open/HeaderPlaningFileOpenMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Open/HeaderPlaningFileOpenMenuItem.cs deleted file mode 100644 index 20d38526..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Open/HeaderPlaningFileOpenMenuItem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class HeaderPlaningFileOpenMenuItem : HeaderMenuItem -{ - public const string UriString = HeaderPlaningFileMenuItem.UriString + "/open"; - public static readonly Uri Uri = new(UriString); - - public HeaderPlaningFileOpenMenuItem() : base(Uri) - { - Header = RS.HeaderPlaningFileOpenMenuItem_Title; - Icon = MaterialIconKind.FolderOpen; - Order = ushort.MaxValue; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Save/HeaderPlaningFileSaveMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Save/HeaderPlaningFileSaveMenuItem.cs deleted file mode 100644 index 42dedc03..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Save/HeaderPlaningFileSaveMenuItem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class HeaderPlaningFileSaveMenuItem : HeaderMenuItem -{ - public const string UriString = HeaderPlaningFileMenuItem.UriString + "/save"; - public static readonly Uri Uri = new(UriString); - - public HeaderPlaningFileSaveMenuItem() : base(Uri) - { - Header = RS.HeaderPlaningFileSaveMenuItem_Title; - Icon = MaterialIconKind.ContentSave; - Order = ushort.MaxValue; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Upload/HeaderPlaningFileUploadMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Upload/HeaderPlaningFileUploadMenuItem.cs deleted file mode 100644 index aa6ea8fc..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Header/File/Items/Upload/HeaderPlaningFileUploadMenuItem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -public class HeaderPlaningFileUploadMenuItem : HeaderMenuItem -{ - public const string UriString = HeaderPlaningFileMenuItem.UriString + "/upload"; - public static readonly Uri Uri = new(UriString); - - public HeaderPlaningFileUploadMenuItem() : base(Uri) - { - Header = RS.HeaderPlaningFileUploadMenuItem_Title; - Icon = MaterialIconKind.Upload; - Order = ushort.MaxValue; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/MissionItemHelper.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/MissionItemHelper.cs deleted file mode 100644 index 5cf5377e..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/MissionItemHelper.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Asv.Common; -using Asv.Mavlink; -using Asv.Mavlink.V2.Common; - -namespace Asv.Drones.Gui.Core; - -public static class MissionItemHelper -{ - public static PlaningMissionPointModel TransformMissionItemToPointModel(this MissionItem missionItem) - { - var pointType = GetMissionPointTypeFromMavlinkCommand(missionItem.Command.Value); - return new PlaningMissionPointModel - { - Index = missionItem.Index, - Type = pointType, - Location = missionItem.Location.Value - }; - } - - public static PlaningMissionPointType GetMissionPointTypeFromMavlinkCommand(MavCmd command) - { - return command switch - { - MavCmd.MavCmdNavLand => PlaningMissionPointType.DoLand, - MavCmd.MavCmdNavTakeoff => PlaningMissionPointType.TakeOff, - MavCmd.MavCmdNavWaypoint => PlaningMissionPointType.Waypoint, - MavCmd.MavCmdDoSetRoi or MavCmd.MavCmdDoSetRoiLocation => PlaningMissionPointType.Roi, - _ => throw new ArgumentOutOfRangeException(command.ToString()) - }; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/PlaningMissionViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/PlaningMissionViewModel.cs deleted file mode 100644 index f7fe2006..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/PlaningMissionViewModel.cs +++ /dev/null @@ -1,280 +0,0 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.Composition.Hosting; -using System.Reactive; -using System.Reactive.Linq; -using Asv.Common; -using Asv.Mavlink.Vehicle; -using Avalonia.Controls; -using DynamicData; -using DynamicData.Alias; -using DynamicData.Binding; -using FluentAvalonia.Core; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Validation.Extensions; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionViewModel : ViewModelBaseWithValidation -{ - private readonly Guid _id; - private readonly IPlaningMission _svc; - private readonly CompositionContainer _container; - private readonly IPlaningMissionPointFactory _pointFactory; - private readonly SourceCache _source; - private readonly ReadOnlyObservableCollection _points; - private readonly IPlaningMissionContext _context; - - public PlaningMissionViewModel() : base("asv:shell.page.planing-mission.mission") - { - if (Design.IsDesignMode) - { - // _points = new ReadOnlyObservableCollection(new ObservableCollection(new[] - // { - // new PlaningMissionPointViewModel($"{1}.{PlaningMissionPointType.TakeOff}.Point") { Name = "Point 1" }, - // new PlaningMissionPointViewModel($"{1}.{PlaningMissionPointType.Navigation}.Point") { Name = "Point 2" }, - // new PlaningMissionPointViewModel($"{1}.{PlaningMissionPointType.DoLand}.Point") { Name = "Point 3" }, - // })); - } - } - public PlaningMissionViewModel(Guid id, string name, ILogService log, IPlaningMissionPointFactory pointFactory, - CompositionContainer container, IPlaningMission svc, IPlaningMissionContext context) : this() - { - _id = id; - _pointFactory = pointFactory; - _container = container; - _context = context; - _svc = svc; - - _source = new SourceCache(x => x.Index) - .DisposeItWith(Disposable); - _source - .Connect() - .Transform(x => - { - var point = pointFactory.Create(x, this); - if (_context.IsInAnchorEditMode) - { - point.MissionAnchor.IsInEditMode = true; - } - return point; - }) - .SortBy(x => x.Point.Index) - .Bind(out _points) - .DisposeMany() - .Subscribe(_ => - { - TotalDistance = 0; - if (Points.Count <= 1) return; - for (int i = 1; i < Points.Count; i++) - { - TotalDistance = GeoMath.Distance(Points[i - 1].Point.Location, Points[i].Point.Location); - } - }) - .DisposeItWith(Disposable); - - _points.ToObservableChangeSet(_ => _.Index) - .WhenValueChanged(x => x.IsChanged) - .Where(x => x) - .Subscribe(_ => IsChanged = true) - .DisposeItWith(Disposable); - - this.WhenAnyValue(_ => _.Name).Subscribe(_ => IsChanged = true).DisposeItWith(Disposable); - this.ValidationRule(x => x.Name, name => !string.IsNullOrWhiteSpace(name), RS.PlaningMissionViewModel_NameMustBeNotEmpty); - - this.WhenValueChanged(_ => _.SelectedPoint) - .Subscribe(_ => - { - if (_ == null) - { - context.SelectedItem = null; - return; - } - - context.SelectedItem = _.MissionAnchor; - - if (!_.MissionAnchor.IsInEditMode) - { - context.Center = _.MissionAnchor.Location; - } - }) - .DisposeItWith(Disposable); - - context.WhenValueChanged(_ => _.SelectedItem) - .Subscribe(_ => - { - if (_ == null) - { - SelectedPoint = null; - return; - } - - var point = _points.FirstOrDefault(__ => __.MissionAnchor == _); - if (point != null) - { - SelectedPoint = point; - if (!point.MissionAnchor.IsInEditMode) - { - context.Center = point.MissionAnchor.Location; - } - } - }) - .DisposeItWith(Disposable); - - _source.CountChanged.Subscribe(_ => IsChanged = true).DisposeItWith(Disposable); - AddPointCmd = ReactiveCommand.CreateFromTask(AddPointImpl).DisposeItWith(Disposable); - ReplacePointCmd = ReactiveCommand.Create(ReplacePointImpl).DisposeItWith(Disposable); - SaveCmd = ReactiveCommand.Create(SaveImpl, this.IsValid()).DisposeItWith(Disposable); - SaveCmd.ThrownExceptions.Subscribe(ex=>log.Error("Planing",ex.Message,ex)).DisposeItWith(Disposable); - MoveTop = ReactiveCommand.Create(() => - { - var previousPoint = Points.LastOrDefault(_ => _.Index < SelectedPoint.Index); - if (previousPoint == null) return; - (previousPoint.Index, SelectedPoint.Index) = (SelectedPoint.Index, previousPoint.Index); - var selectedPointIndex = SelectedPoint.Index; - _source.AddOrUpdate(new [] - { - previousPoint.Point, - SelectedPoint.Point - }); - SelectedPoint = Points.FirstOrDefault(_ => _.Index == selectedPointIndex); - }).DisposeItWith(Disposable); - MoveDown = ReactiveCommand.Create(() => - { - var nextPoint = Points.FirstOrDefault(_ => _.Index > SelectedPoint.Index); - if (nextPoint == null) return; - (nextPoint.Index, SelectedPoint.Index) = (SelectedPoint.Index, nextPoint.Index); - var selectedPointIndex = SelectedPoint.Index; - _source.AddOrUpdate(new[] - { - nextPoint.Point, - SelectedPoint.Point - }); - SelectedPoint = Points.FirstOrDefault(_ => _.Index == selectedPointIndex); - }).DisposeItWith(Disposable); - IsChanged = false; - Name = name; - - } - - public Guid MissionId => _id; - [Reactive] - public string Name { get; set; } - [Reactive] - public bool IsChanged { get; set; } - [Reactive] - public double TotalDistance { get; set; } - public ReadOnlyObservableCollection Points => _points; - public ReactiveCommand AddPointCmd { get; } - public ReactiveCommand ReplacePointCmd { get; } - public ReactiveCommand MoveTop { get; } - public ReactiveCommand MoveDown { get; } - public ReactiveCommand SaveCmd { get; } - [Reactive] - public PlaningMissionPointViewModel SelectedPoint { get; set; } - - - public void AddOrUpdatePoint(PlaningMissionPointModel model) - { - _source.AddOrUpdate(model); - } - - public void RemovePoint(PlaningMissionPointModel model) - { - _source.Remove(model); - } - - public void RemovePoint(int index) - { - _source.Remove(index); - } - - public void ClearAllPoints() - { - _source.Clear(); - } - - public void RemovePoint(PlaningMissionPointViewModel item) - { - _source.Remove(item.Point); - } - - private void Load(PlaningMissionModel model, SemVersion fileVersion) - { - model.Points.ForEach(x=>_source.AddOrUpdate(x)); - _points.ForEach(_ => _.IsChanged = false); - } - - private PlaningMissionModel Save(SemVersion fileVersion) - { - var model = new PlaningMissionModel(); - model.Points.AddRange(_points.Select(x => x.SaveToJson(fileVersion))); - return model; - } - - public void SaveImpl() - { - var needRename = false; - using (var handle = _svc.MissionStore.OpenFile(_id)) - { - handle.File.Save(Save(handle.File.FileVersion)); - if (handle.Name.Equals(Name, StringComparison.InvariantCulture) == false) - { - needRename = true; - } - } - - if (needRename) - { - _svc.MissionStore.RenameFile(_id, Name); - } - - Points.ForEach(_ => _.IsChanged = false); - IsChanged = false; - } - - private void ReplacePointImpl(PlaningMissionPointType typeName) - { - var selectedPoint = SelectedPoint; - selectedPoint.Point.Type = typeName; - _source.Remove(SelectedPoint.Index); - _source.AddOrUpdate(selectedPoint.Point); - } - - private async Task AddPointImpl(PlaningMissionPointType type, CancellationToken cancel) - { - //TODO: Make a possibility to insert points - var indexToAdd = _source.Count == 0 ? 0 : _source.Keys.Max() + 1; - - var model = new PlaningMissionPointModel - { - Type = type, - Index = indexToAdd - }; - - model.Location = await _context.ShowTargetDialog(RS.PlaningMissionViewModel_SelectTargetLocation, cancel); - _source.AddOrUpdate(model); - } - - public void Load(PlaningMissionFile file) - { - var model = file.Load(); - Load(model, file.FileVersion); - } -} - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionLandPointViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionLandPointViewModel.cs deleted file mode 100644 index fc2fdab7..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionLandPointViewModel.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Asv.Common; -using Asv.Mavlink; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionLandPointViewModel : PlaningMissionPointViewModel -{ - public PlaningMissionLandPointViewModel(PlaningMissionPointModel point, PlaningMissionViewModel mission, - IPlaningMission svc, ILocalizationService loc) : base(point, mission) - { - MissionAnchor = new PlaningMissionDoLandPointAnchor(point); - - this.WhenAnyValue(_ => _.Index) - .Subscribe(_ => - { - MissionAnchor.Index = _; - IsChanged = true; - }).DisposeItWith(Disposable); - - MissionAnchor.WhenAnyValue(_ => _.Location) - .Subscribe(_ => - { - Point.Location = _; - IsChanged = true; - }).DisposeItWith(Disposable); - } - - public override void CreateVehicleItems(IVehicleClient vehicle, ISdrClientDevice? sdr) - { - vehicle.Missions.AddLandMissionItem(Point.Location); - } -} - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionNavigationPointViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionNavigationPointViewModel.cs deleted file mode 100644 index 2670a034..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionNavigationPointViewModel.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Asv.Avalonia.Map; -using Asv.Common; -using Asv.Mavlink; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionNavigationPointViewModel : PlaningMissionPointViewModel -{ - public PlaningMissionNavigationPointViewModel(PlaningMissionPointModel point, PlaningMissionViewModel mission, - IPlaningMission svc, ILocalizationService loc) : base(point, mission) - { - MissionAnchor = new PlaningMissionNavigationPointAnchor(point); - - this.WhenAnyValue(_ => _.Index) - .Subscribe(_ => - { - MissionAnchor.Index = _; - IsChanged = true; - }).DisposeItWith(Disposable); - - MissionAnchor.WhenAnyValue(_ => _.Location) - .Subscribe(_ => - { - Point.Location = _; - IsChanged = true; - }).DisposeItWith(Disposable); - } - - public override void CreateVehicleItems(IVehicleClient vehicle, ISdrClientDevice? sdr) - { - vehicle.Missions.AddNavMissionItem(Point.Location, 0); - } -} - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionPointFactory.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionPointFactory.cs deleted file mode 100644 index 78ed18c9..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionPointFactory.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.ComponentModel.Composition; -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -/// -/// Represents a factory for creating planning mission point view models. -/// -public interface IPlaningMissionPointFactory -{ - /// - /// Creates a PlaningMissionPointViewModel object based on the provided PlaningMissionPointModel and PlaningMissionViewModel. - /// - /// The PlaningMissionPointModel object to create the PlaningMissionPointViewModel from. - /// The PlaningMissionViewModel object to associate the PlaningMissionPointViewModel with. - /// The created PlaningMissionPointViewModel object. - public PlaningMissionPointViewModel Create(PlaningMissionPointModel point, PlaningMissionViewModel mission); -} - -/// -/// Factory class for creating instances of PlaningMissionPointViewModel. -/// -/// -/// This factory class is responsible for creating different types of PlaningMissionPointViewModel objects based on the -/// PlaningMissionPointType provided. -/// -[Export(typeof(IPlaningMissionPointFactory))] -[PartCreationPolicy(CreationPolicy.Shared)] -public class PlaningMissionPointFactory : IPlaningMissionPointFactory -{ - /// - /// Represents a private read-only variable that holds an instance of the interface. - /// - private readonly IPlaningMission _svc; - - /// - /// Represents an instance of a localization service. - /// - private readonly ILocalizationService _loc; - - /// - /// Represents a factory for creating planning mission points. - /// - [ImportingConstructor] - public PlaningMissionPointFactory(IPlaningMission svc, ILocalizationService loc) - { - _svc = svc; - _loc = loc; - } - - /// - /// Creates a new instance of PlaningMissionPointViewModel based on the given PlaningMissionPointModel and PlaningMissionViewModel. - /// - /// The PlaningMissionPointModel object representing the point. - /// The PlaningMissionViewModel object representing the mission. - /// A new instance of PlaningMissionPointViewModel. - /// Thrown when the point type is not recognized. - public PlaningMissionPointViewModel Create(PlaningMissionPointModel point, PlaningMissionViewModel mission) - { - switch (point.Type) - { - case PlaningMissionPointType.TakeOff: - return new PlaningMissionTakeOffPointViewModel(point, mission, _svc, _loc); - case PlaningMissionPointType.DoLand: - return new PlaningMissionLandPointViewModel(point, mission, _svc, _loc); - case PlaningMissionPointType.Waypoint: - return new PlaningMissionNavigationPointViewModel(point, mission, _svc, _loc); - case PlaningMissionPointType.Roi: - return new PlaningMissionRoiPointViewModel(point, mission, _svc, _loc); - default: - throw new ArgumentOutOfRangeException(); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionPointViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionPointViewModel.cs deleted file mode 100644 index 8bab4381..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionPointViewModel.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Reactive; -using Asv.Avalonia.Map; -using Asv.Common; -using Asv.Mavlink; -using Avalonia.Media; -using DynamicData; -using DynamicData.Binding; -using Material.Icons; -using Newtonsoft.Json.Linq; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Validation.Extensions; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionPointViewModel : ViewModelBaseWithValidation -{ - private const string _uriString = "asv:shell.page.planing-mission.mission.point"; - private readonly PlaningMissionViewModel _parent; - private readonly PlaningMissionPointModel _point; - - private PlaningMissionPointViewModel(string uri) : base(uri) - { - this.ValidationRule(x=>x.Name, name => !string.IsNullOrWhiteSpace(name), RS.PlaningMissionViewModel_NameMustBeNotEmpty); - } - - protected PlaningMissionPointViewModel(PlaningMissionPointModel point, PlaningMissionViewModel parent) - : this($"{_uriString}.{point.Index}.{point.Type}") - { - _parent = parent; - _point = point; - - Index = point.Index; - Type = point.Type; - - Delete = ReactiveCommand.Create(() => - { - parent.RemovePoint(this); - }).DisposeItWith(Disposable); - - this.WhenValueChanged(_ => _.Name) - .WhereNotNull() - .Subscribe(_ => - { - IsChanged = true; - if(MissionAnchor != null) - MissionAnchor.Title = _; - }) - .DisposeItWith(Disposable); - - this.WhenValueChanged(_ => _.Index) - .Subscribe(_ => - { - IsChanged = true; - _point.Index = _; - if(MissionAnchor != null) - MissionAnchor.Index = _; - Name = $"{Type} {_}"; - }).DisposeItWith(Disposable); - - this.WhenValueChanged(_ => _.Type) - .Subscribe(_ => - { - IsChanged = true; - _point.Type = _; - Name = $"{_} {Index}"; - }).DisposeItWith(Disposable); - - } - public PlaningMissionPointModel Point => _point; - [Reactive] - public int Index { get; set; } - [Reactive] - public string Name { get; set; } - [Reactive] - public PlaningMissionPointType Type { get; set; } - [Reactive] - public bool IsChanged { get; set; } - [Reactive] - public PlaningMissionAnchor MissionAnchor { get; set; } - public ReactiveCommand Delete { get; } - public PlaningMissionPointModel SaveToJson(SemVersion fileVersion) - { - return new PlaningMissionPointModel - { - Index = Index, - Type = Type, - Location = MissionAnchor.Location - }; - } - public virtual void CreateVehicleItems(IVehicleClient vehicle, ISdrClientDevice? sdr) - { - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionRoiPointViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionRoiPointViewModel.cs deleted file mode 100644 index 06ca17f1..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionRoiPointViewModel.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Asv.Avalonia.Map; -using Asv.Common; -using Asv.Mavlink; -using Asv.Mavlink.V2.Common; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionRoiPointViewModel : PlaningMissionPointViewModel -{ - public PlaningMissionRoiPointViewModel(PlaningMissionPointModel point, PlaningMissionViewModel mission, - IPlaningMission svc, ILocalizationService loc) : base(point, mission) - { - MissionAnchor = new PlaningMissionRoiPointAnchor(point); - - this.WhenAnyValue(_ => _.Index) - .Subscribe(_ => - { - MissionAnchor.Index = _; - IsChanged = true; - }).DisposeItWith(Disposable); - - MissionAnchor.WhenAnyValue(_ => _.Location) - .Subscribe(_ => - { - Point.Location = _; - IsChanged = true; - }).DisposeItWith(Disposable); - } - - public override void CreateVehicleItems(IVehicleClient vehicle, ISdrClientDevice? sdr) - { - vehicle.Missions.AddRoiMissionItem(Point.Location, MavRoi.MavRoiLocation); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionTakeOffPointViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionTakeOffPointViewModel.cs deleted file mode 100644 index 52ba4137..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/Mission/Points/PlaningMissionTakeOffPointViewModel.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Asv.Avalonia.Map; -using Asv.Common; -using Asv.Mavlink; -using Material.Icons; -using ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -public class PlaningMissionTakeOffPointViewModel : PlaningMissionPointViewModel -{ - public PlaningMissionTakeOffPointViewModel(PlaningMissionPointModel point, PlaningMissionViewModel mission, - IPlaningMission svc, ILocalizationService loc) : base(point, mission) - { - MissionAnchor = new PlaningMissionTakeOffPointAnchor(point); - - this.WhenAnyValue(_ => _.Index) - .Subscribe(_ => - { - MissionAnchor.Index = _; - IsChanged = true; - }).DisposeItWith(Disposable); - - MissionAnchor.WhenAnyValue(_ => _.Location) - .Subscribe(_ => - { - Point.Location = _; - IsChanged = true; - }).DisposeItWith(Disposable); - } - - public override void CreateVehicleItems(IVehicleClient vehicle, ISdrClientDevice? sdr) - { - vehicle.Missions.AddTakeOffMissionItem(Point.Location); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningPageViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningPageViewModel.cs deleted file mode 100644 index 43a70551..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningPageViewModel.cs +++ /dev/null @@ -1,458 +0,0 @@ -using System.Collections; -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.ComponentModel.Composition.Hosting; -using System.Reactive; -using System.Reactive.Linq; -using Asv.Cfg; -using Asv.Common; -using Asv.Drones.Gui.Core; -using Asv.Drones.Gui.Uav; -using Asv.Mavlink; -using DynamicData; -using DynamicData.Binding; -using DynamicData.PLinq; -using FluentAvalonia.Core; -using FluentAvalonia.UI.Controls; -using Material.Icons; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents the configuration for the PlanningPageViewModel. - /// - public class PlanningPageViewModelConfig - { - /// - /// Gets or sets the zoom level. - /// - /// - /// The zoom level as a double. - /// - public double Zoom { get; set; } - - /// - /// Gets or sets the center point on the map. - /// - /// - /// The center point on the map. - /// - public GeoPoint MapCenter { get; set; } - } - - /// - /// Represents the view model for the Planning page. - /// - [ExportShellPage(UriString)] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class PlaningPageViewModel : MapPageViewModel, IPlaningMissionContext - { - /// - /// Represents the constant string for the URI. - /// - public const string UriString = "asv:shell.page.map.planing"; - - /// - /// Represents a constant Uri. - /// - public static readonly Uri Uri = new(UriString); - private readonly IPlaningMissionAnchorProvider _anchorProvider; - - /// - /// Represents an instance of a that is used to create planning mission points. - /// - private readonly IPlaningMissionPointFactory _taskFactory; - - /// - /// Represents an instance of the IMavlinkDevicesService interface used for managing Mavlink devices. - /// - private readonly IMavlinkDevicesService _devices; - - /// - /// The CompositionContainer used for dependency injection and managing the lifetime of objects. - /// - private readonly CompositionContainer _container; - - /// - /// Represents an instance of the Planning Mission service. - /// - private readonly IPlaningMission _svc; - - /// - /// Represents a private, read-only instance of the interface. - /// - private readonly ILogService _log; - - /// - /// Represents a collection of menu items for uploading. - /// - private ReadOnlyObservableCollection _uploadMenuItems; - - /// - /// Holds the collection of download menu items. - /// - private ReadOnlyObservableCollection _downloadMenuItems; - - /// - /// Represents a private readonly variable that stores configuration information. - /// - /// - /// This variable is of type IConfiguration and is used to access and utilize configuration information - /// within the scope of its class. It is marked as readonly, indicating that its value cannot be modified - /// after initialization. - /// - private readonly IConfiguration _cfg; - - /// - /// View model for the Planning page. - /// - /// - /// This view model provides functionality for uploading and downloading mission files, opening a browser, saving and deleting missions, and updating anchors. - /// It inherits from the base MapViewModel class. - /// - /// The map service. - /// The configuration service. - /// The planning mission service. - /// The log service. - /// The composition container. - /// The planning mission point factory. - /// The MAVLink devices service. - /// A collection of exported menu items. - /// A collection of map markers. - /// A collection of map widgets. - /// A collection of map actions. - /// - [ImportingConstructor] - public PlaningPageViewModel(IMapService map, IConfiguration cfg, IPlaningMission svc, ILogService log, - CompositionContainer container, IPlaningMissionPointFactory taskFactory, IMavlinkDevicesService devices, - [ImportMany(HeaderMenuItem.UriString)] IEnumerable exportedMenuItems, - [ImportMany(UriString)] IEnumerable> markers, - [ImportMany(UriString)] IEnumerable> widgets, - [ImportMany(UriString)] IEnumerable> actions):base(Uri,map,exportedMenuItems,markers,widgets,actions) - { - Title = RS.PlaningShellMenuItem_Name; - Icon = MaterialIconKind.MapMarkerCheck; - PlanningConfig = cfg.Get(); - - _cfg = cfg; - _svc = svc; - _log = log; - _devices = devices; - _container = container; - _taskFactory = taskFactory; - - _devices.Vehicles - .ChangeKey(_ => _.FullId) - .Transform(_ => - { - var item = new HeaderMenuItem($"{HeaderPlaningFileUploadMenuItem.UriString}/{_.FullId}") - { - Icon = MavlinkHelper.GetIcon(_.Class), - Command = ReactiveCommand.CreateFromTask(cancel => UploadMission(_, null, Mission.Points, cancel)) - .DisposeItWith(Disposable) - }; - _.Name.Subscribe(_ => item.Header = _); - return (IHeaderMenuItem)item; - }) - .Bind(out _uploadMenuItems) - .Subscribe() - .DisposeItWith(Disposable); - - _devices.Vehicles - .ChangeKey(_ => _.FullId) - .Transform(_ => - { - var item = new HeaderMenuItem($"{HeaderPlaningFileDownloadMenuItem.UriString}/{_.FullId}") - { - Icon = MavlinkHelper.GetIcon(_.Class), - Command = ReactiveCommand.CreateFromTask(cancel => DownloadMission(_, cancel)) - }; - _.Name.Subscribe(_ => item.Header = _); - return (IHeaderMenuItem)item; - }) - .Bind(out _downloadMenuItems) - .Subscribe() - .DisposeItWith(Disposable); - - var uploadMenuItem = new HeaderPlaningFileUploadMenuItem - { - Command = ReactiveCommand.Create(() => { }, this.WhenAnyValue(_ => _.Mission).Select(_ => _ != null)).DisposeItWith(Disposable), - Items = _uploadMenuItems - }; - - var downloadMenuItem = new HeaderPlaningFileDownloadMenuItem - { - Command = ReactiveCommand.Create(() => { }, this.WhenAnyValue(_ => _.Mission).Select(_ => _ != null)).DisposeItWith(Disposable), - Items = _downloadMenuItems - }; - - HeaderItemsSource.AddOrUpdate( - new HeaderPlaningFileMenuItem - { - Items = new ReadOnlyObservableCollection(new ObservableCollection(new IHeaderMenuItem[] - { - new HeaderPlaningFileOpenMenuItem - { - Command = ReactiveCommand.CreateFromTask(OpenBrowserImpl).DisposeItWith(Disposable) - }, - new HeaderPlaningFileSaveMenuItem - { - Command = ReactiveCommand.Create(() => - { - Mission.SaveCmd.Execute().Subscribe(); - }, this.WhenAnyValue(_ => _.Mission).Select(_ => _ != null)).DisposeItWith(Disposable) - }, - new HeaderPlaningFileDeleteMenuItem - { - Command = ReactiveCommand.Create(() => - { - _svc.MissionStore.DeleteFile(Mission.MissionId); - Mission = null; - }, this.WhenAnyValue(_ => _.Mission).Select(_ => _ != null)).DisposeItWith(Disposable) - }, - uploadMenuItem, - downloadMenuItem - })) - }); - - foreach (var marker in markers) - { - if (marker is IPlaningMissionAnchorProvider anchorProvider) - { - _anchorProvider = anchorProvider; - } - } - - Zoom = PlanningConfig.Zoom is 0 ? 1 : PlanningConfig.Zoom; - - Center = PlanningConfig.MapCenter; - - this.WhenPropertyChanged(_ => _.Zoom) - .Subscribe(_ => - { - PlanningConfig.Zoom = _.Value; - cfg.Set(PlanningConfig); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.Center) - .Subscribe(_ => - { - PlanningConfig.MapCenter = _.Value; - cfg.Set(PlanningConfig); - }) - .DisposeItWith(Disposable); - - this.WhenPropertyChanged(_ => _.Mission) - .Subscribe(_ => - { - _anchorProvider.Update(_.Value); - }).DisposeItWith(Disposable); - } - - /// - /// Uploads a mission to a vehicle using the provided points. - /// - /// The vehicle client to upload the mission to. - /// The SDR client device used for creating vehicle items. - /// The collection of planning mission points. - /// The cancellation token for cancelling the upload. - private async Task UploadMission(IVehicleClient vehicle, ISdrClientDevice sdr, IEnumerable points, CancellationToken cancel) - { - await vehicle.Missions.ClearRemote(cancel); - - vehicle.Missions.ClearLocal(); - - vehicle.Missions.AddNavMissionItem(vehicle.Position.Home.Value ?? GeoPoint.Zero); - - points.ForEach(_ => - { - if(cancel.IsCancellationRequested) return; - _.CreateVehicleItems(vehicle, sdr); - }); - - try - { - await vehicle.Missions.Upload(cancel, progress => UploadProgress = progress); - _log.Info("Planing", RS.PlanningPageViewModel_MissionUploaded); - } - catch (Exception ex) - { - _log.Error("Planing", ex.Message); - } - } - - /// - /// Downloads the mission from the specified vehicle. - /// - /// The vehicle client used to download the mission. - /// The cancellation token used to cancel the download process. - /// A task representing the asynchronous operation. - private async Task DownloadMission(IVehicleClient vehicle, CancellationToken cancel) - { - Mission?.ClearAllPoints(); - var vehicleMission = await vehicle.Missions.Download(cancel); - foreach (var missionItem in vehicleMission) - { - if(cancel.IsCancellationRequested) return; - if (missionItem.Index == 0) continue; - Mission?.AddOrUpdatePoint(missionItem.TransformMissionItemToPointModel()); - } - } - - /// - /// Tries to close the current mission. - /// - /// Returns a task representing the asynchronous operation. The task result is a boolean value indicating whether the mission was successfully closed or not. - public override async Task TryClose() - { - if (Mission == null) return true; - - if (Mission.IsChanged) - { - var dialog = new ContentDialog - { - Title = RS.PlaningPageViewModel_DataLossDialog_Title, - Content = RS.PlaningPageViewModel_DataLossDialog_Content, - PrimaryButtonText = RS.PlaningPageViewModel_DataLossDialog_PrimaryButtonText, - SecondaryButtonText = RS.PlaningPageViewModel_DataLossDialog_SecondaryButtonText, - CloseButtonText = RS.PlaningPageViewModel_DataLossDialog_CloseButtonText, - IsSecondaryButtonEnabled = true - }; - - var result = await dialog.ShowAsync(); - - if (result == ContentDialogResult.Primary) - { - Mission.SaveImpl(); - - return true; - } - - if (result == ContentDialogResult.Secondary) return true; - - if (result == ContentDialogResult.None) return false; - } - - return true; - } - - /// - /// Opens the browser dialog for selecting a mission. - /// - /// The cancellation token. - /// - /// A representing the asynchronous operation. - /// - private async Task OpenBrowserImpl(CancellationToken arg) - { - var dialog = new ContentDialog - { - Title = RS.PlanningPageViewModel_MissionBrowserDialog_Title, - PrimaryButtonText = RS.PlanningPageViewModel_MissionBrowserDialog_PrimaryButton, - IsSecondaryButtonEnabled = true, - SecondaryButtonText = RS.PlanningPageViewModel_MissionBrowserDialog_SecondaryButton - }; - - using var viewModel = new PlaningMissionBrowserViewModel(_svc, _log); - viewModel.ApplyDialog(dialog); - dialog.Content = viewModel; - var result = await dialog.ShowAsync(); - if (result == ContentDialogResult.Primary) - { - OpenMission(viewModel.DialogResult); - } - } - - /// - /// Gets or sets the planning mission for the property. - /// - /// - /// This property represents the planning mission associated with the property. The planning mission - /// contains information related to the mission such as the mission's view model. - /// - /// - [Reactive] - public PlaningMissionViewModel? Mission { get; set; } - - /// - /// Opens a mission with the specified ID. - /// - /// The ID of the mission to open. - public void OpenMission(Guid id) - { - try - { - Mission?.Dispose(); - - using (var handle = _svc.MissionStore.OpenFile(id)) - { - Mission = new PlaningMissionViewModel(handle.Id, handle.Name, _log, _taskFactory, - _container, _svc, this); - - Mission.Load(handle.File); - - _anchorProvider.Update(Mission); - - if (Mission.Points.Count > 0) - Center = Mission.Points.FirstOrDefault()!.MissionAnchor.Location; - - Mission.IsChanged = false; - } - } - catch (Exception e) - { - _log.Error("Planing", e.Message, e); - } - } - - /// - /// Gets or sets the upload progress in a decimal format. - /// - /// - /// A value between 0 and 1 is expected. - /// 0 indicates no progress, - /// while 1 indicates the upload is complete. - /// - public double UploadProgress { get; set; } - - /// - /// Gets or sets the configuration for the PlanningPageViewModel. - /// The PlanningConfig property is decorated with the [Reactive] attribute, indicating that it is a reactive property. - /// - /// The planning configuration. - [Reactive] - public PlanningPageViewModelConfig PlanningConfig { get; set; } - } -} - -/// -/// Represents the context for planning a mission. -/// -public interface IPlaningMissionContext : IMap -{ - /// - /// Gets or sets the Mission property of type PlaningMissionViewModel. - /// This property represents the mission associated with the planning process. - /// - /// - /// The PlaningMissionViewModel object representing the mission. - /// - PlaningMissionViewModel Mission { get; set; } - - /// - /// Opens the mission specified by the given id. - /// - /// The unique identifier of the mission to be opened. - void OpenMission(Guid id); - - /// - /// Gets the progress of the upload as a decimal value between 0 and 1. - /// - /// - /// The upload progress as a decimal value. - /// - public double UploadProgress { get; } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningShellMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningShellMenuItem.cs deleted file mode 100644 index 739db852..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningShellMenuItem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.ComponentModel.Composition; -using Material.Icons; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IShellMenuItem))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class PlaningShellMenuItem : ShellMenuItem - { - public PlaningShellMenuItem():base("asv:shell.menu.planning") - { - Name = RS.PlaningShellMenuItem_Name; - NavigateTo = PlaningPageViewModel.Uri; - Icon = MaterialIconDataProvider.GetData(MaterialIconKind.MapMarkerPath); - Position = ShellMenuPosition.Top; - Type = ShellMenuItemType.PageNavigation; - Order = 0; - - } - - } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningWidgetBase.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningWidgetBase.cs deleted file mode 100644 index f96dd47c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Planing/PlaningWidgetBase.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Asv.Drones.Gui.Core -{ - public abstract class PlaningWidgetBase : MapWidgetBase - { - public const string UriString = PlaningPageViewModel.UriString + ".widget"; - public static readonly Uri Uri = new(UriString); - - protected PlaningWidgetBase(Uri id) : base(id) - { - - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorView.axaml deleted file mode 100644 index ff707e4c..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorView.axaml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorView.axaml.cs deleted file mode 100644 index 3065e307..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorView.axaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(AnchorsEditorViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class AnchorsEditorView : ReactiveUserControl -{ - public AnchorsEditorView() - { - InitializeComponent(); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorViewModel.cs deleted file mode 100644 index 366ccb5f..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorViewModel.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System.ComponentModel.Composition; -using Asv.Common; -using DynamicData.Binding; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Validation.Extensions; - -namespace Asv.Drones.Gui.Core; - -public class AnchorsEditorViewModel : MapWidgetBase -{ - private readonly ILocalizationService _loc; - private bool _internalChange; - private IDisposable? _locationSubscription; - private IMapAnchor _prevAnchor; - - public const string UriString = "asv:shell.page.map.anchors-editor"; - - public AnchorsEditorViewModel() : base(new Uri(UriString)) - { - } - - [ImportingConstructor] - public AnchorsEditorViewModel(ILocalizationService loc) : this() - { - _loc = loc; - Disposable.AddAction(() => - { - _locationSubscription?.Dispose(); - }); - - Order = int.MaxValue; - - this.WhenAnyValue(_ => _.Latitude) - .Subscribe(UpdateLatitude) - .DisposeItWith(Disposable); - this.WhenAnyValue(_ => _.Longitude) - .Subscribe(UpdateLongitude) - .DisposeItWith(Disposable); - this.WhenAnyValue(_ => _.Altitude) - .Subscribe(UpdateAltitude) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.Latitude, - _ => _loc.Latitude.IsValid(_), - _ => _loc.Latitude.GetErrorMessage(_) ?? string.Empty) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.Longitude, - _ => _loc.Longitude.IsValid(_), - _ => _loc.Longitude.GetErrorMessage(_) ?? string.Empty) - .DisposeItWith(Disposable); - - this.ValidationRule(x => x.Altitude, - _ => _loc.Altitude.IsValid(_), - _ => _loc.Altitude.GetErrorMessage(_) ?? string.Empty) - .DisposeItWith(Disposable); - } - - [Reactive] - public bool IsVisible { get; set; } - - [Reactive] - public string Latitude { get; set; } - - [Reactive] - public string LatitudeUnits { get; set; } - - [Reactive] - public string Longitude { get; set; } - - [Reactive] - public string LongitudeUnits { get; set; } - - [Reactive] - public string Altitude { get; set; } - - [Reactive] - public string AltitudeUnits { get; set; } - - private void UpdateLatitude(string latitude) - { - if (_internalChange) return; - if (!string.IsNullOrWhiteSpace(latitude) && _loc.Latitude.IsValid(latitude)) - { - var prevLocation = _prevAnchor.Location; - var newLocation = _prevAnchor.Location = new GeoPoint( - _loc.Latitude.CurrentUnit.Value.ConvertToSi(latitude), - prevLocation.Longitude, prevLocation.Altitude); - // if new location is equal to previous location then we need to update longitude string - if (prevLocation.Equals(newLocation)) - { - _internalChange = true; - Latitude = _loc.Longitude.FromSiToString(prevLocation.Latitude); - _internalChange = false; - } - else - { - _prevAnchor.Location = newLocation; - } - } - } - private void UpdateLongitude(string longitude) - { - if (_internalChange) return; - if (!string.IsNullOrWhiteSpace(longitude) && _loc.Longitude.IsValid(longitude)) - { - var prevLocation = _prevAnchor.Location; - var newLocation = new GeoPoint(prevLocation.Latitude, - _loc.Longitude.CurrentUnit.Value.ConvertToSi(longitude), - prevLocation.Altitude); - // if new location is equal to previous location then we need to update longitude string - if (prevLocation.Equals(newLocation)) - { - _internalChange = true; - Longitude = _loc.Longitude.FromSiToString(prevLocation.Longitude); - _internalChange = false; - } - else - { - _prevAnchor.Location = newLocation; - } - } - } - private void UpdateAltitude(string altitude) - { - if (_internalChange) return; - if (!string.IsNullOrWhiteSpace(altitude) && _loc.Altitude.IsValid(altitude)) - { - var prevLocation = _prevAnchor.Location; - var newLocation = _prevAnchor.Location = new GeoPoint(prevLocation.Latitude, - prevLocation.Longitude, - _loc.Altitude.CurrentUnit.Value.ConvertToSi(altitude)); - // if new location is equal to previous location then we need to update string - if (prevLocation.Equals(newLocation)) - { - _internalChange = true; - Altitude = _loc.Longitude.FromSiToString(prevLocation.Altitude); - _internalChange = false; - } - else - { - _prevAnchor.Location = newLocation; - } - } - } - - protected override void InternalAfterMapInit(IMap context) - { - LatitudeUnits = _loc.Latitude.CurrentUnit.Value.Unit; - LongitudeUnits = _loc.Longitude.CurrentUnit.Value.Unit; - AltitudeUnits = _loc.Altitude.CurrentUnit.Value.Unit; - - context.WhenValueChanged(_ => _.SelectedItem) - .Subscribe(_ => - { - if (_prevAnchor != null && _prevAnchor.IsInEditMode) - { - UpdateLatitude(Latitude); - UpdateLongitude(Longitude); - UpdateAltitude(Altitude); - } - - _locationSubscription?.Dispose(); - _locationSubscription = null; - - if (_ != null) - { - _prevAnchor = _; - IsVisible = true; - - _locationSubscription = _.WhenAnyValue(_ => _.Location) - .Subscribe(_ => - { - _internalChange = true; - - Latitude = _loc.Latitude.FromSiToString(_.Latitude); - Longitude = _loc.Longitude.FromSiToString(_.Longitude); - Altitude = _loc.Altitude.FromSiToString(_.Altitude); - - _internalChange = false; - }); - } - else - { - IsVisible = false; - } - }) - .DisposeItWith(Disposable); - - - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorWidgetProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorWidgetProvider.cs deleted file mode 100644 index 60fa2135..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Map/Widgets/AnchorsEditorWidgetProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core; - -[Export(FlightPageViewModel.UriString, typeof(IViewModelProvider))] -[Export(PlaningPageViewModel.UriString, typeof(IViewModelProvider))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class AnchorsEditorWidgetProvider : ViewModelProviderBase -{ - [ImportingConstructor] - public AnchorsEditorWidgetProvider(ILocalizationService loc) - { - Source.AddOrUpdate(new AnchorsEditorViewModel(loc)); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorView.axaml deleted file mode 100644 index bac73a5f..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorView.axaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorView.axaml.cs deleted file mode 100644 index 4e769053..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorView.axaml.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(SeparatorViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class SeparatorView : ReactiveUserControl -{ - public SeparatorView() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorViewModel.cs deleted file mode 100644 index f68d3e62..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/Dialogs/SeparatorViewModel.cs +++ /dev/null @@ -1,30 +0,0 @@ -using FluentAvalonia.UI.Controls; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -public class SeparatorViewModel : ViewModelBaseWithValidation -{ - public const string UriString = PacketViewerViewModel.UriString + ".dialogs.separator"; - public static readonly Uri Uri = new(UriString); - - public SeparatorViewModel() : base(Uri) - { - IsSemicolon = true; - } - - public void ApplyDialog(ContentDialog dialog) - { - if (dialog == null) throw new ArgumentNullException(nameof(dialog)); - } - - [Reactive] - public bool IsSemicolon { get; set; } - - [Reactive] - public bool IsComa { get; set; } - - [Reactive] - public bool IsTab { get; set; } - -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketFilterViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketFilterViewModel.cs deleted file mode 100644 index c76cc4d9..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketFilterViewModel.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Asv.Common; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -public class PacketFilterViewModel : ViewModelBase -{ - private volatile int _cnt; - - private readonly IncrementalRateCounter _packetRate = new(3); - private readonly ILocalizationService _localization; - public static Uri GenerateUri(string filterId) => new($"{PacketViewerViewModel.UriString}.filter.{filterId}"); - - - [Reactive] - public string Type { get; set; } - [Reactive] - public string Source { get; set; } - [Reactive] - public string MessageRateText { get; set; } - - [Reactive] - public bool IsChecked { get; set; } - - public PacketFilterViewModel() : base(GenerateUri(Guid.NewGuid().ToString())) - { - UpdateRates(); - } - - public PacketFilterViewModel(PacketMessageViewModel pkt, ILocalizationService localizationService) - : base(GenerateUri(Guid.NewGuid().ToString())) - { - _localization = localizationService; - Type = pkt.Type; - Source = pkt.Source; - IsChecked = true; - } - public void UpdateRates() - { - Interlocked.Increment(ref _cnt); - - } - - public void UpdateRateText() - { - var packetRate = Math.Round(_packetRate.Calculate(_cnt),1); - MessageRateText = _localization.ItemsRate.ConvertToStringWithUnits(packetRate); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketViewerShellMenuItem.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketViewerShellMenuItem.cs deleted file mode 100644 index 39c3b447..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketViewerShellMenuItem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.ComponentModel.Composition; -using Material.Icons; - -namespace Asv.Drones.Gui.Core; - -[Export(typeof(IShellMenuItem))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class PacketViewerShellMenuItem : ShellMenuItem -{ - public PacketViewerShellMenuItem() : base("asv:shell.menu.packets") - { - Name = RS.PacketViewerShellMenuItem_Name; - NavigateTo = PacketViewerViewModel.Uri; - Icon = MaterialIconDataProvider.GetData(MaterialIconKind.Package); - Position = ShellMenuPosition.Bottom; - Type = ShellMenuItemType.PageNavigation; - Order = -2; - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketViewerView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketViewerView.axaml deleted file mode 100644 index e1d874ed..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/PacketViewer/PacketViewerView.axaml +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Parameters/ParamPageView.axaml.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Parameters/ParamPageView.axaml.cs deleted file mode 100644 index 39671352..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Parameters/ParamPageView.axaml.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.Composition; -using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; - -namespace Asv.Drones.Gui.Core; - -[ExportView(typeof(ParamPageViewModel))] -[PartCreationPolicy(CreationPolicy.NonShared)] -public partial class ParamPageView : ReactiveUserControl -{ - public ParamPageView() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Parameters/ParamPageViewModel.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Parameters/ParamPageViewModel.cs deleted file mode 100644 index 5cf6b9ae..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Parameters/ParamPageViewModel.cs +++ /dev/null @@ -1,308 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Linq; -using System.Reactive; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Threading; -using System.Threading.Tasks; -using System.Web; -using Asv.Cfg; -using Asv.Common; -using Asv.Drones.Gui.Uav; -using Asv.Mavlink; -using DynamicData; -using DynamicData.Binding; -using FluentAvalonia.UI.Controls; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace Asv.Drones.Gui.Core; - -public class ParamsConfig -{ - public List Params { get; set; } = new(); -} - -[ExportShellPage(UriString)] -[PartCreationPolicy(CreationPolicy.NonShared)] -public class ParamPageViewModel: ShellPage -{ - private readonly IMavlinkDevicesService _svc; - private readonly ILogService _log; - private readonly IConfiguration _cfg; - private CancellationTokenSource _cancellationTokenSource; - private ReadOnlyObservableCollection _viewedParams; - private ObservableAsPropertyHelper _isRefreshing; - private readonly SourceList _viewedParamsList; - private ParamItemViewModel _selectedItem; - private Subject _canClearSearchText = new (); - private ParamsConfig _config; - private IParamsClientEx _paramsIfc; - #region Uri - - public const string UriString = "asv:shell.page.params"; - public static Uri GenerateUri(ushort id, DeviceClass @class) => new($"{UriString}?id={id}&class={@class:G}"); - - #endregion - - public ParamPageViewModel():base(UriString) - { - DeviceName = "Params"; - } - - [ImportingConstructor] - public ParamPageViewModel(IMavlinkDevicesService svc, ILogService log, IConfiguration cfg) : base(UriString) - { - _svc = svc ?? throw new ArgumentNullException(nameof(svc)); - _log = log ?? throw new ArgumentNullException(nameof(log)); - _cfg = cfg ?? throw new ArgumentNullException(nameof(cfg)); - _config = _cfg.Get(); - FilterPipe.DisposeItWith(Disposable); - this.WhenAnyValue(_ => _.SearchText, _ => _.ShowStaredOnly) - .Throttle(TimeSpan.FromMilliseconds(100), RxApp.MainThreadScheduler) - .Subscribe(_ => FilterPipe.OnNext(item => item.Filter(SearchText, ShowStaredOnly))) - .DisposeItWith(Disposable); - _viewedParamsList = new SourceList().DisposeItWith(Disposable); - _cancellationTokenSource = new CancellationTokenSource().DisposeItWith(Disposable); - _viewedParamsList.Connect() - .Bind(out _viewedParams) - .Subscribe() - .DisposeItWith(Disposable); - this.WhenValueChanged(_ => _.SearchText) - .Subscribe(_ => - { - _canClearSearchText.OnNext(!string.IsNullOrWhiteSpace(_)); - }) - .DisposeItWith(Disposable); - - Clear = ReactiveCommand.Create(() => - { - SearchText = string.Empty; - }, _canClearSearchText).DisposeItWith(Disposable); - - Disposable.AddAction(() => - { - _config.Params = _config.Params.Where(_ => _.IsStarred).ToList(); - _cfg.Set(_config); - }); - } - - public override void SetArgs(Uri link) - { - var query = HttpUtility.ParseQueryString(link.Query); - if (ushort.TryParse(query["id"], out var id) == false) return; - if (Enum.TryParse(query["class"], true, out var deviceClass) == false) return; - switch (deviceClass) - { - case DeviceClass.Unknown: - break; - case DeviceClass.Plane: - var plane = _svc.GetVehicleByFullId(id); - if (plane == null) return; - DeviceName = plane.Name.Value; - Init(plane.Params); - break; - case DeviceClass.Copter: - var copter = _svc.GetVehicleByFullId(id); - if (copter == null) return; - DeviceName = copter.Name.Value; - Init(copter.Params); - break; - case DeviceClass.GbsRtk: - var gbs = _svc.GetGbsByFullId(id); - if (gbs == null) return; - DeviceName = gbs.Name.Value; - Init(gbs.Params); - break; - case DeviceClass.SdrPayload: - var sdr = _svc.GetPayloadsByFullId(id); - if (sdr == null) return; - DeviceName = sdr.Name.Value; - Init(sdr.Params); - break; - default: - throw new ArgumentOutOfRangeException(); - } - Title = $"Params: {DeviceName}"; - } - - private void Init(IParamsClientEx paramsIfc) - { - @paramsIfc.RemoteCount.Where(_ => _.HasValue).Subscribe(_ => Total = _.Value).DisposeItWith(Disposable); - var inputPipe = @paramsIfc.Items - .Transform(_ => new ParamItemViewModel(_,_log)) - .DisposeMany() - .RefCount(); - inputPipe - .Bind(out var allItems) - .Subscribe(_ => - { - foreach (var item in _config.Params) - { - var existItem = _.FirstOrDefault(_ => _.Current.Name == item.Name); - if (existItem == null) continue; - existItem.Current?.SetConfig(item); - } - }) - .DisposeItWith(Disposable); - inputPipe - .Filter(FilterPipe) - .SortBy(_ => _.Name) - .AutoRefresh(v => v.IsSynced) - //.Sort(SortExpressionComparer.Descending(v => !v.IsSynced)) - .Bind(out var leftItems) - .Subscribe() - .DisposeItWith(Disposable); - inputPipe - .AutoRefresh(_ => _.IsStarred) - .Filter(_ => _.IsStarred) - .Subscribe(_ => - { - foreach (var item in _) - { - var existItem = _config.Params.FirstOrDefault(__ => __.Name == item.Current.Name); - - if(existItem != null) _config.Params.Remove(existItem); - - _config.Params.Add(new ParamItemViewModelConfig - { - IsStarred = item.Current.IsStarred, - Name = item.Current.Name - }); - } - }) - .DisposeItWith(Disposable); - - FilterPipe.OnNext(_=>true); - Params = leftItems; - - UpdateParams = ReactiveCommand.CreateFromTask(async cancel => - { - _cancellationTokenSource = new CancellationTokenSource().DisposeItWith(Disposable); - var viewed = _viewedParamsList.Items.Select(_ => _.GetConfig()).ToArray(); - _viewedParamsList.Clear(); - try - { - await paramsIfc.ReadAll(new Progress(_ => Progress = _), _cancellationTokenSource.Token); - } - catch (TaskCanceledException) - { - _log.Info("User", "Canceled updating params"); - } - finally - { - foreach (var item in viewed) - { - var existItem = allItems.FirstOrDefault(_ => _.Name == item.Name); - if (existItem == null) continue; - existItem.SetConfig(item); - _viewedParamsList.Add(existItem); - } - } - }).DisposeItWith(Disposable); - UpdateParams.IsExecuting.ToProperty(this, _ => _.IsRefreshing, out _isRefreshing).DisposeItWith(Disposable); - UpdateParams.ThrownExceptions.Subscribe(OnRefreshError).DisposeItWith(Disposable); - StopUpdateParams = ReactiveCommand.Create(() => - { - _cancellationTokenSource.Cancel(); - }); - RemoveAllPins = ReactiveCommand.Create(() => - { - _viewedParamsList.Edit(_ => - { - foreach (var item in _) - { - item.IsPinned = false; - } - }); - }).DisposeItWith(Disposable); - } - - public override async Task TryClose() - { - var notSyncedParams = _viewedParamsList.Items.Where(_ => !_.IsSynced).ToArray(); - - if (notSyncedParams.Any()) - { - var dialog = new ContentDialog() - { - Title = RS.ParamPageViewModel_DataLossDialog_Title, - Content = RS.ParamPageViewModel_DataLossDialog_Content, - IsSecondaryButtonEnabled = true, - PrimaryButtonText = RS.ParamPageViewModel_DataLossDialog_PrimaryButtonText, - SecondaryButtonText = RS.ParamPageViewModel_DataLossDialog_SecondaryButtonText, - CloseButtonText = RS.ParamPageViewModel_DataLossDialog_CloseButtonText - }; - - var result = await dialog.ShowAsync(); - - if (result == ContentDialogResult.Primary) - { - foreach (var param in notSyncedParams) - { - param.WriteParamData(); - param.IsSynced = true; - } - - return true; - } - - if (result == ContentDialogResult.Secondary) return true; - - if (result == ContentDialogResult.None) return false; - } - - return true; - } - - private void OnRefreshError(Exception ex) - { - _log.Error("Params view","Error to read all params items",ex); - } - - public bool IsRefreshing => _isRefreshing.Value; - [Reactive] - public bool ShowStaredOnly { get; set; } - [Reactive] - public double Progress { get; set; } - [Reactive] - public ReactiveCommand Clear { get; set; } - [Reactive] - public ReactiveCommand UpdateParams { get; set; } - [Reactive] - public ReactiveCommand StopUpdateParams { get; set; } - [Reactive] - public ReactiveCommand RemoveAllPins { get; set; } - public Subject> FilterPipe { get; } = new(); - [Reactive] - public ReadOnlyObservableCollection Params { get; set; } - public ReadOnlyObservableCollection ViewedParams => _viewedParams; - [Reactive] - public string DeviceName { get; set; } - [Reactive] - public string SearchText { get; set; } - [Reactive] - public int Total { get; set; } - [Reactive] - public int Loaded { get; set; } - public ParamItemViewModel SelectedItem - { - get => _selectedItem; - set - { - var itemsToDelete = _viewedParamsList.Items.Where(_ => _.IsPinned == false).ToArray(); - _viewedParamsList.RemoveMany(itemsToDelete); - this.RaiseAndSetIfChanged(ref _selectedItem, value); - if (value != null) - { - if (_viewedParamsList.Items.Contains(value) == false) - { - _viewedParamsList.Add(value); - } - } - } - } -} diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/DefaultSettingsPartProvider.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/DefaultSettingsPartProvider.cs deleted file mode 100644 index 41e9ae0e..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/DefaultSettingsPartProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.Composition; -using DynamicData; - -namespace Asv.Drones.Gui.Core -{ - [Export(typeof(IViewModelProvider))] - [PartCreationPolicy(CreationPolicy.NonShared)] - public class DefaultSettingsPartProvider : ViewModelProviderBase - { - [ImportingConstructor] - public DefaultSettingsPartProvider([ImportMany] IEnumerable exportedMenuItems) - { - Source.AddOrUpdate(exportedMenuItems); - } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/ISettingsPart.cs b/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/ISettingsPart.cs deleted file mode 100644 index af06ab42..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/ISettingsPart.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Asv.Drones.Gui.Core -{ - /// - /// Represents a settings part in a view model. - /// - public interface ISettingsPart : IViewModel - { - /// - /// Gets the value of the Order property. - /// - /// An integer representing the order. - int Order { get; } - - /// - /// Gets or sets a value indicating whether a reboot is required. - /// - /// - /// true if a reboot is required; otherwise, false. - /// - bool IsRebootRequired { get; } - } -} \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/Map/MapSettingsView.axaml b/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/Map/MapSettingsView.axaml deleted file mode 100644 index b649fdac..00000000 --- a/src/Asv.Drones.Gui.Core/Shell/Pages/Settings/Map/MapSettingsView.axaml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -