Skip to content

Commit

Permalink
chore: Update MediaGallery to Uno.Sdk 5.4
Browse files Browse the repository at this point in the history
  • Loading branch information
eriklimakc committed Nov 14, 2024
1 parent e9ccf60 commit 044a0ec
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 207 deletions.
37 changes: 23 additions & 14 deletions UI/MediaGallery/src/MediaGallerySample/MainPage.xaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
<Page
x:Class="MediaGallerySample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MediaGallerySample"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="8">
<TextBlock Style="{ThemeResource TitleTextBlockStyle}" Text="MediaGallery Sample" />
<Button HorizontalAlignment="Center" Click="CheckAccessClick">Check access</Button>
<Button HorizontalAlignment="Center" Click="SaveClick">Save UnoLogo.png to gallery</Button>
<Button HorizontalAlignment="Center" Click="SaveRandomNameClick">Save with random name to gallery</Button>
<Page x:Class="MediaGallerySample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MediaGallerySample"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="8">
<TextBlock Style="{ThemeResource TitleTextBlockStyle}"
Text="MediaGallery Sample" />
<Button HorizontalAlignment="Center"
Click="CheckAccessClick">
Check access
</Button>
<Button HorizontalAlignment="Center"
Click="SaveClick">
Save UnoLogo.png to gallery
</Button>
<Button HorizontalAlignment="Center"
Click="SaveRandomNameClick">
Save with random name to gallery
</Button>
</StackPanel>
</Page>
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ namespace Uno.Samples;
/// </summary>
public enum MediaFileType
{
/// <summary>
/// Image media file type.
/// </summary>
Image,
/// <summary>
/// Image media file type.
/// </summary>
Image,

/// <summary>
/// Video media file type.
/// </summary>
Video,
/// <summary>
/// Video media file type.
/// </summary>
Video,
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -20,105 +20,105 @@ namespace Uno.Samples;

partial class MediaGallery
{
private static async Task<bool> CheckAccessAsyncImpl()
{
if ((int)Build.VERSION.SdkInt < 29)
{
return await PermissionsHelper.CheckWriteExternalStoragePermission(default);
}
else
{
return true;
}
}

private static async Task SavePlatformAsyncImpl(MediaFileType type, Stream sourceStream, string targetFileName)
{
var context = Android.App.Application.Context;
var contentResolver = context.ContentResolver ?? throw new InvalidOperationException("ContentResolver is not set.");

var appFolderName = Package.Current.DisplayName;
// Ensure folder name is file system safe
appFolderName = string.Join("_", appFolderName.Split(Path.GetInvalidFileNameChars()));

var dateTimeNow = DateTime.Now;

var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(targetFileName);
var extension = Path.GetExtension(targetFileName).ToLower();

using var values = new ContentValues();

values.Put(IMediaColumns.DateAdded, GetUnixTimestampInSeconds(dateTimeNow));
values.Put(IMediaColumns.Title, fileNameWithoutExtension);
values.Put(IMediaColumns.DisplayName, targetFileName);

var mimeTypeMap = MimeTypeMap.Singleton ?? throw new InvalidOperationException("MimeTypeMap is not set.");

var mimeType = mimeTypeMap.GetMimeTypeFromExtension(extension.Replace(".", string.Empty));
if (!string.IsNullOrWhiteSpace(mimeType))
values.Put(IMediaColumns.MimeType, mimeType);

using var externalContentUri = type == MediaFileType.Image
? Images.Media.ExternalContentUri
: Video.Media.ExternalContentUri;

if (externalContentUri is null)
{
throw new InvalidOperationException($"External Content URI for {type} is not available.");
}

var relativePath = type == MediaFileType.Image
? Environment.DirectoryPictures
: Environment.DirectoryMovies;

if (relativePath is null)
{
throw new InvalidOperationException($"Relative path for {type} is not available.");
}

if ((int)Build.VERSION.SdkInt >= 29)
{
values.Put(IMediaColumns.RelativePath, Path.Combine(relativePath, appFolderName));
values.Put(IMediaColumns.IsPending, true);

using var uri = contentResolver.Insert(externalContentUri, values) ??
throw new InvalidOperationException("Could not generate new content URI");

using var stream = contentResolver.OpenOutputStream(uri) ??
throw new InvalidOperationException("Could not open output stream");

await sourceStream.CopyToAsync(stream);
stream.Close();

values.Put(IMediaColumns.IsPending, false);
context.ContentResolver.Update(uri, values, null, null);
}
else
{
private static async Task<bool> CheckAccessAsyncImpl()
{
if ((int)Build.VERSION.SdkInt < 29)
{
return await PermissionsHelper.CheckWriteExternalStoragePermission(default);
}
else
{
return true;
}
}

private static async Task SavePlatformAsyncImpl(MediaFileType type, Stream sourceStream, string targetFileName)
{
var context = Android.App.Application.Context;
var contentResolver = context.ContentResolver ?? throw new InvalidOperationException("ContentResolver is not set.");

var appFolderName = Package.Current.DisplayName;
// Ensure folder name is file system safe
appFolderName = string.Join("_", appFolderName.Split(Path.GetInvalidFileNameChars()));

var dateTimeNow = DateTime.Now;

var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(targetFileName);
var extension = Path.GetExtension(targetFileName).ToLower();

using var values = new ContentValues();

values.Put(IMediaColumns.DateAdded, GetUnixTimestampInSeconds(dateTimeNow));
values.Put(IMediaColumns.Title, fileNameWithoutExtension);
values.Put(IMediaColumns.DisplayName, targetFileName);

var mimeTypeMap = MimeTypeMap.Singleton ?? throw new InvalidOperationException("MimeTypeMap is not set.");

var mimeType = mimeTypeMap.GetMimeTypeFromExtension(extension.Replace(".", string.Empty));
if (!string.IsNullOrWhiteSpace(mimeType))
values.Put(IMediaColumns.MimeType, mimeType);

using var externalContentUri = type == MediaFileType.Image
? Images.Media.ExternalContentUri
: Video.Media.ExternalContentUri;

if (externalContentUri is null)
{
throw new InvalidOperationException($"External Content URI for {type} is not available.");
}

var relativePath = type == MediaFileType.Image
? Environment.DirectoryPictures
: Environment.DirectoryMovies;

if (relativePath is null)
{
throw new InvalidOperationException($"Relative path for {type} is not available.");
}

if ((int)Build.VERSION.SdkInt >= 29)
{
values.Put(IMediaColumns.RelativePath, Path.Combine(relativePath, appFolderName));
values.Put(IMediaColumns.IsPending, true);

using var uri = contentResolver.Insert(externalContentUri, values) ??
throw new InvalidOperationException("Could not generate new content URI");

using var stream = contentResolver.OpenOutputStream(uri) ??
throw new InvalidOperationException("Could not open output stream");

await sourceStream.CopyToAsync(stream);
stream.Close();

values.Put(IMediaColumns.IsPending, false);
context.ContentResolver.Update(uri, values, null, null);
}
else
{
#pragma warning disable CS0618 // Type or member is obsolete
using var directory = new NativeFile(Environment.GetExternalStoragePublicDirectory(relativePath), appFolderName);
directory.Mkdirs();
using var directory = new NativeFile(Environment.GetExternalStoragePublicDirectory(relativePath), appFolderName);
directory.Mkdirs();

using var file = new NativeFile(directory, targetFileName);
using var file = new NativeFile(directory, targetFileName);

using var fileOutputStream = System.IO.File.Create(file.AbsolutePath);
await sourceStream.CopyToAsync(fileOutputStream);
fileOutputStream.Close();
using var fileOutputStream = System.IO.File.Create(file.AbsolutePath);
await sourceStream.CopyToAsync(fileOutputStream);
fileOutputStream.Close();

values.Put(IMediaColumns.Data, file.AbsolutePath);
contentResolver.Insert(externalContentUri, values);
values.Put(IMediaColumns.Data, file.AbsolutePath);
contentResolver.Insert(externalContentUri, values);

#pragma warning disable CA1422 // Validate platform compatibility
using var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
using var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
#pragma warning restore CA1422 // Validate platform compatibility
mediaScanIntent.SetData(NativeUri.FromFile(file));
context.SendBroadcast(mediaScanIntent);
mediaScanIntent.SetData(NativeUri.FromFile(file));
context.SendBroadcast(mediaScanIntent);
#pragma warning restore CS0618 // Type or member is obsolete
}
}
}
}

private static long GetUnixTimestampInSeconds(DateTime current) => (long)GetTimeDifference(current).TotalSeconds;
private static long GetUnixTimestampInSeconds(DateTime current) => (long)GetTimeDifference(current).TotalSeconds;

private static TimeSpan GetTimeDifference(DateTime current) => current.ToUniversalTime() - DateTime.UnixEpoch;
private static TimeSpan GetTimeDifference(DateTime current) => current.ToUniversalTime() - DateTime.UnixEpoch;
}
#endif
54 changes: 27 additions & 27 deletions UI/MediaGallery/src/MediaGallerySample/MediaGallery/MediaGallery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,34 @@ namespace Uno.Samples;
/// </summary>
public static partial class MediaGallery
{
/// <summary>
/// Checks the user's permission to access the device's gallery.
/// Will trigger the permission request if not already granted.
/// </summary>
/// <returns>A value indicating whether the user has access.</returns>
public static async Task<bool> CheckAccessAsync() => await CheckAccessAsyncImpl();
/// <summary>
/// Checks the user's permission to access the device's gallery.
/// Will trigger the permission request if not already granted.
/// </summary>
/// <returns>A value indicating whether the user has access.</returns>
public static async Task<bool> CheckAccessAsync() => await CheckAccessAsyncImpl();

/// <summary>
/// Saves a media file to the device's gallery.
/// </summary>
/// <param name="type">Media file type.</param>
/// <param name="data">Byte array representing the file.</param>
/// <param name="targetFileName">Target file name.</param>
/// <returns>Task representing the progress of the operation.</returns>
public static async Task SaveAsync(MediaFileType type, byte[] data, string targetFileName)
{
using var memoryStream = new MemoryStream(data);
await SaveAsync(type, memoryStream, targetFileName);
}
/// <summary>
/// Saves a media file to the device's gallery.
/// </summary>
/// <param name="type">Media file type.</param>
/// <param name="data">Byte array representing the file.</param>
/// <param name="targetFileName">Target file name.</param>
/// <returns>Task representing the progress of the operation.</returns>
public static async Task SaveAsync(MediaFileType type, byte[] data, string targetFileName)
{
using var memoryStream = new MemoryStream(data);
await SaveAsync(type, memoryStream, targetFileName);
}

/// <summary>
/// Saves a media file to the device's gallery.
/// </summary>
/// <param name="type">Media file type.</param>
/// <param name="stream">Stream representing the file.</param>
/// <param name="targetFileName">Target file name.</param>
/// <returns>Task representing the progress of the operation.</returns>
public static async Task SaveAsync(MediaFileType type, Stream stream, string targetFileName) =>
await SavePlatformAsyncImpl(type, stream, targetFileName);
/// <summary>
/// Saves a media file to the device's gallery.
/// </summary>
/// <param name="type">Media file type.</param>
/// <param name="stream">Stream representing the file.</param>
/// <param name="targetFileName">Target file name.</param>
/// <returns>Task representing the progress of the operation.</returns>
public static async Task SaveAsync(MediaFileType type, Stream stream, string targetFileName) =>
await SavePlatformAsyncImpl(type, stream, targetFileName);
}
#endif
Loading

0 comments on commit 044a0ec

Please sign in to comment.