Skip to content

Commit 48162ac

Browse files
authored
Merge branch 'main' into BindablePropertiesLayouts
2 parents 3581058 + 44d9173 commit 48162ac

File tree

8 files changed

+125
-112
lines changed

8 files changed

+125
-112
lines changed

samples/CommunityToolkit.Maui.Sample/ViewModels/Essentials/FileSaverViewModel.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,6 @@ async Task SaveFileInstance(CancellationToken cancellationToken)
8888
fileSaverResult.EnsureSuccess();
8989

9090
await Toast.Make($"File is saved: {fileSaverResult.FilePath}").Show(cancellationToken);
91-
#if IOS || MACCATALYST
92-
fileSaverInstance.Dispose();
93-
#endif
9491
}
9592
catch (Exception ex)
9693
{

samples/CommunityToolkit.Maui.Sample/ViewModels/Essentials/FolderPickerViewModel.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,6 @@ async Task PickFolderInstance(CancellationToken cancellationToken)
7979
folderPickerResult.EnsureSuccess();
8080

8181
await Toast.Make($"Folder picked: Name - {folderPickerResult.Folder.Name}, Path - {folderPickerResult.Folder.Path}", ToastDuration.Long).Show(cancellationToken);
82-
#if IOS || MACCATALYST
83-
folderPickerInstance.Dispose();
84-
#endif
8582
}
8683
catch (Exception e)
8784
{

src/CommunityToolkit.Maui.Core/Essentials/FileSaver/FileSaverImplementation.macios.cs

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,85 +6,93 @@ namespace CommunityToolkit.Maui.Storage;
66
/// <inheritdoc cref="IFileSaver" />
77
[SupportedOSPlatform("iOS14.0")]
88
[SupportedOSPlatform("MacCatalyst14.0")]
9-
public sealed partial class FileSaverImplementation : IFileSaver, IDisposable
9+
public sealed partial class FileSaverImplementation : IFileSaver
1010
{
11-
UIDocumentPickerViewController? documentPickerViewController;
12-
TaskCompletionSource<string>? taskCompetedSource;
13-
14-
/// <inheritdoc />
15-
public void Dispose()
11+
Task<string> InternalSaveAsync(string fileName, Stream stream, IProgress<double>? progress, CancellationToken cancellationToken)
1612
{
17-
InternalDispose();
13+
return InternalSaveAsync("/", fileName, stream, progress, cancellationToken);
1814
}
19-
20-
async Task<string> InternalSaveAsync(string initialPath, string fileName, Stream stream, IProgress<double>? progress, CancellationToken cancellationToken)
15+
16+
async Task<string> InternalSaveAsync(
17+
string initialPath,
18+
string fileName,
19+
Stream stream,
20+
IProgress<double>? progress,
21+
CancellationToken cancellationToken)
2122
{
2223
cancellationToken.ThrowIfCancellationRequested();
24+
25+
var currentViewController = Platform.GetCurrentUIViewController()
26+
?? throw new FileSaveException(
27+
"Cannot present file picker: No active view controller found. Ensure the app is active with a visible window.");
28+
2329
var fileManager = NSFileManager.DefaultManager;
24-
var tempDirectoryPath = fileManager.GetTemporaryDirectory().Append(Guid.NewGuid().ToString(), true);
25-
var isDirectoryCreated = fileManager.CreateDirectory(tempDirectoryPath, true, null, out var error);
26-
if (!isDirectoryCreated)
30+
31+
var tempDirectoryPath = fileManager
32+
.GetTemporaryDirectory()
33+
.Append(Guid.NewGuid().ToString(), true);
34+
35+
if (!fileManager.CreateDirectory(tempDirectoryPath, true, null, out var error))
2736
{
2837
throw new FileSaveException(error?.LocalizedDescription ?? "Unable to create temp directory.");
2938
}
3039

3140
var fileUrl = tempDirectoryPath.Append(fileName, false);
32-
await WriteStream(stream, fileUrl.Path ?? throw new Exception("Path cannot be null."), progress, cancellationToken);
3341

34-
cancellationToken.ThrowIfCancellationRequested();
35-
taskCompetedSource?.TrySetCanceled(CancellationToken.None);
36-
var tcs = taskCompetedSource = new(cancellationToken);
42+
await WriteStream(
43+
stream,
44+
fileUrl.Path ?? throw new FileSaveException("Path cannot be null."),
45+
progress,
46+
cancellationToken);
3747

38-
documentPickerViewController = new([fileUrl])
39-
{
40-
DirectoryUrl = NSUrl.FromString(initialPath)
41-
};
42-
documentPickerViewController.DidPickDocumentAtUrls += DocumentPickerViewControllerOnDidPickDocumentAtUrls;
43-
documentPickerViewController.WasCancelled += DocumentPickerViewControllerOnWasCancelled;
48+
var tcs = new TaskCompletionSource<string>(
49+
TaskCreationOptions.RunContinuationsAsynchronously);
4450

45-
var currentViewController = Platform.GetCurrentUIViewController();
46-
if (currentViewController is not null)
47-
{
48-
currentViewController.PresentViewController(documentPickerViewController, true, null);
49-
}
50-
else
51-
{
52-
throw new FileSaveException("Unable to get a window where to present the file saver UI.");
53-
}
51+
await using var registration = cancellationToken.Register(() =>
52+
tcs.TrySetCanceled(cancellationToken));
5453

55-
return await tcs.Task.WaitAsync(cancellationToken).ConfigureAwait(false);
56-
}
54+
using var picker = new UIDocumentPickerViewController([fileUrl], true);
55+
picker.DirectoryUrl = NSUrl.FromString(initialPath);
5756

58-
Task<string> InternalSaveAsync(string fileName, Stream stream, IProgress<double>? progress, CancellationToken cancellationToken)
59-
{
60-
return InternalSaveAsync("/", fileName, stream, progress, cancellationToken);
61-
}
62-
63-
void DocumentPickerViewControllerOnWasCancelled(object? sender, EventArgs e)
64-
{
65-
taskCompetedSource?.TrySetException(new FileSaveException("Operation cancelled."));
66-
InternalDispose();
67-
}
57+
picker.DidPickDocumentAtUrls += OnPicked;
58+
picker.WasCancelled += OnCancelled;
6859

69-
void DocumentPickerViewControllerOnDidPickDocumentAtUrls(object? sender, UIDocumentPickedAtUrlsEventArgs e)
70-
{
7160
try
7261
{
73-
taskCompetedSource?.TrySetResult(e.Urls[0].Path ?? throw new FileSaveException("Unable to retrieve the path of the saved file."));
62+
cancellationToken.ThrowIfCancellationRequested();
63+
currentViewController.PresentViewController(picker, true, null);
64+
65+
return await tcs.Task.WaitAsync(cancellationToken);
7466
}
7567
finally
7668
{
77-
InternalDispose();
69+
fileManager.Remove(tempDirectoryPath, out _);
70+
71+
picker.DidPickDocumentAtUrls -= OnPicked;
72+
picker.WasCancelled -= OnCancelled;
73+
}
74+
75+
void OnPicked(object? sender, UIDocumentPickedAtUrlsEventArgs e)
76+
{
77+
if (e.Urls.Length is 0)
78+
{
79+
tcs.TrySetException(new FileSaveException("No file was selected."));
80+
return;
81+
}
82+
83+
var path = e.Urls[0].Path;
84+
if (path is null)
85+
{
86+
tcs.TrySetException(new FileSaveException("File path cannot be null."));
87+
return;
88+
}
89+
90+
tcs.TrySetResult(path);
7891
}
79-
}
8092

81-
void InternalDispose()
82-
{
83-
if (documentPickerViewController is not null)
93+
void OnCancelled(object? sender, EventArgs e)
8494
{
85-
documentPickerViewController.DidPickDocumentAtUrls -= DocumentPickerViewControllerOnDidPickDocumentAtUrls;
86-
documentPickerViewController.WasCancelled -= DocumentPickerViewControllerOnWasCancelled;
87-
documentPickerViewController.Dispose();
95+
tcs.TrySetCanceled(cancellationToken);
8896
}
8997
}
9098
}

src/CommunityToolkit.Maui.Core/Essentials/FileSaver/FileSaverResult.shared.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics.CodeAnalysis;
2+
using System.Runtime.ExceptionServices;
23

34
namespace CommunityToolkit.Maui.Storage;
45

@@ -15,6 +16,11 @@ public record FileSaverResult(string? FilePath, Exception? Exception)
1516
[MemberNotNullWhen(true, nameof(FilePath))]
1617
[MemberNotNullWhen(false, nameof(Exception))]
1718
public bool IsSuccessful => Exception is null;
19+
20+
/// <summary>
21+
/// Check if the operation was cancelled.
22+
/// </summary>
23+
public bool IsCancelled => Exception is OperationCanceledException;
1824

1925
/// <summary>
2026
/// Check if the operation was successful.
@@ -24,7 +30,7 @@ public void EnsureSuccess()
2430
{
2531
if (!IsSuccessful)
2632
{
27-
throw Exception;
33+
ExceptionDispatchInfo.Throw(Exception);
2834
}
2935
}
3036
}

