Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
using CommunityToolkit.Maui.Core;
using CommunityToolkit.Maui.Core.Primitives;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace CommunityToolkit.Maui.Sample.ViewModels.Views;

public partial class CameraViewViewModel(ICameraProvider cameraProvider) : BaseViewModel
public partial class CameraViewViewModel : BaseViewModel
{
readonly ICameraProvider cameraProvider = cameraProvider;
readonly ICameraProvider cameraProvider;

public CameraViewViewModel(ICameraProvider cameraProvider)
{
this.cameraProvider = cameraProvider;

cameraProvider.AvailableCamerasChanged += HandleAvailableCamerasChanged;
}

public IReadOnlyList<CameraInfo> Cameras => cameraProvider.AvailableCameras ?? [];

Expand Down Expand Up @@ -78,4 +84,9 @@ void UpdateResolutionText()
{
ResolutionText = $"Selected Resolution: {SelectedResolution.Width} x {SelectedResolution.Height}";
}

void HandleAvailableCamerasChanged(object? sender, IReadOnlyList<CameraInfo>? e)
{
OnPropertyChanged(nameof(Cameras));
}
}
31 changes: 26 additions & 5 deletions src/CommunityToolkit.Maui.Camera/CameraInfo.shared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#if IOS || MACCATALYST
using AVFoundation;

#elif ANDROID
using AndroidX.Camera.Core;
#elif WINDOWS
Expand All @@ -23,18 +24,18 @@ public class CameraInfo(
float maximumZoomFactor,
IEnumerable<Size> supportedResolutions
#if ANDROID
,
,
CameraSelector cameraSelector
#elif IOS || MACCATALYST
,
,
AVCaptureDevice captureDevice,
IEnumerable<AVCaptureDeviceFormat> supportedFormats
#elif WINDOWS
,
,
MediaFrameSourceGroup frameSourceGroup,
IEnumerable<ImageEncodingProperties> imageEncodingProperties
#endif
)
) : IEquatable<CameraInfo>
{
/// <summary>
/// Gets the name of the camera device.
Expand Down Expand Up @@ -82,9 +83,29 @@ IEnumerable<ImageEncodingProperties> imageEncodingProperties

#if WINDOWS
internal MediaFrameSourceGroup FrameSourceGroup { get; } = frameSourceGroup;
internal IReadOnlyList<ImageEncodingProperties> ImageEncodingProperties { get; } = [.. imageEncodingProperties];
internal IReadOnlyList<ImageEncodingProperties> ImageEncodingProperties { get; } = [.. imageEncodingProperties];
#endif

/// <inheritdoc cref="Equals(object)"/>
/// <remarks>Equality is determined using <see cref="DeviceId"/></remarks>
public override bool Equals(object? obj) => Equals(obj as CameraInfo);

/// <inheritdoc cref="GetHashCode"/>
/// <remarks>Uses the <see cref="DeviceId"/></remarks>
public override int GetHashCode() => DeviceId.GetHashCode();

/// <inheritdoc cref="IEquatable{T}.Equals(T)"/>
/// <remarks>Equality is determined using <see cref="DeviceId"/></remarks>
public bool Equals(CameraInfo? other)
{
if (other is null)
{
return false;
}

return DeviceId == other.DeviceId;
}

/// <inheritdoc cref="object.ToString" />
public override string ToString()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ namespace CommunityToolkit.Maui.Core;
/// </summary>
public interface ICameraProvider
{
/// <summary>
/// Event fires when the contents <see cref="AvailableCameras"/> has changed
/// </summary>
event EventHandler<IReadOnlyList<CameraInfo>?> AvailableCamerasChanged;

/// <summary>
/// Cameras available on device
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,46 @@
/// </summary>
partial class CameraProvider : ICameraProvider
{
readonly WeakEventManager availableCamerasChangedEventManager = new();

public event EventHandler<IReadOnlyList<CameraInfo>?> AvailableCamerasChanged
{
add => availableCamerasChangedEventManager.AddEventHandler(value);
remove => availableCamerasChangedEventManager.RemoveEventHandler(value);
}

/// <inheritdoc/>
public IReadOnlyList<CameraInfo>? AvailableCameras { get; private set; }
public IReadOnlyList<CameraInfo>? AvailableCameras
{
get;
private set
{
if (!AreCameraInfoListsEqual(field, value))
{
field = value;
availableCamerasChangedEventManager.HandleEvent(this, value, nameof(AvailableCamerasChanged));
}
}
}

/// <inheritdoc/>
public partial ValueTask RefreshAvailableCameras(CancellationToken token);

internal static bool AreCameraInfoListsEqual(in IReadOnlyList<CameraInfo>? cameraInfoList1, in IReadOnlyList<CameraInfo>? cameraInfoList2)
{
if (cameraInfoList1 is null && cameraInfoList2 is null)
{
return true;
}

if (cameraInfoList1 is null || cameraInfoList2 is null)
{
return false;
}

var cameraInfosInList1ButNotInList2 = cameraInfoList1.Except(cameraInfoList2).ToList();
var cameraInfosInList2ButNotInList1 = cameraInfoList2.Except(cameraInfoList1).ToList();

return cameraInfosInList1ButNotInList2.Count is 0 && cameraInfosInList2ButNotInList1.Count is 0;
}
}
15 changes: 14 additions & 1 deletion src/CommunityToolkit.Maui.UnitTests/Mocks/MockCameraProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,20 @@ namespace CommunityToolkit.Maui.UnitTests.Mocks;

public class MockCameraProvider : ICameraProvider
{
public IReadOnlyList<CameraInfo>? AvailableCameras { get; private set; }
public event EventHandler<IReadOnlyList<CameraInfo>?>? AvailableCamerasChanged;

public IReadOnlyList<CameraInfo>? AvailableCameras
{
get;
private set
{
if (!CameraProvider.AreCameraInfoListsEqual(field, value))
{
field = value;
AvailableCamerasChanged?.Invoke(this, value);
}
}
}

public ValueTask RefreshAvailableCameras(CancellationToken token)
{
Expand Down
Loading
Loading