remove migration leftovers

This commit is contained in:
2025-01-26 19:29:44 -06:00
parent 6e8d455980
commit e0b7344e22
94 changed files with 0 additions and 5658 deletions
-14
View File
@@ -1,14 +0,0 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:qControlMAUI"
x:Class="qControlMAUI.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
-12
View File
@@ -1,12 +0,0 @@
namespace qControlMAUI
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
}
}
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="qControlMAUI.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:qControlMAUI"
Shell.FlyoutBehavior="Disabled"
Title="qControlMAUI">
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
</Shell>
-10
View File
@@ -1,10 +0,0 @@
namespace qControlMAUI
{
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}
}
-36
View File
@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="qControlMAUI.MainPage">
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Image
Source="dotnet_bot.png"
HeightRequest="185"
Aspect="AspectFit"
SemanticProperties.Description="dot net bot in a race car number eight" />
<Label
Text="Hello, World!"
Style="{StaticResource Headline}"
SemanticProperties.HeadingLevel="Level1" />
<Label
Text="Welcome to &#10;.NET Multi-platform App UI"
Style="{StaticResource SubHeadline}"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Fill" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
-25
View File
@@ -1,25 +0,0 @@
namespace qControlMAUI
{
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
}
}
}
-25
View File
@@ -1,25 +0,0 @@
using Microsoft.Extensions.Logging;
namespace qControlMAUI
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
}
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
@@ -1,11 +0,0 @@
using Android.App;
using Android.Content.PM;
using Android.OS;
namespace qControlMAUI
{
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
}
}
@@ -1,16 +0,0 @@
using Android.App;
using Android.Runtime;
namespace qControlMAUI
{
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#512BD4</color>
<color name="colorPrimaryDark">#2B0B98</color>
<color name="colorAccent">#2B0B98</color>
</resources>
@@ -1,10 +0,0 @@
using Foundation;
namespace qControlMAUI
{
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<!-- See https://aka.ms/maui-publish-app-store#add-entitlements for more information about adding entitlements.-->
<dict>
<!-- App Sandbox must be enabled to distribute a MacCatalyst app through the Mac App Store. -->
<key>com.apple.security.app-sandbox</key>
<true/>
<!-- When App Sandbox is enabled, this value is required to open outgoing network connections. -->
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- The Mac App Store requires you specify if the app uses encryption. -->
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/itsappusesnonexemptencryption -->
<!-- <key>ITSAppUsesNonExemptEncryption</key> -->
<!-- Please indicate <true/> or <false/> here. -->
<!-- Specify the category for your app here. -->
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype -->
<!-- <key>LSApplicationCategoryType</key> -->
<!-- <string>public.app-category.YOUR-CATEGORY-HERE</string> -->
<key>UIDeviceFamily</key>
<array>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>
@@ -1,16 +0,0 @@
using ObjCRuntime;
using UIKit;
namespace qControlMAUI
{
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
-17
View File
@@ -1,17 +0,0 @@
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using System;
namespace qControlMAUI
{
internal class Program : MauiApplication
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
static void Main(string[] args)
{
var app = new Program();
app.Run(args);
}
}
}
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="maui-application-id-placeholder" version="0.0.0" api-version="8" xmlns="http://tizen.org/ns/packages">
<profile name="common" />
<ui-application appid="maui-application-id-placeholder" exec="qControlMAUI.dll" multiple="false" nodisplay="false" taskmanage="true" type="dotnet" launch_mode="single">
<label>maui-application-title-placeholder</label>
<icon>maui-appicon-placeholder</icon>
<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
</ui-application>
<shortcut-list />
<privileges>
<privilege>http://tizen.org/privilege/internet</privilege>
</privileges>
<dependencies />
<provides-appdefined-privileges />
</manifest>
-8
View File
@@ -1,8 +0,0 @@
<maui:MauiWinUIApplication
x:Class="qControlMAUI.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui"
xmlns:local="using:qControlMAUI.WinUI">
</maui:MauiWinUIApplication>
@@ -1,25 +0,0 @@
using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace qControlMAUI.WinUI
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : MauiWinUIApplication
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
<mp:PhoneIdentity PhoneProductId="B9BD1003-B46F-4997-B80F-501D62A4D047" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>$placeholder$</DisplayName>
<PublisherDisplayName>User Name</PublisherDisplayName>
<Logo>$placeholder$.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="$placeholder$"
Description="$placeholder$"
Square150x150Logo="$placeholder$.png"
Square44x44Logo="$placeholder$.png"
BackgroundColor="transparent">
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
<uap:SplashScreen Image="$placeholder$.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="qControlMAUI.WinUI.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- The combination of below two tags have the following effect:
1) Per-Monitor for >= Windows 10 Anniversary Update
2) System < Windows 10 Anniversary Update
-->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>
-10
View File
@@ -1,10 +0,0 @@
using Foundation;
namespace qControlMAUI
{
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
-32
View File
@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>
-16
View File
@@ -1,16 +0,0 @@
using ObjCRuntime;
using UIKit;
namespace qControlMAUI
{
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
@@ -1,51 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This is the minimum required version of the Apple Privacy Manifest for .NET MAUI apps.
The contents below are needed because of APIs that are used in the .NET framework and .NET MAUI SDK.
You are responsible for adding extra entries as needed for your application.
More information: https://aka.ms/maui-privacy-manifest
-->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>E174.1</string>
</array>
</dict>
<!--
The entry below is only needed when you're using the Preferences API in your app.
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict> -->
</array>
</dict>
</plist>
@@ -1,8 +0,0 @@
{
"profiles": {
"Windows Machine": {
"commandName": "MsixPackage",
"nativeDebugging": false
}
}
}
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="456" height="456" fill="#512BD4" />
</svg>

Before

Width:  |  Height:  |  Size: 231 B

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

@@ -1,15 +0,0 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories). Deployment of the asset to your application
is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
These files will be deployed with your package and will be accessible using Essentials:
async Task LoadMauiAsset()
{
using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
using var reader = new StreamReader(stream);
var contents = reader.ReadToEnd();
}
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

-45
View File
@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<!-- Note: For Android please see also Platforms\Android\Resources\values\colors.xml -->
<Color x:Key="Primary">#512BD4</Color>
<Color x:Key="PrimaryDark">#ac99ea</Color>
<Color x:Key="PrimaryDarkText">#242424</Color>
<Color x:Key="Secondary">#DFD8F7</Color>
<Color x:Key="SecondaryDarkText">#9880e5</Color>
<Color x:Key="Tertiary">#2B0B98</Color>
<Color x:Key="White">White</Color>
<Color x:Key="Black">Black</Color>
<Color x:Key="Magenta">#D600AA</Color>
<Color x:Key="MidnightBlue">#190649</Color>
<Color x:Key="OffBlack">#1f1f1f</Color>
<Color x:Key="Gray100">#E1E1E1</Color>
<Color x:Key="Gray200">#C8C8C8</Color>
<Color x:Key="Gray300">#ACACAC</Color>
<Color x:Key="Gray400">#919191</Color>
<Color x:Key="Gray500">#6E6E6E</Color>
<Color x:Key="Gray600">#404040</Color>
<Color x:Key="Gray900">#212121</Color>
<Color x:Key="Gray950">#141414</Color>
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"/>
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}"/>
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}"/>
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}"/>
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}"/>
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}"/>
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}"/>
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}"/>
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}"/>
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}"/>
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}"/>
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}"/>
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}"/>
</ResourceDictionary>
-427
View File
@@ -1,427 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Style TargetType="ActivityIndicator">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="IndicatorView">
<Setter Property="IndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}"/>
<Setter Property="SelectedIndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray100}}"/>
</Style>
<Style TargetType="Border">
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="StrokeShape" Value="Rectangle"/>
<Setter Property="StrokeThickness" Value="1"/>
</Style>
<Style TargetType="BoxView">
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Button">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource PrimaryDarkText}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource PrimaryDark}}" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="BorderWidth" Value="0"/>
<Setter Property="CornerRadius" Value="8"/>
<Setter Property="Padding" Value="14,10"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOver" />
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="CheckBox">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="DatePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Editor">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Entry">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Frame">
<Setter Property="HasShadow" Value="False" />
<Setter Property="BorderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
</Style>
<Style TargetType="ImageButton">
<Setter Property="Opacity" Value="1" />
<Setter Property="BorderColor" Value="Transparent"/>
<Setter Property="BorderWidth" Value="0"/>
<Setter Property="CornerRadius" Value="0"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Opacity" Value="0.5" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOver" />
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Span">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="Label" x:Key="Headline">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
<Setter Property="FontSize" Value="32" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
<Style TargetType="Label" x:Key="SubHeadline">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
<Setter Property="FontSize" Value="24" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
<Style TargetType="ListView">
<Setter Property="SeparatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="RefreshControlColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Picker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ProgressBar">
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RadioButton">
<Setter Property="BackgroundColor" Value="Transparent"/>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RefreshView">
<Setter Property="RefreshColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="SearchBar">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="CancelButtonColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SearchHandler">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Shadow">
<Setter Property="Radius" Value="15" />
<Setter Property="Opacity" Value="0.5" />
<Setter Property="Brush" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
<Setter Property="Offset" Value="10,10" />
</Style>
<Style TargetType="Slider">
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SwipeItem">
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
</Style>
<Style TargetType="Switch">
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="ThumbColor" Value="{StaticResource White}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="On">
<VisualState.Setters>
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Secondary}, Dark={StaticResource Gray200}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Off">
<VisualState.Setters>
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="TimePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent"/>
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Page" ApplyToDerivedTypes="True">
<Setter Property="Padding" Value="0"/>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
</Style>
<Style TargetType="Shell" ApplyToDerivedTypes="True">
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
<Setter Property="Shell.ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="Shell.UnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray200}}" />
<Setter Property="Shell.NavBarHasShadow" Value="False" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
<Setter Property="IconColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="TabbedPage">
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray950}}" />
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
<Setter Property="UnselectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="SelectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
</ResourceDictionary>
-65
View File
@@ -1,65 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
<!-- Note for MacCatalyst:
The default runtime is maccatalyst-x64, except in Release config, in which case the default is maccatalyst-x64;maccatalyst-arm64.
When specifying both architectures, use the plural <RuntimeIdentifiers> instead of the singular <RuntimeIdentifier>.
The Mac App Store will NOT accept apps with ONLY maccatalyst-arm64 indicated;
either BOTH runtimes must be indicated or ONLY macatalyst-x64. -->
<!-- For example: <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> -->
<OutputType>Exe</OutputType>
<RootNamespace>qControlMAUI</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- Display name -->
<ApplicationTitle>qControlMAUI</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>com.companyname.qcontrolmaui</ApplicationId>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185" />
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1" />
</ItemGroup>
</Project>
@@ -1,49 +0,0 @@
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController
{
public class QButton : Button
{
public QCommand qCommand
{
get;
set;
}
public QButton(QCommand command)
{
qCommand = command;
Text = qCommand.text;
TextColor = Colors.Black;
FontSize = App.WidthUnit * 5;
if (qCommand.osc.Contains("go"))
{
BackgroundColor = Colors.SeaGreen;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:
FontSize = App.HeightUnit * 4;
FontAttributes = FontAttributes.Bold;
break;
case Device.Android:
FontSize = App.HeightUnit * 4;
FontAttributes = FontAttributes.Bold;
break;
}
}
else if (qCommand.osc.Contains("panic"))
{
BackgroundColor = Colors.IndianRed;
}
else
{
BackgroundColor = Color.FromArgb("D8D8D8");
}
}
}
}
@@ -1,32 +0,0 @@
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController
{
public class QLevelsButton : ShadowButton
{
public Button button;
public QLevelsButton()
{
button = new Button
{
Text = QIcon.SLIDERS,
TextColor = Colors.Black,
FontFamily = App.QFont,
FontSize = App.HeightUnit * 4,
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
HeightRequest = App.HeightUnit * 8,
WidthRequest = App.HeightUnit * 8,
CornerRadius = (int)(App.HeightUnit * 4),
BackgroundColor = Colors.LightBlue
};
HeightRequest = button.Height;
WidthRequest = button.Width;
CornerRadius = button.CornerRadius;
Content = button;
}
}
}
@@ -1,31 +0,0 @@
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController
{
public class ShadowButton : Frame
{
public ShadowButton(Button b)
{
//Content = b;
HeightRequest = b.Height;
WidthRequest = b.Width;
CornerRadius = b.CornerRadius;
Padding = new Thickness(0);
Content = b;
HasShadow = true;
BorderColor = Colors.Black;
IsVisible = false;
}
public ShadowButton()
{
HasShadow = true;
BorderColor = Colors.Black;
IsVisible = false;
Padding = new Thickness(0);
}
}
}
@@ -1,131 +0,0 @@
using System;
using System.Collections.Generic;
using qController.Communication;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController.Cell
{
public class QControlsBlock : Frame
{
Microsoft.Maui.Controls.Compatibility.Grid mainG;
EventHandler callback;
public QControlsBlock(EventHandler callback)
{
this.callback = callback;
Margin = new Thickness(10);
Padding = new Thickness(0);
IsVisible = true;
BackgroundColor = Colors.Transparent;
//highlight Button Grid
//BackgroundColor = Color.FromHex("FF0000");
List<QCommand> commands = new List<QCommand>();
commands.Add(QCommands.PREVIOUS);
commands.Add(QCommands.PAUSE);
commands.Add(QCommands.NEXT);
commands.Add(QCommands.PREVIEW);
commands.Add(QCommands.PANIC);
commands.Add(QCommands.RESUME);
//setCustomButtons(commands);
setDefaultButtons();
}
void setDefaultButtons()
{
List<QButton> buttons = new List<QButton>();
buttons.Add(new QButton(QCommands.PREVIOUS));
buttons.Add(new QButton(QCommands.PANIC));
buttons.Add(new QButton(QCommands.NEXT));
buttons.Add(new QButton(QCommands.PREVIEW));
buttons.Add(new QButton(QCommands.PAUSE));
buttons.Add(new QButton(QCommands.RESUME));
mainG = new Microsoft.Maui.Controls.Compatibility.Grid
{
Padding = new Thickness(0),
RowDefinitions = {
new RowDefinition{Height = GridLength.Star},
new RowDefinition{Height = GridLength.Star},
new RowDefinition{Height = GridLength.Star}
},
ColumnDefinitions = {
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)}
},
Margin = new Thickness(0)
};
int row = 0;
int column = 0;
for (int i = 0; i < buttons.Count; i++)
{
QButton b = buttons[i];
b.Clicked += callback;
mainG.Children.Add(b, column, row);
row++;
if (row == 3)
{
row = 0;
column = 2;
}
}
QButton goButton = new QButton(QCommands.GO);
goButton.Clicked += callback;
mainG.Children.Add(goButton, 1, 0);
Microsoft.Maui.Controls.Compatibility.Grid.SetRowSpan(goButton, 3);
Content = mainG;
}
public void setCustomButtons(List<QCommand> commands)
{
mainG = new Microsoft.Maui.Controls.Compatibility.Grid
{
Padding = new Thickness(0),
RowDefinitions = {
new RowDefinition{Height = GridLength.Auto},
new RowDefinition{Height = GridLength.Auto},
new RowDefinition{Height = GridLength.Auto}
},
ColumnDefinitions = {
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)}
},
Margin = new Thickness(0)
};
int row = 0;
int column = 0;
for (int i = 0; i < commands.Count; i++)
{
QButton b = new QButton(commands[i]);
b.Clicked += callback;
mainG.Children.Add(b, column, row);
row++;
if (row == 3)
{
row = 0;
column = 2;
}
}
QButton goButton = new QButton(QCommands.GO);
goButton.Clicked += callback;
mainG.Children.Add(goButton, 1, 0);
Microsoft.Maui.Controls.Compatibility.Grid.SetRowSpan(goButton, 3);
Content = mainG;
}
}
}
@@ -1,132 +0,0 @@
using System.Collections.ObjectModel;
using qController.QItems;
using Microsoft.Maui.Controls.Compatibility;
namespace qController.Cell
{
public class QCueListCell : Frame
{
public ListView cueListView;
public Button closeButton;
public ObservableCollection<OSCListItem> items;
public QCueListCell(QCueList qCueList)
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:
Margin = new Thickness(10, 30, 10, 10);
break;
case Device.Android:
Margin = new Thickness(10, 10, 10, 10);
break;
}
Padding = new Thickness(10);
items = new ObservableCollection<OSCListItem>();
cueListView = new ListView
{
ItemsSource = items,
RowHeight = (int)(App.HeightUnit * 6),
ItemTemplate = new DataTemplate(() =>
{
var grid = new Microsoft.Maui.Controls.Compatibility.Grid { Padding = new Thickness(5, 10) };
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(30) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });
var icon = new Label();
icon.FontFamily = App.QFont;
icon.SetBinding(Label.TextProperty, "Icon");
icon.HorizontalTextAlignment = TextAlignment.Center;
icon.VerticalTextAlignment = TextAlignment.Center;
icon.FontSize = App.HeightUnit * 3;
var label = new Label { VerticalOptions = LayoutOptions.FillAndExpand };
label.SetBinding(Label.TextProperty, "Text");
if (label.Text == "Disconnect")
{
label.TextColor = Colors.DarkRed;
}
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:
label.FontSize = App.HeightUnit * 3;
break;
case Device.Android:
label.FontSize = App.HeightUnit * 2.2;
break;
}
grid.Children.Add(icon);
grid.Children.Add(label, 1, 0);
return new ViewCell { View = grid };
})
};
Microsoft.Maui.Controls.Compatibility.StackLayout layout = new Microsoft.Maui.Controls.Compatibility.StackLayout();
closeButton = new Button
{
BackgroundColor = Colors.Gray,
Text = "Close",
TextColor = Colors.White
};
layout.Children.Add(closeButton);
layout.Children.Add(cueListView);
Content = layout;
for(int j=0; j < qCueList.cues.Count; j++)
{
var cue = qCueList.cues[j];
AddSubCues(cue, 0);
}
}
public void AddSubCues(QCue cue, int level)
{
var cueIcon = cue.getIconString();
var cueTitle = "";
for (int i = 0; i < level; i++)
{
cueTitle += " ";
}
if (cue.number != "")
{
cueTitle += cue.number + " - " + cue.listName;
}
else
{
cueTitle += cue.listName;
}
if (cue.cues != null)
{
items.Add(new OSCListItem
{
Text = cueTitle,
Icon = cueIcon,
Command = "/select_id/" + cue.uniqueID
});
//uncomment to load nested group cues
for (int i = 0; i < cue.cues.Count; i++)
{
var sub_cue = cue.cues[i];
AddSubCues(sub_cue, level + 1);
}
}
else
{
items.Add(new OSCListItem
{
Text = cueTitle,
Icon = cueIcon,
Command = "/select_id/" + cue.uniqueID
});
}
}
}
}
@@ -1,121 +0,0 @@
using System;
using Serilog;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController.Cell
{
public class QInstanceCell : ViewCell
{
public QInstanceCell()
{
Label nameLabel = new Label();
Label addressLabel = new Label();
Label connectLabel = new Label();
Label deleteLabel = new Label();
var connectTapGesture = new TapGestureRecognizer();
var deleteTapGesture = new TapGestureRecognizer();
connectTapGesture.Tapped += Connect;
connectLabel.GestureRecognizers.Add(connectTapGesture);
deleteTapGesture.Tapped += Delete;
deleteLabel.GestureRecognizers.Add(deleteTapGesture);
InitItems();
//SET BINDINGS
nameLabel.SetBinding(Label.TextProperty, new Binding("name"));
addressLabel.SetBinding(Label.TextProperty,new Binding("address"));
Microsoft.Maui.Controls.Compatibility.Grid mainG = new Microsoft.Maui.Controls.Compatibility.Grid
{
//Padding = new Thickness(10),
RowDefinitions = {
new RowDefinition{Height = GridLength.Auto},
new RowDefinition{Height = GridLength.Auto}
},
ColumnDefinitions = {
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(4,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)}
}
};
mainG.Children.Add(nameLabel, 1, 0);
mainG.Children.Add(addressLabel,1,1);
mainG.Children.Add(connectLabel,2,0);
Microsoft.Maui.Controls.Compatibility.Grid.SetRowSpan(connectLabel,2);
mainG.Children.Add(deleteLabel, 0, 0);
Microsoft.Maui.Controls.Compatibility.Grid.SetRowSpan(deleteLabel,2);
Frame f = new Frame
{
Content = mainG,
BorderColor = Colors.Black,
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Padding = 0,
Margin = new Thickness(10,10,10,10),
CornerRadius=20,
BackgroundColor = Color.FromArgb("D8D8D8")
};
View = f;
void InitItems()
{
nameLabel.HorizontalTextAlignment = TextAlignment.Center;
nameLabel.VerticalTextAlignment = TextAlignment.End;
nameLabel.FontAttributes = FontAttributes.Bold;
nameLabel.FontSize = App.HeightUnit * 3;
nameLabel.Margin = new Thickness(0, 20, 0, 0);
addressLabel.HorizontalTextAlignment = TextAlignment.Center;
addressLabel.VerticalTextAlignment = TextAlignment.Start;
addressLabel.FontSize = App.HeightUnit * 2.5;
addressLabel.Margin = new Thickness(0, 0, 0, 20);
connectLabel.HorizontalOptions = LayoutOptions.StartAndExpand;
connectLabel.VerticalOptions = LayoutOptions.CenterAndExpand;
connectLabel.Text = QIcon.WIFI;
connectLabel.FontSize = App.HeightUnit * 5;
connectLabel.TextColor = Colors.LimeGreen;
deleteLabel.HorizontalOptions = LayoutOptions.CenterAndExpand;
deleteLabel.VerticalOptions = LayoutOptions.CenterAndExpand;
deleteLabel.Text = QIcon.TRASH_EMPTY;
deleteLabel.FontSize = App.HeightUnit * 5;
deleteLabel.TextColor = Colors.Red;
connectLabel.FontFamily = App.QFont;
deleteLabel.FontFamily = App.QFont;
}
void Delete(object sender, EventArgs e)
{
Log.Debug("QINSTANCECELL - Delete " + nameLabel.Text + "," + addressLabel.Text + " Pressed");
QStorage.RemoveInstance(nameLabel.Text,addressLabel.Text);
}
void Connect(object sender, EventArgs e)
{
App.rootPage.Detail.Navigation.PushAsync(new ControlPage(nameLabel.Text, addressLabel.Text));
Log.Debug("QINSTANCECELL - Connect To " + nameLabel.Text + " Pressed");
}
}
}
}
-124
View File
@@ -1,124 +0,0 @@
using System.Collections.Generic;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController.Cell
{
public class QLevelsCell : Frame
{
public List<double> levels;
public string activeCue;
public Slider mainSlider;
public Slider leftSlider;
public Slider rightSlider;
public Label mainLabel;
public Label rightLabel;
public Label leftLabel;
public QLevelsCell()
{
Padding = new Thickness(5);
CornerRadius = 20;
BorderColor = Colors.Black;
HasShadow = true;
BackgroundColor = Color.FromArgb("D8D8D8");
IsVisible = false;
//highlight for testing
//BackgroundColor = Color.Red;
Microsoft.Maui.Controls.Compatibility.Grid mainG = new Microsoft.Maui.Controls.Compatibility.Grid
{
Padding = new Thickness(0),
RowDefinitions = {
new RowDefinition{Height = GridLength.Star},
new RowDefinition{Height = GridLength.Star},
new RowDefinition{Height = GridLength.Star}
},
ColumnDefinitions = {
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)}
}
};
mainSlider = new Slider
{
Minimum = -60,
Maximum = 12
};
leftSlider = new Slider
{
Minimum = -60,
Maximum = 12
};
rightSlider = new Slider
{
Minimum = -60,
Maximum = 12
};
mainLabel = new Label
{
Text = "MAIN:",
VerticalTextAlignment = TextAlignment.Center,
HorizontalTextAlignment = TextAlignment.Center
};
leftLabel = new Label
{
Text = "1:",
VerticalTextAlignment = TextAlignment.Center,
HorizontalTextAlignment = TextAlignment.Center
};
rightLabel = new Label
{
Text = "2:",
VerticalTextAlignment = TextAlignment.Center,
HorizontalTextAlignment = TextAlignment.Center
};
mainG.Children.Add(mainSlider, 1, 0);
mainG.Children.Add(leftSlider, 1, 1);
mainG.Children.Add(rightSlider, 1, 2);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(mainSlider, 4);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(leftSlider, 4);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(rightSlider, 4);
mainG.Children.Add(mainLabel, 0, 0);
mainG.Children.Add(leftLabel, 0, 1);
mainG.Children.Add(rightLabel, 0, 2);
Content = mainG;
Margin = new Thickness(10);
}
public void UpdateLevels(List<double> lin_levels)
{
levels = lin_levels;
if (mainSlider != null)
{
mainSlider.Value = levels[0];
}
if (leftSlider != null)
{
leftSlider.Value = levels[1];
}
if (rightSlider != null)
{
rightSlider.Value = levels[2];
}
}
}
}
@@ -1,237 +0,0 @@
using System;
using Acr.UserDialogs;
using qController.QItems;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController.Cell
{
public class CueEditArgs : EventArgs
{
public string CueID
{
get;
set;
}
public string Property
{
get;
set;
}
public string NewValue
{
get;
set;
}
}
public class QSelectedCueCell : Frame
{
public delegate void SelectedCueEditedHandler(object source, CueEditArgs args);
public event SelectedCueEditedHandler SelectedCueEdited;
Label name;
Label number;
Label type;
public Label notes;
public QCue activeCue;
public QSelectedCueCell()
{
Microsoft.Maui.Controls.Compatibility.Grid mainG = new Microsoft.Maui.Controls.Compatibility.Grid
{
Padding = new Thickness(0),
RowDefinitions =
{
new RowDefinition{Height = GridLength.Star},
new RowDefinition{Height = new GridLength(2, GridUnitType.Star)}
},
ColumnDefinitions =
{
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)}
}
};
Microsoft.Maui.Controls.Compatibility.Grid topGrid = new Microsoft.Maui.Controls.Compatibility.Grid
{
Padding = new Thickness(0),
RowDefinitions =
{
new RowDefinition{Height = GridLength.Auto}
},
ColumnDefinitions =
{
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)}
}
};
Microsoft.Maui.Controls.Compatibility.Grid bottomGrid = new Microsoft.Maui.Controls.Compatibility.Grid
{
Padding = new Thickness(0),
RowDefinitions =
{
new RowDefinition{Height = new GridLength(1,GridUnitType.Star)},
new RowDefinition{Height = new GridLength(2,GridUnitType.Star)}
},
ColumnDefinitions =
{
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)}
}
};
number = new Label {
Text = "",
FontAttributes = FontAttributes.Bold,
FontSize = App.HeightUnit * 5
};
name = new Label {
Text = "Loading Workspace....",
FontAttributes = FontAttributes.Bold,
HorizontalTextAlignment = TextAlignment.Center,
FontSize = App.HeightUnit * 3.5,
Margin = new Thickness(0)
};
type = new Label {
Text = QIcon.SPIN3,
FontFamily = App.QFont,
VerticalTextAlignment = TextAlignment.Center,
HorizontalTextAlignment = TextAlignment.End,
FontSize = App.HeightUnit * 5
};
notes = new Label {
Text = "Loading Cue Lists and Playhead Position",
HorizontalTextAlignment = TextAlignment.Center,
Margin = new Thickness(0,0,0,10),
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
//BACKGROUND COLORS FOR TESTING ONLY
//notes.BackgroundColor = Color.Red;
//number.BackgroundColor = Color.Red;
//name.BackgroundColor = Color.Red;
//type.BackgroundColor = Color.Red;
//topGrid.BackgroundColor = Color.Green;
//bottomGrid.BackgroundColor = Color.Green;
topGrid.Children.Add(number, 0, 0);
topGrid.Children.Add(type, 4, 0);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(number, 3);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(type, 1);
bottomGrid.Children.Add(name, 0, 0);
bottomGrid.Children.Add(notes, 0, 1);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(name, 5);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(notes,5);
mainG.Children.Add(topGrid, 0, 0);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(topGrid, 5);
mainG.Children.Add(bottomGrid, 0, 1);
Microsoft.Maui.Controls.Compatibility.Grid.SetColumnSpan(bottomGrid, 5);
CornerRadius = 20;
BackgroundColor = Color.FromArgb("D8D8D8");
HeightRequest = App.HeightUnit * 25;
Margin = new Thickness(10);
Content = mainG;
SetupDoubleTapEdit();
}
void SetupDoubleTapEdit()
{
var notesDoubleTap = new TapGestureRecognizer();
var nameDoubleTap = new TapGestureRecognizer();
var numberDoubleTap = new TapGestureRecognizer();
notesDoubleTap.NumberOfTapsRequired = 2;
nameDoubleTap.NumberOfTapsRequired = 2;
numberDoubleTap.NumberOfTapsRequired = 2;
notesDoubleTap.Tapped += (s, e) =>
{
UserDialogs.Instance.Prompt(new PromptConfig
{
Title = "Update Notes",
Message = "Changes notes to update",
OkText = "Update",
Text = notes.Text,
OnAction = (qNotes) =>
{
if (!qNotes.Ok)
return;
OnSelectedCueEdited("notes", qNotes.Text);
}
});
};
nameDoubleTap.Tapped += (s, e) =>
{
UserDialogs.Instance.Prompt(new PromptConfig
{
Title = "Update Name",
Message = "Change name to update",
OkText = "Update",
Text = name.Text,
OnAction = (qName) =>
{
if (!qName.Ok)
return;
OnSelectedCueEdited("name", qName.Text);
}
});
};
numberDoubleTap.Tapped += (s, e) =>
{
UserDialogs.Instance.Prompt(new PromptConfig
{
Title = "Update Number",
Message = "Change number to update",
OkText = "Update",
Text = number.Text,
OnAction = (qNumber) =>
{
if (!qNumber.Ok)
return;
OnSelectedCueEdited("number", qNumber.Text);
}
});
};
notes.GestureRecognizers.Add(notesDoubleTap);
name.GestureRecognizers.Add(nameDoubleTap);
number.GestureRecognizers.Add(numberDoubleTap);
}
public void UpdateSelectedCue(QCue cue)
{
activeCue = cue;
name.Text = cue.listName;
number.Text = cue.number;
type.Text = cue.getIconString();
notes.Text = cue.notes;
}
protected virtual void OnSelectedCueEdited(string prop, string value)
{
SelectedCueEdited?.Invoke(this, new CueEditArgs() { CueID = activeCue.uniqueID, Property = prop, NewValue = value });
}
}
}
@@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using qController.QItems;
namespace qController.Communication
{
public class CueEventArgs : EventArgs
{
public QCue Cue
{
get;
set;
}
}
public class WorkspaceEventArgs : EventArgs
{
public QWorkspace UpdatedWorkspace
{
get;
set;
}
}
public class PlaybackPositionArgs : EventArgs
{
public string PlaybackPosition
{
get;
set;
}
}
public class ConnectEventArgs : EventArgs
{
public string Status
{
get;
set;
}
public string WorkspaceId
{
get;
set;
}
}
public class WorkspaceInfoArgs : EventArgs
{
public List<QWorkspaceInfo> WorkspaceInfo
{
get;
set;
}
}
public class ChildrenEventArgs : EventArgs
{
public string cue_id
{
get;
set;
}
public List<QCue> children
{
get;
set;
}
}
}
@@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace qController.Communication
{
public delegate void SelectedCueUpdatedHandler(object source, CueEventArgs args);
public delegate void WorkspaceUpdatedHandler(object source, WorkspaceEventArgs args);
public delegate void CueInfoUpdatedHandler(object source, CueEventArgs args);
public delegate void PlaybackPositionUpdatedHandler(object source, PlaybackPositionArgs args);
public delegate void ConnectionStatusHandler(object source, ConnectEventArgs args);
public delegate void ChildrenUpdateHandler(object source, ChildrenEventArgs args);
public delegate void WorkspaceDisconnectHandler(object source, EventArgs args);
public delegate void WorkspaceInfoHandler(object source, WorkspaceInfoArgs args);
public delegate void WorkspaceLoadErrorHandler(object source, WorkspaceEventArgs args);
}
@@ -1,19 +0,0 @@
//IP Address verification
//IMPLEMENT A ISREACHABLE METHOD TO BE ABLE TO DISPLAY ONLINE QINSTANCES
using System.Net;
namespace qController.Communication
{
public class IPHelper
{
public IPHelper()
{
}
public static bool IsValidAddress(string ipString){
if ((ipString.Split('.').Length - 1) != 3) return false;
IPAddress address;
return IPAddress.TryParse(ipString, out address);
}
}
}
@@ -1,109 +0,0 @@
//Class used to facilitate communication with a QInstance
//Listens for incoming messages via qReceiver (UDP) and tcpClient (TCP)
//TODO: WEIRD MESSAGE PARSING RULES NEED FIXED
using System;
using SharpOSC;
using Serilog;
namespace qController.Communication
{
public class QClient
{
private TCPClient tcpClient;
public QParser qParser;
string Address;
int Port;
public bool connected;
public QClient(string address, int port)
{
Address = address;
Port = port;
qParser = new QParser();
tcpClient = new TCPClient(Address, Port);
connected = tcpClient.Connect();
tcpClient.MessageReceived += OnMessageReceived;
}
//one method for messages received whether from TCP or UDP (SAME MSG FORMAT)
private void OnMessageReceived(object source, MessageEventArgs args)
{
Log.Debug("QCLIENT - Message Received: " + args.Message.Address);
//TODO: find a better filtering process
if (!args.Message.Address.Contains("update"))
qParser.ParseMessage(args.Message);
else if (args.Message.Address.Contains("playbackPosition") || args.Message.Address.Contains("cueList") || args.Message.Address.Contains("dashboard"))
qParser.ParseMessage(args.Message);
else if (args.Message.Address.Contains("cue_id"))
{
var parts = args.Message.Address.Split('/');
UpdateSpecificCue(parts[3], parts[5]);
}
else
ProcessUpdate(args.Message);
}
public void sendTCP(string address)
{
//Log.Debug($"QCLIENT - TCP Sent with address: {address}");
try
{
tcpClient.Send(new OscMessage(address));
}
catch (Exception ex)
{
Log.Debug("QCLIENT - Send and Receive Exception: " + ex.Message);
}
}
public void sendTCP(string address, params object[] args)
{
//Log.Debug($"QCLIENT - TCP Sent with address: {address}");
try
{
tcpClient.Send(new OscMessage(address, args));
}
catch (Exception ex)
{
Log.Debug("QCLIENT - Send and Receive w/Args Exception: " + ex.Message);
}
}
public void ProcessUpdate(OscMessage msg)
{
Log.Debug("QCLIENT - Process Update: " + msg.Address);
if (msg.Address.Contains("workspace"))
{
UpdateWorkspace("not yet implemented");
}
}
public void UpdateSpecificCue(string workspace_id,string cue_id)
{
string valuesForKeys = "[\"number\",\"uniqueID\",\"flagged\",\"listName\",\"type\",\"colorName\",\"name\",\"armed\",\"displayName\",\"isBroken\",\"isLoaded\",\"isPaused\",\"isRunning\",\"preWait\",\"duration\",\"postWait\",\"translationX\",\"translationY\",\"opacity\",\"scaleX\",\"scaleY\",\"notes\",\"levels\"]";
string address = "/workspace/" + workspace_id + "/cue_id/" + cue_id + "/valuesForKeys";
sendTCP(address, valuesForKeys);
}
public void UpdateSelectedCue(string workspace_id)
{
string valuesForKeys = "[\"number\",\"uniqueID\",\"flagged\",\"listName\",\"type\",\"colorName\",\"name\",\"armed\",\"displayName\",\"isBroken\",\"isLoaded\",\"isPaused\",\"isRunning\",\"preWait\",\"duration\",\"postWait\",\"translationX\",\"translationY\",\"opacity\",\"scaleX\",\"scaleY\",\"notes\",\"levels\"]";
string address = "/workspace/" + workspace_id + "/cue/selected/valuesForKeys";
sendTCP(address, valuesForKeys);
}
public void UpdateWorkspace(string ws_id)
{
Log.Debug("QCLIENT - Workspace needs to be updated: " + ws_id);
}
public void Close()
{
tcpClient.Close();
}
}
}
@@ -1,81 +0,0 @@
//Class used for overall Workspace control (ONLY REPRESENTS ONE WORKSPACE)
//Contains all necessary items to facilitate communication (sending, receiving) to a QLab workspace
//Also contains the local QWorkspace object which stores all the information that is used in displaying
//TODO: STILL NEED TO WORK ON PASSWORD PROTECTED WORKSPACES
using Serilog;
using qController.QItems;
namespace qController.Communication
{
public class QController
{
public QUpdater qUpdater;
public QClient qClient;
public QWorkspace qWorkspace;
public string playbackPosition;
private string ipAddress;
private int port;
public QController(string address, int port)
{
this.port = port;
this.ipAddress = address;
qClient = new QClient(ipAddress, port);
qUpdater = new QUpdater(this);
}
public void Connect(string workspace_id)
{
Log.Debug($"QCONTROLLER - Connect Called: {workspace_id}");
qWorkspace = new QWorkspace(workspace_id);
qClient.sendTCP("/workspace/"+workspace_id+"/connect");
}
public void Connect(string workspace_id, string passcode)
{
Log.Debug($"QCONTROLLER - Connect with Passcode Called: {workspace_id}:{passcode}");
qWorkspace = new QWorkspace(workspace_id);
qClient.sendTCP("/workspace/" + workspace_id + "/connect", passcode);
}
public void Connect(QWorkspace workspace)
{
if(workspace.passcode != null)
Connect(workspace.workspace_id, workspace.passcode);
else
Connect(workspace.workspace_id);
}
public void KickOff()
{
Log.Debug($"QCONTROLLER - Searching for workspaces on: {ipAddress}");
qClient.sendTCP("/workspaces");
}
public void Disconnect()
{
Log.Debug($"QCONTROLLER - Disconnecting from: {qWorkspace.workspace_id}");
qClient.sendTCP("/workspace/"+qWorkspace.workspace_id+"/disconnect");
}
public void Resume()
{
//qClient = new QClient(ipAddress, port);
//qUpdater = new QUpdater(this);
if(qWorkspace != null)
{
Log.Debug($"QCONTROLLER - Resuming: {qWorkspace.workspace_id}");
}
}
public void Kill(){
Log.Debug("QCONTROLLER - Killing");
if (qClient != null)
qClient.Close();
}
}
}
@@ -1,23 +0,0 @@
//Currently unused would like to reimplement eventually
//Currently being done in qConnectionPage.xaml.cs Scan() method
//TODO: Implement this along with a way of getting active Instances and # of workspaces for an instance
using Serilog;
using System.Collections.Generic;
using Zeroconf;
namespace qController.Communication
{
public class QFinder
{
public QFinder()
{
}
public async void SearchForWorkspaces()
{
Log.Debug("QFINDER - Scanning Started");
IReadOnlyList<IZeroconfHost> results = await ZeroconfResolver.ResolveAsync("_qlab._tcp.local.");
Log.Debug("QFINDER - Scanning Done");
}
}
}
@@ -1,184 +0,0 @@
using System;
using SharpOSC;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Collections.Generic;
using qController.QItems;
using Serilog;
namespace qController.Communication
{
public class QParser
{
public QParser()
{
}
public event WorkspaceLoadErrorHandler WorkspaceLoadError;
public event WorkspaceInfoHandler WorkspaceInfoReceived;
public event WorkspaceDisconnectHandler WorkspaceDisconnect;
public event ChildrenUpdateHandler ChildrenUpdated;
public event ConnectionStatusHandler ConnectionStatusChanged;
public event SelectedCueUpdatedHandler SelectedCueUpdated;
public event WorkspaceUpdatedHandler WorkspaceUpdated;
public event CueInfoUpdatedHandler CueInfoUpdated;
public event PlaybackPositionUpdatedHandler PlaybackPositionUpdated;
public void ParseMessage(OscMessage msg){
if (!msg.Address.Contains("null"))
{
if (msg.Address.Contains("valuesForKeys"))
{
ParseCueUpdateInfo(msg);
}
else if (msg.Address.Contains("cueLists"))
ParseWorkspaceInfo(msg);
else if (msg.Address.Contains("playbackPosition"))
ParsePositionUpdateInfo(msg);
else if (msg.Address.Contains("thump"))
Log.Debug("QPARSER - Heartbeat Received");
else if (msg.Address.Contains("disconnect"))
OnWorkspaceDisconnect();
else if (msg.Address.Contains("connect"))
ParseConnectInfo(msg);
else if (msg.Address.Contains("children"))
ParseChildrenInfo(msg);
else if (msg.Address.Contains("workspaces"))
ParseQInfo(msg);
else
{
Log.Debug("QPARSER - Unkown message type: " + msg.Address);
foreach (var item in msg.Arguments)
{
Log.Debug(item.ToString());
}
}
}
}
public void ParseConnectInfo(OscMessage msg)
{
if (msg.Arguments.Count > 0)
{
JToken connectStatus = OSC2JSON(msg);
;
OnConnectionStatusChanged(connectStatus.ToString(), msg.Address.Split('/')[3]);
}
}
public void ParsePositionUpdateInfo(OscMessage msg)
{
if(msg.Arguments.Count > 0)
{
OnPlaybackPositionUpdated(msg.Arguments[0].ToString());
}
}
public void ParseCueUpdateInfo(OscMessage msg)
{
JToken cueUpdate = OSC2JSON(msg);
QCue cue = JsonConvert.DeserializeObject<QCue>(cueUpdate.ToString());
OnCueInfoUpdated(cue);
}
public void ParseSelectedCueInfo(OscMessage msg){
JToken selectedCue = OSC2JSON(msg);
QCue cue = JsonConvert.DeserializeObject<QCue>(selectedCue.ToString());
OnSelectedCueUpdated(cue);
}
public void ParseQInfo(OscMessage msg)
{
JToken qInfo = OSC2JSON(msg);
List<QWorkspaceInfo> qWorkspaceInfo = JsonConvert.DeserializeObject<List<QWorkspaceInfo>>(qInfo.ToString());
OnWorkspaceInfoReceived(qWorkspaceInfo);
}
public void ParseWorkspaceInfo(OscMessage msg)
{
if (msg.Arguments.Count > 0)
{
var parts = msg.Address.Split('/');
string id = parts[3];
if (msg.Arguments[0].ToString() != "")
{
try
{
QWorkspace workspace = JsonConvert.DeserializeObject<QWorkspace>(msg.Arguments[0].ToString());
OnWorkspaceUpdated(workspace);
}
catch (Exception ex)
{
Log.Debug($"QPARSER - Workspace Load Error: {ex.ToString()}");
OnWorkspaceLoadError(id);
}
}
else
{
OnWorkspaceLoadError(id);
}
}
}
public void ParseChildrenInfo(OscMessage msg)
{
if (msg.Arguments.Count > 0)
{
string cue_id = msg.Address.Split('/')[3];
JToken children_obj = OSC2JSON(msg);
List<QCue> children = JsonConvert.DeserializeObject<List<QCue>>(children_obj.ToString());
OnChildrenUpdated(cue_id, children);
}
}
public JToken OSC2JSON(OscMessage Msg){
JObject json = JObject.Parse(Msg.Arguments.ToArray()[0].ToString());
return json.GetValue("data");
}
protected virtual void OnWorkspaceUpdated(QWorkspace workspace)
{
WorkspaceUpdated?.Invoke(this, new WorkspaceEventArgs() { UpdatedWorkspace = workspace });
}
protected virtual void OnSelectedCueUpdated(QCue cue)
{
SelectedCueUpdated?.Invoke(this, new CueEventArgs() { Cue = cue });
}
protected virtual void OnCueInfoUpdated(QCue cue)
{
CueInfoUpdated?.Invoke(this, new CueEventArgs() { Cue = cue });
}
protected virtual void OnPlaybackPositionUpdated(string id)
{
PlaybackPositionUpdated?.Invoke(this, new PlaybackPositionArgs() { PlaybackPosition = id });
}
protected virtual void OnConnectionStatusChanged(string status, string workspace_id)
{
ConnectionStatusChanged?.Invoke(this, new ConnectEventArgs() { Status = status, WorkspaceId = workspace_id });
}
protected virtual void OnChildrenUpdated(string id, List<QCue> cues)
{
ChildrenUpdated?.Invoke(this, new ChildrenEventArgs() { cue_id = id, children = cues });
}
protected virtual void OnWorkspaceDisconnect()
{
WorkspaceDisconnect?.Invoke(this, new EventArgs());
}
protected virtual void OnWorkspaceInfoReceived(List<QWorkspaceInfo> workspaces)
{
WorkspaceInfoReceived?.Invoke(this, new WorkspaceInfoArgs() { WorkspaceInfo = workspaces });
}
protected virtual void OnWorkspaceLoadError(string id)
{
WorkspaceLoadError?.Invoke(this, new WorkspaceEventArgs { UpdatedWorkspace = new QWorkspace(id) });
}
}
}
@@ -1,75 +0,0 @@
//Class used for updating local "copy" of workspace info, cue-lists, cues, etc.
using Serilog;
namespace qController.Communication
{
public class QUpdater
{
private QController qController;
public QUpdater(QController controller)
{
qController = controller;
qController.qClient.qParser.CueInfoUpdated += OnCueUpdateReceived;
qController.qClient.qParser.WorkspaceUpdated += OnWorkspaceUpdated;
qController.qClient.qParser.PlaybackPositionUpdated += OnPlaybackPositionUpdated;
qController.qClient.qParser.WorkspaceLoadError += OnWorkspaceLoadError;
qController.qClient.qParser.ConnectionStatusChanged += OnConnectionStatusChanged;
}
private void OnConnectionStatusChanged(object source, ConnectEventArgs args)
{
Log.Debug("QUPDATER - Connection Status Changed: " + args.Status);
if (args.Status.Contains("ok"))
{
//new sort of connect format for QLab 5 ok:view|control|edit is connection good
if(args.Status.Contains(":") && !args.Status.Contains("view"))
{
return;
}
qController.qClient.sendTCP("/workspace/" + qController.qWorkspace.workspace_id + "/updates", 1);
qController.qClient.sendTCP("/workspace/" + qController.qWorkspace.workspace_id + "/cueLists");
}
}
private void OnWorkspaceLoadError(object source, WorkspaceEventArgs args)
{
Log.Debug("QUPDATER - Loading cuelists has failed for some reason retrying");
}
public void OnCueUpdateReceived(object source, CueEventArgs args)
{
qController.qWorkspace.UpdateCue(args.Cue);
if (args.Cue.type == "Group")
{
//Log.Debug("QUpdater/Updated cue was group cue, sending children request");
qController.qClient.sendTCP("/workspace/"+qController.qWorkspace.workspace_id+"/cue_id/" + args.Cue.uniqueID + "/children");
}
}
public void OnWorkspaceUpdated(object source, WorkspaceEventArgs args)
{
qController.qWorkspace = args.UpdatedWorkspace;
qController.playbackPosition = null;
qController.qWorkspace.CheckPopulated();
if (qController.qWorkspace.IsPopulated)
{
Log.Debug("QUPDATER - Workspace group cues are already populated");
App.showToast("Workspace cues have been loaded....");
//get selected cue
qController.qClient.UpdateSelectedCue(qController.qWorkspace.workspace_id);
return;
}
}
public void OnPlaybackPositionUpdated(object source, PlaybackPositionArgs args)
{
qController.playbackPosition = args.PlaybackPosition;
Log.Debug("QUPDATER - Update Specific Cue Called because of Playback Position Updated");
qController.qClient.UpdateSpecificCue(qController.qWorkspace.workspace_id,args.PlaybackPosition);
}
}
}
@@ -1,52 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace SharpOSC
{
internal static class Extensions
{
public static int FirstIndexAfter<T>(this IEnumerable<T> items, int start, Func<T, bool> predicate)
{
if (items == null) throw new ArgumentNullException("items");
if (predicate == null) throw new ArgumentNullException("predicate");
if (start >= items.Count()) throw new ArgumentOutOfRangeException("start");
int retVal = 0;
foreach (var item in items)
{
if (retVal >= start && predicate(item)) return retVal;
retVal++;
}
return -1;
}
public static List<List<T>> Split<T>(this IEnumerable<T> data, Func<T, bool> predicate)
{
var output = new List<List<T>>();
var curr = new List<T>();
output.Add(curr);
foreach (var x in data)
{
if (predicate(x))
{
curr = new List<T>();
output.Add(curr);
}
else
curr.Add(x);
}
return output;
}
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
}
}
@@ -1,64 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SharpOSC
{
public struct Midi
{
public byte Port;
public byte Status;
public byte Data1;
public byte Data2;
public Midi(byte port, byte status, byte data1, byte data2)
{
this.Port = port;
this.Status = status;
this.Data1 = data1;
this.Data2 = data2;
}
public override bool Equals(System.Object obj)
{
if (obj.GetType() == typeof(Midi))
{
if (this.Port == ((Midi)obj).Port && this.Status == ((Midi)obj).Status && this.Data1 == ((Midi)obj).Data1 && this.Data2 == ((Midi)obj).Data2)
return true;
else
return false;
}
else if (obj.GetType() == typeof(byte[]))
{
if (this.Port == ((byte[])obj)[0] && this.Status == ((byte[])obj)[1] && this.Data1 == ((byte[])obj)[2] && this.Data2 == ((byte[])obj)[3])
return true;
else
return false;
}
else
return false;
}
public static bool operator ==(Midi a, Midi b)
{
if (a.Equals(b))
return true;
else
return false;
}
public static bool operator !=(Midi a, Midi b)
{
if (!a.Equals(b))
return true;
else
return false;
}
public override int GetHashCode()
{
return (Port << 24) + (Status << 16) + (Data1 << 8) + (Data2);
}
}
}
@@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SharpOSC
{
public class OscBundle : OscPacket
{
Timetag _timetag;
public UInt64 Timetag
{
get { return _timetag.Tag; }
set { _timetag.Tag = value; }
}
public DateTime Timestamp
{
get { return _timetag.Timestamp; }
set { _timetag.Timestamp = value; }
}
public List<OscMessage> Messages;
public OscBundle(UInt64 timetag, params OscMessage[] args)
{
_timetag = new Timetag(timetag);
Messages = new List<OscMessage>();
Messages.AddRange(args);
}
public override byte[] GetBytes()
{
string bundle = "#bundle";
int bundleTagLen = Utils.AlignedStringLength(bundle);
byte[] tag = setULong(_timetag.Tag);
List<byte[]> outMessages = new List<byte[]>();
foreach (OscMessage msg in Messages)
{
outMessages.Add(msg.GetBytes());
}
int len = bundleTagLen + tag.Length + outMessages.Sum(x => x.Length + 4);
int i = 0;
byte[] output = new byte[len];
Encoding.UTF8.GetBytes(bundle).CopyTo(output, i);
i += bundleTagLen;
tag.CopyTo(output, i);
i += tag.Length;
foreach (byte[] msg in outMessages)
{
var size = setInt(msg.Length);
size.CopyTo(output, i);
i += size.Length;
msg.CopyTo(output, i);
i += msg.Length; // msg size is always a multiple of 4
}
return output;
}
}
}
@@ -1,160 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SharpOSC
{
public class OscMessage : OscPacket
{
public string Address;
public List<object> Arguments;
public OscMessage(string address, params object[] args)
{
this.Address = address;
Arguments = new List<object>();
Arguments.AddRange(args);
}
public override byte[] GetBytes()
{
List<byte[]> parts = new List<byte[]>();
List<object> currentList = Arguments;
int ArgumentsIndex = 0;
string typeString = ",";
int i = 0;
while (i < currentList.Count)
{
var arg = currentList[i];
string type = (arg != null) ? arg.GetType().ToString() : "null";
switch (type)
{
case "System.Int32":
typeString += "i";
parts.Add(setInt((int)arg));
break;
case "System.Single":
if (float.IsPositiveInfinity((float)arg))
{
typeString += "I";
}
else
{
typeString += "f";
parts.Add(setFloat((float)arg));
}
break;
case "System.String":
typeString += "s";
parts.Add(setString((string)arg));
break;
case "System.Byte[]":
typeString += "b";
parts.Add(setBlob((byte[])arg));
break;
case "System.Int64":
typeString += "h";
parts.Add(setLong((Int64)arg));
break;
case "System.UInt64":
typeString += "t";
parts.Add(setULong((UInt64)arg));
break;
case "SharpOSC.Timetag":
typeString += "t";
parts.Add(setULong(((Timetag)arg).Tag));
break;
case "System.Double":
if (Double.IsPositiveInfinity((double)arg))
{
typeString += "I";
}
else
{
typeString += "d";
parts.Add(setDouble((double)arg));
}
break;
case "SharpOSC.Symbol":
typeString += "S";
parts.Add(setString(((Symbol)arg).Value));
break;
case "System.Char":
typeString += "c";
parts.Add(setChar((char)arg));
break;
case "SharpOSC.RGBA":
typeString += "r";
parts.Add(setRGBA((RGBA)arg));
break;
case "SharpOSC.Midi":
typeString += "m";
parts.Add(setMidi((Midi)arg));
break;
case "System.Boolean":
typeString += ((bool)arg) ? "T" : "F";
break;
case "null":
typeString += "N";
break;
// This part handles arrays. It points currentList to the array and resets i
// The array is processed like normal and when it is finished we replace
// currentList back with Arguments and continue from where we left off
case "System.Object[]":
case "System.Collections.Generic.List`1[System.Object]":
if(arg.GetType() == typeof(object[]))
arg = ((object[])arg).ToList();
if (Arguments != currentList)
throw new Exception("Nested Arrays are not supported");
typeString += "[";
currentList = (List<object>)arg;
ArgumentsIndex = i;
i = 0;
continue;
default:
throw new Exception("Unable to transmit values of type " + type);
}
i++;
if (currentList != Arguments && i == currentList.Count)
{
// End of array, go back to main Argument list
typeString += "]";
currentList = Arguments;
i = ArgumentsIndex+1;
}
}
int addressLen = (Address.Length == 0 || Address == null ) ? 0 : Utils.AlignedStringLength(Address);
int typeLen = Utils.AlignedStringLength(typeString);
int total = addressLen + typeLen + parts.Sum(x => x.Length);
byte[] output = new byte[total];
i = 0;
Encoding.UTF8.GetBytes(Address).CopyTo(output, i);
i += addressLen;
Encoding.UTF8.GetBytes(typeString).CopyTo(output, i);
i += typeLen;
foreach (byte[] part in parts)
{
part.CopyTo(output, i);
i += part.Length;
}
return output;
}
}
}
@@ -1,493 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Serilog;
namespace SharpOSC
{
public abstract class OscPacket
{
public static OscPacket GetPacket(byte[] OscData)
{
if (OscData[0] == '#')
return parseBundle(OscData);
else
return parseMessage(OscData);
}
public abstract byte[] GetBytes();
#region Parse OSC packages
/// <summary>
/// Takes in an OSC bundle package in byte form and parses it into a more usable OscBundle object
/// </summary>
/// <param name="msg"></param>
/// <returns>Message containing various arguments and an address</returns>
private static OscMessage parseMessage(byte[] msg)
{
int index = 0;
//Log.Debug("Raw ASCII DATA: " + System.Text.Encoding.ASCII.GetString(msg));
//Log.Debug("Raw UTF-8 DATA: " + System.Text.Encoding.UTF8.GetString(msg));
string address = null;
char[] types = new char[0];
List<object> arguments = new List<object>();
List<object> mainArray = arguments; // used as a reference when we are parsing arrays to get the main array back
// Get address
address = getAddress(msg, index);
index += msg.FirstIndexAfter(address.Length, x => x == ',');
if (index % 4 != 0)
throw new Exception("Misaligned OSC Packet data. Address string is not padded correctly and does not align to 4 byte interval");
// Get type tags
types = getTypes(msg, index);
index += types.Length;
while (index % 4 != 0)
index++;
bool commaParsed = false;
foreach (char type in types)
{
// skip leading comma
if (type == ',' && !commaParsed)
{
commaParsed = true;
continue;
}
switch(type)
{
case ('\0'):
break;
case('i'):
int intVal = getInt(msg, index);
arguments.Add(intVal);
index += 4;
break;
case('f'):
float floatVal = getFloat(msg, index);
arguments.Add(floatVal);
index += 4;
break;
case('s'):
string stringVal = getString(msg, index);
arguments.Add(stringVal);
index += stringVal.Length;
break;
case('b'):
byte[] blob = getBlob(msg, index);
arguments.Add(blob);
index += 4 + blob.Length;
break;
case ('h'):
Int64 hval = getLong(msg, index);
arguments.Add(hval);
index += 8;
break;
case ('t'):
UInt64 sval = getULong(msg, index);
arguments.Add(new Timetag(sval));
index += 8;
break;
case ('d'):
double dval = getDouble(msg, index);
arguments.Add(dval);
index += 8;
break;
case ('S'):
string SymbolVal = getString(msg, index);
arguments.Add(new Symbol(SymbolVal));
index += SymbolVal.Length;
break;
case ('c'):
char cval = getChar(msg, index);
arguments.Add(cval);
index += 4;
break;
case ('r'):
RGBA rgbaval = getRGBA(msg, index);
arguments.Add(rgbaval);
index += 4;
break;
case ('m'):
Midi midival = getMidi(msg, index);
arguments.Add(midival);
index += 4;
break;
case ('T'):
arguments.Add(true);
break;
case ('F'):
arguments.Add(false);
break;
case ('N'):
arguments.Add(null);
break;
case ('I'):
arguments.Add(double.PositiveInfinity);
break;
case ('['):
if (arguments != mainArray)
throw new Exception("SharpOSC does not support nested arrays");
arguments = new List<object>(); // make arguments point to a new object array
break;
case (']'):
mainArray.Add(arguments); // add the array to the main array
arguments = mainArray; // make arguments point back to the main array
break;
default:
throw new Exception("OSC type tag '" + type + "' is unknown.");
}
while (index % 4 != 0)
index++;
}
return new OscMessage(address, arguments.ToArray());
}
/// <summary>
/// Takes in an OSC bundle package in byte form and parses it into a more usable OscBundle object
/// </summary>
/// <param name="bundle"></param>
/// <returns>Bundle containing elements and a timetag</returns>
private static OscBundle parseBundle(byte[] bundle)
{
UInt64 timetag;
List<OscMessage> messages = new List<OscMessage>();
int index = 0;
var bundleTag = Encoding.UTF8.GetString(bundle.SubArray(0, 8));
index += 8;
timetag = getULong(bundle, index);
index += 8;
if (bundleTag != "#bundle\0")
throw new Exception("Not a bundle");
while (index < bundle.Length)
{
int size = getInt(bundle, index);
index += 4;
byte[] messageBytes = bundle.SubArray(index, size);
var message = parseMessage(messageBytes);
messages.Add(message);
index += size;
while (index % 4 != 0)
index++;
}
OscBundle output = new OscBundle(timetag, messages.ToArray());
return output;
}
#endregion
#region Get arguments from byte array
private static string getAddress(byte[] msg, int index)
{
int i = index;
string address = "";
for (; i < msg.Length; i += 4)
{
if (msg[i] == ',')
{
if (i == 0)
return "";
address = Encoding.UTF8.GetString(msg.SubArray(index, i - 1));
break;
}
}
if (i >= msg.Length && address == null)
throw new Exception("no comma found");
return address.Replace("\0", "");
}
private static char[] getTypes(byte[] msg, int index)
{
int i = index + 4;
char[] types = null;
for (; i < msg.Length; i += 4)
{
if (msg[i - 1] == 0)
{
types = Encoding.UTF8.GetChars(msg.SubArray(index, i - index));
break;
}
}
if (types == null)
{
byte[] term = { 0 };
types = Encoding.UTF8.GetChars(term);
}
if (i >= msg.Length && types == null)
throw new Exception("No null terminator after type string");
return types;
}
private static int getInt(byte[] msg, int index)
{
int val = (msg[index] << 24) + (msg[index + 1] << 16) + (msg[index + 2] << 8) + (msg[index + 3] << 0);
return val;
}
private static float getFloat(byte[] msg, int index)
{
byte[] reversed = new byte[4];
reversed[3] = msg[index];
reversed[2] = msg[index+1];
reversed[1] = msg[index+2];
reversed[0] = msg[index + 3];
float val = System.BitConverter.ToSingle(reversed, 0);
return val;
}
private static string getString(byte[] msg, int index)
{
string output = null;
int i = index + 4;
for (; (i-1) < msg.Length; i += 4)
{
if (msg[i - 1] == 0)
{
output = Encoding.UTF8.GetString(msg.SubArray(index, i - index));
break;
}
}
if (output == null)
{
byte[] term = { 0 };
output = Encoding.UTF8.GetString(term);
}
if (i >= msg.Length && output == null)
throw new Exception("No null terminator after type string");
return output.Replace("\0", "");
}
private static byte[] getBlob(byte[] msg, int index)
{
int size = getInt(msg, index);
return msg.SubArray(index + 4, size);
}
private static UInt64 getULong(byte[] msg, int index)
{
UInt64 val = ((UInt64)msg[index] << 56) + ((UInt64)msg[index + 1] << 48) + ((UInt64)msg[index + 2] << 40) + ((UInt64)msg[index + 3] << 32)
+ ((UInt64)msg[index + 4] << 24) + ((UInt64)msg[index + 5] << 16) + ((UInt64)msg[index + 6] << 8) + ((UInt64)msg[index + 7] << 0);
return val;
}
private static Int64 getLong(byte[] msg, int index)
{
byte[] var = new byte[8];
var[7] = msg[index];
var[6] = msg[index+1];
var[5] = msg[index+2];
var[4] = msg[index+3];
var[3] = msg[index+4];
var[2] = msg[index+5];
var[1] = msg[index+6];
var[0] = msg[index+7];
Int64 val = BitConverter.ToInt64(var, 0);
return val;
}
private static double getDouble(byte[] msg, int index)
{
byte[] var = new byte[8];
var[7] = msg[index];
var[6] = msg[index + 1];
var[5] = msg[index + 2];
var[4] = msg[index + 3];
var[3] = msg[index + 4];
var[2] = msg[index + 5];
var[1] = msg[index + 6];
var[0] = msg[index + 7];
double val = BitConverter.ToDouble(var, 0);
return val;
}
private static char getChar(byte[] msg, int index)
{
return (char)msg[index + 3];
}
private static RGBA getRGBA(byte[] msg, int index)
{
return new RGBA(msg[index], msg[index + 1], msg[index + 2], msg[index + 3]);
}
private static Midi getMidi(byte[] msg, int index)
{
return new Midi(msg[index], msg[index + 1], msg[index + 2], msg[index + 3]);
}
#endregion
#region Create byte arrays for arguments
protected static byte[] setInt(int value)
{
byte[] msg = new byte[4];
var bytes = BitConverter.GetBytes(value);
msg[0] = bytes[3];
msg[1] = bytes[2];
msg[2] = bytes[1];
msg[3] = bytes[0];
return msg;
}
protected static byte[] setFloat(float value)
{
byte[] msg = new byte[4];
var bytes = BitConverter.GetBytes(value);
msg[0] = bytes[3];
msg[1] = bytes[2];
msg[2] = bytes[1];
msg[3] = bytes[0];
return msg;
}
protected static byte[] setString(string value)
{
var bytes = Encoding.UTF8.GetBytes(value);
int len = bytes.Length + (4 - bytes.Length % 4);
if (len <= bytes.Length) len = len + 4;
byte[] msg = new byte[len];
bytes.CopyTo(msg, 0);
return msg;
}
protected static byte[] setBlob(byte[] value)
{
int len = value.Length + 4;
len = len + (4 - len % 4);
byte[] msg = new byte[len];
byte[] size = setInt(value.Length);
size.CopyTo(msg, 0);
value.CopyTo(msg, 4);
return msg;
}
protected static byte[] setLong(Int64 value)
{
byte[] rev = BitConverter.GetBytes(value);
byte[] output = new byte[8];
output[0] = rev[7];
output[1] = rev[6];
output[2] = rev[5];
output[3] = rev[4];
output[4] = rev[3];
output[5] = rev[2];
output[6] = rev[1];
output[7] = rev[0];
return output;
}
protected static byte[] setULong(UInt64 value)
{
byte[] rev = BitConverter.GetBytes(value);
byte[] output = new byte[8];
output[0] = rev[7];
output[1] = rev[6];
output[2] = rev[5];
output[3] = rev[4];
output[4] = rev[3];
output[5] = rev[2];
output[6] = rev[1];
output[7] = rev[0];
return output;
}
protected static byte[] setDouble(double value)
{
byte[] rev = BitConverter.GetBytes(value);
byte[] output = new byte[8];
output[0] = rev[7];
output[1] = rev[6];
output[2] = rev[5];
output[3] = rev[4];
output[4] = rev[3];
output[5] = rev[2];
output[6] = rev[1];
output[7] = rev[0];
return output;
}
protected static byte[] setChar(char value)
{
byte[] output = new byte[4];
output[0] = 0;
output[1] = 0;
output[2] = 0;
output[3] = (byte)value;
return output;
}
protected static byte[] setRGBA(RGBA value)
{
byte[] output = new byte[4];
output[0] = value.Red;
output[1] = value.Green;
output[2] = value.Blue;
output[3] = value.Alpha;
return output;
}
protected static byte[] setMidi(Midi value)
{
byte[] output = new byte[4];
output[0] = value.Port;
output[1] = value.Status;
output[2] = value.Data1;
output[3] = value.Data2;
return output;
}
#endregion
}
}
@@ -1,59 +0,0 @@
namespace SharpOSC
{
public struct RGBA
{
public byte Red;
public byte Green;
public byte Blue;
public byte Alpha;
public RGBA(byte red, byte green, byte blue, byte alpha)
{
this.Red = red;
this.Green = green;
this.Blue = blue;
this.Alpha = alpha;
}
public override bool Equals(System.Object obj)
{
if (obj.GetType() == typeof(RGBA))
{
if (this.Red == ((RGBA)obj).Red && this.Green == ((RGBA)obj).Green && this.Blue == ((RGBA)obj).Blue && this.Alpha == ((RGBA)obj).Alpha)
return true;
else
return false;
}
else if (obj.GetType() == typeof(byte[]))
{
if (this.Red == ((byte[])obj)[0] && this.Green == ((byte[])obj)[1] && this.Blue == ((byte[])obj)[2] && this.Alpha == ((byte[])obj)[3])
return true;
else
return false;
}
else
return false;
}
public static bool operator ==(RGBA a, RGBA b)
{
if (a.Equals(b))
return true;
else
return false;
}
public static bool operator !=(RGBA a, RGBA b)
{
if (!a.Equals(b))
return true;
else
return false;
}
public override int GetHashCode()
{
return (Red << 24) + (Green << 16) + (Blue << 8) + (Alpha);
}
}
}
@@ -1,82 +0,0 @@
using System.Collections.Generic;
namespace SharpOSC
{
public static class SlipFrame
{
public static readonly byte END = 0xc0;
public static readonly byte ESC = 0xdb;
public static readonly byte ESC_END = 0xDC;
public static readonly byte ESC_ESC = 0xDD;
public static List<byte[]> Decode(byte[] data)
{
List<byte[]> messages = new List<byte[]>();
List<byte> buffer = new List<byte>();
bool escapeNext = false;
for (int i = 0; i < data.Length; i++)
{
if (data[i] == ESC)
{
escapeNext = true;
continue;
}
if (escapeNext)
{
if (data[i] == ESC_END)
{
buffer.Add(END);
}
else if (data[i] == ESC_ESC)
{
buffer.Add(ESC);
}
escapeNext = false;
}
else if (data[i] == END)
{
if(buffer.Count > 0)
{
messages.Add(buffer.ToArray());
}
buffer.Clear();
}
else
{
buffer.Add(data[i]);
}
}
return messages;
}
public static byte[] Encode(byte[] data)
{
List<byte> slipData = new List<byte>();
byte[] esc_end = { ESC, ESC_END };
byte[] esc_esc = { ESC, ESC_ESC };
byte[] end = { END };
int length = data.Length;
for (int i = 0; i < length; i++)
{
if (data[i] == END)
{
slipData.AddRange(esc_end);
}
else if (data[i] == ESC)
{
slipData.AddRange(esc_esc);
}
else
{
slipData.Add(data[i]);
}
}
slipData.AddRange(end);
return slipData.ToArray();
}
}
}
@@ -1,64 +0,0 @@
namespace SharpOSC
{
public class Symbol
{
public string Value;
public Symbol()
{
Value = "";
}
public Symbol(string value)
{
this.Value = value;
}
override
public string ToString()
{
return Value;
}
public override bool Equals(System.Object obj)
{
if (obj.GetType() == typeof(Symbol))
{
if (this.Value == ((Symbol)obj).Value)
return true;
else
return false;
}
else if (obj.GetType() == typeof(string))
{
if (this.Value == ((string)obj))
return true;
else
return false;
}
else
return false;
}
public static bool operator ==(Symbol a, Symbol b)
{
if (a.Equals(b))
return true;
else
return false;
}
public static bool operator !=(Symbol a, Symbol b)
{
if (!a.Equals(b))
return true;
else
return false;
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
}
}
@@ -1,164 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Serilog;
using TcpSharp;
namespace SharpOSC
{
public class MessageEventArgs : EventArgs
{
public OscMessage Message
{
get;
set;
}
}
public class TCPClient
{
private ILogger _log = Log.Logger.ForContext<TCPClient>();
public int Port
{
get { return _port; }
}
int _port;
public string Address
{
get { return _address; }
}
public delegate void MessageReceivedHandler(object source, MessageEventArgs args);
public event MessageReceivedHandler MessageReceived;
string _address;
TcpSharpSocketClient tcpClient;
private List<byte> frameStream = new List<byte>();
public TCPClient(string address, int port)
{
_port = port;
_address = address;
}
public bool Connect()
{
try
{
tcpClient = new TcpSharpSocketClient(Address, Port);
tcpClient.OnConnected += ClientConnected;
tcpClient.OnDataReceived += DataReceived;
tcpClient.OnDisconnected += ClientDisconneted;
tcpClient.OnError += ClientError;
tcpClient.Connect();
return true;
}
catch (Exception e)
{
_log.Error(e.Message);
return false;
}
}
private void ClientError(object sender, OnClientErrorEventArgs e)
{
_log.Error("client error");
_log.Error(e.Exception.ToString());
}
private void ClientDisconneted(object sender, OnClientDisconnectedEventArgs e)
{
_log.Information($"client disconnected: {e.Reason}");
Close();
}
private void DataReceived(object sender, OnClientDataReceivedEventArgs e)
{
frameStream.AddRange(e.Data);
int i = 0;
int frameEnd = frameStream.FindIndex(1, frameByte => frameByte.Equals(SlipFrame.END));
while (frameEnd > 0)
{
List<byte> frame = frameStream.GetRange(0, frameEnd + 1);
frameStream.RemoveRange(0, frameEnd + 1);
List<byte[]> messages = SlipFrame.Decode(frame.ToArray());
foreach (var message in messages)
{
try
{
OscPacket packet = OscPacket.GetPacket(message);
OscMessage responseMessage = (OscMessage)packet;
if (packet == null)
{
_log.Error("packet is null");
}
if (responseMessage == null)
{
_log.Error("responeMessage is null");
}
OnMessageReceived(responseMessage);
}
catch (Exception ex)
{
_log.Error($"Exception parsing OSC message: {ex.ToString()}");
}
}
frameEnd = frameStream.FindIndex(0, frameByte => frameByte.Equals(SlipFrame.END));
}
}
private void ClientConnected(object sender, OnClientConnectedEventArgs e)
{
_log.Debug($"connected to <{Address}:{Port}>");
}
public void Send(byte[] message)
{
byte[] slipData = SlipFrame.Encode(message);
tcpClient.SendBytes(slipData.ToArray());
}
public void Send(OscPacket packet)
{
byte[] data = packet.GetBytes();
Send(data);
}
public bool IsConnected
{
get
{
if (tcpClient == null)
return false;
else
return tcpClient.Connected;
}
}
public void Close()
{
if (tcpClient != null)
{
tcpClient.OnConnected -= ClientConnected;
tcpClient.OnDataReceived -= DataReceived;
tcpClient.OnDisconnected -= ClientDisconneted;
if (tcpClient.Connected)
{
_log.Debug($"closing connection to {Address}");
tcpClient.Disconnect();
}
}
}
protected virtual void OnMessageReceived(OscMessage msg)
{
MessageReceived?.Invoke(this, new MessageEventArgs() { Message = msg });
}
}
}
@@ -1,89 +0,0 @@
using System;
namespace SharpOSC
{
public struct Timetag
{
public UInt64 Tag;
public DateTime Timestamp
{
get
{
return Utils.TimetagToDateTime(Tag);
}
set
{
Tag = Utils.DateTimeToTimetag(value);
}
}
/// <summary>
/// Gets or sets the fraction of a second in the timestamp. the double precision number is multiplied by 2^32
/// giving an accuracy down to about 230 picoseconds ( 1/(2^32) of a second)
/// </summary>
public double Fraction
{
get
{
return Utils.TimetagToFraction(Tag);
}
set
{
Tag = (Tag & 0xFFFFFFFF00000000) + (UInt32)(value * 0xFFFFFFFF);
}
}
public Timetag(UInt64 value)
{
this.Tag = value;
}
public Timetag(DateTime value)
{
Tag = 0;
this.Timestamp = value;
}
public override bool Equals(System.Object obj)
{
if (obj.GetType() == typeof(Timetag))
{
if (this.Tag == ((Timetag)obj).Tag)
return true;
else
return false;
}
else if (obj.GetType() == typeof(UInt64))
{
if (this.Tag == ((UInt64)obj))
return true;
else
return false;
}
else
return false;
}
public static bool operator ==(Timetag a, Timetag b)
{
if (a.Equals(b))
return true;
else
return false;
}
public static bool operator !=(Timetag a, Timetag b)
{
if (a.Equals(b))
return true;
else
return false;
}
public override int GetHashCode()
{
return (int)( ((uint)(Tag >> 32) + (uint)(Tag & 0x00000000FFFFFFFF)) / 2);
}
}
}
@@ -1,180 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using Serilog;
namespace SharpOSC
{
public delegate void HandleOscPacket(OscPacket packet);
public delegate void HandleBytePacket(byte[] packet);
public class UDPListener : IDisposable
{
public int Port { get; private set; }
object callbackLock;
UdpClient receivingUdpClient;
IPEndPoint RemoteIpEndPoint;
HandleBytePacket BytePacketCallback = null;
HandleOscPacket OscPacketCallback = null;
Queue<byte[]> queue;
ManualResetEvent ClosingEvent;
public UDPListener(int port)
{
Port = port;
queue = new Queue<byte[]>();
ClosingEvent = new ManualResetEvent(false);
callbackLock = new object();
// try to open the port 10 times, else fail
for (int i = 0; i < 10; i++)
{
try
{
receivingUdpClient = new UdpClient(port);
break;
}
catch (Exception)
{
// Failed in ten tries, throw the exception and give up
if (i >= 9)
throw;
Thread.Sleep(5);
}
}
RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
// setup first async event
AsyncCallback callBack = new AsyncCallback(ReceiveCallback);
receivingUdpClient.BeginReceive(callBack, null);
}
public UDPListener(int port, HandleOscPacket callback) : this(port)
{
this.OscPacketCallback = callback;
}
public UDPListener(int port, HandleBytePacket callback) : this(port)
{
this.BytePacketCallback = callback;
}
void ReceiveCallback(IAsyncResult result)
{
Monitor.Enter(callbackLock);
Byte[] bytes = null;
try
{
bytes = receivingUdpClient.EndReceive(result, ref RemoteIpEndPoint);
}
catch (ObjectDisposedException e)
{
// Ignore if disposed. This happens when closing the listener
Log.Debug(e.ToString());
}
// Process bytes
if (bytes != null && bytes.Length > 0)
{
if (BytePacketCallback != null)
{
BytePacketCallback(bytes);
}
else if (OscPacketCallback != null)
{
OscPacket packet = null;
try
{
packet = OscPacket.GetPacket(bytes);
}
catch (Exception e)
{
Log.Debug(e.ToString());
// If there is an error reading the packet, null is sent to the callback
}
//Log.Debug("Raw UDP In: " + System.Text.Encoding.ASCII.GetString(bytes));
OscPacketCallback(packet);
}
else
{
lock (queue)
{
queue.Enqueue(bytes);
}
}
}
if (closing)
ClosingEvent.Set();
else
{
// Setup next async event
AsyncCallback callBack = new AsyncCallback(ReceiveCallback);
receivingUdpClient.BeginReceive(callBack, null);
}
Monitor.Exit(callbackLock);
}
bool closing = false;
public void Close()
{
lock (callbackLock)
{
ClosingEvent.Reset();
closing = true;
receivingUdpClient.Close();
}
ClosingEvent.WaitOne();
}
public void Dispose()
{
this.Close();
}
public OscPacket Receive()
{
if (closing) throw new Exception("UDPListener has been closed.");
lock (queue)
{
if (queue.Count() > 0)
{
byte[] bytes = queue.Dequeue();
var packet = OscPacket.GetPacket(bytes);
//Log.Debug("Raw UDP In: " + System.Text.Encoding.ASCII.GetString(bytes));
return packet;
}
else
return null;
}
}
public byte[] ReceiveBytes()
{
if (closing) throw new Exception("UDPListener has been closed.");
lock (queue)
{
if (queue.Count() > 0)
{
byte[] bytes = queue.Dequeue();
return bytes;
}
else
return null;
}
}
}
}
@@ -1,53 +0,0 @@
using System;
using System.Net.Sockets;
using System.Net;
namespace SharpOSC
{
public class UDPSender
{
public int Port
{
get { return _port; }
}
int _port;
public string Address
{
get { return _address; }
}
string _address;
IPEndPoint RemoteIpEndPoint;
Socket sock;
public UDPSender(string address, int port)
{
_port = port;
_address = address;
sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
var addresses = System.Net.Dns.GetHostAddresses(address);
if (addresses.Length == 0) throw new Exception("Unable to find IP address for " + address);
RemoteIpEndPoint = new IPEndPoint(addresses[0], port);
}
public void Send(byte[] message)
{
sock.SendTo(message, RemoteIpEndPoint);
}
public void Send(OscPacket packet)
{
byte[] data = packet.GetBytes();
Send(data);
}
public void Close()
{
sock.Close();
}
}
}
@@ -1,47 +0,0 @@
using System;
namespace SharpOSC
{
public class Utils
{
public static DateTime TimetagToDateTime(UInt64 val)
{
if (val == 1)
return DateTime.Now;
UInt32 seconds = (UInt32)(val >> 32);
var time = DateTime.Parse("1900-01-01 00:00:00");
time = time.AddSeconds(seconds);
var fraction = TimetagToFraction(val);
time = time.AddSeconds(fraction);
return time;
}
public static double TimetagToFraction(UInt64 val)
{
if (val == 1)
return 0.0;
UInt32 seconds = (UInt32)(val & 0x00000000FFFFFFFF);
double fraction = (double)seconds / (UInt32)(0xFFFFFFFF);
return fraction;
}
public static UInt64 DateTimeToTimetag(DateTime value)
{
UInt64 seconds = (UInt32)(value - DateTime.Parse("1900-01-01 00:00:00.000")).TotalSeconds;
UInt64 fraction = (UInt32)(0xFFFFFFFF * ((double)value.Millisecond / 1000));
UInt64 output = (seconds << 32) + fraction;
return output;
}
public static int AlignedStringLength(string val)
{
int len = val.Length + (4 - val.Length % 4);
if (len <= val.Length) len += 4;
return len;
}
}
}
@@ -1,40 +0,0 @@
using Acr.UserDialogs;
using qController.Communication;
namespace qController.Dialogs
{
public class AddInstancePrompt : PromptConfig
{
public AddInstancePrompt()
{
Title = "Enter IP of QLab Computer";
Message = "Enter an IP Address to save";
OkText = "Next";
OnTextChanged = args =>
{
//IPAddress ugh
args.IsValid = IPHelper.IsValidAddress(args.Value);
};
OnAction = (qAddress) =>
{
if (!qAddress.Ok)
return;
UserDialogs.Instance.Prompt(new PromptConfig
{
Title = "Enter Name",
Message = "Enter a Name for " + qAddress.Text,
OkText = "Save",
OnAction = (qName) => {
if (!qName.Ok)
return;
QStorage.AddInstance(qName.Text, qAddress.Text);
App.showToast("Manual Workspace Added!");
}
});
};
}
}
}
@@ -1,22 +0,0 @@
using System;
using Acr.UserDialogs;
using Microsoft.Maui.ApplicationModel;
namespace qController.Dialogs
{
public class DonatePrompt : ConfirmConfig
{
public DonatePrompt()
{
Title = "Support the Project";
Message = "This application will never be a paid app or contain any sort of ads, but if you choose to show your support you may do so by clicking the Donate button below. Thank you!";
OkText = "Donate";
OnAction = (response) =>
{
if (response)
Launcher.OpenAsync(new Uri("https://linktr.ee/JoelWetzell"));
};
}
}
}
@@ -1,15 +0,0 @@
using System;
using Acr.UserDialogs;
namespace qController.Dialogs
{
public class NoWorkspacesConfig : ConfirmConfig
{
public NoWorkspacesConfig(Action<bool> action)
{
Message = "QLab doesn't have any workspaces open?";
OkText = "Disconnect";
OnAction = action;
}
}
}
@@ -1,87 +0,0 @@
using System;
using System.Collections.Generic;
using Acr.UserDialogs;
using qController.QItems;
using Serilog;
namespace qController.Dialogs
{
public class WorkspacePromptArgs : EventArgs
{
public QWorkspace SelectedWorkspace
{
get;
set;
}
}
public class WorkspacePrompt
{
public delegate void WorkspaceSelectedHandler(object source, WorkspacePromptArgs args);
public event WorkspaceSelectedHandler WorkspaceSelected;
public WorkspacePrompt()
{
}
public ActionSheetConfig getActionSheetConfigForWorkspaces(List<QWorkspaceInfo> workspaces)
{
ActionSheetConfig actionSheetConfig = new ActionSheetConfig();
actionSheetConfig.SetTitle("Select Workspace");
for (int i = 0; i < workspaces.Count; i++)
{
QWorkspaceInfo workspace = workspaces[i];
actionSheetConfig.Add(workspace.displayName, new Action(() => {
Log.Debug("CONTROLPAGE - Workspace Selected " + workspace.displayName);
if (!workspace.hasPasscode)
{
OnWorkspaceSelected(new QWorkspace(workspace.uniqueID));
}
else
{
promptWorkspacePasscode(workspace.uniqueID);
}
}));
}
return actionSheetConfig;
}
public void promptWorkspacePasscode(string workspace_id)
{
UserDialogs.Instance.Prompt(new PromptConfig
{
InputType = InputType.Number,
MaxLength = 4,
Title = "Enter Workspace Passcode",
OkText = "Connect",
IsCancellable = true,
OnAction = (resp) =>
{
if (resp.Ok)
{
OnWorkspaceSelected(new QWorkspace(workspace_id,resp.Value));
}
else
{
OnWorkspaceSelected(null);
}
}
});
}
protected virtual void OnWorkspaceSelected(QWorkspace workspace)
{
if (WorkspaceSelected != null)
WorkspaceSelected(this, new WorkspacePromptArgs() { SelectedWorkspace = workspace });
}
}
}
-51
View File
@@ -1,51 +0,0 @@
using System.Collections.Generic;
namespace qController.QItems
{
public class QCue
{
//info loaded from "/cueLists"
public string number { get; set; }
public string uniqueID { get; set; }
public bool flagged { get; set; }
public string listName { get; set; }
public string type { get; set; }
public string colorName { get; set; }
public string name { get; set; }
public bool armed { get; set; }
//info loaded from "/valuesForKeys
public decimal translationX { get; set; }
public bool isRunning { get; set; }
public decimal scaleX { get; set; }
public bool isPaused { get; set; }
public decimal translationY { get; set; }
public decimal preWait { get; set; }
public decimal opacity { get; set; }
public decimal scaleY { get; set; }
public decimal duration { get; set; }
public decimal postWait { get; set; }
public bool isBroken { get; set; }
public string displayName { get; set; }
public bool isLoaded { get; set; }
public string notes { get; set; }
public List<List<double>> levels { get; set; }
//info loaded from /children
public List<QCue> cues { get; set; }
//get string for icon font from cue type
public string getIconString()
{
return QIcon.GetIconFromType(type);
}
public string IconText
{
get
{
return QIcon.GetIconFromType(type);
}
}
}
}
@@ -1,25 +0,0 @@
using System.Collections.Generic;
namespace qController.QItems
{
public class QCueList
{
public string number { get; set; }
public string uniqueID { get; set; }
public List<QCue> cues { get; set; }
public bool flagged { get; set; }
public string listName { get; set; }
public string type { get; set; }
public string colorName { get; set; }
public string name { get; set; }
public bool armed { get; set; }
public string IconText
{
get
{
return QIcon.GetIconFromType("Group");
}
}
}
}
@@ -1,10 +0,0 @@
using System;
namespace qController.Classes.Cues
{
public class QDefinitions
{
public QDefinitions()
{
}
}
}
@@ -1,36 +0,0 @@
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController.QItems
{
public class QInstance
{
public string name { get; set; }
public string address { get; set; }
public QInstance()
{
}
public QInstance(string tName, string tAddress)
{
name = tName;
address = tAddress;
}
public bool IsReachable()
{
/*try
{
IPAddress instanceIP = IPAddress.Parse(address);
Ping p = new System.Net.NetworkInformation.Ping();
PingReply reply = p.Send(instanceIP);
return reply.Status == IPStatus.Success ? true : false;
}
catch
{
return false;
}*/
return true;
}
}
}
@@ -1,126 +0,0 @@
//Class pertains to the local copy of a workspace, with methods for fetching/updating information inside
using System.Collections.Generic;
using Serilog;
namespace qController.QItems
{
public class QWorkspace
{
public string status { get; set; }
public List<QCueList> data { get; set; }
public string workspace_id { get; set; }
public string address { get; set; }
public bool IsPopulated { get; set; }
public string passcode { get; set; }
//ONLY FOR PASSING A WORKSPACE LOAD ERROR
public QWorkspace(string id)
{
workspace_id = id;
}
public QWorkspace(string id, string passcode)
{
workspace_id = id;
this.passcode = passcode;
}
public QWorkspace()
{
}
public QCue GetCue(string cue_id)
{
foreach (var cueList in data)
{
foreach (var cue in cueList.cues)
{
if(cue.uniqueID == cue_id)
{
return cue;
}
}
}
return null;
}
public QCueList GetCueList(string id)
{
foreach (var cueList in data)
{
if(cueList.uniqueID == id)
{
return cueList;
}
}
return null;
}
public void UpdateCue(QCue cue)
{
for (int i = 0; i < data.Count; i++)
{
for (int j = 0; j < data[i].cues.Count; j++)
{
if(data[i].cues[j].uniqueID == cue.uniqueID)
{
//Log.Debug("Cue found and updated in workspace: " + cue.uniqueID);
data[i].cues[j] = cue;
return;
}
}
}
}
public void UpdateChildren(string cue_id, List<QCue> children)
{
for (int i = 0; i < data.Count; i++)
{
for (int j = 0; j < data[i].cues.Count; j++)
{
if (data[i].cues[j].uniqueID == cue_id)
{
if(data[i].cues[j].type == "Group")
{
data[i].cues[j].cues = children;
return;
}
}
}
}
}
public bool CheckPopulated()
{
if(data == null)
{
IsPopulated = false;
return false;
}
for (int i = 0; i < data.Count; i++)
{
for (int j = 0; j < data[i].cues.Count; j++)
{
if (data[i].cues[j].type == "Group" && data[i].cues[j].cues == null)
{
IsPopulated = false;
return false;
}
}
}
IsPopulated = true;
return true;
}
public void PrintStats()
{
foreach (var cueList in data)
{
Log.Debug(cueList.listName + "("+ cueList.cues.Count + " cues)");
}
}
}
}
@@ -1,11 +0,0 @@
//General information about a QLab Workspace
namespace qController.QItems
{
public class QWorkspaceInfo
{
public string version { get; set; }
public string displayName { get; set; }
public string uniqueID { get; set; }
public bool hasPasscode { get; set; }
}
}
@@ -1,11 +0,0 @@
namespace qController
{
public class MenuPageItem
{
public string Title { get; set; }
public string Icon { get; set; }
public string Command { get; set; }
}
}
@@ -1,15 +0,0 @@
using qController.QItems;
namespace qController
{
public class NoQCueSelected : QCue
{
public NoQCueSelected()
{
listName = "No Cue Selected";
type = "";
notes = "Workspace has loaded but no cue is selected";
number = "!";
}
}
}
@@ -1,11 +0,0 @@
namespace qController
{
public class OSCListItem
{
public string Text { get; set; }
public string Icon { get; set; }
public string Command { get; set; }
}
}
@@ -1,17 +0,0 @@
namespace qController
{
public class QCommand
{
public string osc;
public string text;
public string type;
public QCommand(string display, string cmd, string command_type)
{
text = display;
osc = cmd;
type = command_type;
}
}
}
@@ -1,17 +0,0 @@
namespace qController
{
public static class QCommands
{
public static QCommand GO = new QCommand("GO", "/go","WORKSPACE");
public static QCommand PANIC = new QCommand("Panic", "/panic","WORKSPACE");
public static QCommand PAUSE = new QCommand("Pause", "/pause","WORKSPACE");
public static QCommand PREVIEW = new QCommand("Preview", "/preview","WORKSPACE");
public static QCommand RESUME = new QCommand("Resume", "/resume","WORKSPACE");
public static QCommand PREVIOUS = new QCommand("Previous","/select/previous","WORKSPACE");
public static QCommand NEXT = new QCommand("Next", "/select/next","WORKSPACE");
public static QCommand RESET = new QCommand("Reset","/reset","WORKSPACE");
public static QCommand STOP = new QCommand("Stop","/stop","WORKSPACE");
public static QCommand HARDSTOP = new QCommand("Hard Stop", "/hardStop","WORKSPACE");
}
}
-118
View File
@@ -1,118 +0,0 @@
//Get appropriately letter or unicode character for Icon font
namespace qController
{
public static class QIcon
{
public const string SEARCH = "\uE800";
public const string PLUS = "\uE801";
public const string TRASH_EMPTY = "\uE802";
public const string CANCEL = "\uE803";
public const string MUSIC = "\uE804";
public const string VIDEO = "\uE805";
public const string VIDEOCAM = "\uE806";
public const string VOLUME_UP = "\uE807";
public const string CLOCK = "\uE808";
public const string PLAY = "\uE809";
public const string STOP = "\uE80A";
public const string PAUSE = "\uE80B";
public const string CW = "\uE80C";
public const string TARGET = "\uE80D";
public const string CHART_PIE = "\uE80E";
public const string UNDO = "\uE80F";
public const string POWER = "\uE810";
public const string QRCODE = "\uE811";
public const string MAIL = "\uE812";
public const string LEFT_DIR = "\uE813";
public const string LIST = "\uE814";
public const string SPIN3 = "\uE832";
public const string MENU = "\uF0C9";
public const string LIGHTBULB = "\uF0EB";
public const string MIC = "\uF130";
public const string MINUS_SQUARED = "\uF146";
public const string DOLLAR = "\uF155";
public const string RIGHT = "\uF178";
public const string DOT_CIRCLED = "\uF192";
public const string SLIDERS = "\uF1DE";
public const string WIFI = "\uF1EB";
public const string OBJECT_UNGROUP = "\uF248";
public const string HOURGLASS_O = "\uF250";
public const string COMMENTING_O = "\uF27B";
public static string GetIconFromType(string type)
{
switch (type)
{
case "Group":
return "g";
case "Audio":
return "a";
case "Mic":
return "m";
case "Video":
return "v";
case "Camera":
return "c";
case "Text":
return "t";
case "Light":
return LIGHTBULB;
case "Fade":
return "f";
case "Network":
return "o";
case "MIDI":
return "M";
case "MIDI File":
return "F";
case "Timecode":
return "T";
case "Start":
return "s";
case "Stop":
return "S";
case "Pause":
return "p";
case "Load":
return "l";
case "Reset":
return "r";
case "Devamp":
return "d";
case "GoTo":
return "G";
case "Target":
return "R";
case "Arm":
return "A";
case "Disarm":
return "D";
case "Wait":
return "W";
case "Memo":
return "e";
case "Script":
return "C";
default:
return "";
}
}
}
}
@@ -1,70 +0,0 @@
using Serilog;
using System.Collections.ObjectModel;
using Acr.Settings;
using qController.QItems;
namespace qController
{
public class QStorage
{
public static ObservableCollection<QInstance> qInstances;
static QStorage(){
qInstances = (ObservableCollection<QInstance>)CrossSettings.Current.GetValue(new ObservableCollection<QInstance>().GetType(), "qInstances", null);
if (qInstances == null)
{
Log.Debug("QSTORAGE - No qInstance exists creating one");
qInstances = new ObservableCollection<QInstance>();
updateStorage();
}
}
public static bool AddInstance(string name, string address){
return AddInstance(new QInstance(name, address));
}
public static bool AddInstance(QInstance q){
if(!Contains(q.name, q.address)){
qInstances.Add(q);
updateStorage();
return true;
}else{
return false;
}
}
public static void RemoveInstance(string name, string address){
foreach (var item in qInstances)
{
if(item.address == address && item.name == name){
RemoveInstance(item);
return;
}
}
}
public static void RemoveInstance(QInstance q){
qInstances.Remove(q);
updateStorage();
}
private static void updateStorage(){
CrossSettings.Current.SetValue("qInstances", qInstances);
}
public static bool Contains(string name, string address){
foreach (var item in qInstances)
{
Log.Information("Item name: " + item.name + " Found Name: " + name);
if (item.address == address)
{
return true;
}
}
return false;
}
public bool IsEmpty(){
return qInstances.Count == 0;
}
}
}
-18
View File
@@ -1,18 +0,0 @@
namespace qController;
public static class MauiProgramExtensions
{
public static MauiAppBuilder UseSharedMauiApp(this MauiAppBuilder builder)
{
builder
.UseMauiApp<App>();
// TODO: Add the entry points to your Apps here.
// See also: https://learn.microsoft.com/dotnet/maui/fundamentals/app-lifecycle
//builder.Services.AddTransient<AppShell, AppShell>();
return builder;
}
}
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="qController.App">
<Application.Resources>
<!-- Application resource dictionary -->
<OnPlatform x:Key="qfont" x:TypeArguments="x:String">
<On Platform="Android" Value="qfont.ttf#qfont" />
<On Platform="iOS" Value="qfont" />
</OnPlatform>
</Application.Resources>
</Application>
-71
View File
@@ -1,71 +0,0 @@
using Acr.UserDialogs;
using qController.Communication;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Microsoft.Maui.Devices;
namespace qController
{
public partial class App : Application
{
public static INavigation iNav;
public static NavigationPage NavigationPage { get; private set; }
public static RootPage rootPage;
public static string QFont;
public static DisplayInfo mainDisplayInfo;
public static double Height;
public static double Width;
public static double HeightUnit;
public static double WidthUnit;
public static QController qControllerToResume;
public static bool MenuIsPresented
{
get
{
return rootPage.IsPresented;
}
set
{
rootPage.IsPresented = value;
}
}
public App()
{
InitializeComponent();
/*MainPage = new NavigationPage(new QConnectionPage());
iNav = MainPage.Navigation;*/
mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
Height = mainDisplayInfo.Height / mainDisplayInfo.Density;
Width = mainDisplayInfo.Width / mainDisplayInfo.Density;
HeightUnit = Height / 100.0;
WidthUnit = Width / 100.0;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:
QFont = "qfont";
break;
case Device.Android:
QFont = "qfont.ttf#qfont";
break;
}
rootPage = new RootPage();
rootPage.Detail = new NavigationPage(new QConnectionPage());
MainPage = rootPage;
}
public static void showToast(string message)
{
var toastConfig = new ToastConfig(message);
toastConfig.SetDuration(3000);
toastConfig.SetPosition(ToastPosition.Bottom);
UserDialogs.Instance.Toast(toastConfig);
}
}
}
-21
View File
@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="qController.ControlPage"
BackgroundColor="#4A4A4A">
<ContentPage.Content>
<AbsoluteLayout x:Name="sLayout">
<Grid x:Name="topBar" HorizontalOptions="FillAndExpand" AbsoluteLayout.LayoutBounds="0,0,1,.09" AbsoluteLayout.LayoutFlags="All" BackgroundColor="#71AEFF">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<Label x:Name="menuButton" FontFamily = "{StaticResource qfont}" HorizontalOptions = "Start" VerticalOptions="End" Margin="20,10,20,10" Grid.Row="0" Grid.Column="0" FontSize="25" Text="&#xF0C9;"/>
<Label x:Name="instanceName" HorizontalTextAlignment="End" HorizontalOptions = "FillAndExpand" VerticalOptions="End" Margin="20,10,20,10" Grid.Row="0" Grid.Column="1"/>
</Grid>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
-400
View File
@@ -1,400 +0,0 @@
using System;
using System.Collections.Generic;
using Serilog;
using Acr.UserDialogs;
using qController.Dialogs;
using qController.QItems;
using qController.Cell;
using qController.Communication;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Layouts;
namespace qController
{
public partial class ControlPage : ContentPage
{
QController qController;
QSelectedCueCell qCell;
QLevelsCell qLevelsCell;
QCueListCell qCueListCell;
QLevelsButton showLevelsButton;
QControlsBlock qControlsBlock;
WorkspacePrompt workspacePrompt = new WorkspacePrompt();
public ControlPage(string name, string address)
{
InitializeComponent();
qController = new QController(address, 53000);
qController.qClient.qParser.WorkspaceInfoReceived += WorkspaceInfoReceived;
qController.qClient.qParser.WorkspaceUpdated += WorkspaceUpdated;
qController.qClient.qParser.WorkspaceDisconnect += WorkspaceDisconnected;
qController.qClient.qParser.PlaybackPositionUpdated += PlaybackPositionUpdated;
qController.qClient.qParser.ConnectionStatusChanged += OnConnectionStatusChanged;
qController.qClient.qParser.CueInfoUpdated += OnCueUpdateReceived;
qController.qClient.qParser.ChildrenUpdated += OnChildrenUpdated;
workspacePrompt.WorkspaceSelected += OnWorkspaceSelected;
App.rootPage.MenuItemSelected += OnMenuItemSelected;
instanceName.Text = name;
InitGUI();
if (!qController.qClient.connected) {
App.showToast("Error connecting...make sure QLab is running");
Back();
} else {
qController.KickOff();
}
}
private void OnWorkspaceSelected(object source, WorkspacePromptArgs args)
{
if (args.SelectedWorkspace != null) {
qController.Connect(args.SelectedWorkspace);
} else {
Log.Debug("CONTROLPAGE - No Workspace selected backing out");
Back();
}
}
private void OnConnectionStatusChanged(object source, ConnectEventArgs args)
{
Log.Debug($"CONTROLPAGE - Connection Status Changed: {args.WorkspaceId} : {args.Status}");
if (args.Status.Contains("ok")) {
if(args.Status.Contains(":") && !args.Status.Contains("view")) {
workspacePrompt.promptWorkspacePasscode(args.WorkspaceId);
return;
}
Device.BeginInvokeOnMainThread(() => {
FinishUI();
});
} else if (args.Status.Contains("badpass")) {
workspacePrompt.promptWorkspacePasscode(args.WorkspaceId);
}
}
private void WorkspaceInfoReceived(object source, WorkspaceInfoArgs args)
{
if (args.WorkspaceInfo.Count > 1) {
Log.Debug("CONTROLPAGE - MULTIPLE WORKSPACES ON SELECTED COMPUTER");
PromptForWorkspace(args.WorkspaceInfo);
} else if (args.WorkspaceInfo.Count == 1) {
Log.Debug("CONTROLPAGE - ONLY ONE WORKSPACE ON SELECTED COMPUTER");
if (!args.WorkspaceInfo[0].hasPasscode) {
qController.Connect(args.WorkspaceInfo[0].uniqueID);
} else {
workspacePrompt.promptWorkspacePasscode(args.WorkspaceInfo[0].uniqueID);
}
} else {
NoWorkspacesConfig noWorkspacesConfig = new NoWorkspacesConfig(NoWorkspaceDetected);
UserDialogs.Instance.Confirm(noWorkspacesConfig);
}
}
private void PromptForWorkspace(List<QWorkspaceInfo> workspaces)
{
UserDialogs.Instance.ActionSheet(workspacePrompt.getActionSheetConfigForWorkspaces(workspaces));
}
private void InitGUI()
{
App.rootPage.MenuPage.ChangeToControl();
NavigationPage.SetHasNavigationBar(this, false);
qCell = new QSelectedCueCell();
qCell.SelectedCueEdited += OnSelectedCueEdited;
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutFlags(qCell, AbsoluteLayoutFlags.All);
instanceName.FontSize = App.HeightUnit * 3;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(qCell, new Rect(0, 0.13, 1, 0.30));
topBar.HeightRequest = App.Height * .09;
menuButton.FontSize = App.Height * .04;
break;
case Device.Android:
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(qCell, new Rect(0, 0.13, 1, 0.35));
topBar.HeightRequest = App.Height * .06;
menuButton.FontSize = App.Height * .05;
break;
}
//Menu Button Setup
var menuButtonGesture = new TapGestureRecognizer();
menuButtonGesture.Tapped += ShowMenu;
menuButton.GestureRecognizers.Add(menuButtonGesture);
menuButton.Margin = new Thickness(App.WidthUnit * 2, 0, 0, App.WidthUnit * 2);
sLayout.Children.Add(qCell);
}
private void SendOSCFromButton(object sender, EventArgs args)
{
if (((QButton)sender).qCommand.type == "WORKSPACE")
{
string workspace_prefix = "/workspace/" + qController.qWorkspace.workspace_id;
string command = workspace_prefix + ((QButton)sender).qCommand.osc;
qController.qClient.sendTCP(command);
}
}
private void OnSelectedCueEdited(object source, CueEditArgs args)
{
string address = "/workspace/" + qController.qWorkspace.workspace_id + "/cue_id/" + args.CueID + "/" + args.Property;
qController.qClient.sendTCP(address, args.NewValue);
}
void FinishUI()
{
string workspace_prefix = "/workspace/" + qController.qWorkspace.workspace_id;
qLevelsCell = new QLevelsCell();
qLevelsCell.mainSlider.ValueChanged += (sender, args) =>
{
qController.qClient.sendTCP(workspace_prefix + "/cue_id/" + qLevelsCell.activeCue + "/sliderLevel/0", (float)args.NewValue);
};
qLevelsCell.leftSlider.ValueChanged += (sender, args) =>
{
qController.qClient.sendTCP(workspace_prefix + "/cue_id/" + qLevelsCell.activeCue + "/sliderLevel/1", (float)args.NewValue);
};
qLevelsCell.rightSlider.ValueChanged += (sender, args) =>
{
qController.qClient.sendTCP(workspace_prefix + "/cue_id/" + qLevelsCell.activeCue + "/sliderLevel/2", (float)args.NewValue);
};
showLevelsButton = new QLevelsButton();
showLevelsButton.button.Clicked += (s, e) =>
{
qLevelsCell.IsVisible = !qLevelsCell.IsVisible;
};
qControlsBlock = new QControlsBlock(SendOSCFromButton);
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutFlags(qControlsBlock, AbsoluteLayoutFlags.All);
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutFlags(qLevelsCell, AbsoluteLayoutFlags.All);
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutFlags(showLevelsButton, AbsoluteLayoutFlags.PositionProportional);
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(qControlsBlock, new Rect(0, 0.53, 1, 0.25));
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(qLevelsCell, new Rect(0.9, 0.40, 0.8, 0.25));
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(showLevelsButton, new Rect(0.02, 0.34, App.HeightUnit * 8, App.HeightUnit * 8));
break;
case Device.Android:
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(qControlsBlock, new Rect(0, 0.58, 1, 0.25));
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(qLevelsCell, new Rect(0.9, 0.45, 0.8, 0.25));
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(showLevelsButton, new Rect(0.02, 0.39, App.HeightUnit * 8, App.HeightUnit * 8));
break;
}
sLayout.Children.Add(qControlsBlock);
sLayout.Children.Add(qLevelsCell);
sLayout.Children.Add(showLevelsButton);
}
private void ToggeQLevelsCellVisiblity(object sender, EventArgs e)
{
qLevelsCell.IsVisible = !qLevelsCell.IsVisible;
}
void ShowMenu(object sender, EventArgs e)
{
App.MenuIsPresented = true;
}
void Back()
{
if (qController.qClient.connected)
{
qController.Kill();
}
App.rootPage.MenuItemSelected -= OnMenuItemSelected;
Device.BeginInvokeOnMainThread(() =>
{
App.rootPage.MenuPage.ChangeToHome();
App.rootPage.Detail.Navigation.PopAsync();
});
}
public void NoWorkspaceDetected(bool resp)
{
if (resp)
{
Back();
}
}
public void WorkspaceDisconnected(object sender, EventArgs e)
{
Back();
}
public void WorkspaceUpdated(object sender, WorkspaceEventArgs e)
{
if(e.UpdatedWorkspace.data == null)
{
Log.Debug("[ControlPage] Workspace Update contains null data.");
return;
}
if(e.UpdatedWorkspace.data.Count > 0)
{
qController.qWorkspace = e.UpdatedWorkspace;
qController.qWorkspace.CheckPopulated();
if (qController.qWorkspace.IsPopulated)
{
Device.BeginInvokeOnMainThread(() =>
{
App.rootPage.MenuPage.ChangeToWorkspace(e.UpdatedWorkspace);
});
if (qCell.activeCue == null)
{
Device.BeginInvokeOnMainThread(() => {
qCell.UpdateSelectedCue(new NoQCueSelected());
});
Log.Debug("CONTROLPAGE - Update Selected Cue Called because of Inital Workspace Load");
qController.qClient.UpdateSelectedCue(qController.qWorkspace.workspace_id);
}
Log.Debug("CONTROLPAGE - Workspace Updated " + qController.qWorkspace.workspace_id);
}
}
}
public void PlaybackPositionUpdated(object sender, PlaybackPositionArgs e)
{
qController.playbackPosition = e.PlaybackPosition;
Log.Debug("CONTROLPAGE - Playback Position Updated " + qController.playbackPosition);
QCue cue = qController.qWorkspace.GetCue(qController.playbackPosition);
if(cue != null)
{
Device.BeginInvokeOnMainThread(() => {
if (cue.levels != null)
showLevelsButton.IsVisible = true;
else
{
showLevelsButton.IsVisible = false;
qLevelsCell.IsVisible = false;
}
qCell.UpdateSelectedCue(cue);
});
}
}
public void OnCueUpdateReceived(object sender, CueEventArgs args)
{
if(qController != null)
{
if(qController.qWorkspace != null)
{
qController.qWorkspace.UpdateCue(args.Cue);
if (qController.playbackPosition == null)
{
qController.playbackPosition = args.Cue.uniqueID;
}
if (args.Cue.uniqueID == qController.playbackPosition)
{
Device.BeginInvokeOnMainThread(() =>
{
Log.Debug("CONTROLPAGE - Refreshing Currently Displayed Cue");
if (args.Cue.levels != null) {
Log.Debug("before show levels button and cue.levels isnt null");
showLevelsButton.IsVisible = true;
Log.Debug("after show levels button and cue.levels isnt null");
} else {
showLevelsButton.IsVisible = false;
qLevelsCell.IsVisible = false;
}
qCell.UpdateSelectedCue(args.Cue);
if(qLevelsCell != null)
{
qLevelsCell.activeCue = args.Cue.uniqueID;
if (args.Cue.levels != null)
{
qLevelsCell.UpdateLevels(args.Cue.levels[0]);
}
}
});
}
}
}
}
private void OnChildrenUpdated(object source, ChildrenEventArgs args)
{
if(qController != null)
{
if(qController.qWorkspace != null)
{
qController.qWorkspace.UpdateChildren(args.cue_id, args.children);
}
}
}
private void OnMenuItemSelected(object source, MenuEventArgs args)
{
if (args.Command.Contains("/"))
{
qController.qClient.sendTCP(args.Command);
} else if (args.Command == "disconnect") {
Back();
} else if (args.Command.Contains("cueList")) {
var parts = args.Command.Split(' ');
if(parts.Length > 1)
{
Device.BeginInvokeOnMainThread(() =>
{
qCueListCell = new QCueListCell(qController.qWorkspace.GetCueList(parts[1]));
qCueListCell.closeButton.Clicked += CloseCueList;
qCueListCell.cueListView.ItemSelected += OnCueListItemSelected;
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutFlags(qCueListCell, AbsoluteLayoutFlags.All);
Microsoft.Maui.Controls.Compatibility.AbsoluteLayout.SetLayoutBounds(qCueListCell, new Rect(0, 0.2, 1, 0.9));
sLayout.Children.Add(qCueListCell);
});
}
}
}
private void CloseCueList(object sender, EventArgs e)
{
Device.BeginInvokeOnMainThread(() =>
{
sLayout.Children.Remove(qCueListCell);
});
}
private void OnCueListItemSelected(object sender, SelectedItemChangedEventArgs e)
{
OSCListItem cue = (OSCListItem)e.SelectedItem;
string selectCueOSC = "/workspace/" + qController.qWorkspace.workspace_id + cue.Command;
qController.qClient.sendTCP(selectCueOSC);
CloseCueList(sender,e);
}
protected override bool OnBackButtonPressed()
{
Back();
return true;
}
}
}
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="qController.MenuPage">
<StackLayout>
<ListView x:Name="listView">
</ListView>
</StackLayout>
</ContentPage>
-139
View File
@@ -1,139 +0,0 @@
using System.Collections.ObjectModel;
using qController.QItems;
using System;
using Microsoft.Maui.Controls.PlatformConfiguration;
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController
{
public partial class MenuPage : ContentPage
{
public ObservableCollection<MenuPageItem> items { get; } = new ObservableCollection<MenuPageItem>();
public MenuPage()
{
On<iOS>().SetUseSafeArea(true);
Title = "Menu";
InitializeComponent();
ChangeToHome();
listView.ItemsSource = items;
listView.RowHeight = (int)(App.HeightUnit * 6);
listView.ItemTemplate = new DataTemplate(() =>
{
var grid = new Microsoft.Maui.Controls.Compatibility.Grid
{
Padding = new Thickness(5, 10),
ColumnDefinitions =
{
new ColumnDefinition{Width = new GridLength(30)},
new ColumnDefinition { Width = GridLength.Star }
}
};
var icon = new Label {
FontFamily = App.QFont,
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
FontSize = App.HeightUnit * 3
};
icon.SetBinding(Label.TextProperty, "Icon");
var label = new Label {
VerticalOptions = LayoutOptions.FillAndExpand
};
label.SetBinding(Label.TextProperty, "Title");
if (label.Text == "Disconnect")
label.TextColor = Colors.DarkRed;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:
label.FontSize = App.HeightUnit * 3;
break;
case Device.Android:
label.FontSize = App.HeightUnit * 2.2;
break;
}
grid.Children.Add(icon);
grid.Children.Add(label, 1, 0);
return new ViewCell { View = grid };
});
}
public void setItemSelected(EventHandler<SelectedItemChangedEventArgs> ItemSelected){
listView.ItemSelected += ItemSelected;
}
public void clearSelectedItem()
{
listView.SelectedItem = null;
}
public void ChangeToControl()
{
items.Clear();
items.Add(new MenuPageItem
{
Title = "Disconnect",
Icon = QIcon.CANCEL,
Command = "disconnect"
});
}
public void ChangeToWorkspace(QWorkspace workspace)
{
for(int i = 0; i < workspace.data.Count; i++)
{
var cueList = workspace.data[i];
items.Add(new MenuPageItem
{
Title = cueList.listName,
Icon = cueList.IconText,
Command = "cueList " + cueList.uniqueID
});
}
}
public void ChangeToHome()
{
items.Clear();
items.Add(new MenuPageItem
{
Title = "Scan Network",
Icon = "\uE800",
Command = "scan"
});
items.Add(new MenuPageItem
{
Title = "Add Manually",
Icon = "\uE801",
Command = "add"
});
items.Add(new MenuPageItem
{
Title = "Send Feedback",
Icon = QIcon.MAIL,
Command = "feedback"
});
items.Add(new MenuPageItem
{
Title = "Support Project",
Icon = QIcon.DOLLAR,
Command = "support"
});
}
}
}
-5
View File
@@ -1,5 +0,0 @@
<FlyoutPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="qController.RootPage">
</FlyoutPage>
-43
View File
@@ -1,43 +0,0 @@
using System;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
namespace qController
{
public class MenuEventArgs : EventArgs
{
public string Command
{
get;
set;
}
}
public partial class RootPage : FlyoutPage
{
public MenuPage MenuPage;
public delegate void MenuItemSelectedHandler(object source, MenuEventArgs args);
public event MenuItemSelectedHandler MenuItemSelected;
public RootPage()
{
InitializeComponent();
MenuPage = new MenuPage();
MenuPage.setItemSelected(OnItemSelected);
Flyout = MenuPage;
}
void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as MenuPageItem;
if (item != null)
{
MenuPage.clearSelectedItem();
IsPresented = false;
MenuItemSelected?.Invoke(this, new MenuEventArgs { Command = item.Command });
}
}
}
}
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:qController" x:Class="qController.QConnectionPage">
<StackLayout x:Name="sLayout">
<Grid x:Name="topBar" HorizontalOptions="FillAndExpand" BackgroundColor="#71AEFF">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label x:Name = "menuButton" FontFamily = "{StaticResource qfont}" HorizontalOptions = "Start" VerticalOptions="End" Margin="20,10,20,10" Grid.Row="0" Grid.Column="0" Text="&#xF0C9;"/>
</Grid>
<ListView x:Name="listView" HasUnevenRows="true" BackgroundColor="#4A4A4A" SeparatorVisibility="None"></ListView>
</StackLayout>
</ContentPage>
@@ -1,124 +0,0 @@
using System;
using Acr.UserDialogs;
using Zeroconf;
using System.Collections.Generic;
using Serilog;
using qController.QItems;
using qController.Dialogs;
using qController.Cell;
using Microsoft.Maui.Controls.PlatformConfiguration;
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Microsoft.Maui.ApplicationModel;
namespace qController
{
public partial class QConnectionPage : ContentPage
{
public QConnectionPage()
{
InitializeComponent();
InitGUI();
App.rootPage.MenuItemSelected += OnMenuItemSelected;
}
private void OnMenuItemSelected(object source, MenuEventArgs args)
{
if(args.Command == "scan")
{
Scan();
}
else if(args.Command == "add")
{
AddWorkspace();
}
else if (args.Command == "feedback")
{
Launcher.OpenAsync(new Uri("mailto:feedback@jwetzell.com?subject=qController%20feedback"));
}
else if(args.Command == "support")
{
UserDialogs.Instance.Confirm(new DonatePrompt());
}
}
private void InitGUI()
{
Microsoft.Maui.Controls.NavigationPage.SetHasNavigationBar(this, false);
//ListView Setup
listView.ItemsSource = QStorage.qInstances;
listView.ItemTemplate = new DataTemplate(typeof(QInstanceCell));
listView.ItemTapped += (object sender, ItemTappedEventArgs e) =>
{
// don't do anything if we just de-selected the row
if (e.Item == null) return;
// do something with e.SelectedItem
((Microsoft.Maui.Controls.ListView)sender).SelectedItem = null; // de-select the row
};
//Platform Specific Setup
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:
topBar.HeightRequest = App.Height * .09;
menuButton.FontSize = App.Height * .04;
menuButton.Margin = new Thickness(App.WidthUnit * 2, 0, 0, App.WidthUnit * 2);
break;
case Device.Android:
topBar.HeightRequest = App.Height * .09;
menuButton.FontSize = App.Height * .05;
menuButton.Margin = new Thickness(App.WidthUnit * 2, 0, 0, App.WidthUnit * 2);
break;
}
BackgroundColor = Color.FromArgb("4A4A4A");
//MenuButton Setup
var menuButtonGesture = new TapGestureRecognizer();
menuButtonGesture.Tapped += showMenu;
menuButton.GestureRecognizers.Add(menuButtonGesture);
}
void AddWorkspace(){
UserDialogs.Instance.Prompt(new AddInstancePrompt());
}
async void Scan(){
bool workspacesFound = false;
App.showToast("Scanning for Instances...");
Log.Debug("QCONNECTIONPAGE - Begin Scanning");
IReadOnlyList<IZeroconfHost> results = await ZeroconfResolver.ResolveAsync("_qlab._tcp.local.",TimeSpan.FromSeconds(3));
if(results != null){
foreach (var result in results)
{
if (result != null)
{
QInstance instance = new QInstance(result.DisplayName, result.IPAddress);
if(QStorage.AddInstance(instance)){
Log.Debug($"QCONNECTIONPAGE - {result.DisplayName} @ {result.IPAddress} added");
workspacesFound = true;
}
}
}
}
if(workspacesFound){
App.showToast("Instance Found and Added!");
}else{
App.showToast("No New Instances Found!");
}
}
void showMenu(object sender, EventArgs e)
{
App.MenuIsPresented = true;
}
}
}
-40
View File
@@ -1,40 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<UseMaui>true</UseMaui>
<TargetFrameworks>net8.0-ios;net8.0-android;net8.0</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<OutputType>Library</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
<EnableDefaultMauiItems>False</EnableDefaultMauiItems>
<SingleProject>true</SingleProject>
</PropertyGroup>
<ItemGroup>
<None Remove="Pages\App.xaml" />
<None Remove="Pages\ControlPage.xaml" />
<None Remove="Pages\MenuPage.xaml" />
<None Remove="Pages\qConnectionPage.xaml" />
<None Remove="Pages\RootPage.xaml" />
</ItemGroup>
<ItemGroup>
<MauiXaml Include="Pages\App.xaml" />
<MauiXaml Include="Pages\ControlPage.xaml" />
<MauiXaml Include="Pages\MenuPage.xaml" />
<MauiXaml Include="Pages\qConnectionPage.xaml" />
<MauiXaml Include="Pages\RootPage.xaml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
<PackageReference Include="Acr.Settings" Version="9.0.1" />
<PackageReference Include="Acr.UserDialogs" Version="7.2.0.562" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="TcpSharp" Version="1.3.6" />
<PackageReference Include="Zeroconf" Version="3.5.11" />
</ItemGroup>
</Project>