flower-story/FlowerApp/Controls/AppContentPage.cs
2023-08-02 23:45:04 +08:00

227 lines
6.0 KiB
C#

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<T>(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<Location?> 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<Location?> GetLastLocationAsync()
{
if (MainThread.IsMainThread)
{
return GetLastLocationAsyncInternal();
}
var source = new TaskCompletionSource<Location?>();
MainThread.BeginInvokeOnMainThread(async () =>
{
var location = await GetLastLocationAsyncInternal();
source.TrySetResult(location);
});
return source.Task;
}
TaskCompletionSource<Location?>? locationTaskSource;
CancellationTokenSource? locationCancellationTokenSource;
async Task<Location?> GetCurrentLocationAsyncInternal()
{
if (locationTaskSource == null)
{
locationTaskSource = new TaskCompletionSource<Location?>();
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<Location?> GetCurrentLocationAsync()
{
if (MainThread.IsMainThread)
{
return GetCurrentLocationAsyncInternal();
}
var source = new TaskCompletionSource<Location?>();
MainThread.BeginInvokeOnMainThread(async () =>
{
var location = await GetCurrentLocationAsyncInternal();
source.TrySetResult(location);
});
return source.Task;
}
protected void CancelRequestLocation()
{
if (locationCancellationTokenSource?.IsCancellationRequested == false)
{
locationCancellationTokenSource.Cancel();
}
}
async Task<FileResult?> TakePhotoInternal()
{
var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
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<Permissions.Camera>();
}
if (status != PermissionStatus.Granted)
{
return null;
}
var file = await MediaPicker.Default.CapturePhotoAsync();
return file;
}
protected Task<FileResult?> TakePhoto()
{
if (MainThread.IsMainThread)
{
return TakePhotoInternal();
}
var source = new TaskCompletionSource<FileResult?>();
MainThread.BeginInvokeOnMainThread(async () =>
{
var file = await TakePhotoInternal();
source.TrySetResult(file);
});
return source.Task;
}
}