Bläddra i källkod

Attempting to get PRS Avalonia and PRS Digital to App Store

Frank van den Bos 1 månad sedan
förälder
incheckning
83dadc7056

+ 6 - 4
InABox.Avalonia.Platform.Android/InABox.Avalonia.Platform.Android.csproj

@@ -18,14 +18,16 @@
     </PropertyGroup>
 
     <ItemGroup>
-      <ProjectReference Include="..\..\..\..\..\development\inabox\inabox.logging.shared\InABox.Logging.Shared.csproj" />
       <ProjectReference Include="..\InABox.Avalonia.Platform\InABox.Avalonia.Platform.csproj" />
     </ItemGroup>
     
     <ItemGroup>
-      <PackageReference Include="Avalonia" Version="11.2.3" />
-      <PackageReference Include="bblanchon.PDFium.Android" Version="135.0.7009" />
-      <PackageReference Include="Microsoft.Maui.Essentials" Version="8.0.93" />
+      <PackageReference Include="Avalonia" Version="11.2.5" />
+      <PackageReference Include="Avalonia.Android" Version="11.2.5" />
+      <PackageReference Include="Avalonia.Remote.Protocol" Version="11.2.5" />
+      <PackageReference Include="Avalonia.Skia" Version="11.2.5" />
+      <PackageReference Include="bblanchon.PDFium.Android" Version="136.0.7073" />
+      <PackageReference Include="Microsoft.Maui.Essentials" Version="9.0.50" />
       <PackageReference Include="PDFtoImage" Version="5.0.0" />
     </ItemGroup>
 

+ 165 - 0
InABox.Avalonia.Platform.iOS/Bluetooth/Bluetooth.iOS.cs

