Essentials sample. (#393)
This commit is contained in:
Родитель
af6124c34a
Коммит
38f5f7f50a
|
@ -0,0 +1,26 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34219.65
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformIntegrationDemo", "PlatformIntegrationDemo\PlatformIntegrationDemo.csproj", "{1420EC25-7D89-4DB0-9D6B-D9A99F0D892E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1420EC25-7D89-4DB0-9D6B-D9A99F0D892E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1420EC25-7D89-4DB0-9D6B-D9A99F0D892E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1420EC25-7D89-4DB0-9D6B-D9A99F0D892E}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{1420EC25-7D89-4DB0-9D6B-D9A99F0D892E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1420EC25-7D89-4DB0-9D6B-D9A99F0D892E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E78EE56A-FD76-40CF-9335-6C4746F9AA6A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,28 @@
|
|||
<?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:converters="clr-namespace:PlatformIntegrationDemo.Converters"
|
||||
x:Class="PlatformIntegrationDemo.App">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<converters:InverterConverter x:Key="InverterConverter" />
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style TargetType="StackLayout">
|
||||
<Setter Property="Spacing"
|
||||
Value="6" />
|
||||
</Style>
|
||||
<Style TargetType="Grid">
|
||||
<Setter Property="RowSpacing"
|
||||
Value="6" />
|
||||
<Setter Property="ColumnSpacing"
|
||||
Value="6" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
|
@ -0,0 +1,33 @@
|
|||
using PlatformIntegrationDemo.Views;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
MainPage = new AppShell();
|
||||
}
|
||||
|
||||
public static void HandleAppActions(AppAction appAction)
|
||||
{
|
||||
App.Current.Dispatcher.Dispatch(async () =>
|
||||
{
|
||||
var page = appAction.Id switch
|
||||
{
|
||||
"battery_info" => new BatteryPage(),
|
||||
"app_info" => new AppInfoPage(),
|
||||
_ => default(Page)
|
||||
};
|
||||
|
||||
if (page != null)
|
||||
{
|
||||
await Application.Current.MainPage.Navigation.PopToRootAsync();
|
||||
await Application.Current.MainPage.Navigation.PushAsync(page);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<Shell
|
||||
x:Class="PlatformIntegrationDemo.AppShell"
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
Shell.FlyoutBehavior="Disabled"
|
||||
Title="PlatformIntegrationDemo">
|
||||
|
||||
<ShellContent
|
||||
Title="Home"
|
||||
ContentTemplate="{DataTemplate views:MainPage}"
|
||||
Route="MainPage" />
|
||||
|
||||
</Shell>
|
|
@ -0,0 +1,10 @@
|
|||
namespace PlatformIntegrationDemo;
|
||||
|
||||
public partial class AppShell : Shell
|
||||
{
|
||||
public AppShell()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using System.Globalization;
|
||||
|
||||
namespace PlatformIntegrationDemo.Converters
|
||||
{
|
||||
public class InverterConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool v)
|
||||
return !v;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool v)
|
||||
return !v;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
namespace PlatformIntegrationDemo.Helpers
|
||||
{
|
||||
public static class ViewHelpers
|
||||
{
|
||||
public static Rect GetAbsoluteBounds(this Microsoft.Maui.Controls.View element)
|
||||
{
|
||||
Element looper = element;
|
||||
|
||||
var absoluteX = element.X + element.Margin.Top;
|
||||
var absoluteY = element.Y + element.Margin.Left;
|
||||
|
||||
while (looper.Parent != null)
|
||||
{
|
||||
looper = looper.Parent;
|
||||
if (looper is Microsoft.Maui.Controls.View v)
|
||||
{
|
||||
absoluteX += v.X + v.Margin.Top;
|
||||
absoluteY += v.Y + v.Margin.Left;
|
||||
}
|
||||
}
|
||||
|
||||
return new Rect(absoluteX, absoluteY, element.Width, element.Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
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");
|
||||
})
|
||||
.ConfigureEssentials(essentials =>
|
||||
{
|
||||
essentials.UseVersionTracking();
|
||||
essentials.AddAppAction("app_info", "App Info", icon: "app_info_action_icon");
|
||||
essentials.AddAppAction("battery_info", "Battery Info");
|
||||
essentials.OnAppAction(App.HandleAppActions);
|
||||
#if WINDOWS
|
||||
essentials.UseMapServiceToken("INSERT_MAP_TOKEN_HERE");
|
||||
#endif
|
||||
});
|
||||
|
||||
#if DEBUG
|
||||
builder.Logging.AddDebug();
|
||||
#endif
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using PlatformIntegrationDemo.ViewModels;
|
||||
|
||||
namespace PlatformIntegrationDemo.Models
|
||||
{
|
||||
public class PermissionItem : ObservableObject
|
||||
{
|
||||
public PermissionItem(string title, Permissions.BasePermission permission)
|
||||
{
|
||||
Title = title;
|
||||
Permission = permission;
|
||||
Status = PermissionStatus.Unknown;
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Rationale { get; set; }
|
||||
|
||||
public PermissionStatus Status { get; set; }
|
||||
|
||||
public Permissions.BasePermission Permission { get; set; }
|
||||
|
||||
public ICommand CheckStatusCommand =>
|
||||
new Command(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Status = await Permission.CheckStatusAsync();
|
||||
OnPropertyChanged(nameof(Status));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(ex, nameof(PermissionException));
|
||||
}
|
||||
});
|
||||
|
||||
public ICommand RequestCommand =>
|
||||
new Command(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Status = await Permission.RequestAsync();
|
||||
OnPropertyChanged(nameof(Status));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(ex, nameof(PermissionException));
|
||||
}
|
||||
});
|
||||
|
||||
public ICommand ShouldShowRationaleCommand =>
|
||||
new Command(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Rationale = $"Should show rationale: {Permission.ShouldShowRationale()}";
|
||||
OnPropertyChanged(nameof(Rationale));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(ex, nameof(PermissionException));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
namespace PlatformIntegrationDemo.Models
|
||||
{
|
||||
public class SampleItem
|
||||
{
|
||||
public string Icon { get; }
|
||||
public string Name { get; }
|
||||
public string Description { get; }
|
||||
public Type PageType { get; }
|
||||
public string[] Tags { get; }
|
||||
|
||||
public SampleItem(string icon, string name, Type pageType, string description, params string[] tags)
|
||||
{
|
||||
Icon = icon;
|
||||
Name = name;
|
||||
Description = description;
|
||||
PageType = pageType;
|
||||
Tags = tags ?? new string[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<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 <RuntimeIdentifer>.
|
||||
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>PlatformIntegrationDemo</RootNamespace>
|
||||
<UseMaui>true</UseMaui>
|
||||
<SingleProject>true</SingleProject>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
||||
<!-- Display name -->
|
||||
<ApplicationTitle>PlatformIntegrationDemo</ApplicationTitle>
|
||||
|
||||
<!-- App Identifier -->
|
||||
<ApplicationId>com.companyname.platformintegrationdemo</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 -->
|
||||
<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="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\Images\app_info_action_icon.png" />
|
||||
<BundleResource Include="Resources\Images\battery_action_icon.png" />
|
||||
<BundleResource Include="Resources\Raw\FileSystemTemplate.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,54 @@
|
|||
<?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" android:fullBackupContent="@xml/my_backup_rules"></application>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.FLASHLIGHT" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<queries>
|
||||
<!-- Email -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.SENDTO" />
|
||||
<data android:scheme="mailto" />
|
||||
</intent>
|
||||
<!-- Browser -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="http" />
|
||||
</intent>
|
||||
<!-- Browser -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
<!-- Sms -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="smsto" />
|
||||
</intent>
|
||||
<!-- PhoneDialer -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.DIAL" />
|
||||
<data android:scheme="tel" />
|
||||
</intent>
|
||||
<!-- MediaPicker -->
|
||||
<intent>
|
||||
<action android:name="android.media.action.IMAGE_CAPTURE" />
|
||||
</intent>
|
||||
<!-- Maps -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="geo" />
|
||||
</intent>
|
||||
</queries>
|
||||
<uses-feature android:name="android.hardware.location" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.location.network" android:required="false" />
|
||||
</manifest>
|
|
@ -0,0 +1,62 @@
|
|||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using Android.Widget;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density, ScreenOrientation = ScreenOrientation.FullSensor)]
|
||||
[IntentFilter(
|
||||
new[] { Microsoft.Maui.ApplicationModel.Platform.Intent.ActionAppAction },
|
||||
Categories = new[] { Intent.CategoryDefault })]
|
||||
public class MainActivity : MauiAppCompatActivity
|
||||
{
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
base.OnCreate(bundle);
|
||||
|
||||
Microsoft.Maui.ApplicationModel.Platform.Init(this, bundle);
|
||||
Microsoft.Maui.ApplicationModel.Platform.ActivityStateChanged += Platform_ActivityStateChanged;
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
|
||||
Microsoft.Maui.ApplicationModel.Platform.OnResume(this);
|
||||
}
|
||||
|
||||
protected override void OnNewIntent(Intent intent)
|
||||
{
|
||||
base.OnNewIntent(intent);
|
||||
|
||||
Microsoft.Maui.ApplicationModel.Platform.OnNewIntent(intent);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
Microsoft.Maui.ApplicationModel.Platform.ActivityStateChanged -= Platform_ActivityStateChanged;
|
||||
}
|
||||
|
||||
void Platform_ActivityStateChanged(object sender, Microsoft.Maui.ApplicationModel.ActivityStateChangedEventArgs e) =>
|
||||
Toast.MakeText(this, e.State.ToString(), ToastLength.Short).Show();
|
||||
|
||||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
|
||||
{
|
||||
Microsoft.Maui.ApplicationModel.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
||||
|
||||
[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
|
||||
[IntentFilter(
|
||||
new[] { Intent.ActionView },
|
||||
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
|
||||
DataScheme = "xamarinessentials")]
|
||||
public class WebAuthenticationCallbackActivity : Microsoft.Maui.Authentication.WebAuthenticatorCallbackActivity
|
||||
{
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using Android.App;
|
||||
using Android.Runtime;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
[Application]
|
||||
public class MainApplication : MauiApplication
|
||||
{
|
||||
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
|
||||
: base(handle, ownership)
|
||||
{
|
||||
}
|
||||
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#512BD4</color>
|
||||
<color name="colorPrimaryDark">#2B0B98</color>
|
||||
<color name="colorAccent">#2B0B98</color>
|
||||
</resources>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<full-backup-content>
|
||||
<include domain="sharedpref" path="."/>
|
||||
<exclude domain="sharedpref" path="${applicationId}.xamarinessentials.xml"/>
|
||||
</full-backup-content>
|
|
@ -0,0 +1,10 @@
|
|||
using Foundation;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
[Register("AppDelegate")]
|
||||
public class AppDelegate : MauiUIApplicationDelegate
|
||||
{
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<?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>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Access to your location is required for cool things to happen!</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>xamarinessentials</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>xamarinessentials</string>
|
||||
</array>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Camera Photos</string>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>Calendar Access</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>Get Location</string>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
<string>Get Location</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Pick Photos</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Pick Photos</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Catpure Video</string>
|
||||
<key>NSContactsUsageDescription</key>
|
||||
<string>Contacts</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>mailto</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,16 @@
|
|||
using ObjCRuntime;
|
||||
using UIKit;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using Microsoft.Maui;
|
||||
using Microsoft.Maui.Hosting;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
class Program : MauiApplication
|
||||
{
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var app = new Program();
|
||||
app.Run(args);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="maui-application-id-placeholder" version="0.0.0" api-version="7" xmlns="http://tizen.org/ns/packages">
|
||||
<profile name="common" />
|
||||
<ui-application appid="maui-application-id-placeholder" exec="PlatformIntegrationDemo.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>
|
|
@ -0,0 +1,8 @@
|
|||
<maui:MauiWinUIApplication
|
||||
x:Class="PlatformIntegrationDemo.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:PlatformIntegrationDemo.WinUI">
|
||||
|
||||
</maui:MauiWinUIApplication>
|
|
@ -0,0 +1,25 @@
|
|||
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 PlatformIntegrationDemo.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();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?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="2C7A2684-B1EA-4BBF-8818-A199BFB9D3AA" 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>
|
||||
<Extensions>
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="xamarinessentials">
|
||||
<uap:DisplayName>Xamarin Essentials</uap:DisplayName>
|
||||
</uap:Protocol>
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
|
||||
</Package>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?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="PlatformIntegrationDemo.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>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using Foundation;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
[Register("AppDelegate")]
|
||||
public class AppDelegate : MauiUIApplicationDelegate
|
||||
{
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?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>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)$(CFBundleIdentifier)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,67 @@
|
|||
<?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>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Access to your location is required for cool things to happen!</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>xamarinessentials</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>xamarinessentials</string>
|
||||
</array>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Camera Photos</string>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>Calendar Access</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>Get Location</string>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
<string>Get Location</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Add Photos</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Pick Photos</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Catpure Video</string>
|
||||
<key>NSContactsUsageDescription</key>
|
||||
<string>Contacts</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>mailto</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,16 @@
|
|||
using ObjCRuntime;
|
||||
using UIKit;
|
||||
|
||||
namespace PlatformIntegrationDemo;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profiles": {
|
||||
"Windows Machine": {
|
||||
"commandName": "MsixPackage",
|
||||
"nativeDebugging": false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?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>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?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>
|
Двоичные данные
8.0/PlatformIntegration/PlatformIntegrationDemos/PlatformIntegrationDemo/Resources/Fonts/OpenSans-Regular.ttf
Normal file
Двоичные данные
8.0/PlatformIntegration/PlatformIntegrationDemos/PlatformIntegrationDemo/Resources/Fonts/OpenSans-Regular.ttf
Normal file
Двоичный файл не отображается.
Двоичные данные
8.0/PlatformIntegration/PlatformIntegrationDemos/PlatformIntegrationDemo/Resources/Fonts/OpenSans-Semibold.ttf
Normal file
Двоичные данные
8.0/PlatformIntegration/PlatformIntegrationDemos/PlatformIntegrationDemo/Resources/Fonts/OpenSans-Semibold.ttf
Normal file
Двоичный файл не отображается.
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 4.7 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.9 KiB |
|
@ -0,0 +1,18 @@
|
|||
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 you 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();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
This file was loaded from the app package.
|
||||
|
||||
You can use this as a starting point for your comments...
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?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>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?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="Secondary">#DFD8F7</Color>
|
||||
<Color x:Key="Tertiary">#2B0B98</Color>
|
||||
<Color x:Key="White">White</Color>
|
||||
<Color x:Key="Black">Black</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}"/>
|
||||
|
||||
<Color x:Key="Yellow100Accent">#F7B548</Color>
|
||||
<Color x:Key="Yellow200Accent">#FFD590</Color>
|
||||
<Color x:Key="Yellow300Accent">#FFE5B9</Color>
|
||||
<Color x:Key="Cyan100Accent">#28C2D1</Color>
|
||||
<Color x:Key="Cyan200Accent">#7BDDEF</Color>
|
||||
<Color x:Key="Cyan300Accent">#C3F2F4</Color>
|
||||
<Color x:Key="Blue100Accent">#3E8EED</Color>
|
||||
<Color x:Key="Blue200Accent">#72ACF1</Color>
|
||||
<Color x:Key="Blue300Accent">#A7CBF6</Color>
|
||||
|
||||
</ResourceDictionary>
|
|
@ -0,0 +1,408 @@
|
|||
<?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 Primary}}" />
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<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" />
|
||||
</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 Gray900}, 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="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 Black}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Shell" ApplyToDerivedTypes="True">
|
||||
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource Gray950}}" />
|
||||
<Setter Property="Shell.ForegroundColor" Value="{OnPlatform WinUI={StaticResource Primary}, Default={StaticResource White}}" />
|
||||
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
|
||||
<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 Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Primary}, 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 Primary}, Dark={StaticResource Gray950}}" />
|
||||
<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 Primary}, 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>
|
|
@ -0,0 +1,134 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class AccelerometerViewModel : BaseViewModel
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
string shakeTime = string.Empty;
|
||||
bool isActive;
|
||||
int speed = 0;
|
||||
|
||||
public AccelerometerViewModel()
|
||||
{
|
||||
StartCommand = new Command(OnStart);
|
||||
StopCommand = new Command(OnStop);
|
||||
}
|
||||
|
||||
public ICommand StartCommand { get; }
|
||||
|
||||
public ICommand StopCommand { get; }
|
||||
|
||||
public string ShakeTime
|
||||
{
|
||||
get => shakeTime;
|
||||
set => SetProperty(ref shakeTime, value);
|
||||
}
|
||||
|
||||
public double X
|
||||
{
|
||||
get => x;
|
||||
set => SetProperty(ref x, value);
|
||||
}
|
||||
|
||||
public double Y
|
||||
{
|
||||
get => y;
|
||||
set => SetProperty(ref y, value);
|
||||
}
|
||||
|
||||
public double Z
|
||||
{
|
||||
get => z;
|
||||
set => SetProperty(ref z, value);
|
||||
}
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => isActive;
|
||||
set => SetProperty(ref isActive, value);
|
||||
}
|
||||
|
||||
public string[] Speeds { get; } =
|
||||
Enum.GetNames(typeof(SensorSpeed));
|
||||
|
||||
public int Speed
|
||||
{
|
||||
get => speed;
|
||||
set => SetProperty(ref speed, value);
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
Accelerometer.ReadingChanged += OnReadingChanged;
|
||||
Accelerometer.ShakeDetected += Accelerometer_OnShaked;
|
||||
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
void Accelerometer_OnShaked(object sender, EventArgs e) =>
|
||||
ShakeTime = $"Shake detected: {DateTime.Now.ToLongTimeString()}";
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnStop();
|
||||
|
||||
Accelerometer.ReadingChanged -= OnReadingChanged;
|
||||
Accelerometer.ShakeDetected -= Accelerometer_OnShaked;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
async void OnStart()
|
||||
{
|
||||
try
|
||||
{
|
||||
Accelerometer.Start((SensorSpeed)Speed);
|
||||
IsActive = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable to start accelerometer: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnStop()
|
||||
{
|
||||
try
|
||||
{
|
||||
Accelerometer.Stop();
|
||||
IsActive = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Unable to stop accelerometer: {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
void OnReadingChanged(object sender, AccelerometerChangedEventArgs e)
|
||||
{
|
||||
var data = e.Reading;
|
||||
switch ((SensorSpeed)Speed)
|
||||
{
|
||||
case SensorSpeed.Fastest:
|
||||
case SensorSpeed.Game:
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
X = data.Acceleration.X;
|
||||
Y = data.Acceleration.Y;
|
||||
Z = data.Acceleration.Z;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
X = data.Acceleration.X;
|
||||
Y = data.Acceleration.Y;
|
||||
Z = data.Acceleration.Z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class AppInfoViewModel : BaseViewModel
|
||||
{
|
||||
public string AppPackageName => AppInfo.PackageName;
|
||||
public string AppName => AppInfo.Name;
|
||||
public string AppVersion => AppInfo.VersionString;
|
||||
public string AppBuild => AppInfo.BuildString;
|
||||
public string AppTheme => AppInfo.RequestedTheme.ToString();
|
||||
public Command ShowSettingsUICommand { get; }
|
||||
|
||||
public AppInfoViewModel()
|
||||
{
|
||||
ShowSettingsUICommand = new Command(() => AppInfo.ShowSettingsUI());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class BarometerViewModel : BaseViewModel
|
||||
{
|
||||
bool isActive;
|
||||
double pressure;
|
||||
int speed = 0;
|
||||
|
||||
public BarometerViewModel()
|
||||
{
|
||||
StartCommand = new Command(OnStartBarometer);
|
||||
StopCommand = new Command(OnStop);
|
||||
}
|
||||
|
||||
public ICommand StartCommand { get; }
|
||||
|
||||
public ICommand StopCommand { get; }
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => isActive;
|
||||
set => SetProperty(ref isActive, value);
|
||||
}
|
||||
|
||||
public double Pressure
|
||||
{
|
||||
get => pressure;
|
||||
set => SetProperty(ref pressure, value);
|
||||
}
|
||||
|
||||
public string[] Speeds { get; } = Enum.GetNames(typeof(SensorSpeed));
|
||||
|
||||
public int Speed
|
||||
{
|
||||
get => speed;
|
||||
set => SetProperty(ref speed, value);
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
Barometer.ReadingChanged += OnBarometerReadingChanged;
|
||||
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnStop();
|
||||
|
||||
Barometer.ReadingChanged -= OnBarometerReadingChanged;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
async void OnStartBarometer()
|
||||
{
|
||||
try
|
||||
{
|
||||
Barometer.Start((SensorSpeed)Speed);
|
||||
IsActive = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable to start barometer: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnStop()
|
||||
{
|
||||
try
|
||||
{
|
||||
Barometer.Stop();
|
||||
IsActive = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Unable to stop barometer: {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
void OnBarometerReadingChanged(object sender, BarometerChangedEventArgs e)
|
||||
{
|
||||
Pressure = e.Reading.PressureInHectopascals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class BaseViewModel : ObservableObject
|
||||
{
|
||||
bool isBusy;
|
||||
|
||||
public bool IsBusy
|
||||
{
|
||||
get => isBusy;
|
||||
set => SetProperty(ref isBusy, value, onChanged: () => OnPropertyChanged(nameof(IsNotBusy)));
|
||||
}
|
||||
|
||||
public bool IsNotBusy => !IsBusy;
|
||||
|
||||
public virtual void OnAppearing()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnDisappearing()
|
||||
{
|
||||
}
|
||||
|
||||
internal event Func<string, Task> DoDisplayAlert;
|
||||
|
||||
internal event Func<BaseViewModel, bool, Task> DoNavigate;
|
||||
|
||||
public Task DisplayAlertAsync(string message)
|
||||
{
|
||||
return DoDisplayAlert?.Invoke(message) ?? Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task NavigateAsync(BaseViewModel vm, bool showModal = false)
|
||||
{
|
||||
return DoNavigate?.Invoke(vm, showModal) ?? Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class BatteryViewModel : BaseViewModel
|
||||
{
|
||||
public BatteryViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public double Level => Battery.ChargeLevel;
|
||||
|
||||
public BatteryState State => Battery.State;
|
||||
|
||||
public BatteryPowerSource PowerSource => Battery.PowerSource;
|
||||
|
||||
public EnergySaverStatus EnergySaverStatus => Battery.EnergySaverStatus;
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
|
||||
Battery.BatteryInfoChanged += OnBatteryInfoChanged;
|
||||
Battery.EnergySaverStatusChanged += OnEnergySaverStatusChanged;
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
Battery.BatteryInfoChanged -= OnBatteryInfoChanged;
|
||||
Battery.EnergySaverStatusChanged -= OnEnergySaverStatusChanged;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
void OnEnergySaverStatusChanged(object sender, EnergySaverStatusChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(EnergySaverStatus));
|
||||
}
|
||||
|
||||
void OnBatteryInfoChanged(object sender, BatteryInfoChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(Level));
|
||||
OnPropertyChanged(nameof(State));
|
||||
OnPropertyChanged(nameof(PowerSource));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class BrowserViewModel : BaseViewModel
|
||||
{
|
||||
string browserStatus;
|
||||
string uri = "https://learn.microsoft.com/dotnet/maui";
|
||||
int browserType = (int)BrowserLaunchMode.SystemPreferred;
|
||||
int browserTitleType = (int)BrowserTitleMode.Default;
|
||||
int controlColor = 0;
|
||||
int toolbarColor = 0;
|
||||
bool presentAsFormSheet = false;
|
||||
bool presentAsPageSheet = false;
|
||||
bool launchAdjacent = false;
|
||||
|
||||
Dictionary<string, Color> colorDictionary;
|
||||
|
||||
public List<string> AllColors { get; }
|
||||
|
||||
public BrowserViewModel()
|
||||
{
|
||||
OpenUriCommand = new Command(OpenUri);
|
||||
|
||||
colorDictionary = typeof(Color)
|
||||
.GetFields()
|
||||
.Where(f => f.FieldType == typeof(Color) && f.IsStatic && f.IsPublic)
|
||||
.ToDictionary(f => f.Name, f => (Color)f.GetValue(null));
|
||||
|
||||
var colors = colorDictionary.Keys.ToList();
|
||||
colors.Insert(0, "None");
|
||||
|
||||
AllColors = colors;
|
||||
}
|
||||
|
||||
public ICommand OpenUriCommand { get; }
|
||||
|
||||
public string BrowserStatus
|
||||
{
|
||||
get => browserStatus;
|
||||
set => SetProperty(ref browserStatus, value);
|
||||
}
|
||||
|
||||
public string Uri
|
||||
{
|
||||
get => uri;
|
||||
set => SetProperty(ref uri, value);
|
||||
}
|
||||
|
||||
public List<string> BrowserLaunchModes { get; } =
|
||||
new List<string>
|
||||
{
|
||||
$"Use System-Preferred Browser",
|
||||
$"Use Default Browser App"
|
||||
};
|
||||
|
||||
public int BrowserType
|
||||
{
|
||||
get => browserType;
|
||||
set => SetProperty(ref browserType, value);
|
||||
}
|
||||
|
||||
public List<string> BrowserTitleModes { get; } =
|
||||
new List<string>
|
||||
{
|
||||
$"Use Default Mode",
|
||||
$"Show Title",
|
||||
$"Hide Title"
|
||||
};
|
||||
|
||||
public int BrowserTitleType
|
||||
{
|
||||
get => browserTitleType;
|
||||
set => SetProperty(ref browserTitleType, value);
|
||||
}
|
||||
|
||||
public int ToolbarColor
|
||||
{
|
||||
get => toolbarColor;
|
||||
set => SetProperty(ref toolbarColor, value);
|
||||
}
|
||||
|
||||
public int ControlColor
|
||||
{
|
||||
get => controlColor;
|
||||
set => SetProperty(ref controlColor, value);
|
||||
}
|
||||
|
||||
public bool PresentAsFormSheet
|
||||
{
|
||||
get => presentAsFormSheet;
|
||||
set => SetProperty(ref presentAsFormSheet, value);
|
||||
}
|
||||
|
||||
public bool PresentAsPageSheet
|
||||
{
|
||||
get => presentAsPageSheet;
|
||||
set => SetProperty(ref presentAsPageSheet, value);
|
||||
}
|
||||
|
||||
public bool LaunchAdjacent
|
||||
{
|
||||
get => launchAdjacent;
|
||||
set => SetProperty(ref launchAdjacent, value);
|
||||
}
|
||||
|
||||
async void OpenUri()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
var flags = BrowserLaunchFlags.None;
|
||||
if (PresentAsPageSheet)
|
||||
flags |= BrowserLaunchFlags.PresentAsPageSheet;
|
||||
if (PresentAsFormSheet)
|
||||
flags |= BrowserLaunchFlags.PresentAsFormSheet;
|
||||
if (LaunchAdjacent)
|
||||
flags |= BrowserLaunchFlags.LaunchAdjacent;
|
||||
|
||||
await Browser.OpenAsync(uri, new BrowserLaunchOptions
|
||||
{
|
||||
LaunchMode = (BrowserLaunchMode)BrowserType,
|
||||
TitleMode = (BrowserTitleMode)BrowserTitleType,
|
||||
PreferredToolbarColor = GetColor(ToolbarColor),
|
||||
PreferredControlColor = GetColor(ControlColor),
|
||||
Flags = flags
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BrowserStatus = $"Unable to open Uri {e.Message}";
|
||||
Debug.WriteLine(browserStatus);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
Color GetColor(int index)
|
||||
{
|
||||
return index <= 0
|
||||
? (Color)null
|
||||
: colorDictionary[AllColors[index]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
class ClipboardViewModel : BaseViewModel
|
||||
{
|
||||
string fieldValue;
|
||||
string lastCopied;
|
||||
|
||||
public ClipboardViewModel()
|
||||
{
|
||||
CopyCommand = new Command(OnCopy);
|
||||
PasteCommand = new Command(OnPaste);
|
||||
CheckCommand = new Command(OnCheck);
|
||||
}
|
||||
|
||||
public ICommand CopyCommand { get; }
|
||||
|
||||
public ICommand PasteCommand { get; }
|
||||
|
||||
public ICommand CheckCommand { get; }
|
||||
|
||||
public string FieldValue
|
||||
{
|
||||
get => fieldValue;
|
||||
set => SetProperty(ref fieldValue, value);
|
||||
}
|
||||
|
||||
public string LastCopied
|
||||
{
|
||||
get => lastCopied;
|
||||
set => SetProperty(ref lastCopied, value);
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
try
|
||||
{
|
||||
Clipboard.ClipboardContentChanged += OnClipboardContentChanged;
|
||||
}
|
||||
catch (FeatureNotSupportedException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
try
|
||||
{
|
||||
Clipboard.ClipboardContentChanged -= OnClipboardContentChanged;
|
||||
}
|
||||
catch (FeatureNotSupportedException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void OnClipboardContentChanged(object sender, EventArgs args)
|
||||
{
|
||||
LastCopied = $"Last copied text at {DateTime.UtcNow:T}";
|
||||
}
|
||||
|
||||
async void OnCopy()
|
||||
{
|
||||
await Clipboard.SetTextAsync(FieldValue);
|
||||
}
|
||||
|
||||
async void OnPaste()
|
||||
{
|
||||
var text = await Clipboard.GetTextAsync();
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
FieldValue = text;
|
||||
}
|
||||
}
|
||||
|
||||
async void OnCheck()
|
||||
{
|
||||
await DisplayAlertAsync($"Has text: {Clipboard.HasText}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class ColorConvertersViewModel : BaseViewModel
|
||||
{
|
||||
int alpha = 100;
|
||||
int saturation = 100;
|
||||
int hue = 360;
|
||||
int luminosity = 100;
|
||||
string hex = "#3498db";
|
||||
|
||||
public ColorConvertersViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public int Alpha
|
||||
{
|
||||
get => alpha;
|
||||
set => SetProperty(ref alpha, value, onChanged: SetColor);
|
||||
}
|
||||
|
||||
public int Luminosity
|
||||
{
|
||||
get => luminosity;
|
||||
set => SetProperty(ref luminosity, value, onChanged: SetColor);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => hue;
|
||||
set => SetProperty(ref hue, value, onChanged: SetColor);
|
||||
}
|
||||
|
||||
public int Saturation
|
||||
{
|
||||
get => saturation;
|
||||
set => SetProperty(ref saturation, value, onChanged: SetColor);
|
||||
}
|
||||
|
||||
public string Hex
|
||||
{
|
||||
get => hex;
|
||||
set => SetProperty(ref hex, value, onChanged: SetColor);
|
||||
}
|
||||
|
||||
public Color RegularColor { get; set; }
|
||||
|
||||
public Color AlphaColor { get; set; }
|
||||
|
||||
public Color SaturationColor { get; set; }
|
||||
|
||||
public Color HueColor { get; set; }
|
||||
|
||||
public Color ComplementColor { get; set; }
|
||||
|
||||
public Color LuminosityColor { get; set; }
|
||||
|
||||
public string ComplementHex { get; set; }
|
||||
|
||||
async void SetColor()
|
||||
{
|
||||
try
|
||||
{
|
||||
var color = Color.FromArgb(Hex);
|
||||
|
||||
RegularColor = color;
|
||||
AlphaColor = color.WithAlpha(Alpha / 255f);
|
||||
SaturationColor = color.WithSaturation(Saturation / 100f);
|
||||
HueColor = color.WithHue(Hue / 255f);
|
||||
LuminosityColor = color.WithLuminosity(Luminosity / 100f);
|
||||
ComplementColor = color.GetComplementary();
|
||||
ComplementHex = ComplementColor.ToHex();
|
||||
|
||||
OnPropertyChanged(nameof(RegularColor));
|
||||
OnPropertyChanged(nameof(AlphaColor));
|
||||
OnPropertyChanged(nameof(SaturationColor));
|
||||
OnPropertyChanged(nameof(HueColor));
|
||||
OnPropertyChanged(nameof(ComplementColor));
|
||||
OnPropertyChanged(nameof(LuminosityColor));
|
||||
OnPropertyChanged(nameof(ComplementHex));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable to convert colors: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
class CompassViewModel : BaseViewModel
|
||||
{
|
||||
bool isActive;
|
||||
bool applyLowPassFilter;
|
||||
double heading;
|
||||
int speed = 0;
|
||||
|
||||
public CompassViewModel()
|
||||
{
|
||||
StartCommand = new Command(OnStart);
|
||||
StopCommand = new Command(OnStop);
|
||||
}
|
||||
|
||||
public ICommand StartCommand { get; }
|
||||
|
||||
public ICommand StopCommand { get; }
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => isActive;
|
||||
set => SetProperty(ref isActive, value);
|
||||
}
|
||||
|
||||
public bool ApplyLowPassFilter
|
||||
{
|
||||
get => applyLowPassFilter;
|
||||
set => SetProperty(ref applyLowPassFilter, value);
|
||||
}
|
||||
|
||||
public double Heading
|
||||
{
|
||||
get => heading;
|
||||
set => SetProperty(ref heading, value);
|
||||
}
|
||||
|
||||
public int Speed
|
||||
{
|
||||
get => speed;
|
||||
set => SetProperty(ref speed, value);
|
||||
}
|
||||
|
||||
public string[] Speeds { get; } =
|
||||
Enum.GetNames(typeof(SensorSpeed));
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
Compass.ReadingChanged += OnCompassReadingChanged;
|
||||
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnStop();
|
||||
|
||||
Compass.ReadingChanged -= OnCompassReadingChanged;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
async void OnStart()
|
||||
{
|
||||
try
|
||||
{
|
||||
Compass.Start((SensorSpeed)Speed, ApplyLowPassFilter);
|
||||
IsActive = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable to start compass: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnStop()
|
||||
{
|
||||
try
|
||||
{
|
||||
Compass.Stop();
|
||||
IsActive = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Unable to stop compass: {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
void OnCompassReadingChanged(object sender, CompassChangedEventArgs e)
|
||||
{
|
||||
switch ((SensorSpeed)Speed)
|
||||
{
|
||||
case SensorSpeed.Fastest:
|
||||
case SensorSpeed.Game:
|
||||
MainThread.BeginInvokeOnMainThread(() => Heading = e.Reading.HeadingMagneticNorth);
|
||||
break;
|
||||
default:
|
||||
Heading = e.Reading.HeadingMagneticNorth;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class ConnectivityViewModel : BaseViewModel
|
||||
{
|
||||
public string NetworkAccess =>
|
||||
Connectivity.NetworkAccess.ToString();
|
||||
|
||||
public string ConnectionProfiles
|
||||
{
|
||||
get
|
||||
{
|
||||
var profiles = string.Empty;
|
||||
foreach (var p in Connectivity.ConnectionProfiles)
|
||||
profiles += "\n" + p.ToString();
|
||||
return profiles;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
|
||||
Connectivity.ConnectivityChanged += OnConnectivityChanged;
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
Connectivity.ConnectivityChanged -= OnConnectivityChanged;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
void OnConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(ConnectionProfiles));
|
||||
OnPropertyChanged(nameof(NetworkAccess));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
class ContactDetailsViewModel : BaseViewModel
|
||||
{
|
||||
public ContactDetailsViewModel(Contact contact)
|
||||
{
|
||||
Contact = contact;
|
||||
}
|
||||
|
||||
public Contact Contact { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Windows.Input;
|
||||
using ContactsManager = Microsoft.Maui.ApplicationModel.Communication.Contacts;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
class ContactsViewModel : BaseViewModel
|
||||
{
|
||||
Contact selectedContact;
|
||||
|
||||
public ContactsViewModel()
|
||||
{
|
||||
GetContactCommand = new Command(OnGetContact);
|
||||
GetAllContactCommand = new Command(OnGetAllContact);
|
||||
}
|
||||
|
||||
public ICommand GetContactCommand { get; }
|
||||
|
||||
public ICommand GetAllContactCommand { get; }
|
||||
|
||||
public ObservableCollection<Contact> ContactsList { get; } = new ObservableCollection<Contact>();
|
||||
|
||||
public Contact SelectedContact
|
||||
{
|
||||
get => selectedContact;
|
||||
set => SetProperty(ref selectedContact, value, onChanged: OnContactSelected);
|
||||
}
|
||||
|
||||
async void OnGetContact()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
IsBusy = true;
|
||||
|
||||
try
|
||||
{
|
||||
var contact = await ContactsManager.PickContactAsync();
|
||||
if (contact == null)
|
||||
return;
|
||||
|
||||
var details = new ContactDetailsViewModel(contact);
|
||||
await NavigateAsync(details);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MainThread.BeginInvokeOnMainThread(async () => await DisplayAlertAsync($"Error:{ex.Message}"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
async void OnGetAllContact()
|
||||
{
|
||||
if (await Permissions.RequestAsync<Permissions.ContactsRead>() != PermissionStatus.Granted)
|
||||
return;
|
||||
|
||||
if (IsBusy)
|
||||
return;
|
||||
IsBusy = true;
|
||||
|
||||
ContactsList.Clear();
|
||||
try
|
||||
{
|
||||
var contacts = await ContactsManager.GetAllAsync();
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
foreach (var contact in contacts)
|
||||
{
|
||||
MainThread.BeginInvokeOnMainThread(() => ContactsList.Add(contact));
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Error:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
async void OnContactSelected()
|
||||
{
|
||||
if (SelectedContact == null)
|
||||
return;
|
||||
|
||||
var details = new ContactDetailsViewModel(SelectedContact);
|
||||
|
||||
SelectedContact = null;
|
||||
|
||||
await NavigateAsync(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class DeviceInfoViewModel : BaseViewModel
|
||||
{
|
||||
DisplayInfo screenMetrics;
|
||||
|
||||
public string Model => DeviceInfo.Model;
|
||||
|
||||
public string Manufacturer => DeviceInfo.Manufacturer;
|
||||
|
||||
public string Name => DeviceInfo.Name;
|
||||
|
||||
public string VersionString => DeviceInfo.VersionString;
|
||||
|
||||
public string Version => DeviceInfo.Version.ToString();
|
||||
|
||||
public DevicePlatform Platform => DeviceInfo.Platform;
|
||||
|
||||
public DeviceIdiom Idiom => DeviceInfo.Idiom;
|
||||
|
||||
public DeviceType DeviceType => DeviceInfo.DeviceType;
|
||||
|
||||
public double Rotation =>
|
||||
ScreenMetrics.Rotation switch
|
||||
{
|
||||
DisplayRotation.Rotation0 => 0,
|
||||
DisplayRotation.Rotation90 => -90,
|
||||
DisplayRotation.Rotation180 => -180,
|
||||
DisplayRotation.Rotation270 => -270,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
public DisplayInfo ScreenMetrics
|
||||
{
|
||||
get => screenMetrics;
|
||||
set => SetProperty(ref screenMetrics, value, onChanged: () => OnPropertyChanged(nameof(Rotation)));
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
|
||||
DeviceDisplay.MainDisplayInfoChanged += OnScreenMetricsChanged;
|
||||
ScreenMetrics = DeviceDisplay.MainDisplayInfo;
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
DeviceDisplay.MainDisplayInfoChanged -= OnScreenMetricsChanged;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
void OnScreenMetricsChanged(object sender, DisplayInfoChangedEventArgs e)
|
||||
{
|
||||
ScreenMetrics = e.DisplayInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class EmailViewModel : BaseViewModel
|
||||
{
|
||||
string subject = "Hello World!";
|
||||
string body = "This is the email body.\nWe hope you like it!";
|
||||
string recipientsTo = "someone@example.org";
|
||||
string recipientsCc;
|
||||
string recipientsBcc;
|
||||
string attachmentContents;
|
||||
string attachmentName;
|
||||
bool hasMultipleAttachements;
|
||||
bool isHtml;
|
||||
|
||||
public EmailViewModel()
|
||||
{
|
||||
SendEmailCommand = new Command(OnSendEmail);
|
||||
}
|
||||
|
||||
public ICommand SendEmailCommand { get; }
|
||||
|
||||
public string Subject
|
||||
{
|
||||
get => subject;
|
||||
set => SetProperty(ref subject, value);
|
||||
}
|
||||
|
||||
public string Body
|
||||
{
|
||||
get => body;
|
||||
set => SetProperty(ref body, value);
|
||||
}
|
||||
|
||||
public string RecipientsTo
|
||||
{
|
||||
get => recipientsTo;
|
||||
set => SetProperty(ref recipientsTo, value);
|
||||
}
|
||||
|
||||
public string RecipientsCc
|
||||
{
|
||||
get => recipientsCc;
|
||||
set => SetProperty(ref recipientsCc, value);
|
||||
}
|
||||
|
||||
public string RecipientsBcc
|
||||
{
|
||||
get => recipientsBcc;
|
||||
set => SetProperty(ref recipientsBcc, value);
|
||||
}
|
||||
|
||||
public string AttachmentContents
|
||||
{
|
||||
get => attachmentContents;
|
||||
set => SetProperty(ref attachmentContents, value);
|
||||
}
|
||||
|
||||
public string AttachmentName
|
||||
{
|
||||
get => attachmentName;
|
||||
set => SetProperty(ref attachmentName, value);
|
||||
}
|
||||
|
||||
public bool HasMultipleAttachements
|
||||
{
|
||||
get => hasMultipleAttachements;
|
||||
set => SetProperty(ref hasMultipleAttachements, value);
|
||||
}
|
||||
|
||||
public bool IsHtml
|
||||
{
|
||||
get => isHtml;
|
||||
set => SetProperty(ref isHtml, value);
|
||||
}
|
||||
|
||||
async void OnSendEmail()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
var message = new EmailMessage
|
||||
{
|
||||
Subject = Subject,
|
||||
Body = Body,
|
||||
BodyFormat = isHtml ? EmailBodyFormat.Html : EmailBodyFormat.PlainText,
|
||||
To = Split(RecipientsTo),
|
||||
Cc = Split(RecipientsCc),
|
||||
Bcc = Split(RecipientsBcc),
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(AttachmentName) || !string.IsNullOrWhiteSpace(AttachmentContents))
|
||||
{
|
||||
// create a temprary file
|
||||
var fn = string.IsNullOrWhiteSpace(AttachmentName) ? "Attachment.txt" : AttachmentName.Trim();
|
||||
var file = Path.Combine(FileSystem.CacheDirectory, fn);
|
||||
File.WriteAllText(file, AttachmentContents);
|
||||
|
||||
message.Attachments.Add(new EmailAttachment(file));
|
||||
|
||||
if (HasMultipleAttachements)
|
||||
{
|
||||
fn = "1" + fn;
|
||||
file = Path.Combine(FileSystem.CacheDirectory, fn);
|
||||
File.WriteAllText(file, AttachmentContents);
|
||||
|
||||
message.Attachments.Add(new EmailAttachment(file));
|
||||
}
|
||||
}
|
||||
|
||||
await Email.ComposeAsync(message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
List<string> Split(string recipients)
|
||||
=> recipients?.Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries)?.ToList();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class FilePickerViewModel : BaseViewModel
|
||||
{
|
||||
string text;
|
||||
ImageSource image;
|
||||
bool isImageVisible;
|
||||
|
||||
public FilePickerViewModel()
|
||||
{
|
||||
PickFileCommand = new Command(() => DoPickFile());
|
||||
PickImageCommand = new Command(() => DoPickImage());
|
||||
PickPdfCommand = new Command(() => DoPickPdf());
|
||||
PickCustomTypeCommand = new Command(() => DoPickCustomType());
|
||||
PickAndSendCommand = new Command(() => DoPickAndSend());
|
||||
PickMultipleFilesCommand = new Command(() => DoPickMultipleFiles());
|
||||
}
|
||||
|
||||
public ICommand PickFileCommand { get; }
|
||||
|
||||
public ICommand PickImageCommand { get; }
|
||||
|
||||
public ICommand PickPdfCommand { get; }
|
||||
|
||||
public ICommand PickCustomTypeCommand { get; }
|
||||
|
||||
public ICommand PickAndSendCommand { get; }
|
||||
|
||||
public ICommand PickMultipleFilesCommand { get; }
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => text;
|
||||
set => SetProperty(ref text, value);
|
||||
}
|
||||
|
||||
public ImageSource Image
|
||||
{
|
||||
get => image;
|
||||
set => SetProperty(ref image, value);
|
||||
}
|
||||
|
||||
public bool IsImageVisible
|
||||
{
|
||||
get => isImageVisible;
|
||||
set => SetProperty(ref isImageVisible, value);
|
||||
}
|
||||
|
||||
async void DoPickFile()
|
||||
{
|
||||
await PickAndShow(PickOptions.Default);
|
||||
}
|
||||
|
||||
async void DoPickImage()
|
||||
{
|
||||
var options = new PickOptions
|
||||
{
|
||||
PickerTitle = "Please select an image",
|
||||
FileTypes = FilePickerFileType.Images,
|
||||
};
|
||||
|
||||
await PickAndShow(options);
|
||||
}
|
||||
|
||||
async void DoPickPdf()
|
||||
{
|
||||
var options = new PickOptions
|
||||
{
|
||||
PickerTitle = "Please select a pdf",
|
||||
FileTypes = FilePickerFileType.Pdf,
|
||||
};
|
||||
|
||||
await PickAndShow(options);
|
||||
}
|
||||
|
||||
async void DoPickCustomType()
|
||||
{
|
||||
var customFileType =
|
||||
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
|
||||
{
|
||||
{ DevicePlatform.iOS, new[] { "public.my.comic.extension" } }, // or general UTType values
|
||||
{ DevicePlatform.Android, new[] { "application/comics" } },
|
||||
{ DevicePlatform.WinUI, new[] { ".cbr", ".cbz" } },
|
||||
{ DevicePlatform.Tizen, new[] { "*/*" } },
|
||||
{ DevicePlatform.macOS, new[] { "cbr", "cbz" } }, // or general UTType values
|
||||
});
|
||||
|
||||
var options = new PickOptions
|
||||
{
|
||||
PickerTitle = "Please select a comic file",
|
||||
FileTypes = customFileType,
|
||||
};
|
||||
|
||||
await PickAndShow(options);
|
||||
}
|
||||
|
||||
async void DoPickAndSend()
|
||||
{
|
||||
// pick a file
|
||||
var result = await PickAndShow(PickOptions.Images);
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
// copy it locally
|
||||
var copyDir = FileSystem.CacheDirectory;
|
||||
Directory.CreateDirectory(copyDir);
|
||||
var copyPath = Path.Combine(copyDir, result.FileName);
|
||||
using (var destination = File.Create(copyPath))
|
||||
using (var source = await result.OpenReadAsync())
|
||||
await source.CopyToAsync(destination);
|
||||
|
||||
// send it via an email
|
||||
await Email.ComposeAsync(new EmailMessage
|
||||
{
|
||||
Subject = "Test Subject",
|
||||
Body = "This is the body. There should be an image attached.",
|
||||
Attachments =
|
||||
{
|
||||
new EmailAttachment(copyPath)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async Task<FileResult> PickAndShow(PickOptions options)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await FilePicker.PickAsync(options);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
var size = await GetStreamSizeAsync(result);
|
||||
|
||||
Text = $"File Name: {result.FileName} ({size:0.00} KB)";
|
||||
|
||||
var ext = Path.GetExtension(result.FileName).ToLowerInvariant();
|
||||
if (ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif")
|
||||
{
|
||||
var stream = await result.OpenReadAsync();
|
||||
|
||||
Image = ImageSource.FromStream(() => stream);
|
||||
IsImageVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsImageVisible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = $"Pick cancelled.";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Text = ex.ToString();
|
||||
IsImageVisible = false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async Task<double> GetStreamSizeAsync(FileResult result)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var stream = await result.OpenReadAsync();
|
||||
return stream.Length / 1024.0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
async void DoPickMultipleFiles()
|
||||
{
|
||||
try
|
||||
{
|
||||
var resultList = await FilePicker.PickMultipleAsync();
|
||||
|
||||
if (resultList != null && resultList.Any())
|
||||
{
|
||||
Text = "File Names: " + string.Join(", ", resultList.Select(result => result.FileName));
|
||||
|
||||
// only showing the first file's content
|
||||
var firstResult = resultList.First();
|
||||
|
||||
if (firstResult.FileName.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) ||
|
||||
firstResult.FileName.EndsWith("png", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var stream = await firstResult.OpenReadAsync();
|
||||
Image = ImageSource.FromStream(() => stream);
|
||||
IsImageVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsImageVisible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = $"Pick cancelled.";
|
||||
IsImageVisible = false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Text = ex.ToString();
|
||||
IsImageVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class FileSystemViewModel : BaseViewModel
|
||||
{
|
||||
const string templateFileName = "FileSystemTemplate.txt";
|
||||
const string localFileName = "TheFile.txt";
|
||||
|
||||
static string localPath = Path.Combine(FileSystem.AppDataDirectory, localFileName);
|
||||
|
||||
string currentContents;
|
||||
|
||||
public FileSystemViewModel()
|
||||
{
|
||||
LoadFileCommand = new Command(DoLoadFile);
|
||||
SaveFileCommand = new Command(DoSaveFile);
|
||||
DeleteFileCommand = new Command(DoDeleteFile);
|
||||
|
||||
DoLoadFile();
|
||||
}
|
||||
|
||||
public ICommand LoadFileCommand { get; }
|
||||
|
||||
public ICommand SaveFileCommand { get; }
|
||||
|
||||
public ICommand DeleteFileCommand { get; }
|
||||
|
||||
public string AppDataDirectory => FileSystem.AppDataDirectory;
|
||||
|
||||
public string CacheDirectory => FileSystem.CacheDirectory;
|
||||
|
||||
public string CurrentContents
|
||||
{
|
||||
get => currentContents;
|
||||
set => SetProperty(ref currentContents, value);
|
||||
}
|
||||
|
||||
async void DoLoadFile()
|
||||
{
|
||||
if (File.Exists(localPath))
|
||||
{
|
||||
CurrentContents = File.ReadAllText(localPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var stream = await FileSystem.OpenAppPackageFileAsync(templateFileName))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
CurrentContents = await reader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoSaveFile()
|
||||
{
|
||||
var dir = Path.GetDirectoryName(localPath);
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
File.WriteAllText(localPath, CurrentContents);
|
||||
}
|
||||
|
||||
void DoDeleteFile()
|
||||
{
|
||||
if (File.Exists(localPath))
|
||||
File.Delete(localPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class FlashlightViewModel : BaseViewModel
|
||||
{
|
||||
bool isOn;
|
||||
bool isSupported = true;
|
||||
|
||||
public FlashlightViewModel()
|
||||
{
|
||||
ToggleCommand = new Command(OnToggle);
|
||||
App.Current.Dispatcher.Dispatch(async () => await InitViewModel());
|
||||
}
|
||||
|
||||
public ICommand ToggleCommand { get; }
|
||||
|
||||
public bool IsOn
|
||||
{
|
||||
get => isOn;
|
||||
set => SetProperty(ref isOn, value);
|
||||
}
|
||||
|
||||
public bool IsSupported
|
||||
{
|
||||
get => isSupported;
|
||||
set => SetProperty(ref isSupported, value);
|
||||
}
|
||||
|
||||
async Task InitViewModel()
|
||||
{
|
||||
IsSupported = await Flashlight.IsSupportedAsync();
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
if (!IsOn)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Flashlight.TurnOffAsync();
|
||||
IsOn = false;
|
||||
}
|
||||
catch (FeatureNotSupportedException)
|
||||
{
|
||||
IsSupported = false;
|
||||
}
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
async void OnToggle()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsOn)
|
||||
{
|
||||
await Flashlight.TurnOffAsync();
|
||||
IsOn = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Flashlight.TurnOnAsync();
|
||||
IsOn = true;
|
||||
}
|
||||
}
|
||||
catch (FeatureNotSupportedException fnsEx)
|
||||
{
|
||||
IsSupported = false;
|
||||
await DisplayAlertAsync($"Unable toggle flashlight: {fnsEx.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable toggle flashlight: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class GeocodingViewModel : BaseViewModel
|
||||
{
|
||||
string lat = 47.67398.ToString();
|
||||
string lon = (-122.121513).ToString();
|
||||
string address = "Microsoft Building 25 Redmond WA";
|
||||
string geocodeAddress;
|
||||
string geocodePosition;
|
||||
|
||||
public GeocodingViewModel()
|
||||
{
|
||||
GetAddressCommand = new Command(OnGetAddress);
|
||||
GetPositionCommand = new Command(OnGetPosition);
|
||||
}
|
||||
|
||||
public ICommand GetAddressCommand { get; }
|
||||
|
||||
public ICommand GetPositionCommand { get; }
|
||||
|
||||
public string Latitude
|
||||
{
|
||||
get => lat;
|
||||
set => SetProperty(ref lat, value);
|
||||
}
|
||||
|
||||
public string Longitude
|
||||
{
|
||||
get => lon;
|
||||
set => SetProperty(ref lon, value);
|
||||
}
|
||||
|
||||
public string GeocodeAddress
|
||||
{
|
||||
get => geocodeAddress;
|
||||
set => SetProperty(ref geocodeAddress, value);
|
||||
}
|
||||
|
||||
public string Address
|
||||
{
|
||||
get => address;
|
||||
set => SetProperty(ref address, value);
|
||||
}
|
||||
|
||||
public string GeocodePosition
|
||||
{
|
||||
get => geocodePosition;
|
||||
set => SetProperty(ref geocodePosition, value);
|
||||
}
|
||||
|
||||
async void OnGetPosition()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
var locations = await Geocoding.GetLocationsAsync(Address);
|
||||
var location = locations?.FirstOrDefault();
|
||||
if (location == null)
|
||||
{
|
||||
GeocodePosition = "Unable to detect locations";
|
||||
}
|
||||
else
|
||||
{
|
||||
GeocodePosition =
|
||||
$"{nameof(location.Latitude)}: {location.Latitude}\n" +
|
||||
$"{nameof(location.Longitude)}: {location.Longitude}\n";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GeocodePosition = $"Unable to detect locations: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
async void OnGetAddress()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
double.TryParse(lat, out var lt);
|
||||
double.TryParse(lon, out var ln);
|
||||
|
||||
var placemarks = await Geocoding.GetPlacemarksAsync(lt, ln);
|
||||
var placemark = placemarks?.FirstOrDefault();
|
||||
if (placemark == null)
|
||||
{
|
||||
GeocodeAddress = "Unable to detect placemarks.";
|
||||
}
|
||||
else
|
||||
{
|
||||
GeocodeAddress =
|
||||
$"{nameof(placemark.AdminArea)}: {placemark.AdminArea}\n" +
|
||||
$"{nameof(placemark.CountryCode)}: {placemark.CountryCode}\n" +
|
||||
$"{nameof(placemark.CountryName)}: {placemark.CountryName}\n" +
|
||||
$"{nameof(placemark.FeatureName)}: {placemark.FeatureName}\n" +
|
||||
$"{nameof(placemark.Locality)}: {placemark.Locality}\n" +
|
||||
$"{nameof(placemark.PostalCode)}: {placemark.PostalCode}\n" +
|
||||
$"{nameof(placemark.SubAdminArea)}: {placemark.SubAdminArea}\n" +
|
||||
$"{nameof(placemark.SubLocality)}: {placemark.SubLocality}\n" +
|
||||
$"{nameof(placemark.SubThoroughfare)}: {placemark.SubThoroughfare}\n" +
|
||||
$"{nameof(placemark.Thoroughfare)}: {placemark.Thoroughfare}\n";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GeocodeAddress = $"Unable to detect placemarks: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class GeolocationViewModel : BaseViewModel
|
||||
{
|
||||
string notAvailable = "not available";
|
||||
string lastLocation;
|
||||
string currentLocation;
|
||||
int accuracy = (int)GeolocationAccuracy.Default;
|
||||
CancellationTokenSource cts;
|
||||
string listeningLocation;
|
||||
string listeningLocationStatus;
|
||||
|
||||
public GeolocationViewModel()
|
||||
{
|
||||
GetLastLocationCommand = new Command(OnGetLastLocation);
|
||||
GetCurrentLocationCommand = new Command(OnGetCurrentLocation);
|
||||
StartListeningCommand = new Command(OnStartListening);
|
||||
StopListeningCommand = new Command(OnStopListening);
|
||||
}
|
||||
|
||||
public ICommand GetLastLocationCommand { get; }
|
||||
|
||||
public ICommand GetCurrentLocationCommand { get; }
|
||||
|
||||
public ICommand StartListeningCommand { get; }
|
||||
|
||||
public ICommand StopListeningCommand { get; }
|
||||
|
||||
public string LastLocation
|
||||
{
|
||||
get => lastLocation;
|
||||
set => SetProperty(ref lastLocation, value);
|
||||
}
|
||||
|
||||
public string CurrentLocation
|
||||
{
|
||||
get => currentLocation;
|
||||
set => SetProperty(ref currentLocation, value);
|
||||
}
|
||||
|
||||
public string[] Accuracies
|
||||
=> Enum.GetNames(typeof(GeolocationAccuracy));
|
||||
|
||||
public int Accuracy
|
||||
{
|
||||
get => accuracy;
|
||||
set => SetProperty(ref accuracy, value);
|
||||
}
|
||||
|
||||
public bool IsListening => Geolocation.IsListeningForeground;
|
||||
|
||||
public bool IsNotListening => !IsListening;
|
||||
|
||||
public string ListeningLocation
|
||||
{
|
||||
get => listeningLocation;
|
||||
set => SetProperty(ref listeningLocation, value);
|
||||
}
|
||||
|
||||
public string ListeningLocationStatus
|
||||
{
|
||||
get => listeningLocationStatus;
|
||||
set => SetProperty(ref listeningLocationStatus, value);
|
||||
}
|
||||
|
||||
async void OnGetLastLocation()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
var location = await Geolocation.GetLastKnownLocationAsync();
|
||||
LastLocation = FormatLocation(location);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LastLocation = FormatLocation(null, ex);
|
||||
}
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
async void OnGetCurrentLocation()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
var request = new GeolocationRequest((GeolocationAccuracy)Accuracy);
|
||||
cts = new CancellationTokenSource();
|
||||
var location = await Geolocation.GetLocationAsync(request, cts.Token);
|
||||
CurrentLocation = FormatLocation(location);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CurrentLocation = FormatLocation(null, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
cts.Dispose();
|
||||
cts = null;
|
||||
}
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
async void OnStartListening()
|
||||
{
|
||||
try
|
||||
{
|
||||
Geolocation.LocationChanged += Geolocation_LocationChanged;
|
||||
|
||||
var request = new GeolocationListeningRequest((GeolocationAccuracy)Accuracy);
|
||||
|
||||
var success = await Geolocation.StartListeningForegroundAsync(request);
|
||||
|
||||
ListeningLocationStatus = success
|
||||
? "Started listening for foreground location updates"
|
||||
: "Couldn't start listening";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ListeningLocationStatus = FormatLocation(null, ex);
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(IsListening));
|
||||
OnPropertyChanged(nameof(IsNotListening));
|
||||
}
|
||||
|
||||
void Geolocation_LocationChanged(object sender, GeolocationLocationChangedEventArgs e)
|
||||
{
|
||||
ListeningLocation = FormatLocation(e.Location);
|
||||
}
|
||||
|
||||
void OnStopListening()
|
||||
{
|
||||
try
|
||||
{
|
||||
Geolocation.LocationChanged -= Geolocation_LocationChanged;
|
||||
|
||||
Geolocation.StopListeningForeground();
|
||||
|
||||
ListeningLocationStatus = "Stopped listening for foreground location updates";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ListeningLocationStatus = FormatLocation(null, ex);
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(IsListening));
|
||||
OnPropertyChanged(nameof(IsNotListening));
|
||||
}
|
||||
|
||||
string FormatLocation(Location location, Exception ex = null)
|
||||
{
|
||||
if (location == null)
|
||||
{
|
||||
return $"Unable to detect location. Exception: {ex?.Message ?? string.Empty}";
|
||||
}
|
||||
|
||||
return
|
||||
$"Latitude: {location.Latitude}\n" +
|
||||
$"Longitude: {location.Longitude}\n" +
|
||||
$"HorizontalAccuracy: {location.Accuracy}\n" +
|
||||
$"Altitude: {(location.Altitude.HasValue ? location.Altitude.Value.ToString() : notAvailable)}\n" +
|
||||
$"AltitudeRefSys: {location.AltitudeReferenceSystem.ToString()}\n" +
|
||||
$"VerticalAccuracy: {(location.VerticalAccuracy.HasValue ? location.VerticalAccuracy.Value.ToString() : notAvailable)}\n" +
|
||||
$"Heading: {(location.Course.HasValue ? location.Course.Value.ToString() : notAvailable)}\n" +
|
||||
$"Speed: {(location.Speed.HasValue ? location.Speed.Value.ToString() : notAvailable)}\n" +
|
||||
$"Date (UTC): {location.Timestamp:d}\n" +
|
||||
$"Time (UTC): {location.Timestamp:T}\n" +
|
||||
$"Mocking Provider: {location.IsFromMockProvider}";
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
if (IsBusy)
|
||||
{
|
||||
if (cts != null && !cts.IsCancellationRequested)
|
||||
cts.Cancel();
|
||||
}
|
||||
|
||||
OnStopListening();
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class GyroscopeViewModel : BaseViewModel
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
bool isActive;
|
||||
int speed = 0;
|
||||
|
||||
public GyroscopeViewModel()
|
||||
{
|
||||
StartCommand = new Command(OnStart);
|
||||
StopCommand = new Command(OnStop);
|
||||
}
|
||||
|
||||
public ICommand StartCommand { get; }
|
||||
|
||||
public ICommand StopCommand { get; }
|
||||
|
||||
public double X
|
||||
{
|
||||
get => x;
|
||||
set => SetProperty(ref x, value);
|
||||
}
|
||||
|
||||
public double Y
|
||||
{
|
||||
get => y;
|
||||
set => SetProperty(ref y, value);
|
||||
}
|
||||
|
||||
public double Z
|
||||
{
|
||||
get => z;
|
||||
set => SetProperty(ref z, value);
|
||||
}
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => isActive;
|
||||
set => SetProperty(ref isActive, value);
|
||||
}
|
||||
|
||||
public string[] Speeds { get; } =
|
||||
Enum.GetNames(typeof(SensorSpeed));
|
||||
|
||||
public int Speed
|
||||
{
|
||||
get => speed;
|
||||
set => SetProperty(ref speed, value);
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
Gyroscope.ReadingChanged += OnReadingChanged;
|
||||
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnStop();
|
||||
|
||||
Gyroscope.ReadingChanged -= OnReadingChanged;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
async void OnStart()
|
||||
{
|
||||
try
|
||||
{
|
||||
Gyroscope.Start((SensorSpeed)Speed);
|
||||
IsActive = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable to start gyroscope: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnStop()
|
||||
{
|
||||
try
|
||||
{
|
||||
Gyroscope.Stop();
|
||||
IsActive = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Unable to stop gyroscope: {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
void OnReadingChanged(object sender, GyroscopeChangedEventArgs e)
|
||||
{
|
||||
var data = e.Reading;
|
||||
switch ((SensorSpeed)Speed)
|
||||
{
|
||||
case SensorSpeed.Fastest:
|
||||
case SensorSpeed.Game:
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
X = data.AngularVelocity.X;
|
||||
Y = data.AngularVelocity.Y;
|
||||
Z = data.AngularVelocity.Z;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
X = data.AngularVelocity.X;
|
||||
Y = data.AngularVelocity.Y;
|
||||
Z = data.AngularVelocity.Z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class HapticFeedbackViewModel : BaseViewModel
|
||||
{
|
||||
bool isSupported = true;
|
||||
|
||||
public HapticFeedbackViewModel()
|
||||
{
|
||||
ClickCommand = new Command(OnClick);
|
||||
LongPressCommand = new Command(OnLongPress);
|
||||
}
|
||||
|
||||
public ICommand ClickCommand { get; }
|
||||
|
||||
public ICommand LongPressCommand { get; }
|
||||
|
||||
public bool IsSupported
|
||||
{
|
||||
get => isSupported;
|
||||
set => SetProperty(ref isSupported, value);
|
||||
}
|
||||
|
||||
void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
HapticFeedback.Perform(HapticFeedbackType.Click);
|
||||
}
|
||||
catch (FeatureNotSupportedException)
|
||||
{
|
||||
IsSupported = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayAlertAsync($"Unable to HapticFeedback: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnLongPress()
|
||||
{
|
||||
try
|
||||
{
|
||||
HapticFeedback.Perform(HapticFeedbackType.LongPress);
|
||||
}
|
||||
catch (FeatureNotSupportedException)
|
||||
{
|
||||
IsSupported = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayAlertAsync($"Unable to HapticFeedback: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class KeepScreenOnViewModel : BaseViewModel
|
||||
{
|
||||
public KeepScreenOnViewModel()
|
||||
{
|
||||
RequestActiveCommand = new Command(OnRequestActive);
|
||||
RequestReleaseCommand = new Command(OnRequestRelease);
|
||||
}
|
||||
|
||||
public bool IsActive => DeviceDisplay.KeepScreenOn;
|
||||
|
||||
public ICommand RequestActiveCommand { get; }
|
||||
|
||||
public ICommand RequestReleaseCommand { get; }
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnRequestRelease();
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
void OnRequestActive()
|
||||
{
|
||||
DeviceDisplay.KeepScreenOn = true;
|
||||
|
||||
OnPropertyChanged(nameof(IsActive));
|
||||
}
|
||||
|
||||
void OnRequestRelease()
|
||||
{
|
||||
DeviceDisplay.KeepScreenOn = false;
|
||||
|
||||
OnPropertyChanged(nameof(IsActive));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
using PlatformIntegrationDemo.Helpers;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class LauncherViewModel : BaseViewModel
|
||||
{
|
||||
string fileAttachmentName;
|
||||
string fileAttachmentContents;
|
||||
|
||||
public string LaunchUri { get; set; }
|
||||
|
||||
public ICommand LaunchCommand { get; }
|
||||
|
||||
public ICommand CanLaunchCommand { get; }
|
||||
|
||||
public ICommand LaunchMailCommand { get; }
|
||||
|
||||
public ICommand LaunchBrowserCommand { get; }
|
||||
|
||||
public ICommand LaunchFileCommand { get; }
|
||||
|
||||
public LauncherViewModel()
|
||||
{
|
||||
LaunchCommand = new Command(OnLaunch);
|
||||
LaunchMailCommand = new Command(OnLaunchMail);
|
||||
LaunchBrowserCommand = new Command(OnLaunchBrowser);
|
||||
CanLaunchCommand = new Command(CanLaunch);
|
||||
LaunchFileCommand = new Command<Microsoft.Maui.Controls.View>(OnFileRequest);
|
||||
}
|
||||
|
||||
public string FileAttachmentContents
|
||||
{
|
||||
get => fileAttachmentContents;
|
||||
set => SetProperty(ref fileAttachmentContents, value);
|
||||
}
|
||||
|
||||
public string FileAttachmentName
|
||||
{
|
||||
get => fileAttachmentName;
|
||||
set => SetProperty(ref fileAttachmentName, value);
|
||||
}
|
||||
|
||||
async void OnLaunchBrowser()
|
||||
{
|
||||
await Launcher.OpenAsync("https://github.com/dotnet/maui");
|
||||
}
|
||||
|
||||
async void OnLaunch()
|
||||
{
|
||||
try
|
||||
{
|
||||
await Launcher.OpenAsync(LaunchUri);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Uri {LaunchUri} could not be launched: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
async void OnLaunchMail()
|
||||
{
|
||||
await Launcher.OpenAsync("mailto:");
|
||||
}
|
||||
|
||||
async void CanLaunch()
|
||||
{
|
||||
try
|
||||
{
|
||||
var canBeLaunched = await Launcher.CanOpenAsync(LaunchUri);
|
||||
await DisplayAlertAsync($"Uri {LaunchUri} can be launched: {canBeLaunched}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Uri {LaunchUri} could not be verified as launchable: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
async void OnFileRequest(Microsoft.Maui.Controls.View element)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(FileAttachmentContents))
|
||||
{
|
||||
// create a temprary file
|
||||
var fn = string.IsNullOrWhiteSpace(FileAttachmentName) ? "Attachment.txt" : FileAttachmentName.Trim();
|
||||
var file = Path.Combine(FileSystem.CacheDirectory, fn);
|
||||
File.WriteAllText(file, FileAttachmentContents);
|
||||
|
||||
var rect = element.GetAbsoluteBounds();
|
||||
rect.Y += 40;
|
||||
await Launcher.OpenAsync(new OpenFileRequest
|
||||
{
|
||||
File = new ReadOnlyFile(file),
|
||||
PresentationSourceBounds = rect
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class MagnetometerViewModel : BaseViewModel
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
bool isActive;
|
||||
int speed = 0;
|
||||
|
||||
public MagnetometerViewModel()
|
||||
{
|
||||
StartCommand = new Command(OnStart);
|
||||
StopCommand = new Command(OnStop);
|
||||
}
|
||||
|
||||
public ICommand StartCommand { get; }
|
||||
|
||||
public ICommand StopCommand { get; }
|
||||
|
||||
public double X
|
||||
{
|
||||
get => x;
|
||||
set => SetProperty(ref x, value);
|
||||
}
|
||||
|
||||
public double Y
|
||||
{
|
||||
get => y;
|
||||
set => SetProperty(ref y, value);
|
||||
}
|
||||
|
||||
public double Z
|
||||
{
|
||||
get => z;
|
||||
set => SetProperty(ref z, value);
|
||||
}
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => isActive;
|
||||
set => SetProperty(ref isActive, value);
|
||||
}
|
||||
|
||||
public string[] Speeds { get; } =
|
||||
Enum.GetNames(typeof(SensorSpeed));
|
||||
|
||||
public int Speed
|
||||
{
|
||||
get => speed;
|
||||
set => SetProperty(ref speed, value);
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
Magnetometer.ReadingChanged += OnReadingChanged;
|
||||
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnStop();
|
||||
|
||||
Magnetometer.ReadingChanged -= OnReadingChanged;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
async void OnStart()
|
||||
{
|
||||
try
|
||||
{
|
||||
Magnetometer.Start((SensorSpeed)Speed);
|
||||
IsActive = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable to start magnetometer: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnStop()
|
||||
{
|
||||
try
|
||||
{
|
||||
Magnetometer.Stop();
|
||||
IsActive = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Unable to stop magnetometer: {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
void OnReadingChanged(object sender, MagnetometerChangedEventArgs e)
|
||||
{
|
||||
var data = e.Reading;
|
||||
switch ((SensorSpeed)Speed)
|
||||
{
|
||||
case SensorSpeed.Fastest:
|
||||
case SensorSpeed.Game:
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
X = data.MagneticField.X;
|
||||
Y = data.MagneticField.Y;
|
||||
Z = data.MagneticField.Z;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
X = data.MagneticField.X;
|
||||
Y = data.MagneticField.Y;
|
||||
Z = data.MagneticField.Z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
using PlatformIntegrationDemo.Models;
|
||||
using PlatformIntegrationDemo.Views;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class MainPageViewModel : BaseViewModel
|
||||
{
|
||||
bool alreadyAppeared;
|
||||
SampleItem[] samples;
|
||||
IEnumerable<SampleItem> filteredItems;
|
||||
string filterText;
|
||||
|
||||
public MainPageViewModel()
|
||||
{
|
||||
alreadyAppeared = false;
|
||||
samples = new SampleItem[]
|
||||
{
|
||||
new SampleItem(
|
||||
"📏",
|
||||
"Accelerometer",
|
||||
typeof(AccelerometerPage),
|
||||
"Retrieve acceleration data of the device in 3D space.",
|
||||
new[] { "accelerometer", "sensors", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"📏",
|
||||
"All Sensors",
|
||||
typeof(AllSensorsPage),
|
||||
"Have a look at the accelerometer, barometer, compass, gyroscope, magnetometer, and orientation sensors.",
|
||||
new[] { "accelerometer", "barometer", "compass", "gyroscope", "magnetometer", "orientation", "sensors", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"📦",
|
||||
"App Info",
|
||||
typeof(AppInfoPage),
|
||||
"Find out about the app with ease.",
|
||||
new[] { "app", "info" }),
|
||||
new SampleItem(
|
||||
"📏",
|
||||
"Barometer",
|
||||
typeof(BarometerPage),
|
||||
"Easily detect pressure level, via the device barometer.",
|
||||
new[] { "barometer", "hardware", "device", "sensor" }),
|
||||
new SampleItem(
|
||||
"🔋",
|
||||
"Battery",
|
||||
typeof(BatteryPage),
|
||||
"Easily detect battery level, source, and state.",
|
||||
new[] { "battery", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"🌐",
|
||||
"Browser",
|
||||
typeof(BrowserPage),
|
||||
"Quickly and easily open a browser to a specific website.",
|
||||
new[] { "browser", "web", "internet" }),
|
||||
new SampleItem(
|
||||
"📋",
|
||||
"Clipboard",
|
||||
typeof(ClipboardPage),
|
||||
"Quickly and easily use the clipboard.",
|
||||
new[] { "clipboard", "copy", "paste" }),
|
||||
new SampleItem(
|
||||
"🎨",
|
||||
"Color Converters",
|
||||
typeof(ColorConvertersPage),
|
||||
"Convert and adjust colors.",
|
||||
new[] { "color", "drawing", "style" }),
|
||||
new SampleItem(
|
||||
"🧭",
|
||||
"Compass",
|
||||
typeof(CompassPage),
|
||||
"Monitor compass for changes.",
|
||||
new[] { "compass", "sensors", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"📶",
|
||||
"Connectivity",
|
||||
typeof(ConnectivityPage),
|
||||
"Check connectivity state and detect changes.",
|
||||
new[] { "connectivity", "internet", "wifi" }),
|
||||
new SampleItem(
|
||||
"👶",
|
||||
"Contacts",
|
||||
typeof(ContactsPage),
|
||||
"Get and add contacts in your device.",
|
||||
new[] { "contacts", "people", "device" }),
|
||||
new SampleItem(
|
||||
"📱",
|
||||
"Device Info",
|
||||
typeof(DeviceInfoPage),
|
||||
"Find out about the device with ease.",
|
||||
new[] { "hardware", "device", "info", "screen", "display", "orientation", "rotation" }),
|
||||
new SampleItem(
|
||||
"📧",
|
||||
"Email",
|
||||
typeof(EmailPage),
|
||||
"Easily send email messages.",
|
||||
new[] { "email", "share", "communication", "message" }),
|
||||
new SampleItem(
|
||||
"📁",
|
||||
"File Picker",
|
||||
typeof(FilePickerPage),
|
||||
"Easily pick files from storage.",
|
||||
new[] { "files", "picking", "filesystem", "storage" }),
|
||||
new SampleItem(
|
||||
"📁",
|
||||
"File System",
|
||||
typeof(FileSystemPage),
|
||||
"Easily save files to app data.",
|
||||
new[] { "files", "directory", "filesystem", "storage" }),
|
||||
new SampleItem(
|
||||
"🔦",
|
||||
"Flashlight",
|
||||
typeof(FlashlightPage),
|
||||
"A simple way to turn the flashlight on/off.",
|
||||
new[] { "flashlight", "torch", "hardware", "flash", "device" }),
|
||||
new SampleItem(
|
||||
"📍",
|
||||
"Geocoding",
|
||||
typeof(GeocodingPage),
|
||||
"Easily geocode and reverse geocoding.",
|
||||
new[] { "geocoding", "geolocation", "position", "address", "mapping" }),
|
||||
new SampleItem(
|
||||
"📍",
|
||||
"Geolocation",
|
||||
typeof(GeolocationPage),
|
||||
"Quickly get the current location.",
|
||||
new[] { "geolocation", "position", "address", "mapping" }),
|
||||
new SampleItem(
|
||||
"💤",
|
||||
"Keep Screen On",
|
||||
typeof(KeepScreenOnPage),
|
||||
"Keep the device screen awake.",
|
||||
new[] { "screen", "awake", "sleep" }),
|
||||
new SampleItem(
|
||||
"📏",
|
||||
"Launcher",
|
||||
typeof(LauncherPage),
|
||||
"Launch other apps via Uri",
|
||||
new[] { "launcher", "app", "run" }),
|
||||
new SampleItem(
|
||||
"📏",
|
||||
"Gyroscope",
|
||||
typeof(GyroscopePage),
|
||||
"Retrieve rotation around the device's three primary axes.",
|
||||
new[] { "gyroscope", "sensors", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"📏",
|
||||
"Magnetometer",
|
||||
typeof(MagnetometerPage),
|
||||
"Detect device's orientation relative to Earth's magnetic field.",
|
||||
new[] { "compass", "magnetometer", "sensors", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"🗺",
|
||||
"Launch Maps",
|
||||
typeof(MapsPage),
|
||||
"Easily launch maps with coordinates.",
|
||||
new[] { "geocoding", "geolocation", "position", "address", "mapping", "maps", "route", "navigation" }),
|
||||
new SampleItem(
|
||||
"📏",
|
||||
"Orientation Sensor",
|
||||
typeof(OrientationSensorPage),
|
||||
"Retrieve orientation of the device in 3D space.",
|
||||
new[] { "orientation", "sensors", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"📷",
|
||||
"Media Picker",
|
||||
typeof(MediaPickerPage),
|
||||
"Pick or capture a photo or video.",
|
||||
new[] { "media", "picker", "video", "picture", "photo", "image", "movie" }),
|
||||
new SampleItem(
|
||||
"🔒",
|
||||
"Permissions",
|
||||
typeof(PermissionsPage),
|
||||
"Request various permissions.",
|
||||
new[] { "permissions" }),
|
||||
new SampleItem(
|
||||
"📞",
|
||||
"Phone Dialer",
|
||||
typeof(PhoneDialerPage),
|
||||
"Easily open the phone dialer.",
|
||||
new[] { "phone", "dialer", "communication", "call" }),
|
||||
new SampleItem(
|
||||
"⚙️",
|
||||
"Preferences",
|
||||
typeof(PreferencesPage),
|
||||
"Quickly and easily add persistent preferences.",
|
||||
new[] { "settings", "preferences", "prefs", "storage" }),
|
||||
new SampleItem(
|
||||
"📷",
|
||||
"Screenshot",
|
||||
typeof(ScreenshotPage),
|
||||
"Quickly and easily take screenshots of your app.",
|
||||
new[] { "screenshot", "picture", "media", "display" }),
|
||||
new SampleItem(
|
||||
"🔒",
|
||||
"Secure Storage",
|
||||
typeof(SecureStoragePage),
|
||||
"Securely store data.",
|
||||
new[] { "settings", "preferences", "prefs", "security", "storage" }),
|
||||
new SampleItem(
|
||||
"🐊",
|
||||
"Semantic Screen Reader",
|
||||
typeof(SemanticScreenReaderPage),
|
||||
"Read out the semanic contents of a screen.",
|
||||
new[] { "accessibility", "a11y", "screen reader", "semantic" }),
|
||||
new SampleItem(
|
||||
"📲",
|
||||
"Share",
|
||||
typeof(SharePage),
|
||||
"Send text, website uris and files to other apps.",
|
||||
new[] { "data", "transfer", "share", "communication" }),
|
||||
new SampleItem(
|
||||
"💬",
|
||||
"SMS",
|
||||
typeof(SMSPage),
|
||||
"Easily send SMS messages.",
|
||||
new[] { "sms", "message", "text", "communication", "share" }),
|
||||
new SampleItem(
|
||||
"🔊",
|
||||
"Text To Speech",
|
||||
typeof(TextToSpeechPage),
|
||||
"Vocalize text on the device.",
|
||||
new[] { "text", "message", "speech", "communication" }),
|
||||
new SampleItem(
|
||||
"🌡",
|
||||
"Unit Converters",
|
||||
typeof(UnitConvertersPage),
|
||||
"Easily converter different units.",
|
||||
new[] { "units", "converters", "calculations" }),
|
||||
new SampleItem(
|
||||
"📳",
|
||||
"Vibration",
|
||||
typeof(VibrationPage),
|
||||
"Quickly and easily make the device vibrate.",
|
||||
new[] { "vibration", "vibrate", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"📳",
|
||||
"Haptic Feedback",
|
||||
typeof(HapticFeedbackPage),
|
||||
"Quickly and easily make the device provide haptic feedback",
|
||||
new[] { "haptic", "feedback", "hardware", "device" }),
|
||||
new SampleItem(
|
||||
"🔓",
|
||||
"Web Authenticator",
|
||||
typeof(WebAuthenticatorPage),
|
||||
"Quickly and easily authenticate and wait for a callback.",
|
||||
new[] { "auth", "authenticate", "authenticator", "web", "webauth" }),
|
||||
};
|
||||
filteredItems = samples;
|
||||
filterText = string.Empty;
|
||||
}
|
||||
|
||||
public IEnumerable<SampleItem> FilteredItems
|
||||
{
|
||||
get => filteredItems;
|
||||
private set => SetProperty(ref filteredItems, value);
|
||||
}
|
||||
|
||||
public string FilterText
|
||||
{
|
||||
get => filterText;
|
||||
set
|
||||
{
|
||||
SetProperty(ref filterText, value);
|
||||
FilteredItems = Filter(samples, value);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
|
||||
if (!alreadyAppeared)
|
||||
{
|
||||
alreadyAppeared = true;
|
||||
|
||||
if (VersionTracking.IsFirstLaunchEver)
|
||||
{
|
||||
DisplayAlertAsync("Welcome to the sample! This is the first time you are launching the app!");
|
||||
}
|
||||
else if (VersionTracking.IsFirstLaunchForCurrentVersion)
|
||||
{
|
||||
var count = VersionTracking.VersionHistory.Count();
|
||||
DisplayAlertAsync($"Welcome to the NEW sample! You have tried {count} versions.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IEnumerable<SampleItem> Filter(IEnumerable<SampleItem> samples, string filterText)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(filterText))
|
||||
{
|
||||
samples = samples.Where(s =>
|
||||
{
|
||||
var tags = s.Tags.Union(new[] { s.Name });
|
||||
return tags.Any(t => t.Contains(filterText, StringComparison.OrdinalIgnoreCase));
|
||||
});
|
||||
}
|
||||
|
||||
return samples.OrderBy(s => s.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class MapsViewModel : BaseViewModel
|
||||
{
|
||||
string name = "Microsoft Building 25";
|
||||
string longitude = (-122.130603).ToString();
|
||||
string latitude = 47.645160.ToString();
|
||||
string locality = "Redmond";
|
||||
string adminArea = "WA";
|
||||
string thoroughfare = "Microsoft Building 25";
|
||||
string country = "United States";
|
||||
string zipCode = "98052";
|
||||
int navigationMode;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => name;
|
||||
set => SetProperty(ref name, value);
|
||||
}
|
||||
|
||||
public string Longitude
|
||||
{
|
||||
get => longitude;
|
||||
set => SetProperty(ref longitude, value);
|
||||
}
|
||||
|
||||
public string Latitude
|
||||
{
|
||||
get => latitude;
|
||||
set => SetProperty(ref latitude, value);
|
||||
}
|
||||
|
||||
public string Locality
|
||||
{
|
||||
get => locality;
|
||||
set => SetProperty(ref locality, value);
|
||||
}
|
||||
|
||||
public string AdminArea
|
||||
{
|
||||
get => adminArea;
|
||||
set => SetProperty(ref adminArea, value);
|
||||
}
|
||||
|
||||
public string Thoroughfare
|
||||
{
|
||||
get => thoroughfare;
|
||||
set => SetProperty(ref thoroughfare, value);
|
||||
}
|
||||
|
||||
public string Country
|
||||
{
|
||||
get => country;
|
||||
set => SetProperty(ref country, value);
|
||||
}
|
||||
|
||||
public string ZipCode
|
||||
{
|
||||
get => zipCode;
|
||||
set => SetProperty(ref zipCode, value);
|
||||
}
|
||||
|
||||
public string[] NavigationModes { get; } =
|
||||
Enum.GetNames(typeof(NavigationMode));
|
||||
|
||||
public int NavigationMode
|
||||
{
|
||||
get => navigationMode;
|
||||
set => SetProperty(ref navigationMode, value);
|
||||
}
|
||||
|
||||
public ICommand MapsCommand { get; }
|
||||
|
||||
public ICommand LaunchPlacemarkCommand { get; }
|
||||
|
||||
public MapsViewModel()
|
||||
{
|
||||
MapsCommand = new Command(OpenLocation);
|
||||
LaunchPlacemarkCommand = new Command(OpenPlacemark);
|
||||
}
|
||||
|
||||
async void OpenLocation()
|
||||
{
|
||||
var canOpen = await Map.TryOpenAsync(
|
||||
double.Parse(Latitude),
|
||||
double.Parse(Longitude),
|
||||
new MapLaunchOptions
|
||||
{
|
||||
Name = Name,
|
||||
NavigationMode = (NavigationMode)NavigationMode
|
||||
});
|
||||
|
||||
if (!canOpen)
|
||||
{
|
||||
await DisplayAlertAsync("Unable to open map, possibly due to the fact that there is no default maps app installed.");
|
||||
}
|
||||
}
|
||||
|
||||
async void OpenPlacemark()
|
||||
{
|
||||
var placemark = new Placemark
|
||||
{
|
||||
Locality = Locality,
|
||||
AdminArea = AdminArea,
|
||||
CountryName = Country,
|
||||
Thoroughfare = Thoroughfare,
|
||||
PostalCode = ZipCode
|
||||
};
|
||||
|
||||
var canOpen = await Map.TryOpenAsync(placemark, new MapLaunchOptions
|
||||
{
|
||||
Name = Name,
|
||||
NavigationMode = (NavigationMode)NavigationMode
|
||||
});
|
||||
|
||||
if (!canOpen)
|
||||
{
|
||||
await DisplayAlertAsync("Unable to open map, possibly due to the fact that there is no default maps app installed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class MediaPickerViewModel : BaseViewModel
|
||||
{
|
||||
string photoPath;
|
||||
string videoPath;
|
||||
|
||||
bool showPhoto;
|
||||
bool showVideo;
|
||||
|
||||
public MediaPickerViewModel()
|
||||
{
|
||||
PickPhotoCommand = new Command(DoPickPhoto);
|
||||
CapturePhotoCommand = new Command(DoCapturePhoto, () => MediaPicker.IsCaptureSupported);
|
||||
|
||||
PickVideoCommand = new Command(DoPickVideo);
|
||||
CaptureVideoCommand = new Command(DoCaptureVideo, () => MediaPicker.IsCaptureSupported);
|
||||
}
|
||||
|
||||
public ICommand PickPhotoCommand { get; }
|
||||
|
||||
public ICommand CapturePhotoCommand { get; }
|
||||
|
||||
public ICommand PickVideoCommand { get; }
|
||||
|
||||
public ICommand CaptureVideoCommand { get; }
|
||||
|
||||
public bool ShowPhoto
|
||||
{
|
||||
get => showPhoto;
|
||||
set => SetProperty(ref showPhoto, value);
|
||||
}
|
||||
|
||||
public bool ShowVideo
|
||||
{
|
||||
get => showVideo;
|
||||
set => SetProperty(ref showVideo, value);
|
||||
}
|
||||
|
||||
public string PhotoPath
|
||||
{
|
||||
get => photoPath;
|
||||
set => SetProperty(ref photoPath, value);
|
||||
}
|
||||
|
||||
public string VideoPath
|
||||
{
|
||||
get => videoPath;
|
||||
set => SetProperty(ref videoPath, value);
|
||||
}
|
||||
|
||||
async void DoPickPhoto()
|
||||
{
|
||||
try
|
||||
{
|
||||
var photo = await MediaPicker.PickPhotoAsync();
|
||||
|
||||
await LoadPhotoAsync(photo);
|
||||
|
||||
Console.WriteLine($"PickPhotoAsync COMPLETED: {PhotoPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"PickPhotoAsync THREW: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
async void DoCapturePhoto()
|
||||
{
|
||||
try
|
||||
{
|
||||
var photo = await MediaPicker.CapturePhotoAsync();
|
||||
|
||||
await LoadPhotoAsync(photo);
|
||||
|
||||
Console.WriteLine($"CapturePhotoAsync COMPLETED: {PhotoPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"CapturePhotoAsync THREW: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
async void DoPickVideo()
|
||||
{
|
||||
try
|
||||
{
|
||||
var video = await MediaPicker.PickVideoAsync();
|
||||
|
||||
await LoadVideoAsync(video);
|
||||
|
||||
Console.WriteLine($"PickVideoAsync COMPLETED: {PhotoPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"PickVideoAsync THREW: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
async void DoCaptureVideo()
|
||||
{
|
||||
try
|
||||
{
|
||||
var photo = await MediaPicker.CaptureVideoAsync();
|
||||
|
||||
await LoadVideoAsync(photo);
|
||||
|
||||
Console.WriteLine($"CaptureVideoAsync COMPLETED: {VideoPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"CaptureVideoAsync THREW: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
async Task LoadPhotoAsync(FileResult photo)
|
||||
{
|
||||
// canceled
|
||||
if (photo == null)
|
||||
{
|
||||
PhotoPath = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// save the file into local storage
|
||||
var newFile = Path.Combine(FileSystem.CacheDirectory, photo.FileName);
|
||||
using (var stream = await photo.OpenReadAsync())
|
||||
using (var newStream = File.OpenWrite(newFile))
|
||||
{
|
||||
await stream.CopyToAsync(newStream);
|
||||
}
|
||||
|
||||
PhotoPath = newFile;
|
||||
ShowVideo = false;
|
||||
ShowPhoto = true;
|
||||
}
|
||||
|
||||
async Task LoadVideoAsync(FileResult video)
|
||||
{
|
||||
// canceled
|
||||
if (video == null)
|
||||
{
|
||||
VideoPath = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// save the file into local storage
|
||||
var newFile = Path.Combine(FileSystem.CacheDirectory, video.FileName);
|
||||
using (var stream = await video.OpenReadAsync())
|
||||
using (var newStream = File.OpenWrite(newFile))
|
||||
{
|
||||
await stream.CopyToAsync(newStream);
|
||||
}
|
||||
|
||||
VideoPath = newFile;
|
||||
ShowVideo = true;
|
||||
ShowPhoto = false;
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
PhotoPath = null;
|
||||
VideoPath = null;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class ObservableObject : INotifyPropertyChanged
|
||||
{
|
||||
protected virtual bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName] string propertyName = "", Action onChanged = null, Func<T, T, bool> validateValue = null)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(backingStore, value))
|
||||
return false;
|
||||
|
||||
if (validateValue != null && !validateValue(backingStore, value))
|
||||
return false;
|
||||
|
||||
backingStore = value;
|
||||
onChanged?.Invoke();
|
||||
OnPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool SetProperty<T>(T originalValue, T value, Action onChanged, [CallerMemberName] string propertyName = "", Func<T, T, bool> validateValue = null)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(originalValue, value))
|
||||
return false;
|
||||
|
||||
if (validateValue != null && !validateValue(originalValue, value))
|
||||
return false;
|
||||
|
||||
onChanged?.Invoke();
|
||||
OnPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "") =>
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
class OrientationSensorViewModel : BaseViewModel
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
double w;
|
||||
bool isActive;
|
||||
int speed = 0;
|
||||
|
||||
public OrientationSensorViewModel()
|
||||
{
|
||||
StartCommand = new Command(OnStart);
|
||||
StopCommand = new Command(OnStop);
|
||||
}
|
||||
|
||||
public ICommand StartCommand { get; }
|
||||
|
||||
public ICommand StopCommand { get; }
|
||||
|
||||
public double X
|
||||
{
|
||||
get => x;
|
||||
set => SetProperty(ref x, value);
|
||||
}
|
||||
|
||||
public double Y
|
||||
{
|
||||
get => y;
|
||||
set => SetProperty(ref y, value);
|
||||
}
|
||||
|
||||
public double Z
|
||||
{
|
||||
get => z;
|
||||
set => SetProperty(ref z, value);
|
||||
}
|
||||
|
||||
public double W
|
||||
{
|
||||
get => w;
|
||||
set => SetProperty(ref w, value);
|
||||
}
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => isActive;
|
||||
set => SetProperty(ref isActive, value);
|
||||
}
|
||||
|
||||
public string[] Speeds { get; } =
|
||||
Enum.GetNames(typeof(SensorSpeed));
|
||||
|
||||
public int Speed
|
||||
{
|
||||
get => speed;
|
||||
set => SetProperty(ref speed, value);
|
||||
}
|
||||
|
||||
public override void OnAppearing()
|
||||
{
|
||||
OrientationSensor.ReadingChanged += OnReadingChanged;
|
||||
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnStop();
|
||||
|
||||
OrientationSensor.ReadingChanged -= OnReadingChanged;
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
async void OnStart()
|
||||
{
|
||||
try
|
||||
{
|
||||
OrientationSensor.Start((SensorSpeed)Speed);
|
||||
IsActive = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable to start orientation sensor: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnStop()
|
||||
{
|
||||
try
|
||||
{
|
||||
OrientationSensor.Stop();
|
||||
IsActive = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Unable to stop orientation sensor: {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
void OnReadingChanged(object sender, OrientationSensorChangedEventArgs e)
|
||||
{
|
||||
var data = e.Reading;
|
||||
switch ((SensorSpeed)Speed)
|
||||
{
|
||||
case SensorSpeed.Fastest:
|
||||
case SensorSpeed.Game:
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
X = data.Orientation.X;
|
||||
Y = data.Orientation.Y;
|
||||
Z = data.Orientation.Z;
|
||||
W = data.Orientation.W;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
X = data.Orientation.X;
|
||||
Y = data.Orientation.Y;
|
||||
Z = data.Orientation.Z;
|
||||
W = data.Orientation.W;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
using PlatformIntegrationDemo.Models;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class PermissionsViewModel : BaseViewModel
|
||||
{
|
||||
public List<PermissionItem> PermissionItems =>
|
||||
new List<PermissionItem>
|
||||
{
|
||||
new PermissionItem("Battery", new Permissions.Battery()),
|
||||
new PermissionItem("Calendar (Read)", new Permissions.CalendarRead()),
|
||||
new PermissionItem("Calendar (Write)", new Permissions.CalendarWrite()),
|
||||
new PermissionItem("Camera", new Permissions.Camera()),
|
||||
new PermissionItem("Contacts (Read)", new Permissions.ContactsRead()),
|
||||
new PermissionItem("Contacts (Write)", new Permissions.ContactsWrite()),
|
||||
new PermissionItem("Flashlight", new Permissions.Flashlight()),
|
||||
new PermissionItem("Launch Apps", new Permissions.LaunchApp()),
|
||||
new PermissionItem("Location (Always)", new Permissions.LocationAlways()),
|
||||
new PermissionItem("Location (Only When In Use)", new Permissions.LocationWhenInUse()),
|
||||
new PermissionItem("Maps", new Permissions.Maps()),
|
||||
new PermissionItem("Media Library", new Permissions.Media()),
|
||||
new PermissionItem("Microphone", new Permissions.Microphone()),
|
||||
new PermissionItem("Network State", new Permissions.NetworkState()),
|
||||
new PermissionItem("Phone", new Permissions.Phone()),
|
||||
new PermissionItem("Photos", new Permissions.Photos()),
|
||||
new PermissionItem("Photos AddOnly", new Permissions.PhotosAddOnly()),
|
||||
new PermissionItem("Reminders", new Permissions.Reminders()),
|
||||
new PermissionItem("Sensors", new Permissions.Sensors()),
|
||||
new PermissionItem("SMS", new Permissions.Sms()),
|
||||
new PermissionItem("Speech", new Permissions.Speech()),
|
||||
new PermissionItem("Storage (Read)", new Permissions.StorageRead()),
|
||||
new PermissionItem("Storage (Write)", new Permissions.StorageWrite()),
|
||||
new PermissionItem("Vibrate", new Permissions.Vibrate())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class PhoneDialerViewModel : BaseViewModel
|
||||
{
|
||||
string phoneNumber;
|
||||
|
||||
public PhoneDialerViewModel()
|
||||
{
|
||||
OpenPhoneDialerCommand = new Command(OnOpenPhoneDialer);
|
||||
}
|
||||
|
||||
public ICommand OpenPhoneDialerCommand { get; }
|
||||
|
||||
public string PhoneNumber
|
||||
{
|
||||
get => phoneNumber;
|
||||
set => SetProperty(ref phoneNumber, value);
|
||||
}
|
||||
|
||||
async void OnOpenPhoneDialer()
|
||||
{
|
||||
try
|
||||
{
|
||||
PhoneDialer.Open(PhoneNumber);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Dialer is not supported: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class PreferencesViewModel : BaseViewModel
|
||||
{
|
||||
const string preferenceKey = "PreferenceKey";
|
||||
|
||||
string preferenceValue;
|
||||
|
||||
public PreferencesViewModel()
|
||||
{
|
||||
preferenceValue = Preferences.Get(preferenceKey, string.Empty);
|
||||
}
|
||||
|
||||
public string PreferenceValue
|
||||
{
|
||||
get => preferenceValue;
|
||||
set
|
||||
{
|
||||
preferenceValue = value;
|
||||
Preferences.Set(preferenceKey, value);
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
class ScreenshotViewModel : BaseViewModel
|
||||
{
|
||||
ImageSource screenshot;
|
||||
|
||||
public ScreenshotViewModel()
|
||||
{
|
||||
ScreenshotCommand = new Command(async () => await CaptureScreenshot(), () => Screenshot.IsCaptureSupported);
|
||||
EmailCommand = new Command(async () => await EmailScreenshot(), () => Screenshot.IsCaptureSupported);
|
||||
}
|
||||
|
||||
public ICommand ScreenshotCommand { get; }
|
||||
|
||||
public ICommand EmailCommand { get; }
|
||||
|
||||
public ImageSource Image
|
||||
{
|
||||
get => screenshot;
|
||||
set => SetProperty(ref screenshot, value);
|
||||
}
|
||||
|
||||
async Task CaptureScreenshot()
|
||||
{
|
||||
var mediaFile = await Screenshot.CaptureAsync();
|
||||
var stream = await mediaFile.OpenReadAsync(ScreenshotFormat.Png);
|
||||
|
||||
Image = ImageSource.FromStream(() => stream);
|
||||
}
|
||||
|
||||
async Task EmailScreenshot()
|
||||
{
|
||||
var mediaFile = await Screenshot.CaptureAsync();
|
||||
|
||||
var temp = Path.Combine(FileSystem.CacheDirectory, "screenshot.jpg");
|
||||
using (var stream = await mediaFile.OpenReadAsync(ScreenshotFormat.Jpeg))
|
||||
using (var file = File.Create(temp))
|
||||
{
|
||||
await stream.CopyToAsync(file);
|
||||
}
|
||||
|
||||
await Email.ComposeAsync(new EmailMessage
|
||||
{
|
||||
Attachments = { new EmailAttachment(temp) }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class SecureStorageViewModel : BaseViewModel
|
||||
{
|
||||
string key;
|
||||
string securedValue;
|
||||
|
||||
public SecureStorageViewModel()
|
||||
{
|
||||
LoadCommand = new Command(OnLoad);
|
||||
SaveCommand = new Command(OnSave);
|
||||
RemoveCommand = new Command(OnRemove);
|
||||
RemoveAllCommand = new Command(OnRemoveAll);
|
||||
}
|
||||
|
||||
public string Key
|
||||
{
|
||||
get => key;
|
||||
set => SetProperty(ref key, value);
|
||||
}
|
||||
|
||||
public string SecuredValue
|
||||
{
|
||||
get => securedValue;
|
||||
set => SetProperty(ref securedValue, value);
|
||||
}
|
||||
|
||||
public ICommand LoadCommand { get; }
|
||||
|
||||
public ICommand SaveCommand { get; }
|
||||
|
||||
public ICommand RemoveCommand { get; }
|
||||
|
||||
public ICommand RemoveAllCommand { get; }
|
||||
|
||||
async void OnLoad()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
IsBusy = true;
|
||||
|
||||
try
|
||||
{
|
||||
SecuredValue = await SecureStorage.GetAsync(Key) ?? string.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync(ex.Message);
|
||||
}
|
||||
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
async void OnSave()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
IsBusy = true;
|
||||
|
||||
try
|
||||
{
|
||||
await SecureStorage.SetAsync(Key, SecuredValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync(ex.Message);
|
||||
}
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
async void OnRemove()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
IsBusy = true;
|
||||
|
||||
try
|
||||
{
|
||||
SecureStorage.Remove(Key);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync(ex.Message);
|
||||
}
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
async void OnRemoveAll()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
IsBusy = true;
|
||||
|
||||
try
|
||||
{
|
||||
SecureStorage.RemoveAll();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync(ex.Message);
|
||||
}
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
using PlatformIntegrationDemo.Helpers;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
class ShareViewModel : BaseViewModel
|
||||
{
|
||||
bool shareText = true;
|
||||
bool shareUri;
|
||||
string text;
|
||||
string uri;
|
||||
string subject;
|
||||
string title;
|
||||
string shareFileAttachmentContents;
|
||||
string shareFileAttachmentName;
|
||||
string shareFileTitle;
|
||||
string shareFilesTitle;
|
||||
string shareFile1AttachmentContents;
|
||||
string shareFile1AttachmentName;
|
||||
string shareFile2AttachmentContents;
|
||||
string shareFile2AttachmentName;
|
||||
|
||||
public ICommand RequestCommand { get; }
|
||||
|
||||
public ICommand RequestFileCommand { get; }
|
||||
|
||||
public ICommand RequestFilesCommand { get; }
|
||||
|
||||
public ShareViewModel()
|
||||
{
|
||||
RequestCommand = new Command<Microsoft.Maui.Controls.View>(OnRequest);
|
||||
RequestFileCommand = new Command<Microsoft.Maui.Controls.View>(OnFileRequest);
|
||||
RequestFilesCommand = new Command<Microsoft.Maui.Controls.View>(OnFilesRequest);
|
||||
}
|
||||
|
||||
public bool ShareText
|
||||
{
|
||||
get => shareText;
|
||||
set => SetProperty(ref shareText, value);
|
||||
}
|
||||
|
||||
public bool ShareUri
|
||||
{
|
||||
get => shareUri;
|
||||
set => SetProperty(ref shareUri, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => text;
|
||||
set => SetProperty(ref text, value);
|
||||
}
|
||||
|
||||
public string Uri
|
||||
{
|
||||
get => uri;
|
||||
set => SetProperty(ref uri, value);
|
||||
}
|
||||
|
||||
public string Subject
|
||||
{
|
||||
get => subject;
|
||||
set => SetProperty(ref subject, value);
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get => title;
|
||||
set => SetProperty(ref title, value);
|
||||
}
|
||||
|
||||
public string ShareFileTitle
|
||||
{
|
||||
get => shareFileTitle;
|
||||
set => SetProperty(ref shareFileTitle, value);
|
||||
}
|
||||
|
||||
public string ShareFileAttachmentContents
|
||||
{
|
||||
get => shareFileAttachmentContents;
|
||||
set => SetProperty(ref shareFileAttachmentContents, value);
|
||||
}
|
||||
|
||||
public string ShareFileAttachmentName
|
||||
{
|
||||
get => shareFileAttachmentName;
|
||||
set => SetProperty(ref shareFileAttachmentName, value);
|
||||
}
|
||||
|
||||
public string ShareFilesTitle
|
||||
{
|
||||
get => shareFilesTitle;
|
||||
set => SetProperty(ref shareFilesTitle, value);
|
||||
}
|
||||
|
||||
public string ShareFile1AttachmentContents
|
||||
{
|
||||
get => shareFile1AttachmentContents;
|
||||
set => SetProperty(ref shareFile1AttachmentContents, value);
|
||||
}
|
||||
|
||||
public string ShareFile1AttachmentName
|
||||
{
|
||||
get => shareFile1AttachmentName;
|
||||
set => SetProperty(ref shareFile1AttachmentName, value);
|
||||
}
|
||||
|
||||
public string ShareFile2AttachmentContents
|
||||
{
|
||||
get => shareFile2AttachmentContents;
|
||||
set => SetProperty(ref shareFile2AttachmentContents, value);
|
||||
}
|
||||
|
||||
public string ShareFile2AttachmentName
|
||||
{
|
||||
get => shareFile2AttachmentName;
|
||||
set => SetProperty(ref shareFile2AttachmentName, value);
|
||||
}
|
||||
|
||||
async void OnRequest(Microsoft.Maui.Controls.View element)
|
||||
=> await Share.RequestAsync(new ShareTextRequest
|
||||
{
|
||||
Subject = Subject,
|
||||
Text = ShareText ? Text : null,
|
||||
Uri = ShareUri ? Uri : null,
|
||||
Title = Title,
|
||||
PresentationSourceBounds = element.GetAbsoluteBounds()
|
||||
});
|
||||
|
||||
async void OnFileRequest(Microsoft.Maui.Controls.View element)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ShareFileAttachmentContents))
|
||||
return;
|
||||
|
||||
var file = CreateFile(ShareFileAttachmentName, ShareFileAttachmentContents, "Attachment.txt");
|
||||
|
||||
await Share.RequestAsync(new ShareFileRequest
|
||||
{
|
||||
Title = ShareFileTitle,
|
||||
File = new ShareFile(file),
|
||||
PresentationSourceBounds = element.GetAbsoluteBounds()
|
||||
});
|
||||
}
|
||||
|
||||
async void OnFilesRequest(Microsoft.Maui.Controls.View element)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ShareFile1AttachmentContents) ||
|
||||
string.IsNullOrWhiteSpace(ShareFile2AttachmentContents))
|
||||
return;
|
||||
|
||||
var file1 = CreateFile(ShareFile1AttachmentName, ShareFile1AttachmentContents, "Attachment1.txt");
|
||||
var file2 = CreateFile(ShareFile2AttachmentName, ShareFile2AttachmentContents, "Attachment2.txt");
|
||||
|
||||
await Share.RequestAsync(new ShareMultipleFilesRequest
|
||||
{
|
||||
Title = ShareFilesTitle,
|
||||
Files = new List<ShareFile> { new ShareFile(file1), new ShareFile(file2) },
|
||||
PresentationSourceBounds = element.GetAbsoluteBounds()
|
||||
});
|
||||
}
|
||||
|
||||
string CreateFile(string fileName, string fileContents, string emptyName)
|
||||
{
|
||||
var fn = string.IsNullOrWhiteSpace(fileName) ? emptyName : fileName.Trim();
|
||||
var file = Path.Combine(FileSystem.CacheDirectory, fn);
|
||||
File.WriteAllText(file, fileContents);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class SmsViewModel : BaseViewModel
|
||||
{
|
||||
string recipient;
|
||||
string messageText;
|
||||
|
||||
public SmsViewModel()
|
||||
{
|
||||
SendSmsCommand = new Command(OnSendSms);
|
||||
}
|
||||
|
||||
public string Recipient
|
||||
{
|
||||
get => recipient;
|
||||
set => SetProperty(ref recipient, value);
|
||||
}
|
||||
|
||||
public string MessageText
|
||||
{
|
||||
get => messageText;
|
||||
set => SetProperty(ref messageText, value);
|
||||
}
|
||||
|
||||
public ICommand SendSmsCommand { get; }
|
||||
|
||||
async void OnSendSms()
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
IsBusy = true;
|
||||
|
||||
try
|
||||
{
|
||||
var message = new SmsMessage(MessageText, Recipient.Split(',', '*'));
|
||||
await Sms.ComposeAsync(message);
|
||||
}
|
||||
catch (FeatureNotSupportedException)
|
||||
{
|
||||
await DisplayAlertAsync("Sending an SMS is not supported on this device.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlertAsync($"Unable to send Sms: {ex.Message}");
|
||||
}
|
||||
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class TextToSpeechViewModel : BaseViewModel
|
||||
{
|
||||
CancellationTokenSource cts;
|
||||
|
||||
string text;
|
||||
bool advancedOptions;
|
||||
float volume;
|
||||
float pitch;
|
||||
string locale = "Default";
|
||||
Locale selectedLocale;
|
||||
|
||||
public TextToSpeechViewModel()
|
||||
{
|
||||
SpeakCommand = new Command<bool>(OnSpeak);
|
||||
CancelCommand = new Command(OnCancel);
|
||||
PickLocaleCommand = new Command(async () => await OnPickLocale());
|
||||
|
||||
Text = ".NET MAUI platform integration functionality makes text to speech easy!";
|
||||
|
||||
AdvancedOptions = false;
|
||||
Volume = 1.0f;
|
||||
Pitch = 1.0f;
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnCancel();
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
void OnSpeak(bool multiple)
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
|
||||
IsBusy = true;
|
||||
|
||||
cts = new CancellationTokenSource();
|
||||
|
||||
SpeechOptions options = null;
|
||||
if (AdvancedOptions)
|
||||
{
|
||||
options = new SpeechOptions
|
||||
{
|
||||
Volume = Volume,
|
||||
Pitch = Pitch,
|
||||
Locale = selectedLocale
|
||||
};
|
||||
}
|
||||
|
||||
Task speaks = null;
|
||||
if (multiple)
|
||||
{
|
||||
speaks = Task.WhenAll(
|
||||
TextToSpeech.SpeakAsync(Text + " 1 ", options, cancelToken: cts.Token),
|
||||
TextToSpeech.SpeakAsync(Text + " 2 ", options, cancelToken: cts.Token),
|
||||
TextToSpeech.SpeakAsync(Text + " 3 ", options, cancelToken: cts.Token));
|
||||
}
|
||||
else
|
||||
{
|
||||
speaks = TextToSpeech.SpeakAsync(Text, options, cts.Token);
|
||||
}
|
||||
|
||||
// use ContinueWith so we don't have to catch the cancelled exceptions
|
||||
speaks.ContinueWith(t => IsBusy = false);
|
||||
}
|
||||
|
||||
void OnCancel()
|
||||
{
|
||||
if (!IsBusy && (cts?.IsCancellationRequested ?? true))
|
||||
return;
|
||||
|
||||
cts.Cancel();
|
||||
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
async Task OnPickLocale()
|
||||
{
|
||||
var allLocales = await TextToSpeech.GetLocalesAsync();
|
||||
var locales = allLocales
|
||||
.OrderBy(i => i.Language.ToLowerInvariant())
|
||||
.ToArray();
|
||||
|
||||
var languages = locales
|
||||
.Select(i => string.IsNullOrEmpty(i.Country) ? i.Language : $"{i.Language} ({i.Country})")
|
||||
.ToArray();
|
||||
|
||||
var result = await Application.Current.MainPage.DisplayActionSheet("Pick", "OK", null, languages);
|
||||
|
||||
if (!string.IsNullOrEmpty(result) && Array.IndexOf(languages, result) is int idx && idx != -1)
|
||||
{
|
||||
selectedLocale = locales[idx];
|
||||
Locale = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedLocale = null;
|
||||
Locale = "Default";
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand CancelCommand { get; }
|
||||
|
||||
public ICommand SpeakCommand { get; }
|
||||
|
||||
public ICommand PickLocaleCommand { get; }
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => text;
|
||||
set => SetProperty(ref text, value);
|
||||
}
|
||||
|
||||
public bool AdvancedOptions
|
||||
{
|
||||
get => advancedOptions;
|
||||
set => SetProperty(ref advancedOptions, value);
|
||||
}
|
||||
|
||||
public float Volume
|
||||
{
|
||||
get => volume;
|
||||
set => SetProperty(ref volume, value);
|
||||
}
|
||||
|
||||
public float Pitch
|
||||
{
|
||||
get => pitch;
|
||||
set => SetProperty(ref pitch, value);
|
||||
}
|
||||
|
||||
public string Locale
|
||||
{
|
||||
get => locale;
|
||||
set => SetProperty(ref locale, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class UnitConvertersViewModel : BaseViewModel
|
||||
{
|
||||
double fahrenheit;
|
||||
double celsius;
|
||||
double miles;
|
||||
double kilometers;
|
||||
|
||||
public UnitConvertersViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public double Fahrenheit
|
||||
{
|
||||
get => fahrenheit;
|
||||
set => SetProperty(ref fahrenheit, value, onChanged: () => Celsius = UnitConverters.FahrenheitToCelsius(fahrenheit));
|
||||
}
|
||||
|
||||
public double Celsius
|
||||
{
|
||||
get => celsius;
|
||||
set => SetProperty(ref celsius, value);
|
||||
}
|
||||
|
||||
public double Miles
|
||||
{
|
||||
get => miles;
|
||||
set => SetProperty(ref miles, value, onChanged: () => Kilometers = UnitConverters.MilesToKilometers(miles));
|
||||
}
|
||||
|
||||
public double Kilometers
|
||||
{
|
||||
get => kilometers;
|
||||
set => SetProperty(ref kilometers, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class VibrationViewModel : BaseViewModel
|
||||
{
|
||||
int duration = 500;
|
||||
bool isSupported = true;
|
||||
|
||||
public VibrationViewModel()
|
||||
{
|
||||
VibrateCommand = new Command(OnVibrate);
|
||||
CancelCommand = new Command(OnCancel);
|
||||
}
|
||||
|
||||
public ICommand VibrateCommand { get; }
|
||||
|
||||
public ICommand CancelCommand { get; }
|
||||
|
||||
public int Duration
|
||||
{
|
||||
get => duration;
|
||||
set => SetProperty(ref duration, value);
|
||||
}
|
||||
|
||||
public bool IsSupported
|
||||
{
|
||||
get => isSupported;
|
||||
set => SetProperty(ref isSupported, value);
|
||||
}
|
||||
|
||||
public override void OnDisappearing()
|
||||
{
|
||||
OnCancel();
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
|
||||
void OnVibrate()
|
||||
{
|
||||
try
|
||||
{
|
||||
Vibration.Vibrate(duration);
|
||||
}
|
||||
catch (FeatureNotSupportedException)
|
||||
{
|
||||
IsSupported = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayAlertAsync($"Unable to vibrate: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnCancel()
|
||||
{
|
||||
try
|
||||
{
|
||||
Vibration.Cancel();
|
||||
}
|
||||
catch (FeatureNotSupportedException)
|
||||
{
|
||||
IsSupported = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayAlertAsync($"Unable to cancel: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
using System.Windows.Input;
|
||||
|
||||
namespace PlatformIntegrationDemo.ViewModels
|
||||
{
|
||||
public class WebAuthenticatorViewModel : BaseViewModel
|
||||
{
|
||||
const string authenticationUrl = "https://xamarin-essentials-auth-sample.azurewebsites.net/mobileauth/";
|
||||
|
||||
public WebAuthenticatorViewModel()
|
||||
{
|
||||
MicrosoftCommand = new Command(async () => await OnAuthenticate("Microsoft"));
|
||||
GoogleCommand = new Command(async () => await OnAuthenticate("Google"));
|
||||
FacebookCommand = new Command(async () => await OnAuthenticate("Facebook"));
|
||||
AppleCommand = new Command(async () => await OnAuthenticate("Apple"));
|
||||
}
|
||||
|
||||
public ICommand MicrosoftCommand { get; }
|
||||
|
||||
public ICommand GoogleCommand { get; }
|
||||
|
||||
public ICommand FacebookCommand { get; }
|
||||
|
||||
public ICommand AppleCommand { get; }
|
||||
|
||||
string accessToken = string.Empty;
|
||||
|
||||
public string AuthToken
|
||||
{
|
||||
get => accessToken;
|
||||
set => SetProperty(ref accessToken, value);
|
||||
}
|
||||
|
||||
async Task OnAuthenticate(string scheme)
|
||||
{
|
||||
try
|
||||
{
|
||||
WebAuthenticatorResult r = null;
|
||||
|
||||
if (scheme.Equals("Apple", StringComparison.Ordinal)
|
||||
&& DeviceInfo.Platform == DevicePlatform.iOS
|
||||
&& DeviceInfo.Version.Major >= 13)
|
||||
{
|
||||
// Make sure to enable Apple Sign In in both the
|
||||
// entitlements and the provisioning profile.
|
||||
var options = new AppleSignInAuthenticator.Options
|
||||
{
|
||||
IncludeEmailScope = true,
|
||||
IncludeFullNameScope = true,
|
||||
};
|
||||
r = await AppleSignInAuthenticator.AuthenticateAsync(options);
|
||||
}
|
||||
else
|
||||
{
|
||||
var authUrl = new Uri(authenticationUrl + scheme);
|
||||
var callbackUrl = new Uri("xamarinessentials://");
|
||||
|
||||
r = await WebAuthenticator.AuthenticateAsync(authUrl, callbackUrl);
|
||||
}
|
||||
|
||||
AuthToken = string.Empty;
|
||||
if (r.Properties.TryGetValue("name", out var name) && !string.IsNullOrEmpty(name))
|
||||
AuthToken += $"Name: {name}{Environment.NewLine}";
|
||||
if (r.Properties.TryGetValue("email", out var email) && !string.IsNullOrEmpty(email))
|
||||
AuthToken += $"Email: {email}{Environment.NewLine}";
|
||||
AuthToken += r?.AccessToken ?? r?.IdToken;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Console.WriteLine("Login canceled.");
|
||||
|
||||
AuthToken = string.Empty;
|
||||
await DisplayAlertAsync("Login canceled.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed: {ex.Message}");
|
||||
|
||||
AuthToken = string.Empty;
|
||||
await DisplayAlertAsync($"Failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.AccelerometerPage"
|
||||
Title="Accelerometer">
|
||||
<views:BasePage.BindingContext>
|
||||
<viewmodels:AccelerometerViewModel />
|
||||
</views:BasePage.BindingContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Retrieve acceleration data of the device in 3D space. Additionally, this page will detect if you shake your device."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<Grid Padding="12,0,12,12"
|
||||
ColumnDefinitions="*,*"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding X, StringFormat='X: {0:N}'}" />
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Y, StringFormat='Y: {0:N}'}" />
|
||||
<Label Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Z, StringFormat='Z: {0:N}'}" />
|
||||
|
||||
<Picker Grid.Row="4"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
|
||||
<Label Grid.Row="6"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding ShakeTime}" />
|
||||
</Grid>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
|
||||
</views:BasePage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class AccelerometerPage : BasePage
|
||||
{
|
||||
public AccelerometerPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.AllSensorsPage"
|
||||
Title="All Sensors">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Have a look at the accelerometer, compass, gyroscope and magnetometer."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<StackLayout Padding="0,0,0,12"
|
||||
Spacing="6">
|
||||
|
||||
<Label Text="Accelerometer"
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
<Grid x:Name="GridAccelerometer">
|
||||
<Grid.BindingContext>
|
||||
<viewmodels:AccelerometerViewModel />
|
||||
</Grid.BindingContext>
|
||||
<Grid Padding="12,0,12,12"
|
||||
ColumnDefinitions="*,*"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding X, StringFormat='X: {0:N}'}" />
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Y, StringFormat='Y: {0:N}'}" />
|
||||
<Label Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Z, StringFormat='Z: {0:N}'}" />
|
||||
|
||||
<Picker Grid.Row="4"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
|
||||
<Label Grid.Row="6"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding ShakeTime}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Label Text="Barometer"
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
<Grid x:Name="GridBarometer">
|
||||
<Grid.BindingContext>
|
||||
<viewmodels:BarometerViewModel />
|
||||
</Grid.BindingContext>
|
||||
<Grid Padding="12,0,12,12"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,*">
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Pressure, StringFormat='Barometer pressure (hPA): {0:N}'}" />
|
||||
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="Speed:" />
|
||||
|
||||
<Picker Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}"
|
||||
Margin="0,0,0,10" />
|
||||
|
||||
|
||||
<Button Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Label Text="Compass"
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
<Grid x:Name="GridCompass">
|
||||
<Grid.BindingContext>
|
||||
<viewmodels:CompassViewModel />
|
||||
</Grid.BindingContext>
|
||||
<Grid Padding="12,0,12,12"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,*">
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Heading, StringFormat='Heading (degrees): {0:N}'}" />
|
||||
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="Speed:" />
|
||||
|
||||
<Picker Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}"
|
||||
Margin="0,0,0,10" />
|
||||
|
||||
<Label Grid.Row="3"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="Apply low pass filter:" />
|
||||
|
||||
<Switch Grid.Row="4"
|
||||
Grid.ColumnSpan="2"
|
||||
IsToggled="{Binding ApplyLowPassFilter}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Label Text="Gyroscope"
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
<Grid x:Name="GridGyro">
|
||||
<Grid.BindingContext>
|
||||
<viewmodels:GyroscopeViewModel />
|
||||
</Grid.BindingContext>
|
||||
<Grid Padding="12,0,12,12"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,*">
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding X, StringFormat='X: {0:N}'}" />
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Y, StringFormat='Y: {0:N}'}" />
|
||||
<Label Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Z, StringFormat='Z: {0:N}'}" />
|
||||
|
||||
<Picker Grid.Row="4"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Label Text="Magnetometer"
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
<Grid x:Name="GridMagnetometer">
|
||||
<Grid.BindingContext>
|
||||
<viewmodels:MagnetometerViewModel />
|
||||
</Grid.BindingContext>
|
||||
<Grid Padding="12,0,12,12"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,*">
|
||||
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding X, StringFormat='X: {0:N}'}" />
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Y, StringFormat='Y: {0:N}'}" />
|
||||
<Label Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Z, StringFormat='Z: {0:N}'}" />
|
||||
|
||||
<Picker Grid.Row="4"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Label Text="Orientation Sensor"
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
<Grid x:Name="GridOrientation">
|
||||
<Grid.BindingContext>
|
||||
<viewmodels:OrientationSensorViewModel />
|
||||
</Grid.BindingContext>
|
||||
<Grid Padding="12,0,12,12"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,*">
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding X, StringFormat='X: {0:N}'}" />
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Y, StringFormat='Y: {0:N}'}" />
|
||||
<Label Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Z, StringFormat='Z: {0:N}'}" />
|
||||
<Label Grid.Row="3"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding W, StringFormat='W: {0:N}'}" />
|
||||
|
||||
<Picker Grid.Row="4"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
</views:BasePage>
|
|
@ -0,0 +1,33 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class AllSensorsPage : BasePage
|
||||
{
|
||||
public AllSensorsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
|
||||
SetupBinding(GridAccelerometer.BindingContext);
|
||||
SetupBinding(GridCompass.BindingContext);
|
||||
SetupBinding(GridGyro.BindingContext);
|
||||
SetupBinding(GridMagnetometer.BindingContext);
|
||||
SetupBinding(GridOrientation.BindingContext);
|
||||
SetupBinding(GridBarometer.BindingContext);
|
||||
}
|
||||
|
||||
protected override void OnDisappearing()
|
||||
{
|
||||
TearDownBinding(GridAccelerometer.BindingContext);
|
||||
TearDownBinding(GridCompass.BindingContext);
|
||||
TearDownBinding(GridGyro.BindingContext);
|
||||
TearDownBinding(GridMagnetometer.BindingContext);
|
||||
TearDownBinding(GridOrientation.BindingContext);
|
||||
TearDownBinding(GridBarometer.BindingContext);
|
||||
|
||||
base.OnDisappearing();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.AppInfoPage"
|
||||
Title="App Info">
|
||||
<views:BasePage.BindingContext>
|
||||
<viewmodels:AppInfoViewModel />
|
||||
</views:BasePage.BindingContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Find out about the app with ease."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<StackLayout Padding="12,0,12,12"
|
||||
Spacing="6">
|
||||
<Label Text="App Info:"
|
||||
FontAttributes="Bold"
|
||||
Margin="0,6,0,0" />
|
||||
<Label Text="{Binding AppName, StringFormat='Name: {0}'}" />
|
||||
<Label Text="{Binding AppPackageName, StringFormat='Package Name: {0}'}" />
|
||||
<Label Text="{Binding AppTheme, StringFormat='Theme: {0}'}" />
|
||||
|
||||
<Label Text="Version Info:"
|
||||
FontAttributes="Bold"
|
||||
Margin="0,6,0,0" />
|
||||
<Label Text="{Binding AppVersion, StringFormat='Version: {0}'}" />
|
||||
<Label Text="{Binding AppBuild, StringFormat='Build: {0}'}" />
|
||||
<Label Text="{Binding RequestedLayoutDirection, StringFormat='Layout Direction: {0}'}" />
|
||||
|
||||
<Button Text="Open Settings"
|
||||
Command="{Binding ShowSettingsUICommand}" />
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
</views:BasePage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class AppInfoPage : BasePage
|
||||
{
|
||||
public AppInfoPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.BarometerPage"
|
||||
Title="Barometer">
|
||||
<views:BasePage.BindingContext>
|
||||
<viewmodels:BarometerViewModel />
|
||||
</views:BasePage.BindingContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Monitor barometer for changes."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<Grid Padding="12,0,12,12"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,*">
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Pressure, StringFormat='Barometer pressure (hPA): {0:N}'}" />
|
||||
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="Speed:" />
|
||||
|
||||
<Picker Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}"
|
||||
Margin="0,0,0,10" />
|
||||
|
||||
<Button Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
</Grid>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
</views:BasePage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class BarometerPage : BasePage
|
||||
{
|
||||
public BarometerPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
using PlatformIntegrationDemo.ViewModels;
|
||||
|
||||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public class BasePage : ContentPage
|
||||
{
|
||||
public BasePage()
|
||||
{
|
||||
NavigationPage.SetBackButtonTitle(this, "Back");
|
||||
|
||||
Loaded += OnLoaded;
|
||||
Unloaded += OnUnloaded;
|
||||
}
|
||||
|
||||
void OnLoaded(object sender, EventArgs e)
|
||||
{
|
||||
SetupBinding(BindingContext);
|
||||
}
|
||||
|
||||
void OnUnloaded(object sender, EventArgs e)
|
||||
{
|
||||
TearDownBinding(BindingContext);
|
||||
}
|
||||
|
||||
protected void SetupBinding(object bindingContext)
|
||||
{
|
||||
if (bindingContext is BaseViewModel vm)
|
||||
{
|
||||
vm.DoDisplayAlert += OnDisplayAlert;
|
||||
vm.DoNavigate += OnNavigate;
|
||||
vm.OnAppearing();
|
||||
}
|
||||
}
|
||||
|
||||
protected void TearDownBinding(object bindingContext)
|
||||
{
|
||||
if (bindingContext is BaseViewModel vm)
|
||||
{
|
||||
vm.OnDisappearing();
|
||||
vm.DoDisplayAlert -= OnDisplayAlert;
|
||||
vm.DoNavigate -= OnNavigate;
|
||||
}
|
||||
}
|
||||
|
||||
Task OnDisplayAlert(string message)
|
||||
{
|
||||
return DisplayAlert(Title, message, "OK");
|
||||
}
|
||||
|
||||
Task OnNavigate(BaseViewModel vm, bool showModal)
|
||||
{
|
||||
var name = vm.GetType().Name;
|
||||
name = name.Replace("ViewModel", "Page", StringComparison.Ordinal);
|
||||
|
||||
var ns = GetType().Namespace;
|
||||
var pageType = Type.GetType($"{ns}.{name}");
|
||||
|
||||
var page = (BasePage)Activator.CreateInstance(pageType);
|
||||
page.BindingContext = vm;
|
||||
|
||||
return showModal
|
||||
? Navigation.PushModalAsync(page)
|
||||
: Navigation.PushAsync(page);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.BatteryPage"
|
||||
Title="Battery">
|
||||
<views:BasePage.BindingContext>
|
||||
<viewmodels:BatteryViewModel />
|
||||
</views:BasePage.BindingContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Easily detect battery level, source, and state."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<StackLayout Padding="12,0,12,12"
|
||||
Spacing="6">
|
||||
<Label Text="Battery State:"
|
||||
FontAttributes="Bold"
|
||||
Margin="0,6,0,0" />
|
||||
<Label Text="{Binding Level, StringFormat='Charge Level: {0:P1}'}" />
|
||||
<Label Text="{Binding State, StringFormat='State: {0}'}" />
|
||||
<Label Text="{Binding PowerSource, StringFormat='Power Source: {0}'}" />
|
||||
<Label Text="{Binding EnergySaverStatus, StringFormat='Energy Saver: {0}'}" />
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
</views:BasePage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class BatteryPage : BasePage
|
||||
{
|
||||
public BatteryPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.BrowserPage"
|
||||
Title="Browser">
|
||||
<views:BasePage.BindingContext>
|
||||
<viewmodels:BrowserViewModel />
|
||||
</views:BasePage.BindingContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Quickly and easily open URIs."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<StackLayout Padding="12,0,12,12"
|
||||
Spacing="6">
|
||||
|
||||
<Label Text="URI:"
|
||||
FontAttributes="Bold"
|
||||
Margin="0,6,0,0" />
|
||||
|
||||
<Label Text="Enter URI:" />
|
||||
<Entry Placeholder="https://..."
|
||||
Text="{Binding Uri}" />
|
||||
|
||||
<Button Text="Open URI"
|
||||
Command="{Binding OpenUriCommand}"
|
||||
IsEnabled="{Binding IsNotBusy}" />
|
||||
|
||||
|
||||
<Label Text="Launch Type:"
|
||||
FontAttributes="Bold"
|
||||
Margin="0,6,0,0" />
|
||||
<Picker HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding BrowserLaunchModes}"
|
||||
SelectedIndex="{Binding BrowserType, Mode=TwoWay}" />
|
||||
|
||||
<Label Text="Launch Options:"
|
||||
FontAttributes="Bold"
|
||||
Margin="0,6,0,0" />
|
||||
<Label Text="Title Mode:" />
|
||||
<Picker HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding BrowserTitleModes}"
|
||||
SelectedIndex="{Binding BrowserTitleType, Mode=TwoWay}" />
|
||||
|
||||
<Label Text="Toolbar Color:" />
|
||||
<Picker HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding AllColors}"
|
||||
SelectedIndex="{Binding ToolbarColor, Mode=TwoWay}" />
|
||||
|
||||
<Label Text="Control Tint Color (iOS):" />
|
||||
<Picker HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding AllColors}"
|
||||
SelectedIndex="{Binding ControlColor, Mode=TwoWay}" />
|
||||
|
||||
<Label Text="Flags:"
|
||||
FontAttributes="Bold"
|
||||
Margin="0,6,0,0" />
|
||||
|
||||
<Grid ColumnDefinitions="*,Auto"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<Label Text="Launch Adjacent (Android)"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0" />
|
||||
<Switch IsToggled="{Binding LaunchAdjacent, Mode=TwoWay}"
|
||||
Grid.Column="1"
|
||||
Grid.Row="0" />
|
||||
|
||||
<Label Text="Present as Form Sheet (iOS)"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1" />
|
||||
<Switch IsToggled="{Binding PresentAsFormSheet, Mode=TwoWay}"
|
||||
Grid.Column="1"
|
||||
Grid.Row="1" />
|
||||
|
||||
<Label Text="Present as Page Sheet (iOS)"
|
||||
Grid.Column="0"
|
||||
Grid.Row="2" />
|
||||
<Switch IsToggled="{Binding PresentAsPageSheet, Mode=TwoWay}"
|
||||
Grid.Column="1"
|
||||
Grid.Row="2" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<Label Text="{Binding BrowserStatus}" />
|
||||
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
</views:BasePage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class BrowserPage : BasePage
|
||||
{
|
||||
public BrowserPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.ClipboardPage"
|
||||
Title="Clipboard">
|
||||
<views:BasePage.BindingContext>
|
||||
<viewmodels:ClipboardViewModel />
|
||||
</views:BasePage.BindingContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Quickly and easily use the clipboard."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<StackLayout Padding="12,0,12,12"
|
||||
Spacing="6">
|
||||
<Label Text="Enter some text:" />
|
||||
<Entry Placeholder="Enter text..."
|
||||
Text="{Binding FieldValue}" />
|
||||
<Button Text="Copy to clipboard"
|
||||
Command="{Binding CopyCommand}" />
|
||||
<Button Text="Paste from clipboard"
|
||||
Command="{Binding PasteCommand}" />
|
||||
<Button Text="Check Status"
|
||||
Command="{Binding CheckCommand}" />
|
||||
<Label Text="{Binding LastCopied}" />
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
</views:BasePage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class ClipboardPage : BasePage
|
||||
{
|
||||
public ClipboardPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.ColorConvertersPage"
|
||||
Title="Color Converters">
|
||||
<views:BasePage.BindingContext>
|
||||
<viewmodels:ColorConvertersViewModel />
|
||||
</views:BasePage.BindingContext>
|
||||
|
||||
<views:BasePage.Resources>
|
||||
<ResourceDictionary>
|
||||
<Style TargetType="BoxView">
|
||||
<Setter Property="CornerRadius"
|
||||
Value="8" />
|
||||
<Setter Property="HeightRequest"
|
||||
Value="24" />
|
||||
<Setter Property="WidthRequest"
|
||||
Value="100" />
|
||||
<Setter Property="VerticalOptions"
|
||||
Value="Center" />
|
||||
</Style>
|
||||
<Style TargetType="Slider">
|
||||
<Setter Property="VerticalOptions"
|
||||
Value="Center" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</views:BasePage.Resources>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Create, convert, and adjust colors."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<Grid Padding="12,0,12,12"
|
||||
RowSpacing="6"
|
||||
ColumnSpacing="6"
|
||||
ColumnDefinitions="*,Auto"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<Label Text="Hex Color:"
|
||||
Grid.Row="0"
|
||||
Grid.ColumnSpan="2" />
|
||||
<Entry Text="{Binding Hex}"
|
||||
HorizontalOptions="Fill"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0" />
|
||||
<BoxView Color="{Binding RegularColor}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1" />
|
||||
|
||||
<Label Text="Complementary Color:"
|
||||
Grid.Row="2"
|
||||
Grid.ColumnSpan="2" />
|
||||
<Label Text="{Binding ComplementHex}"
|
||||
HorizontalOptions="Fill"
|
||||
Grid.Row="3"
|
||||
Grid.Column="0" />
|
||||
<BoxView Color="{Binding ComplementColor}"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1" />
|
||||
|
||||
<Label Text="{Binding Alpha, StringFormat='Alpha: {0:F0}'}"
|
||||
Grid.Row="4"
|
||||
Grid.ColumnSpan="2" />
|
||||
<Slider Minimum="0"
|
||||
Maximum="255"
|
||||
Value="{Binding Alpha}"
|
||||
Grid.Row="5"
|
||||
Grid.Column="0" />
|
||||
<BoxView Color="{Binding AlphaColor}"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1" />
|
||||
|
||||
<Label Text="{Binding Hue, StringFormat='Hue: {0:F0}'}"
|
||||
Grid.Row="6"
|
||||
Grid.ColumnSpan="2" />
|
||||
<Slider Minimum="0"
|
||||
Maximum="360"
|
||||
Value="{Binding Hue}"
|
||||
Grid.Row="7"
|
||||
Grid.Column="0" />
|
||||
<BoxView Color="{Binding HueColor}"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1" />
|
||||
|
||||
<Label Text="{Binding Luminosity, StringFormat='Luminosity: {0:F0}'}"
|
||||
Grid.Row="8"
|
||||
Grid.ColumnSpan="2" />
|
||||
<Slider Minimum="0"
|
||||
Maximum="100"
|
||||
Value="{Binding Luminosity}"
|
||||
Grid.Row="9"
|
||||
Grid.Column="0" />
|
||||
<BoxView Color="{Binding LuminosityColor}"
|
||||
Grid.Row="9"
|
||||
Grid.Column="1" />
|
||||
|
||||
<Label Text="{Binding Saturation, StringFormat='Saturation: {0:F0}'}"
|
||||
Grid.Row="10"
|
||||
Grid.ColumnSpan="2" />
|
||||
<Slider Minimum="0"
|
||||
Maximum="100"
|
||||
Value="{Binding Saturation}"
|
||||
Grid.Row="11"
|
||||
Grid.Column="0" />
|
||||
<BoxView Color="{Binding SaturationColor}"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1" />
|
||||
|
||||
</Grid>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
</views:BasePage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class ColorConvertersPage : BasePage
|
||||
{
|
||||
public ColorConvertersPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<views:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:PlatformIntegrationDemo.Views"
|
||||
xmlns:viewmodels="clr-namespace:PlatformIntegrationDemo.ViewModels"
|
||||
x:Class="PlatformIntegrationDemo.Views.CompassPage"
|
||||
Title="Compass">
|
||||
<views:BasePage.BindingContext>
|
||||
<viewmodels:CompassViewModel />
|
||||
</views:BasePage.BindingContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Text="Monitor compass for changes."
|
||||
FontAttributes="Bold"
|
||||
Margin="12" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<Grid Padding="12,0,12,12"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,*">
|
||||
<Label Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="{Binding Heading, StringFormat='Heading (degrees): {0:N}'}" />
|
||||
|
||||
<Label Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="Speed:" />
|
||||
|
||||
<Picker Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
ItemsSource="{Binding Speeds}"
|
||||
SelectedIndex="{Binding Speed, Mode=TwoWay}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}"
|
||||
Margin="0,0,0,10" />
|
||||
|
||||
<Label Grid.Row="3"
|
||||
Grid.ColumnSpan="2"
|
||||
Text="Apply low pass filter:" />
|
||||
|
||||
<Switch Grid.Row="4"
|
||||
Grid.ColumnSpan="2"
|
||||
IsToggled="{Binding ApplyLowPassFilter}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Text="Start"
|
||||
Command="{Binding StartCommand}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InverterConverter}}" />
|
||||
|
||||
<Button Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Text="Stop"
|
||||
Command="{Binding StopCommand}"
|
||||
IsEnabled="{Binding IsActive}" />
|
||||
</Grid>
|
||||
</ScrollView>
|
||||
</Grid>
|
||||
</views:BasePage>
|
|
@ -0,0 +1,9 @@
|
|||
namespace PlatformIntegrationDemo.Views;
|
||||
|
||||
public partial class CompassPage : BasePage
|
||||
{
|
||||
public CompassPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче