using System.ComponentModel; using System.Drawing; using System.Runtime.CompilerServices; using InABox.Core; namespace InABox.Avalonia.Platform; public class DefaultGeolocation : INotifyPropertyChanged, IGeolocation { private DateTime _nextCheck = DateTime.MaxValue; private TimeSpan _remaining = TimeSpan.Zero; public bool Scanning { get => _nextCheck == DateTime.MaxValue; set => SetField(ref _nextCheck, value ? DateTime.MinValue : DateTime.MaxValue); } private GeoPoint? _currentLocation; public GeoPoint? CurrentLocation { get => _currentLocation; set { SetField(ref _currentLocation, value); LocationChanged?.Invoke(this, new GeoLocationChangedArgs(value)); } } private TimeSpan _frequency = TimeSpan.FromSeconds(10); public TimeSpan Frequency { get => _frequency; set => SetField(ref _frequency, value); } public event GeoLocationChangedHandler? LocationChanged; public event GeoLocationTimerHandler? TimerChanged; public Logger? Logger { get; set; } public virtual Task GetLocationAsync(CancellationTokenSource cancel) { return Task.FromResult(new GeoPoint()); } private readonly CancellationTokenSource _cancelTokenSource; private bool _isCheckingLocation; public DefaultGeolocation() { _cancelTokenSource = new CancellationTokenSource(); try { _ = Task.Run(async () => { while (!_cancelTokenSource.Token.IsCancellationRequested) { if (!_isCheckingLocation) { if (_nextCheck < DateTime.Now) { try { _isCheckingLocation = true; CurrentLocation = await PlatformTools.Geolocation.GetLocationAsync(_cancelTokenSource); } catch (Exception ex) { Logger?.Send(LogType.Error, "", $"GPS Location Error: {ex.Message}"); CurrentLocation = null; } _isCheckingLocation = false; _nextCheck = DateTime.Now.Add(_frequency); } else { _remaining = _nextCheck - DateTime.Now; TimerChanged?.Invoke(this, new GeoLocationTimerArgs(_frequency, _remaining)); Thread.Sleep(100); } } } } ); } catch (OperationCanceledException e) { Logger?.Send(LogType.Error, "", $"GPS Scanning Cancelled: {e.Message}"); } catch (Exception e) { Logger?.Send(LogType.Error, "", $"GPS Error: {e.Message}"); } } public void Cancel() { if (_isCheckingLocation && _cancelTokenSource.IsCancellationRequested == false) _cancelTokenSource.Cancel(); } #region INotifyPropertyChanged public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } #endregion }