src/CommunityToolkit.Maui.Core/Essentials/FolderPicker/FolderPickerImplementation.macios.cs

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,65 +8,64 @@ namespace CommunityToolkit.Maui.Storage;
88
/// <inheritdoc cref="IFolderPicker" />
99
[SupportedOSPlatform("iOS14.0")]
1010
[SupportedOSPlatform("MacCatalyst14.0")]
11-
public sealed partial class FolderPickerImplementation : IFolderPicker, IDisposable
11+
public sealed partial class FolderPickerImplementation : IFolderPicker
1212
{
13-
readonly UIDocumentPickerViewController documentPickerViewController = new([UTTypes.Folder])
14-
{
15-
AllowsMultipleSelection = false
16-
};
17-
18-
TaskCompletionSource<Folder>? taskCompetedSource;
19-
20-
/// <summary>
21-
/// Initializes a new instance of the <see cref="FolderPickerImplementation"/> class.
22-
/// </summary>
23-
public FolderPickerImplementation()
24-
{
25-
documentPickerViewController.DidPickDocumentAtUrls += DocumentPickerViewControllerOnDidPickDocumentAtUrls;
26-
documentPickerViewController.WasCancelled += DocumentPickerViewControllerOnWasCancelled;
27-
}
28-
29-
/// <inheritdoc />
30-
public void Dispose()
13+
Task<Folder> InternalPickAsync(CancellationToken cancellationToken)
3114
{
32-
documentPickerViewController.DidPickDocumentAtUrls -= DocumentPickerViewControllerOnDidPickDocumentAtUrls;
33-
documentPickerViewController.WasCancelled -= DocumentPickerViewControllerOnWasCancelled;
34-
documentPickerViewController.Dispose();
15+
return InternalPickAsync("/", cancellationToken);
3516
}
36-
17+
3718
async Task<Folder> InternalPickAsync(string initialPath, CancellationToken cancellationToken)
3819
{
3920
cancellationToken.ThrowIfCancellationRequested();
40-
documentPickerViewController.DirectoryUrl = NSUrl.FromString(initialPath);
41-
var currentViewController = Platform.GetCurrentUIViewController();
4221

43-
taskCompetedSource?.TrySetCanceled(CancellationToken.None);
44-
var tcs = taskCompetedSource = new();
45-
if (currentViewController is not null)
22+
var currentViewController = Platform.GetCurrentUIViewController()
23+
?? throw new FolderPickerException("Unable to get a window where to present the folder picker UI.");
24+
25+
var tcs = new TaskCompletionSource<Folder>(
26+
TaskCreationOptions.RunContinuationsAsynchronously);
27+
28+
await using var registration = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
29+
30+
using var picker = new UIDocumentPickerViewController([UTTypes.Folder]);
31+
picker.AllowsMultipleSelection = false;
32+
picker.DirectoryUrl = NSUrl.FromString(initialPath);
33+
34+
picker.DidPickDocumentAtUrls += OnPicked;
35+
picker.WasCancelled += OnCancelled;
36+
37+
try
4638
{
47-
currentViewController.PresentViewController(documentPickerViewController, true, null);
39+
currentViewController.PresentViewController(picker, true, null);
40+
return await tcs.Task.WaitAsync(cancellationToken);
4841
}
49-
else
42+
finally
5043
{
51-
throw new FolderPickerException("Unable to get a window where to present the folder picker UI.");
44+
picker.DidPickDocumentAtUrls -= OnPicked;
45+
picker.WasCancelled -= OnCancelled;
5246
}
47+
48+
void OnPicked(object? sender, UIDocumentPickedAtUrlsEventArgs e)
49+
{
50+
if (e.Urls.Length is 0)
51+
{
52+
tcs.TrySetException(new FolderPickerException("No folder was selected."));
53+
return;
54+
}
5355

54-
return await tcs.Task.WaitAsync(cancellationToken).ConfigureAwait(false);
55-
}
56-
57-
Task<Folder> InternalPickAsync(CancellationToken cancellationToken)
58-
{
59-
return InternalPickAsync("/", cancellationToken);
60-
}
56+
var path = e.Urls[0].Path;
57+
if (path is null)
58+
{
59+
tcs.TrySetException(new FolderPickerException("File path cannot be null."));
60+
return;
61+
}
6162

62-
void DocumentPickerViewControllerOnWasCancelled(object? sender, EventArgs e)
63-
{
64-
taskCompetedSource?.TrySetException(new FolderPickerException("Operation cancelled."));
65-
}
63+
tcs.TrySetResult(new Folder(path, new DirectoryInfo(path).Name));
64+
}
6665

67-
void DocumentPickerViewControllerOnDidPickDocumentAtUrls(object? sender, UIDocumentPickedAtUrlsEventArgs e)
68-
{
69-
var path = e.Urls[0].Path ?? throw new FolderPickerException("Path cannot be null.");
70-
taskCompetedSource?.TrySetResult(new Folder(path, new DirectoryInfo(path).Name));
66+
void OnCancelled(object? sender, EventArgs e)
67+
{
68+
tcs.TrySetCanceled(cancellationToken);
69+
}
7170
}
7271
}

