using Blahblah.FlowerApp.Data; using Microsoft.Extensions.Logging; using static Blahblah.FlowerApp.Extensions; namespace Blahblah.FlowerApp; public abstract class AppContentPage : ContentPage, ILoggerContent { public ILogger Logger { get; } = null!; public FlowerDatabase Database { get; } = null!; protected AppContentPage(FlowerDatabase database, ILogger logger) { Database = database; Logger = logger; } protected T GetValue(BindableProperty property) { return (T)GetValue(property); } bool hasLoading = true; ContentView? loading; #if IOS private async Task DoLoading(bool flag) #else private Task DoLoading(bool flag) #endif { if (loading == null && hasLoading) { try { loading = (ContentView)FindByName("loading"); } catch { hasLoading = false; } } if (loading != null) { if (flag) { #if IOS loading.IsVisible = true; await loading.FadeTo(1, easing: Easing.CubicOut); #else loading.Opacity = 1; loading.IsVisible = true; #endif } else { #if IOS await loading.FadeTo(0, easing: Easing.CubicIn); loading.IsVisible = false; #else loading.IsVisible = false; loading.Opacity = 0; #endif } } #if ANDROID return Task.CompletedTask; #endif } protected Task Loading(bool flag) { IsBusy = flag; if (MainThread.IsMainThread) { return DoLoading(flag); } var source = new TaskCompletionSource(); MainThread.BeginInvokeOnMainThread(async () => { await DoLoading(flag); source.TrySetResult(); }); return source.Task; } async Task GetLastLocationAsyncInternal() { try { var location = await Geolocation.Default.GetLastKnownLocationAsync(); return location; } catch (FeatureNotSupportedException fnsEx) { this.LogError(fnsEx, $"Not supported on device, {fnsEx.Message}."); } catch (FeatureNotEnabledException fneEx) { this.LogError(fneEx, $"Not enabled on device, {fneEx.Message}."); } catch (PermissionException) { this.LogWarning($"User denied."); } catch (Exception ex) { this.LogError(ex, $"Error occurs while getting cached location, {ex.Message}"); } return null; } protected Task GetLastLocationAsync() { if (MainThread.IsMainThread) { return GetLastLocationAsyncInternal(); } var source = new TaskCompletionSource(); MainThread.BeginInvokeOnMainThread(async () => { var location = await GetLastLocationAsyncInternal(); source.TrySetResult(location); }); return source.Task; } TaskCompletionSource? locationTaskSource; CancellationTokenSource? locationCancellationTokenSource; async Task GetCurrentLocationAsyncInternal() { if (locationTaskSource == null) { locationTaskSource = new TaskCompletionSource(); try { var request = new GeolocationRequest(GeolocationAccuracy.Best, TimeSpan.FromSeconds(10)); #if IOS request.RequestFullAccuracy = true; #endif locationCancellationTokenSource = new CancellationTokenSource(); var location = await Geolocation.Default.GetLocationAsync(request, locationCancellationTokenSource.Token); locationTaskSource.SetResult(location); } catch (Exception ex) { this.LogError(ex, $"Error occurs while getting current location, {ex.Message}"); } } return await locationTaskSource.Task; } protected Task GetCurrentLocationAsync() { if (MainThread.IsMainThread) { return GetCurrentLocationAsyncInternal(); } var source = new TaskCompletionSource(); MainThread.BeginInvokeOnMainThread(async () => { var location = await GetCurrentLocationAsyncInternal(); source.TrySetResult(location); }); return source.Task; } protected void CancelRequestLocation() { if (locationCancellationTokenSource?.IsCancellationRequested == false) { locationCancellationTokenSource.Cancel(); } } async Task TakePhotoInternal() { var status = await Permissions.CheckStatusAsync(); if (status == PermissionStatus.Denied) { await this.AlertError(L("needCameraPermission", "Flower Story needs access to the camera to take photos.")); #if IOS var settingsUrl = UIKit.UIApplication.OpenSettingsUrlString; await Launcher.TryOpenAsync(settingsUrl); #endif return null; } if (status != PermissionStatus.Granted) { status = await Permissions.RequestAsync(); } if (status != PermissionStatus.Granted) { return null; } var file = await MediaPicker.Default.CapturePhotoAsync(); return file; } protected Task TakePhoto() { if (MainThread.IsMainThread) { return TakePhotoInternal(); } var source = new TaskCompletionSource(); MainThread.BeginInvokeOnMainThread(async () => { var file = await TakePhotoInternal(); source.TrySetResult(file); }); return source.Task; } }