@@ -0,0 +1,165 @@
+using InABox.Core;
+using Plugin.BLE;
+using Plugin.BLE.Abstractions;
+using Plugin.BLE.Abstractions.Contracts;
+using Plugin.BLE.Abstractions.EventArgs;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace InABox.Avalonia.Platform.iOS;
+
+
+public class iOS_Bluetooth : IBluetooth
+{
+    public Logger? Logger { get; set; }
+
+    public event EventHandler? Changed;
+    public CoreObservableCollection<IBluetoothDevice> Devices { get; } = new ();
+    
+    private IBluetoothLE _ble;
+    private IAdapter _adapter;
+    private ScanFilterOptions _scanoptions = new ScanFilterOptions();
+    private StaleItemMonitor<IBluetoothDevice> _staleItemMonitor;
+    public iOS_Bluetooth()
+    {
+        
+        _staleItemMonitor = new StaleItemMonitor<IBluetoothDevice>(
+            Devices,
+            x=>x.LastSeen,
+            x =>x.ID,
+            TimeSpan.FromSeconds(10), 
+            TimeSpan.FromMilliseconds(500)
+        );
+        
+        _ble = CrossBluetoothLE.Current; 
+        _adapter = CrossBluetoothLE.Current.Adapter;
+        _adapter.ScanTimeout = 5000;
+        _adapter.ScanTimeoutElapsed += async (sender, args) => { await _adapter.StartScanningForDevicesAsync(_scanoptions); };
+        _adapter.DeviceDiscovered += AdapterOnDeviceDiscovered;
+        //_adapter.ScanMatchMode = ScanMatchMode.AGRESSIVE;
+        //_adapter.ScanMode = ScanMode.LowLatency;
+        
+        // Task.Run(() =>
+        // {
+        //     while (true)
+        //     {
+        //         var stale = Devices.ToArray().Where(x => (x == null) || (x.LastSeen < DateTime.Now.Subtract(new TimeSpan(0, 0, 10))))
+        //             .ToArray();
+        //         if (stale.Any())
+        //         {
+        //             Devices.RemoveRange(stale);
+        //             Changed?.Invoke(this, EventArgs.Empty);
+        //         }
+        //             
+        //         Task.Delay(500);
+        //     }
+        // });
+    }
+    
+    // public static async Task<bool> IsPermitted<TPermission>() where TPermission : Permissions.BasePermission, new()
+    // {
+    //     try
+    //     {
+    //         PermissionStatus status = await Permissions.CheckStatusAsync<TPermission>();
+    //         if (status == PermissionStatus.Granted)
+    //             return true;
+    //         var request = await Permissions.RequestAsync<TPermission>();
+    //         return request == PermissionStatus.Granted;
+    //
+    //     }
+    //     catch (TaskCanceledException ex)
+    //     {
+    //         return false;
+    //     }
+    // }
+    
+    public async Task<bool> IsAvailable()
+    {
+        //if (await IsPermitted<Permissions.Bluetooth>())
+        //{
+
+        //}
+        return _adapter != null;
+    }
+
+    public async Task<bool> StartScanningAsync(Guid configServiceId)
+    {
+        
+        _scanoptions.ServiceUuids = [configServiceId];
+        return await StartScanningAsync();
+    }
+
+    private async Task<bool> StartScanningAsync()
+    {
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Starting Bluetooth Scanning...");
+        await _staleItemMonitor.StartAsync();
+        await _adapter.StartScanningForDevicesAsync(_scanoptions);
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Scanning Started.");
+        return true;
+    }
+
+    private void AdapterOnDeviceDiscovered(object? sender, DeviceEventArgs e)
+    {
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Found device {e.Device.Name}...");
+        var device = Devices.FirstOrDefault(x => string.Equals(x.ID, e.Device.Id.ToString()));
+        if (device == null)
+        {
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Adding device {e.Device.Id}...");
+            device = new iOS_BluetoothDevice(e.Device);
+            Devices.Add(device);
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Added device {device.ID}.");
+        }
+
+        device.LastSeen = DateTime.Now;
+        device.ManufacturerData = e.Device.AdvertisementRecords
+            .FirstOrDefault(x => x.Type == AdvertisementRecordType.ManufacturerSpecificData)?.Data ?? [];
+        
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Notifying Changes...");
+        Changed?.Invoke(this, EventArgs.Empty);
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Changes Notified.");
+    }
+    
+
+    public async Task<bool> StopScanningAsync()
+    {
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stopping Bluetooth Scanning...");
+        await _staleItemMonitor.StopAsync();
+        await _adapter.StopScanningForDevicesAsync();
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Scanning Stopped.");
+        return true;
+    }
+
+    public async Task<IConnectedBluetoothDevice?> Connect(IBluetoothDevice device)
+    {
+        if (Guid.TryParse(device.ID, out var deviceid))
+        {
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Connecting Bluetooth Device {device.ID}...");
+            await StopScanningAsync();
+            var connected = await _adapter.ConnectToKnownDeviceAsync(deviceid);
+            if (connected != null)
+            {
+                var result = new iOS_ConnectedBluetoothDevice(device);
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Device {device.ID} connected.");
+                return result;
+            }
+            await StartScanningAsync();
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Connection to {device.ID} failed.");
+        }
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Device has invalid ID.");
+        return null;
+    }
+
+    public async Task<bool> Disconnect(IConnectedBluetoothDevice device)
+    {
+        if (device is iOS_ConnectedBluetoothDevice connected)
+        {
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Disconnecting Bluetooth Device {device.ID}...");
+            await _adapter.DisconnectDeviceAsync(connected.Device.Native);
+            await StartScanningAsync();
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Device {device.ID} disconnected.");
+        }
+        return true;
+    }
+
+}

+ 51 - 0
InABox.Avalonia.Platform.iOS/Bluetooth/iOS_BluetoothDevice.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Linq;
+using Plugin.BLE.Abstractions;
+using Plugin.BLE.Abstractions.Contracts;
+
+namespace InABox.Avalonia.Platform.iOS;
+
+public class iOS_BluetoothDevice(IDevice native) : IBluetoothDevice
+{
+    public void Dispose()
+    {
+        Native.Dispose();
+    }
+
+    public IDevice Native { get; } = native;
+
+    public string ID => Native.Id.ToString();
+    public string Name => Native.Name;
+
+        
+    private Guid GuidFromDisplayOrderBytes(byte[] displayBytes)
+    {
+        if (displayBytes == null || displayBytes.Length != 16)
+            throw new ArgumentException("Byte array must be exactly 16 bytes.", nameof(displayBytes));
+
+        return new Guid(new byte[]
+        {
+            // Data1 (4 bytes, little-endian)
+            displayBytes[3], displayBytes[2], displayBytes[1], displayBytes[0],
+
+            // Data2 (2 bytes, little-endian)
+            displayBytes[5], displayBytes[4],
+
+            // Data3 (2 bytes, little-endian)
+            displayBytes[7], displayBytes[6],
+
+            // Data4 (8 bytes, as-is)
+            displayBytes[8], displayBytes[9], displayBytes[10], displayBytes[11],
+            displayBytes[12], displayBytes[13], displayBytes[14], displayBytes[15]
+        });
+    }
+
+    
+    public Guid[] AvailableServices => Native.AdvertisementRecords
+        .Where(x => x.Type == AdvertisementRecordType.UuidsComplete128Bit)
+        .Select(x => GuidFromDisplayOrderBytes(x.Data))
+        .ToArray();
+
+    public DateTime LastSeen { get; set; }
+    public byte[]? ManufacturerData { get; set; }
+}