src/CommunityToolkit.Maui.Core/Essentials/FolderPicker/FolderPickerResult.shared.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics.CodeAnalysis;
2+
using System.Runtime.ExceptionServices;
23
using CommunityToolkit.Maui.Core.Primitives;
34

45
namespace CommunityToolkit.Maui.Storage;
@@ -17,6 +18,11 @@ public record FolderPickerResult(Folder? Folder, Exception? Exception)
1718
[MemberNotNullWhen(false, nameof(Exception))]
1819
public bool IsSuccessful => Exception is null;
1920

21+
/// <summary>
22+
/// Check if the operation was cancelled.
23+
/// </summary>
24+
public bool IsCancelled => Exception is OperationCanceledException;
25+
2026
/// <summary>
2127
/// Check if operation was successful.
2228
/// </summary>
@@ -25,7 +31,7 @@ public void EnsureSuccess()
2531
{
2632
if (!IsSuccessful)
2733
{
28-
throw Exception;
34+
ExceptionDispatchInfo.Throw(Exception);
2935
}
3036
}
3137
}

src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ protected virtual async partial ValueTask PlatformUpdateSource()
291291
var uri = uriMediaSource.Uri?.AbsoluteUri;
292292
if (!string.IsNullOrWhiteSpace(uri))
293293
{
294-
Player.Source = WinMediaSource.CreateFromUri(new Uri(uri));
294+
Player.MediaPlayer.SetUriSource(new Uri(uri));
295295
}
296296
}
297297
else if (MediaElement.Source is FileMediaSource fileMediaSource)
@@ -300,7 +300,7 @@ protected virtual async partial ValueTask PlatformUpdateSource()
300300
if (!string.IsNullOrWhiteSpace(filename))
301301
{
302302
StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filename);
303-
Player.Source = WinMediaSource.CreateFromStorageFile(storageFile);
303+
Player.MediaPlayer.SetFileSource(storageFile);
304304
}
305305
}
306306
else if (MediaElement.Source is ResourceMediaSource resourceMediaSource)
@@ -314,7 +314,7 @@ protected virtual async partial ValueTask PlatformUpdateSource()
314314
string path = GetFullAppPackageFilePath(resourceMediaSource.Path);
315315
if (!string.IsNullOrWhiteSpace(path))
316316
{
317-
Player.Source = WinMediaSource.CreateFromUri(new Uri(path));
317+
Player.MediaPlayer.SetUriSource(new Uri(path));
318318
}
319319
}
320320
}

src/CommunityToolkit.Maui.SourceGenerators.Internal.UnitTests/CommunityToolkit.Maui.SourceGenerators.Internal.UnitTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing" Version="1.1.2" />
2020
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing" Version="1.1.2" />
2121
<PackageReference Include="xunit.v3.mtp-v2" Version="3.2.1" />
22-
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.1.0" />
22+
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.3.1" />
2323
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.0.0" />
2424
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing" Version="1.1.2" />
2525
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiPackageVersion)" />

0 commit comments

Comments
 (0)