12using System.Collections.Concurrent;
13using System.Collections.ObjectModel;
14using System.Diagnostics;
15using System.Diagnostics.CodeAnalysis;
30 private readonly Dictionary<string, NavigationArgs> navigationArgsMap = [];
31 private readonly ConcurrentQueue<UiTask> taskQueue =
new();
33 private bool isExecutingUiTasks =
false;
34 private bool isNavigating =
false;
45 private void AddTask(
UiTask Task)
47 this.taskQueue.Enqueue(Task);
49 if (!this.isExecutingUiTasks)
51 this.isExecutingUiTasks =
true;
53 MainThread.BeginInvokeOnMainThread(async () =>
55 await this.ProcessAllTasks();
60 private async Task ProcessAllTasks()
66 if (this.taskQueue.TryDequeue(out
UiTask? Task))
69 while (!this.taskQueue.IsEmpty);
73 this.isExecutingUiTasks =
false;
82 public Task<bool>
DisplayAlert(
string Title,
string Message,
string? Accept =
null,
string? Cancel =
null)
86 return Task.CompletionSource.Task;
99 private static string GetUserFriendlyMessage(Exception? Exception)
101 if (Exception is
null)
104 Exception? Current = Exception;
106 while (Current is not
null)
111 if (Current is TimeoutException)
114 if (Current is TaskCanceledException || Current is OperationCanceledException)
129 Current = Current.InnerException;
137 #region DisplayPrompt
140 public Task<string?>
DisplayPrompt(
string Title,
string Message,
string? Accept =
null,
string? Cancel =
null)
144 return Task.CompletionSource.Task;
165 IScreenshotResult? Screen = await Screenshot.CaptureAsync();
173 using Stream PngStream = await Screen.OpenReadAsync(ScreenshotFormat.Png, 20);
179 SKBitmap OriginalBitmap = SKBitmap.FromImage(SKImage.FromEncodedData(PngStream));
185 int DesiredWidth = OriginalBitmap.Width / 4;
186 int DesiredHeight = OriginalBitmap.Height / 4;
189 SKImageInfo ResizedInfo =
new(DesiredWidth, DesiredHeight, SKColorType.Gray8);
192 SKBitmap ResizedBitmap = OriginalBitmap.Resize(ResizedInfo, SKFilterQuality.Medium);
199 IMatrix GreyChannelMatrix = RezisedMatrix.GrayScale();
216 ImageSource BlurredScreen = ImageSource.FromStream(() =>
new MemoryStream(Blurred));
223 await
App.SendAlert(
"```uml\r\n" + TimingUml +
"\r\n```",
"text/markdown");
225 return BlurredScreen;
242 IScreenshotResult? Result = await Screenshot.CaptureAsync();
247 using Stream Stream = await Result.OpenReadAsync();
248 MemoryStream MemoryStream =
new();
249 await Stream.CopyToAsync(MemoryStream);
250 byte[] Bytes = MemoryStream.ToArray();
253 return ImageSource.FromStream(() =>
new MemoryStream(Bytes));
274 if (this.
BeginLoad(IsResuming, CancellationToken))
278 Application? Application = Application.Current;
280 if (Application is not
null)
282 Application.PropertyChanging += this.OnApplicationPropertyChanging;
283 Application.PropertyChanged += this.OnApplicationPropertyChanged;
286 this.SubscribeToShellNavigatingIfNecessary(Application);
298 return Task.CompletedTask;
308 Application? Application = Application.Current;
309 if (Application is not
null)
311 this.UnsubscribeFromShellNavigatingIfNecessary(Application);
312 Application.PropertyChanged -= this.OnApplicationPropertyChanged;
313 Application.PropertyChanging -= this.OnApplicationPropertyChanging;
324 return Task.CompletedTask;
332 return this.GoToAsync<NavigationArgs>(Route,
null,
BackMethod, UniqueId);
338 await MainThread.InvokeOnMainThreadAsync(async () =>
351 if (!
string.IsNullOrEmpty(UniqueId))
352 Route +=
"?UniqueId=" + UniqueId;
356 this.isNavigating =
true;
363 string ExtraInfo = Environment.NewLine + ex.Message;
371 this.isNavigating =
false;
388 this.isNavigating =
true;
389 await Shell.Current.GoToAsync(BackRoute, Animate);
393 ShellNavigationState State = Shell.Current.CurrentState;
394 if (Uri.TryCreate(State.Location,
"..", out Uri? BackLocation))
395 await Shell.Current.GoToAsync(BackLocation);
410 this.isNavigating =
false;
422 if (this.latestArguments is TArgs Result)
424 this.latestArguments =
null;
439 if (this.TryGetArgs(out TArgs? Result, UniqueId))
455 if (this.CurrentPage is Page Page)
458 string Route = Routing.GetRoute(Page);
474 return (Args is not
null);
483 private void OnApplicationPropertyChanged(
object? Sender,
System.ComponentModel.PropertyChangedEventArgs Args)
485 if (Args.PropertyName == nameof(Application.MainPage))
486 this.SubscribeToShellNavigatingIfNecessary((Application?)Sender);
489 private void OnApplicationPropertyChanging(
object? Sender, PropertyChangingEventArgs Args)
491 if (Args.PropertyName == nameof(Application.MainPage))
492 this.UnsubscribeFromShellNavigatingIfNecessary((Application?)Sender);
495 private void SubscribeToShellNavigatingIfNecessary(Application? Application)
497 if (Application?.MainPage is Shell Shell)
498 Shell.Navigating += this.Shell_Navigating;
501 private void UnsubscribeFromShellNavigatingIfNecessary(Application? Application)
503 if (Application?.MainPage is Shell Shell)
504 Shell.Navigating -= this.Shell_Navigating;
507 private void Shell_Navigating(
object? Sender, ShellNavigatingEventArgs e)
511 if ((e.Source == ShellNavigationSource.Pop) && e.CanCancel && !
this.isNavigating)
515 MainThread.BeginInvokeOnMainThread(async () =>
527 private static bool TryGetPageName(
string Route, [NotNullWhen(
true)] out
string? PageName)
531 if (!
string.IsNullOrWhiteSpace(Route))
533 PageName = Route.TrimStart(
'.',
'/');
534 return !
string.IsNullOrWhiteSpace(PageName);
542 this.latestArguments = Args;
544 if (TryGetPageName(Route, out
string? PageName))
546 if (Args is not
null)
550 if (!
string.IsNullOrEmpty(UniqueId))
551 PageName +=
"?UniqueId=" + UniqueId;
553 this.navigationArgsMap[PageName] = Args;
556 this.navigationArgsMap.Remove(PageName);
560 private NavigationArgs? TryGetArgs(
string Route,
string? UniqueId)
562 if (!
string.IsNullOrEmpty(UniqueId))
563 Route +=
"?UniqueId=" + UniqueId;
565 if (TryGetPageName(Route, out
string? PageName) &&
566 this.navigationArgsMap.TryGetValue(PageName, out
NavigationArgs? Args))
582 using HttpClient HttpClient =
new();
583 using HttpResponseMessage Response = await HttpClient.GetAsync(svgUri);
584 if (!Response.IsSuccessStatusCode)
588 byte[] ContentBytes = await Response.Content.ReadAsByteArrayAsync();
590 using (MemoryStream Stream =
new(ContentBytes))
596 if (Svg.Picture is
null)
599 using (MemoryStream Stream =
new())
601 if (Svg.Picture.ToImage(Stream, SKColor.Parse(
"#00FFFFFF"), SKEncodedImageFormat.Png, 100, 1, 1, SKColorType.Rgba8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb()))
602 return ImageSource.FromStream(() =>
new MemoryStream(Stream.ToArray()));
Static methods managing conversion to and from bitmap representations.
static byte[] EncodeAsPng(IMatrix M)
Encodes an image in a matrix using PNG.
static IMatrix FromBitmap(SKBitmap Bmp)
Craetes a matrix from a bitmap.
Represents an instance of the Neuro-Access app.
Absolute paths to important pages.
const string MainPage
Path to main page.
A set of never changing property constants and helpful values.
Represents network errors.
A strongly-typed resource class, for looking up localized strings, etc.
static string RequestTimedOut
Looks up a localized string similar to The request timed out.
static string ThereIsNoNetwork
Looks up a localized string similar to There is no network.
static string NotAuthorized
Looks up a localized string similar to You're not authorized to perform this action....
static string RequestWasCancelled
Looks up a localized string similar to The request was cancelled.
static string FailedToNavigateToPage
Looks up a localized string similar to Failed to navigate to page {0} {1}.
static string ActionNotAllowed
Looks up a localized string similar to This action isn't allowed..
static string Ok
Looks up a localized string similar to OK.
static string FailedToClosePage
Looks up a localized string similar to Failed to close page.
static string SomethingWentWrong
Looks up a localized string similar to Something went wrong.
static string ServiceUnavailable
Looks up a localized string similar to The service is currently unavailable. Please try again later....
static string ErrorTitle
Looks up a localized string similar to An error has occurred.
bool BeginLoad(bool IsResuming, CancellationToken CancellationToken)
Sets the IsLoading flag if the service isn't already loading.
void EndLoad(bool isLoaded)
Sets the IsLoading and IsLoaded flags and fires an event representing the current load state of the s...
bool IsResuming
If App is resuming service.
bool BeginUnload()
Sets the IsLoading flag if the service isn't already unloading.
void EndUnload()
Sets the IsLoading and IsLoaded flags and fires an event representing the current load state of the s...
Base class that references services in the app.
static ILogService LogService
Log service.
static IUiService UiService
Service serializing and managing UI-related tasks.
static IReportingStringLocalizer Localizer
Localization service
static IPlatformSpecific PlatformSpecific
Localization service
An base class holding page specific navigation parameters.
string? UniqueId
An unique view identifier used to search the args of similar view types.
readonly TaskCompletionSource< bool > NavigationCompletionSource
The completion source for the navigation task. Will return true when the navigation and transitions a...
void SetBackArguments(NavigationArgs? ParentArgs, BackMethod BackMethod=BackMethod.Inherited, string? UniqueId=null)
Sets the reference to the main parent's NavigationArgs.
string GetBackRoute()
Get the route used for the IUiService.GoBackAsync method.
bool Animated
Is the navigation animated
Abstract base class for UI tasks.
abstract Task Execute()
Executes the task.
UiService()
Creates a new instance of the UiService class.
override Task Unload()
Unloads the specified service.
async Task GoToAsync< TArgs >(string Route, TArgs? Args, BackMethod BackMethod=BackMethod.Inherited, string? UniqueId=null)
Navigates the AppShell to the specified route, with page arguments to match.
TArgs? TryGetArgs< TArgs >(string? UniqueId=null)
Returns the page's arguments from the (one-level) deep navigation stack.
Task< bool > DisplayAlert(string Title, string Message, string? Accept=null, string? Cancel=null)
Displays an alert/message box to the user. If Accept or Cancel was pressed
TArgs? PopLatestArgs< TArgs >()
Pops the latests navigation arguments. Can only be used once to get the navigation arguments....
Task DisplayException(Exception Exception, string? Title=null)
Displays an alert/message box to the user.
override Task Load(bool IsResuming, CancellationToken CancellationToken)
Loads the specified service.
Task GoToAsync(string Route, BackMethod BackMethod=BackMethod.Inherited, string? UniqueId=null)
Navigates the AppShell to the specified route, with page arguments to match.
Page CurrentPage
Current page
async Task< ImageSource?> ConvertSvgUriToImageSource(string svgUri)
Fetches a SVG and converts it to a PNG image source. An image Source representing the SVG file or nul...
async Task GoBackAsync(bool Animate=true)
Returns to the previous page/route.
async Task< ImageSource?> TakeScreenshotAsync()
Takes a screen-shot.
async Task< ImageSource?> TakeBlurredScreenshotAsync()
Takes a blurred screen shot
Task< string?> DisplayPrompt(string Title, string Message, string? Accept=null, string? Cancel=null)
Prompts the user for some input. User input
Static class managing the application event log. Applications and services log events on this static ...
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
The server has experienced a misconfiguration or other internal error that prevents it from processin...
The recipient or server does not allow any entity to perform the action (e.g., sending to entities at...
The sender needs to provide credentials before being allowed to perform the action,...
The intended recipient is temporarily unavailable, undergoing maintenance, etc.; the associated error...
Class that keeps track of events and timing.
void Stop()
Stops measuring time.
void NewState(string State)
Main Thread changes state.
string ExportPlantUml(TimeUnit TimeUnit)
Exports events to PlantUML.
void Start()
Starts measuring time.
Service serializing and managing UI-related tasks.
BackMethod
Navigation Back Method
TimeUnit
Options for presenting time in reports.
ProfilerThreadType
Type of profiler thread.