+ 114 - 0
InABox.Avalonia.Platform.iOS/Bluetooth/iOS_ConnectedBluetoothDevice.cs

@@ -0,0 +1,114 @@
+using System;
+using System.Text;
+using System.Threading.Tasks;
+using Plugin.BLE.Abstractions;
+
+namespace InABox.Avalonia.Platform.iOS;
+
+public class iOS_ConnectedBluetoothDevice(IBluetoothDevice device)
+    : IConnectedBluetoothDevice
+{
+    public void Dispose()
+    {
+        Device.Dispose();
+    }
+
+    public iOS_BluetoothDevice Device { get; } = (iOS_BluetoothDevice)device;
+
+    public string ID => Device.ID;
+    public string Name => Device.Name;
+    public Guid[] AvailableServices => Device.AvailableServices;
+
+    public DateTime LastSeen
+    {
+        get => Device.LastSeen; 
+        set => device.LastSeen = value;
+    }
+
+    public byte[]? ManufacturerData
+    {
+        get => Device.ManufacturerData; 
+        set => Device.ManufacturerData = value;
+    }
+    
+    public async Task<bool> WriteBytesAsync(Guid serviceid, Guid characteristicid, byte[] data)
+    {
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} WriteBytesAsync::Getting Service {serviceid}...");
+        using (var service = await Device.Native.GetServiceAsync(serviceid))
+        {
+            if (service == null)
+            {
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} WriteBytesAsync::Failed to find service");
+                return false;
+            }
+
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} WriteBytesAsync::Getting Characteritsic {characteristicid}...");
+            var characteristic = await service.GetCharacteristicAsync(characteristicid);
+            
+            if (characteristic == null)
+            {
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} WriteBytesAsync::Failed to find characteristic");
+                return false;
+            }
+
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} WriteBytesAsync::Writing [{string.Join(" ",data.Select(x=>$"{x:X2}"))}]...");
+            
+            // for some reason the async call fails randomly
+            //var result = await characteristic.WriteAsync(data);
+            
+            // So lets hack in a one-second timeout...
+            var writeTask = characteristic.WriteAsync(data);
+            var waitTask = Task.Delay(1000);
+            await Task.WhenAny(writeTask, waitTask);
+            if (writeTask.Status == TaskStatus.RanToCompletion)
+            {
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} WriteBytesAsync::Wrote {writeTask.Result} bytes.");
+                return writeTask.Result == data.Length;
+            }
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} WriteBytesAsync::Timeout while writing!");
+            return false;
+        }
+    }
+
+    public async Task<bool> WriteStringAsync(Guid serviceid, Guid characteristicid, string data)
+    {
+        var encoded = Encoding.UTF8.GetBytes(data);
+        return await WriteBytesAsync(serviceid, characteristicid, encoded);
+    }
+
+    public async Task<byte[]?> ReadBytesAsync(Guid serviceid, Guid characteristicid)
+    {
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} ReadBytesAsync::Getting Service {serviceid}...");
+        using (var service = await Device.Native.GetServiceAsync(serviceid))
+        {
+            if (service == null)
+            {
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} ReadBytesAsync::Failed to find service");
+                return [];
+            }
+
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} ReadBytesAsync::Getting Characteritsic {characteristicid}...");
+            var characteristic = await service.GetCharacteristicAsync(characteristicid);
+            
+            if (characteristic == null)
+            {
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} ReadBytesAsync::Failed to find characteristic");
+                return [];
+            }
+
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} ReadBytesAsync::Reading data...");
+            var result = await characteristic.ReadAsync();
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} ReadBytesAsync:: [{result.resultCode}] => [{string.Join(" ",result.data.Select(x=>$"{x:X2}"))}].");
+            
+            return result.data;
+            
+        }
+        
+    }
+
+    public async Task<string?> ReadStringAsync(Guid serviceid, Guid characteristicid)
+    {
+        var data = await ReadBytesAsync(serviceid,characteristicid);
+        return data != null ? Encoding.UTF8.GetString(data) : null;
+    }
+}

