Skip to content

Instantly share code, notes, and snippets.

@ericbrunner
Last active April 8, 2022 09:04
Show Gist options
  • Save ericbrunner/5a4c76cb5cbabc3a992c5a97a216c81c to your computer and use it in GitHub Desktop.
Save ericbrunner/5a4c76cb5cbabc3a992c5a97a216c81c to your computer and use it in GitHub Desktop.
Media Plugin Usage
using Acr.UserDialogs;
using Plugin.Connectivity;
using Plugin.Media;
using Plugin.Media.Abstractions;
using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using trucker_rolsped.AzureStorage;
using trucker_rolsped.Helper.HockeyApp;
using trucker_rolsped.Interfaces;
using trucker_rolsped.Interfaces.Utils;
using trucker_rolsped.Models;
using trucker_rolsped.StoreManager;
using trucker_rolsped.ViewModels.Media;
using Xamarin.Forms;
namespace trucker_rolsped.Pages.Media
{
[Flags]
public enum MediaType : byte
{
None = 0x00, // 0d, 0000 0000b
Photo = 0x01, // 2^0 = 1d, 0000 0001b
Video = 0x02, // 2^1 = 2d, 0000 0010b
TakenPhoto = 0x04, // 2^2 = 4d, 0000 0100b
PickedPhoto = 0x08 // 2^3 = 8d, 0000 1000b
}
public enum MediaState
{
Created = 0,
Uploaded = 1,
Queued = 2,
Error = 3,
NotFound = 4
}
public sealed class TruckerAppMediaFile : IDisposable
{
public MediaType Type { get; set; }
public MediaFile File { get; set; }
public string DokArt { get; set; }
public MediaState MediaState { get; set; }
public int TruckAppId { get; set; }
public string FilePath { get; set; }
public TruckerAppMediaFile()
{
MediaState = MediaState.Created;
}
public async void Dispose()
{
File?.Dispose();
}
}
public partial class Task70PhotoUploadPage : ContentPage, IRefreshPage
{
private readonly string _dokArt;
private readonly Task70PhotoUploadViewModel _task70PhotoUploadViewModel;
private readonly TaskCompletionSource<bool> _tcs;
private readonly int _truckAppId;
private readonly WorkflowItem _workflowItem;
public Task70PhotoUploadPage(TaskCompletionSource<bool> tcs, WorkflowItem workflowItem, string dokArt)
{
InitializeComponent();
_tcs = tcs;
_workflowItem = workflowItem;
_dokArt = dokArt;
_truckAppId = _workflowItem.TruckAppId;
_task70PhotoUploadViewModel = new Task70PhotoUploadViewModel(_workflowItem, dokArt);
BindingContext = _task70PhotoUploadViewModel;
NavigationPage.SetHasNavigationBar(this, false);
Device.OnPlatform(iOS: () => { Padding = new Thickness(0, 20, 0, 0); });
}
protected override bool OnBackButtonPressed()
{
return true;
}
private void ChangeMediaButtonEnableState(bool enable)
{
if (TakePhoto.IsVisible)
TakePhoto.IsEnabled = enable;
if (PickPhoto.IsVisible)
PickPhoto.IsEnabled = enable;
if (TakeNextPhoto.IsVisible)
TakeNextPhoto.IsEnabled = enable;
if (PickNextPhoto.IsVisible)
PickNextPhoto.IsEnabled = enable;
}
private async Task CheckToUploadPhoto()
{
try
{
if (SelectedMedia?.File != null)
{
bool isOk = await DisplayAlert("Foto geladen", "Wollen Sie das Foto zur Roland Spedition senden?", "Ja", "Nein");
if (isOk)
{
await UploadPhoto();
}
}
}
finally
{
SelectedMedia?.Dispose();
}
}
private async void CloseFotoDialogClicked(object sender, EventArgs e)
{
await CheckToUploadPhoto();
await Navigation.PopAsync(animated: false);
_tcs.SetResult(true);
}
// prevent that a user invoked Take and Pick Photo event at same time
private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
private async void PickPhotoClicked(object sender, EventArgs e)
{
await _semaphoreSlim.WaitAsync();
try
{
ChangeMediaButtonEnableState(enable: false);
SelectedMedia?.Dispose();
SelectedMedia = null;
await CrossMedia.Current.Initialize();
var cameraStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
var storageStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
if (cameraStatus != PermissionStatus.Granted || storageStatus != PermissionStatus.Granted)
{
var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] {Permission.Camera, Permission.Storage});
cameraStatus = results[Permission.Camera];
storageStatus = results[Permission.Storage];
}
if (cameraStatus == PermissionStatus.Granted && storageStatus == PermissionStatus.Granted)
{
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await MetricsManagerHelper.Instance.SendGenericMessageToApplicationInsightsAsync($"{nameof(Task70PhotoUploadPage)}", "Not allowed to choose a photo.");
await DisplayAlert("Media Info", "Keine Berechtigung ein Foto auszuwählen.", "OK");
return;
}
SelectedMedia = new TruckerAppMediaFile
{
Type = MediaType.Photo | MediaType.PickedPhoto,
File = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
{
CompressionQuality = 92,
PhotoSize = PhotoSize.Medium
})
};
if (SelectedMedia?.File == null)
{
SelectedMedia = null;
return;
}
var imageStream = await DependencyService.Get<Interfaces.Media.IMedia>().CopyMediaAsync(SelectedMedia.File.GetStream());
Image.Source = ImageSource.FromStream(() => imageStream);
SendMedia.IsEnabled = true;
}
else
{
await MetricsManagerHelper.Instance.SendGenericMessageToApplicationInsightsAsync($"{nameof(Task70PhotoUploadPage)}", "Not allowed to choose a photo.");
await DisplayAlert("Media Info", "Keine Berechtigung ein Foto auszuwählen.", "OK");
if (Device.OS == TargetPlatform.iOS)
//On iOS you may want to send your user to the settings screen.
CrossPermissions.Current.OpenAppSettings();
}
}
catch (Exception ex)
{
await MetricsManagerHelper.Instance.SendExceptionToApplicationInsightsAsync(ex).ConfigureAwait(true);
}
finally
{
ChangeMediaButtonEnableState(enable: true);
_semaphoreSlim.Release();
}
}
private async void TakePhotoClicked(object sender, EventArgs e)
{
await _semaphoreSlim.WaitAsync();
try
{
ChangeMediaButtonEnableState(enable: false);
SelectedMedia?.Dispose();
SelectedMedia = null;
await CrossMedia.Current.Initialize();
var cameraStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
var storageStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
if (cameraStatus != PermissionStatus.Granted || storageStatus != PermissionStatus.Granted)
{
var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] {Permission.Camera, Permission.Storage});
cameraStatus = results[Permission.Camera];
storageStatus = results[Permission.Storage];
}
if (cameraStatus == PermissionStatus.Granted && storageStatus == PermissionStatus.Granted)
{
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await MetricsManagerHelper.Instance.SendGenericMessageToApplicationInsightsAsync($"{nameof(Task70PhotoUploadPage)}", "No camera available.");
await DisplayAlert("Media Info", "Keine Kamera verfügbar.", "OK");
return;
}
var localFileName = $"{DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture)}_{_truckAppId}_{_dokArt}.jpg";
SelectedMedia = new TruckerAppMediaFile
{
Type = MediaType.Photo | MediaType.TakenPhoto,
File = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
PhotoSize = PhotoSize.Medium,
CompressionQuality = 92,
Name = localFileName,
Directory = "Truckerapp"
})
};
if (SelectedMedia?.File == null)
{
SelectedMedia = null;
return;
}
var imageStream = await DependencyService.Get<Interfaces.Media.IMedia>().CopyMediaAsync(SelectedMedia.File.GetStream());
Image.Source = ImageSource.FromStream(() => imageStream);
SendMedia.IsEnabled = true;
}
else
{
await MetricsManagerHelper.Instance.SendGenericMessageToApplicationInsightsAsync($"{nameof(Task70PhotoUploadPage)}", "Not allowed to use camera.");
await DisplayAlert("Media Info", "Keine Berechtigung die Kamera zu verwenden.", "OK");
if (Device.OS == TargetPlatform.iOS)
//On iOS you may want to send your user to the settings screen.
CrossPermissions.Current.OpenAppSettings();
}
}
catch (Exception ex)
{
await MetricsManagerHelper.Instance.SendExceptionToApplicationInsightsAsync(ex).ConfigureAwait(true);
}
finally
{
ChangeMediaButtonEnableState(enable: true);
_semaphoreSlim.Release();
}
}
private async void SendMediaOnClicked(object sender, EventArgs e)
{
SendMedia.IsEnabled = false;
try
{
await UploadPhoto();
}
catch (Exception exception)
{
await MetricsManagerHelper.Instance.SendExceptionToApplicationInsightsAsync(exception);
Image.Source = Device.OnPlatform(
iOS: ImageSource.FromFile("image_photo_plain.png"),
Android: ImageSource.FromFile("image_photo_plain.png"),
WinPhone: null
);
SelectedMedia?.Dispose();
SelectedMedia = null;
}
finally
{
EnabledNextButtons();
}
}
private async Task UploadPhoto()
{
try
{
SelectedMedia.DokArt = _dokArt;
SelectedMedia.TruckAppId = _truckAppId;
UserDialogs.Instance.ShowLoading("Foto wird hochgeladen...");
await AzureBlobStorageManager.Instance.UploadMediaAsync(SelectedMedia);
UserDialogs.Instance.HideLoading();
switch (SelectedMedia.MediaState)
{
case MediaState.Uploaded:
//var result = await DisplayAlert("Foto Upload", "Foto wurde erfolgreich hochgeladen. Möchten Sie das Foto jetzt vom Handy löschen?", "Ja", "Nein");
break;
case MediaState.Queued:
UserDialogs.Instance.ShowLoading("Upload erfolgt automatisch wenn Sie wieder mit Internet oder dem mobilem Netz verbunden sind!");
await Task.Delay(1500);
UserDialogs.Instance.HideLoading();
break;
case MediaState.Created:
await DisplayAlert("Foto Upload", "Sie müssen das Foto erneut auswählen bzw. machen, da es nicht gesendet wurde!", "Ok");
break;
case MediaState.Error:
await DisplayAlert("Foto Upload", "Sie müssen das Foto erneut auswählen bzw. machen, da es nicht gesendet wurde!", "Ok");
break;
default:
await DisplayAlert("Foto Upload", "Sie müssen das Foto erneut auswählen bzw. machen, da es nicht gesendet wurde!", "Ok");
break;
}
}
catch (Exception ex)
{
SelectedMedia.MediaState = MediaState.Error;
await DisplayAlert("Sende Media Fehler", ex.Message, "Ok");
}
finally
{
Image.Source = Device.OnPlatform(
iOS: ImageSource.FromFile("image_photo_plain.png"),
Android: ImageSource.FromFile("image_photo_plain.png"),
WinPhone: null
);
if (SelectedMedia.MediaState == MediaState.Uploaded || SelectedMedia.MediaState == MediaState.Queued)
{
_workflowItem.TruckAuftragWorkFlow.DokAnzahl++;
}
SelectedMedia?.Dispose();
if (SelectedMedia?.MediaState == MediaState.Uploaded)
{
await DeleteFileAfterUploadAsync();
}
SelectedMedia = null;
}
}
private async Task DeleteFileAfterUploadAsync()
{
//Platform specific file delete
var truckerappMedia = SelectedMedia.FilePath;
var platformFileHandler = DependencyService.Get<IFileHandling>();
if (platformFileHandler != null)
if (await platformFileHandler.FileExistsAsync(truckerappMedia))
{
var deleted = await platformFileHandler.DeleteFileAsync(truckerappMedia);
if (!deleted)
{
await MetricsManagerHelper.Instance.SendErrorToApplicationInsightsAsync($"Photo couldn't be deleted: {truckerappMedia}");
}
}
}
private void EnabledNextButtons()
{
TakePhoto.IsVisible = false;
PickPhoto.IsVisible = false;
TakeNextPhoto.IsVisible = true;
PickNextPhoto.IsVisible = true;
}
private bool IsTakenPhoto => (SelectedMedia.Type & MediaType.TakenPhoto) != 0x00;
private TruckerAppMediaFile SelectedMedia { get; set; }
protected override async void OnAppearing()
{
base.OnAppearing();
try
{
await RefreshItemsAsync(showActivityIndicator: false, syncItems: false);
}
catch (Exception e)
{
await MetricsManagerHelper.Instance.SendExceptionToApplicationInsightsAsync(e);
}
}
public async Task RefreshItemsAsync(bool showActivityIndicator, bool syncItems)
{
syncItems = syncItems && CrossConnectivity.Current.IsConnected;
//UserDialogs.Instance.ShowLoading("Daten werden geladen...", MaskType.Black);
_task70PhotoUploadViewModel.LanguageItems = await OfflineSyncStoreManager.Instance.TagSpracheStore.GetTagSpracheItemsAsync(syncItems);
//UserDialogs.Instance.HideLoading();
}
}
}
@Ines-Diaz
Copy link

@ericbrunner Thank you very much for your response. I'll put into practice. All the best :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment