diff --git a/samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs b/samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs index 12721c1b46..9c5d1ef42a 100644 --- a/samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs +++ b/samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs @@ -118,6 +118,7 @@ public partial class AppShell : Shell CreateViewModelMapping(), CreateViewModelMapping(), CreateViewModelMapping(), + CreateViewModelMapping(), CreateViewModelMapping(), CreateViewModelMapping(), CreateViewModelMapping(), diff --git a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj index 0436550172..9c4272a54f 100644 --- a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj +++ b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj @@ -89,6 +89,11 @@ + + + + + win-x64 diff --git a/samples/CommunityToolkit.Maui.Sample/MauiProgram.cs b/samples/CommunityToolkit.Maui.Sample/MauiProgram.cs index 1dd763355a..41bdde8417 100644 --- a/samples/CommunityToolkit.Maui.Sample/MauiProgram.cs +++ b/samples/CommunityToolkit.Maui.Sample/MauiProgram.cs @@ -247,6 +247,7 @@ static void RegisterViewsAndViewModels(in IServiceCollection services) services.AddTransientWithShellRoute(); // Add Views Pages + ViewModels + services.AddTransientWithShellRoute(); services.AddTransientWithShellRoute(); services.AddTransientWithShellRoute(); services.AddTransientWithShellRoute(); diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml new file mode 100644 index 0000000000..dfc7214ab7 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs new file mode 100644 index 0000000000..362db8961e --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs @@ -0,0 +1,19 @@ +using CommunityToolkit.Maui.Sample.ViewModels.Views; + +namespace CommunityToolkit.Maui.Sample.Pages.Views; + +public partial class BarcodeScanningPage : BasePage +{ + public BarcodeScanningPage(BarcodeScanningViewModel viewModel) : base(viewModel) + { + InitializeComponent(); + } + + protected override async void OnAppearing() + { + base.OnAppearing(); + + var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3)); + await BindingContext.RefreshCamerasCommand.ExecuteAsync(cancellationTokenSource.Token); + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..d896c41faf --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,25 @@ +using System.Windows.Input; +using CommunityToolkit.Maui.Core; + +namespace CommunityToolkit.Maui.Sample; + +/// +/// +/// +public partial class PlatformBarcodeScanningScenario : PlatformCameraScenario +{ + /// + /// Backing BindableProperty for the property. + /// + public static readonly BindableProperty CommandProperty = + BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(PlatformBarcodeScanningScenario)); + + /// + /// The Command that should be executed when a barcode is detected. + /// + public ICommand? Command + { + get => (ICommand?)GetValue(CommandProperty); + set => SetValue(CommandProperty, value); + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/Android/BarcodeAnalyzer.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/BarcodeAnalyzer.cs new file mode 100644 index 0000000000..a35c4a3b11 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/BarcodeAnalyzer.cs @@ -0,0 +1,93 @@ +using System.Diagnostics; +using System.Windows.Input; +using Android.Gms.Tasks; +using Android.Runtime; +using AndroidX.Camera.Core; +using Xamarin.Google.MLKit.Vision.Barcode.Common; +using Xamarin.Google.MLKit.Vision.BarCode; +using Xamarin.Google.MLKit.Vision.Common; + +using Scanner = Xamarin.Google.MLKit.Vision.BarCode.BarcodeScanning; + +namespace CommunityToolkit.Maui.Sample; + +public class BarcodeAnalyzer : Java.Lang.Object, ImageAnalysis.IAnalyzer +{ + readonly ICommand command; + IBarcodeScanner? barcodeScanner; + readonly Lock resultsLock = new(); + + public BarcodeAnalyzer(ICommand command) + { + this.command = command; + } + + internal void UpdateSymbologies() + { + barcodeScanner?.Dispose(); + barcodeScanner = Scanner.GetClient(new BarcodeScannerOptions.Builder() + .SetBarcodeFormats(Barcode.FormatAllFormats) + .Build()); + } + + public void Analyze(IImageProxy proxy) + { + try + { + ArgumentNullException.ThrowIfNull(proxy?.Image); + ArgumentNullException.ThrowIfNull(barcodeScanner); + + using var inputImage = InputImage.FromMediaImage(proxy.Image, 0); + using var task = barcodeScanner.Process(inputImage); + var result = TasksClass.Await(task); + + lock (resultsLock) + { + ProcessResults(result); + } + + result?.Dispose(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + finally + { + try + { + proxy?.Close(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + } + + void ProcessResults(Java.Lang.Object? result) + { + if (result is not JavaList javaList) + { + return; + } + + foreach (Barcode barcode in javaList) + { + if (barcode is null) + { + continue; + } + + if (string.IsNullOrEmpty(barcode.DisplayValue) && string.IsNullOrEmpty(barcode.RawValue)) + { + continue; + } + + if (this.command?.CanExecute(barcode.RawValue) is true) + { + this.command.Execute(barcode.RawValue); + } + } + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..107a690351 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,30 @@ +using AndroidX.Camera.Core; + +namespace CommunityToolkit.Maui.Sample; + +public partial class PlatformBarcodeScanningScenario +{ + readonly Lazy? lazyUseCase = null; + + public PlatformBarcodeScanningScenario() + { + lazyUseCase = new Lazy(() => + { + var imageAnalysis = + new ImageAnalysis.Builder() + .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest) + .Build(); + + if (imageAnalysis.BackgroundExecutor is null) + { + throw new InvalidOperationException("Background executor must be set before use case."); + } + + imageAnalysis.SetAnalyzer(imageAnalysis.BackgroundExecutor, new BarcodeAnalyzer(Command!)); + + return imageAnalysis; + }); + } + + public override UseCase UseCase => lazyUseCase?.Value!; +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..9a20a29ae0 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,60 @@ +using System.Windows.Input; +using AVFoundation; +using CoreFoundation; + +namespace CommunityToolkit.Maui.Sample; + +/// +/// Apple based implementation +/// +public partial class PlatformBarcodeScanningScenario +{ + readonly Lazy lazyOutput; + + public PlatformBarcodeScanningScenario() + { + lazyOutput = new Lazy(() => + { + var output = new AVCaptureMetadataOutput(); + + output.SetDelegate(new BarcodeDetectionDelegate(Command), DispatchQueue.MainQueue); + output.MetadataObjectTypes = + AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code; + + return output; + }); + } + + public override AVCaptureOutput Output => lazyOutput.Value; +} + +sealed class BarcodeDetectionDelegate : AVCaptureMetadataOutputObjectsDelegate +{ + readonly ICommand? command; + + public BarcodeDetectionDelegate(ICommand? command) + { + this.command = command; + } + + public override void DidOutputMetadataObjects( + AVCaptureMetadataOutput captureOutput, + AVMetadataObject[] metadataObjects, + AVCaptureConnection connection) + { + foreach (var metadataObject in metadataObjects) + { + if (metadataObject is AVMetadataMachineReadableCodeObject readableObject) + { + var code = readableObject.StringValue; + + Console.WriteLine($"Metadata object {code} at {string.Join(",", readableObject.Corners?? [])}"); + + if (this.command?.CanExecute(readableObject.StringValue) is true) + { + this.command.Execute(readableObject.StringValue); + } + } + } + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..05562ea582 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,12 @@ +using System.Windows.Input; +using CommunityToolkit.Maui.Core; + +namespace CommunityToolkit.Maui.Sample; + +/// +/// +/// +public partial class PlatformBarcodeScanningScenario : PlatformCameraScenario +{ + public ICommand? Command { get; set; } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..9a20a29ae0 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,60 @@ +using System.Windows.Input; +using AVFoundation; +using CoreFoundation; + +namespace CommunityToolkit.Maui.Sample; + +/// +/// Apple based implementation +/// +public partial class PlatformBarcodeScanningScenario +{ + readonly Lazy lazyOutput; + + public PlatformBarcodeScanningScenario() + { + lazyOutput = new Lazy(() => + { + var output = new AVCaptureMetadataOutput(); + + output.SetDelegate(new BarcodeDetectionDelegate(Command), DispatchQueue.MainQueue); + output.MetadataObjectTypes = + AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code; + + return output; + }); + } + + public override AVCaptureOutput Output => lazyOutput.Value; +} + +sealed class BarcodeDetectionDelegate : AVCaptureMetadataOutputObjectsDelegate +{ + readonly ICommand? command; + + public BarcodeDetectionDelegate(ICommand? command) + { + this.command = command; + } + + public override void DidOutputMetadataObjects( + AVCaptureMetadataOutput captureOutput, + AVMetadataObject[] metadataObjects, + AVCaptureConnection connection) + { + foreach (var metadataObject in metadataObjects) + { + if (metadataObject is AVMetadataMachineReadableCodeObject readableObject) + { + var code = readableObject.StringValue; + + Console.WriteLine($"Metadata object {code} at {string.Join(",", readableObject.Corners?? [])}"); + + if (this.command?.CanExecute(readableObject.StringValue) is true) + { + this.command.Execute(readableObject.StringValue); + } + } + } + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs new file mode 100644 index 0000000000..3a9da2db49 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs @@ -0,0 +1,22 @@ +using CommunityToolkit.Maui.Core; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +namespace CommunityToolkit.Maui.Sample.ViewModels.Views; + +public partial class BarcodeScanningViewModel(ICameraProvider cameraProvider) : BaseViewModel +{ + readonly ICameraProvider cameraProvider = cameraProvider; + + [ObservableProperty] + public partial string DetectedCode { get; set; } + + [RelayCommand] + void OnCodeDetected(string code) + { + DetectedCode = code; + } + + [RelayCommand] + async Task RefreshCameras(CancellationToken token) => await cameraProvider.RefreshAvailableCameras(token); +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGalleryViewModel.cs b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGalleryViewModel.cs index ea038112a0..f3c8267d29 100644 --- a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGalleryViewModel.cs +++ b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGalleryViewModel.cs @@ -15,6 +15,7 @@ public sealed partial class ViewsGalleryViewModel() : BaseGalleryViewModel( SectionModel.Create("AvatarView Shadows Page", Colors.Red, "A page demonstrating AvatarViews with various shadow options."), SectionModel.Create("AvatarView Shapes Page", Colors.Red, "A page demonstrating AvatarViews with various shape options."), SectionModel.Create("AvatarView Sizes Page", Colors.Red, "A page demonstrating AvatarViews with various size options."), + SectionModel.Create("Barcode Page", Colors.Red, "Barcode scanning support using the CameraView."), SectionModel.Create("CameraView Page", Colors.Red, "CameraView is a view for displaying camera output."), SectionModel.Create("DrawingView", Colors.Red, "DrawingView provides a canvas for users to \"paint\" on the screen. The drawing can also be captured and displayed as an Image."), SectionModel.Create("Expander Page", Colors.Red, "Expander allows collapse and expand content."), diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs index c642ca4218..cd2fd590e6 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs @@ -19,6 +19,8 @@ namespace CommunityToolkit.Maui.Core; partial class CameraManager { readonly Context context = mauiContext.Context ?? throw new CameraException($"Unable to retrieve {nameof(Context)}"); + + readonly IList additionalUseCases = []; NativePlatformCameraPreviewView? previewView; IExecutorService? cameraExecutor; @@ -220,7 +222,14 @@ protected virtual async partial Task PlatformStartCameraPreview(CancellationToke var cameraSelector = cameraView.SelectedCamera.CameraSelector ?? throw new CameraException($"Unable to retrieve {nameof(CameraSelector)}"); var owner = (ILifecycleOwner)context; - camera = processCameraProvider.BindToLifecycle(owner, cameraSelector, cameraPreview, imageCapture); + camera = processCameraProvider.BindToLifecycle( + owner, + cameraSelector, + [ + .. additionalUseCases, + cameraPreview, + imageCapture + ]); cameraControl = camera.CameraControl; @@ -257,6 +266,26 @@ protected virtual partial ValueTask PlatformTakePicture(CancellationToken token) imageCapture?.TakePicture(cameraExecutor, imageCallback); return ValueTask.CompletedTask; } + + internal virtual partial void AddPlatformScenario(PlatformCameraScenario scenario) + { + AddUseCase(scenario.UseCase); + } + + internal virtual partial void RemovePlatformScenario(PlatformCameraScenario scenario) + { + RemoveUseCase(scenario.UseCase); + } + + internal void AddUseCase(UseCase useCase) + { + additionalUseCases.Add(useCase); + } + + internal void RemoveUseCase(UseCase useCase) + { + additionalUseCases.Remove(useCase); + } void SetImageCaptureTargetRotation(int rotation) { diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs index 17941d0cf7..0c3b3c234c 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs @@ -11,6 +11,8 @@ partial class CameraManager { // TODO: Check if we really need this readonly NSDictionary codecSettings = new([AVVideo.CodecKey], [new NSString("jpeg")]); + + readonly IList additionalCaptureOutputs = []; AVCaptureSession? captureSession; AVCapturePhotoOutput? photoOutput; @@ -157,6 +159,11 @@ protected virtual async partial Task PlatformStartCameraPreview(CancellationToke captureDevice = cameraView.SelectedCamera.CaptureDevice ?? throw new CameraException($"No Camera found"); captureInput = new AVCaptureDeviceInput(captureDevice, out _); captureSession.AddInput(captureInput); + + foreach (var output in additionalCaptureOutputs) + { + captureSession.AddOutput(output); + } if (photoOutput is null) { @@ -265,6 +272,26 @@ protected virtual void Dispose(bool disposing) } } + internal virtual partial void AddPlatformScenario(PlatformCameraScenario scenario) + { + AddOutput(scenario.Output); + } + + internal virtual partial void RemovePlatformScenario(PlatformCameraScenario scenario) + { + RemoveOutput(scenario.Output); + } + + internal void AddOutput(AVCaptureOutput captureOutput) + { + additionalCaptureOutputs.Add(captureOutput); + } + + internal void RemoveOutput(AVCaptureOutput captureOutput) + { + additionalCaptureOutputs.Remove(captureOutput); + } + static AVCaptureVideoOrientation GetVideoOrientation() { IEnumerable scenes = UIApplication.SharedApplication.ConnectedScenes; diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.net.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.net.cs index 41dae1d618..69eef9b7d8 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.net.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.net.cs @@ -23,4 +23,8 @@ partial class CameraManager protected virtual partial void PlatformDisconnect() => throw new NotSupportedException(notSupportedMessage); protected virtual partial ValueTask PlatformTakePicture(CancellationToken token) => throw new NotSupportedException(notSupportedMessage); + + internal virtual partial void AddPlatformScenario(PlatformCameraScenario scenario) => throw new NotSupportedException(notSupportedMessage); + + internal virtual partial void RemovePlatformScenario(PlatformCameraScenario scenario) => throw new NotSupportedException(notSupportedMessage); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs index d7703d2572..307d048572 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs @@ -18,6 +18,10 @@ partial class CameraManager( ICameraProvider cameraProvider, Action onLoaded) : IDisposable { + readonly IList scenarios = []; + + protected IReadOnlyList Scenarios => scenarios.AsReadOnly(); + internal Action OnLoaded { get; } = onLoaded; internal bool IsInitialized { get; private set; } @@ -131,4 +135,28 @@ public async ValueTask UpdateCurrentCamera(CameraInfo? cameraInfo, CancellationT /// Stops the preview from the camera, at the platform-specific level. /// protected virtual partial void PlatformStopCameraPreview(); + + internal void AddScenario(CameraScenario scenario) + { + this.scenarios.Add(scenario); + + if (scenario is PlatformCameraScenario platformScenario) + { + AddPlatformScenario(platformScenario); + } + } + + internal void RemoveScenario(CameraScenario scenario) + { + this.scenarios.Remove(scenario); + + if (scenario is PlatformCameraScenario platformScenario) + { + RemovePlatformScenario(platformScenario); + } + } + + internal virtual partial void AddPlatformScenario(PlatformCameraScenario scenario); + + internal virtual partial void RemovePlatformScenario(PlatformCameraScenario scenario); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs b/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs new file mode 100644 index 0000000000..6652592f94 --- /dev/null +++ b/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs @@ -0,0 +1,20 @@ +namespace CommunityToolkit.Maui.Core; + +/// +/// Base class for output based processing for camera related activities. +/// +public abstract class CameraScenario : BindableObject +{ + /// + /// Gets whether the scenario has been initialized. + /// + public bool IsInitialized { get; protected set; } + + /// + /// Initializes the scenario. + /// + public virtual void Initialize() + { + IsInitialized = true; + } +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs new file mode 100644 index 0000000000..18ff8675a9 --- /dev/null +++ b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs @@ -0,0 +1,15 @@ +using AndroidX.Camera.Core; + +namespace CommunityToolkit.Maui.Core; + +/// +/// +/// +partial class PlatformCameraScenario : CameraScenario +{ + /// + /// + /// + /// + public abstract UseCase UseCase { get; } +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs new file mode 100644 index 0000000000..6d703c0ec3 --- /dev/null +++ b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs @@ -0,0 +1,14 @@ +using AVFoundation; + +namespace CommunityToolkit.Maui.Core; + +/// +/// +/// +partial class PlatformCameraScenario : CameraScenario +{ + /// + /// + /// + public abstract AVCaptureOutput Output { get; } +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.shared.cs b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.shared.cs new file mode 100644 index 0000000000..987b58dd33 --- /dev/null +++ b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.shared.cs @@ -0,0 +1,8 @@ +namespace CommunityToolkit.Maui.Core; + +/// +/// +/// +public abstract partial class PlatformCameraScenario : CameraScenario +{ +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs index edbd26460d..c97aa48a23 100644 --- a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.ObjectModel; +using System.ComponentModel; using System.Runtime.Versioning; using System.Windows.Input; using CommunityToolkit.Maui.Core; @@ -18,6 +19,24 @@ public partial class CameraView : View, ICameraView, IDisposable static readonly BindablePropertyKey isAvailablePropertyKey = BindableProperty.CreateReadOnly(nameof(IsAvailable), typeof(bool), typeof(CameraView), CameraViewDefaults.IsAvailable); + internal static readonly BindablePropertyKey ScenariosPropertyKey = BindableProperty.CreateReadOnly(nameof(Scenarios), typeof(IList), typeof(CameraView), default(IList), + defaultValueCreator: bindable => + { + var collection = new ObservableCollection(); + return collection; + }); + + /// Bindable property for . + public static readonly BindableProperty ScenariosProperty = ScenariosPropertyKey.BindableProperty; + + /// + /// + /// + public IList Scenarios + { + get { return (IList)GetValue(ScenariosProperty); } + } + /// /// Backing for the property. /// @@ -251,12 +270,26 @@ public async Task CaptureImage(CancellationToken token) } /// - public Task StartCameraPreview(CancellationToken token) => - Handler.CameraManager.StartCameraPreview(token); + public Task StartCameraPreview(CancellationToken token) + { + foreach (var scenario in Scenarios) + { + Handler.CameraManager.AddScenario(scenario); + } + + return Handler.CameraManager.StartCameraPreview(token); + } /// - public void StopCameraPreview() => + public void StopCameraPreview() + { + foreach (var scenario in Scenarios) + { + Handler.CameraManager.RemoveScenario(scenario); + } + Handler.CameraManager.StopCameraPreview(); + } /// protected virtual void Dispose(bool disposing)