+ 3 - 4
InABox.Avalonia.Platform.iOS/InABox.Avalonia.Platform.iOS.csproj

@@ -6,6 +6,7 @@
         <Nullable>enable</Nullable>
         <RootNamespace>InABox.Avalonia.Platform.iOS</RootNamespace>
         <LangVersion>default</LangVersion>
+        <SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
     </PropertyGroup>
 
     <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
@@ -21,11 +22,9 @@
     </ItemGroup>
 
     <ItemGroup>
-      <PackageReference Include="Avalonia.iOS" Version="11.2.3" />
-      <PackageReference Include="bblanchon.PDFium.iOS" Version="135.0.7009" />
-      <PackageReference Include="Microsoft.Maui.Essentials" Version="8.0.93" />
+      <PackageReference Include="Microsoft.Maui.Essentials" Version="9.0.60" />
       <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
-      <PackageReference Include="SkiaSharp" Version="3.116.1" />
+      <PackageReference Include="Plugin.BLE" Version="3.1.0" />
     </ItemGroup>
     
 </Project>

+ 1 - 1
InABox.Avalonia.Platform/Bluetooth/DefaultBluetooth.cs

@@ -22,7 +22,7 @@ public class DefaultBluetooth : IBluetooth
         return await Task.FromResult(false);
     }
 
-    public async Task<IConnectedBluetoothDevice?> Connect(IBluetoothDevice device)
+    public async Task<IConnectedBluetoothDevice> Connect(IBluetoothDevice device)
     {
         return await Task.FromResult<IConnectedBluetoothDevice?>(null);
     }

+ 1 - 26
InABox.Avalonia.Platform/Bluetooth/IBluetooth.cs

@@ -4,31 +4,6 @@ using InABox.Core;
 
 namespace InABox.Avalonia.Platform;
 
-public interface IBluetoothDevice : IDisposable
-{
-     String ID { get; }
-     
-     String Name { get; }
-
-     Guid[] AvailableServices { get; }
-     
-     DateTime LastSeen { get; set; }
-     
-     byte[]? ManufacturerData { get; set; }
-}
-
-public interface IConnectedBluetoothDevice : IBluetoothDevice
-{
-
-     Task<bool> WriteBytesAsync(Guid serviceid, Guid characteristicid, byte[] data);
-     
-     Task<bool> WriteStringAsync(Guid serviceid, Guid characteristicid, string data);
-     
-     Task<byte[]?> ReadBytesAsync(Guid serviceid, Guid characteristicid);
-     
-     Task<string?> ReadStringAsync(Guid serviceid, Guid characteristicid);
-}
-
 public interface IBluetooth : ILoggable
 {
      Logger? Logger { get; set; }
@@ -39,7 +14,7 @@ public interface IBluetooth : ILoggable
      
      Task<bool> StopScanningAsync();
      
-     Task<IConnectedBluetoothDevice?> Connect(IBluetoothDevice deviceid);
+     Task<IConnectedBluetoothDevice> Connect(IBluetoothDevice deviceid);
      
      Task<bool> Disconnect(IConnectedBluetoothDevice device);
 

+ 14 - 0
InABox.Avalonia.Platform/Bluetooth/IBluetoothDevice.cs

@@ -0,0 +1,14 @@
+namespace InABox.Avalonia.Platform;
+
+public interface IBluetoothDevice : IDisposable
+{
+    String ID { get; }
+     
+    String Name { get; }
+
+    Guid[] AvailableServices { get; }
+     
+    DateTime LastSeen { get; set; }
+     
+    byte[]? ManufacturerData { get; set; }
+}

+ 13 - 0
InABox.Avalonia.Platform/Bluetooth/IConnectedBluetoothDevice.cs

@@ -0,0 +1,13 @@
+namespace InABox.Avalonia.Platform;
+
+public interface IConnectedBluetoothDevice : IBluetoothDevice
+{
+
+    Task<bool> WriteBytesAsync(Guid serviceid, Guid characteristicid, byte[] data);
+     
+    Task<bool> WriteStringAsync(Guid serviceid, Guid characteristicid, string data);
+     
+    Task<byte[]?> ReadBytesAsync(Guid serviceid, Guid characteristicid);
+     
+    Task<string?> ReadStringAsync(Guid serviceid, Guid characteristicid);
+}

+ 122 - 0
InABox.Avalonia.Platform/Bluetooth/StaleItemMonitor.cs

@@ -0,0 +1,122 @@
+using InABox.Core;
+
+namespace InABox.Avalonia.Platform;
+
+public class StaleItemMonitor<T>
+{
+    private readonly CoreObservableCollection<T> _items;
+    private readonly Func<T, DateTime> _timestampSelector;
+    private readonly Func<T, string> _displaySelector;
+    private readonly TimeSpan _staleThreshold;
+    private readonly TimeSpan _pollInterval;
+    private CancellationTokenSource? _cts;
+    private Task? _monitorTask;
+
+    private readonly object _lock = new object();
+    
+    public event EventHandler? Changed;
+
+    public StaleItemMonitor(
+        CoreObservableCollection<T> items,
+        Func<T, DateTime> timestampSelector,
+        Func<T, String> displaySelector,
+        TimeSpan staleThreshold,
+        TimeSpan pollInterval)
+    {
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Initializing Stale Item monitor for {typeof(T).Name}");
+        _items = items ?? throw new ArgumentNullException(nameof(items));
+        _timestampSelector = timestampSelector ?? throw new ArgumentNullException(nameof(timestampSelector));
+        _displaySelector = displaySelector ?? throw new ArgumentNullException(nameof(displaySelector));
+        _staleThreshold = staleThreshold;
+        _pollInterval = pollInterval;
+    }
+
+    public Task StartAsync()
+    {
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Starting Stale Item monitor for {typeof(T).Name}");
+        if (_monitorTask != null && !_monitorTask.IsCompleted)
+        {
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stale Item monitor already started");
+            return Task.CompletedTask; // Already running
+        }
+
+        _cts = new CancellationTokenSource();
+        _monitorTask = Task.Run(() => MonitorLoop(_cts.Token));
+        
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stale Item monitor started successfully");
+        return Task.CompletedTask;
+    }
+
+    public async Task StopAsync()
+    {
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stopping Stale Item monitor for {typeof(T).Name}");
+        if (_monitorTask == null)
+        {
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stale Item monitor already stopped");
+            return;
+        }
+
+        if (_cts == null)
+        {
+            System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stale Item Monitor cancellation token is not set");
+            return;
+        }
+        
+        _cts.Cancel(); 
+
+        try
+        {
+            await _monitorTask;
+        }
+        catch (OperationCanceledException)
+        {
+            // Expected during cancellation
+        }
+        finally
+        {
+            _cts.Dispose();
+            _cts = null;
+            _monitorTask = null;
+        }
+        System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stale Item monitor stopped successfully");
+        
+    }
+
+    private async Task MonitorLoop(CancellationToken token)
+    {
+        while (!token.IsCancellationRequested)
+        {
+            try
+            {
+                RemoveStaleItems();
+                await Task.Delay(_pollInterval, token);
+            }
+            catch (OperationCanceledException)
+            {
+                // Cancellation requested, exit loop
+                break;
+            }
+            catch (Exception ex)
+            {
+                // Log or handle other exceptions
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Monitor error: {ex.Message}");
+            }
+        }
+    }
+
+    private void RemoveStaleItems()
+    {
+        DateTime now = DateTime.UtcNow;
+        lock (_lock)
+        {
+            var stale = _items.Where(item => (now - _timestampSelector(item)) > _staleThreshold).ToArray();
+            if (stale.Any())
+            {
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Removing Stale Items {string.Join(", ", stale.Select(x=>_displaySelector(x)))}...");
+                _items.RemoveAll(x => stale.Contains(x)); ;
+                Changed?.Invoke(this, EventArgs.Empty);
+                System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Removed {stale.Length} Stale Items.");
+            }
+        }
+    }
+}

+ 2 - 2
InABox.Avalonia.Platform/InABox.Avalonia.Platform.csproj

@@ -9,8 +9,8 @@
     </PropertyGroup>
 
     <ItemGroup>
-      <PackageReference Include="Autofac" Version="8.2.0" />
-      <PackageReference Include="Microsoft.Maui.Essentials" Version="8.0.93" />
+      <PackageReference Include="Autofac" Version="8.3.0" />
+      <PackageReference Include="Microsoft.Maui.Essentials" Version="9.0.60" />
     </ItemGroup>
 
     <ItemGroup>

+ 10 - 17
InABox.Avalonia/InABox.Avalonia.csproj

@@ -7,12 +7,11 @@
         <RootNamespace>InABox.Avalonia</RootNamespace>
         <LangVersion>default</LangVersion>
         <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
-        <Configurations>Debug;Release;DebugDev</Configurations>
+        <Configurations>Debug;Release</Configurations>
     </PropertyGroup>
 
     <ItemGroup>
       <None Remove="Images\cross.svg" />
-      <None Remove="Images\refresh.svg" />
       <None Remove="Images\search.svg" />
       <None Remove="Images\tick.svg" />
     </ItemGroup>
@@ -23,20 +22,18 @@
     </ItemGroup>
 
     <ItemGroup>
-      <PackageReference Include="Autofac" Version="8.2.0" />
-      <PackageReference Include="Avalonia" Version="11.2.3" />
-      <PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.3" />
-      <PackageReference Include="Avalonia.Native" Version="11.2.3" />
+      <PackageReference Include="Autofac" Version="8.3.0" />
+      <PackageReference Include="Avalonia" Version="11.2.2" />
+      <PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.2" />
+      <PackageReference Include="Avalonia.Diagnostics" Version="11.2.2" />
+      <PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.2" />
+      <PackageReference Include="Avalonia.Skia" Version="11.2.2" />
       <PackageReference Include="Avalonia.Svg.Skia" Version="11.2.0.2" />
       <PackageReference Include="AvaloniaDialogs" Version="3.6.1" />
-      <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
-      <PackageReference Include="Material.Avalonia" Version="3.9.2" />
-      <PackageReference Include="Material.Avalonia.DataGrid" Version="3.9.2" />
-      <PackageReference Include="Material.Avalonia.Dialogs" Version="3.9.2" />
-      <PackageReference Include="Microsoft.Maui.Essentials" Version="8.0.93" />
+      <PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
+      <PackageReference Include="Microsoft.Maui.Essentials" Version="9.0.60" />
       <PackageReference Include="Serilog" Version="4.2.0" />
-      <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
-      <PackageReference Include="SkiaSharp" Version="3.116.1" />
+      <PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
       <PackageReference Include="Syncfusion.Licensing" Version="26.2.14" />
       <PackageReference Include="Syncfusion.Pdf.Net.Core" Version="26.2.14" />
     </ItemGroup>
@@ -81,8 +78,4 @@
       <UpToDateCheckInput Remove="Dialogs\TextBoxDialog\TextBoxDialogView.axaml" />
     </ItemGroup>
 
-    <ItemGroup>
-      <AvaloniaResource Include="Images\refresh.svg" />
-    </ItemGroup>
-
 </Project>

+ 0 - 6
InABox.Avalonia/MobileDocument/MobileDocumentSource.cs

@@ -1,11 +1,5 @@
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using AvaloniaDialogs.Views;
-using JetBrains.Annotations;
 using Microsoft.Maui.ApplicationModel;
 using Microsoft.Maui.Storage;
-using InABox.Avalonia;
 
 
 namespace InABox.Avalonia

+ 7 - 6
InABox.Avalonia/Theme/Layouts.axaml

@@ -7,12 +7,13 @@
 
     <system:Double x:Key="PrsLineThickness">0.75</system:Double>
 
-    <inabox:ThicknessProvider x:Key="PrsBorderThickness"
-                              Left="{StaticResource PrsLineThickness}"
-                              Top="{StaticResource PrsLineThickness}"
-                              Right="{StaticResource PrsLineThickness}"
-                              Bottom="{StaticResource PrsLineThickness}" />
-
+    <!-- <inabox:ThicknessProvider x:Key="PrsBorderThickness" -->
+    <!--                           Left="{StaticResource PrsLineThickness}" -->
+    <!--                           Top="{StaticResource PrsLineThickness}" -->
+    <!--                           Right="{StaticResource PrsLineThickness}" -->
+    <!--                           Bottom="{StaticResource PrsLineThickness}" /> -->
+    <Thickness x:Key="PrsBorderThickness">0.75</Thickness>
+    
     <CornerRadius x:Key="PrsCornerRadius">4</CornerRadius>
 
     <system:Double x:Key="PrsSmallImageWidth">20</system:Double>

+ 4 - 2
InABox.Client.RPC/InABox.Client.RPC.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>netstandard2.1</TargetFramework>
+        <TargetFrameworks>net8.0;netstandard2.1</TargetFrameworks>
         <ImplicitUsings>disable</ImplicitUsings>
         <Nullable>enable</Nullable>
         <RootNamespace>InABox.RPC.Client</RootNamespace>
@@ -12,7 +12,9 @@
     </ItemGroup>
 
     <ItemGroup>
-      <PackageReference Include="H.Pipes" Version="2.0.59" />
+      <PackageReference Include="H.Formatters" Version="15.0.0" />
+      <PackageReference Include="H.Formatters.BinaryFormatter" Version="15.0.0" />
+      <PackageReference Include="H.Pipes" Version="15.0.0" />
       <PackageReference Include="WebSocket4Net" Version="0.15.2" />
     </ItemGroup>
 

+ 1 - 0
InABox.Core/Authenticator.cs

@@ -68,6 +68,7 @@ namespace InABox.Core
 
         public static bool CheckAuthenticationCode(byte[] key, string code)
         {
+            
             var _time = DateTimeOffset.Now.ToUnixTimeSeconds();
             for (long _l = _time - 30; _l <= _time; _l += 30)
             {

+ 6 - 4
InABox.Core/InABox.Core.csproj

@@ -4,8 +4,10 @@
         <ReleaseVersion>1.00</ReleaseVersion>
         <SynchReleaseVersion>false</SynchReleaseVersion>
         <OutputType>Library</OutputType>
-        <TargetFramework>netstandard2.1</TargetFramework>
+        <TargetFrameworks>net8.0;netstandard2.1</TargetFrameworks>
 		<Nullable>enable</Nullable>
+        <IsTrimmable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">false</IsTrimmable>
+        <PublishTrimmed Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">false</PublishTrimmed>
 	</PropertyGroup>
 
 	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -25,12 +27,12 @@
     <ItemGroup>
         <PackageReference Include="AutoProperties.Fody" Version="1.25.0" />
         <PackageReference Include="ExpressiveParser" Version="3.0.1" />
-        <PackageReference Include="FluentResults" Version="3.15.2" />
-        <PackageReference Include="Fody" Version="6.8.1">
+        <PackageReference Include="FluentResults" Version="3.16.0" />
+        <PackageReference Include="Fody" Version="6.9.2">
             <PrivateAssets>all</PrivateAssets>
             <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
         </PackageReference>
-        <PackageReference Include="HtmlAgilityPack" Version="1.11.65" />
+        <PackageReference Include="HtmlAgilityPack" Version="1.12.1" />
         <PackageReference Include="Inflector.NetStandard" Version="1.2.2" />
         <PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
         <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

+ 1 - 1
InABox.RPC.Shared/InABox.RPC.Shared.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>netstandard2.1</TargetFramework>
+        <TargetFrameworks>netstandard2.1;net8.0</TargetFrameworks>
         <ImplicitUsings>disable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>

+ 3 - 1
inabox.logging.shared/InABox.Logging.Shared.csproj

@@ -1,7 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks>
+        <TargetFrameworks>netcoreapp3.1;netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
+        <IsTrimmable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">false</IsTrimmable>
+        <PublishTrimmed Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">false</PublishTrimmed>
     </PropertyGroup>
 
     <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">