diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000000000000000000000000000000000000..70fefc060eed4610e13a5433a6fa7369c63556df --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,7 @@ +{ + "ExpandedNodes": [ + "" + ], + "SelectedNode": "\\App.sln", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite index ddce4cda1e8734ebd50cba8503c15bb5c329d3f6..7768cbea50d0c8b6d0079797bfd1b57a875121e4 100644 Binary files a/.vs/slnx.sqlite and b/.vs/slnx.sqlite differ diff --git a/App/RobobinApp/MauiProgram.cs b/App/RobobinApp/MauiProgram.cs index 90697e0e34c6feb93ca99d19460e62a7fd1d623f..df11d1d0253ed9e1380af53e47f3d813d0b5a3f8 100644 --- a/App/RobobinApp/MauiProgram.cs +++ b/App/RobobinApp/MauiProgram.cs @@ -1,24 +1,27 @@ -using Microsoft.Extensions.Logging; + +using Shiny; namespace RobobinApp; + public static class MauiProgram { - public static MauiApp CreateMauiApp() - { - var builder = MauiApp.CreateBuilder(); - builder - .UseMauiApp<App>() - .ConfigureFonts(fonts => - { - fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); - fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); - }); + public static MauiApp CreateMauiApp() + { + var builder = MauiApp + .CreateBuilder() + .UseMauiApp<App>() + .UseShiny() + + .ConfigureFonts(fonts => + { + fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); + fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); + }); + -#if DEBUG - builder.Logging.AddDebug(); -#endif + builder.Services.AddBluetoothLE(); - return builder.Build(); - } -} + return builder.Build(); + } +} \ No newline at end of file diff --git a/App/RobobinApp/RobobinApp.csproj b/App/RobobinApp/RobobinApp.csproj index fe8ef06b6563ae3d0be1d94040e532c88a417eb4..4a445af54da62b7ae14b333adfdfa9216f1c317a 100644 --- a/App/RobobinApp/RobobinApp.csproj +++ b/App/RobobinApp/RobobinApp.csproj @@ -58,9 +58,13 @@ <ItemGroup> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" /> - <PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" /> - <PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" /> - <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" /> + <PackageReference Include="Microsoft.Maui.Controls" Version="8.0.91" /> + <PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.91" /> + <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1" /> + <PackageReference Include="Plugin.BLE" Version="3.1.0" /> + <PackageReference Include="Shiny" Version="2.7.3" /> + <PackageReference Include="Shiny.BluetoothLE" Version="3.3.3" /> + <PackageReference Include="Shiny.Hosting.Maui" Version="3.3.3" /> </ItemGroup> <ItemGroup> diff --git a/App/RobobinApp/RobobinApp.csproj.user b/App/RobobinApp/RobobinApp.csproj.user index 5ac6ce85f74619c22e653ccc66e3362a9450ec3b..d5dbc44f4a17c86bc16c6e731262903590f5f0a1 100644 --- a/App/RobobinApp/RobobinApp.csproj.user +++ b/App/RobobinApp/RobobinApp.csproj.user @@ -4,6 +4,11 @@ <IsFirstTimeProjectOpen>False</IsFirstTimeProjectOpen> <ActiveDebugFramework>net8.0-windows10.0.19041.0</ActiveDebugFramework> <ActiveDebugProfile>Windows Machine</ActiveDebugProfile> + <SelectedPlatformGroup>Emulator</SelectedPlatformGroup> + <DefaultDevice>pixel_5_-_api_34</DefaultDevice> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-android|AnyCPU'"> + <DebuggerFlavor>ProjectDebugger</DebuggerFlavor> </PropertyGroup> <ItemGroup> <MauiXaml Update="Views\ConnectionPage.xaml"> diff --git a/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs b/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs index 9802d25ee5ff90ea672e7112f239e28392acc894..fe675991f21ac7576e19d9d32c029db7e1de94ba 100644 --- a/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs +++ b/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs @@ -2,6 +2,9 @@ using System.Windows.Input; using Microsoft.Maui.Controls; using RobobinApp.Views; +using Plugin.BLE; +using Plugin.BLE.Abstractions.Contracts; +using Plugin.BLE.Abstractions.Exceptions; namespace RobobinApp.ViewModels { @@ -12,33 +15,74 @@ namespace RobobinApp.ViewModels public ObservableCollection<BluetoothDevice> BluetoothDevices { get; } public ICommand ConnectCommand { get; } + // BLE plugin fields + private readonly IAdapter _adapter; + private readonly IBluetoothLE _bluetoothLE; + public ConnectionPageViewModel() { BluetoothDevices = new ObservableCollection<BluetoothDevice>(); ConnectCommand = new Command(OnConnect); - LoadBluetoothDevices(); // Load available devices GoHomeCommand = new Command(async () => await OnGoHome()); + + // Initialize BLE manager and adapter + _bluetoothLE = CrossBluetoothLE.Current; + _adapter = _bluetoothLE.Adapter; + + ScanDevices(); // Start scanning for devices } - public async Task OnGoHome() - { - await Application.Current.MainPage.Navigation.PushAsync(new MainPage()); - } + public BluetoothDevice SelectedDevice { get => _selectedDevice; set { _selectedDevice = value; - OnPropertyChanged(); // Notify UI that SelectedDevice has changed + OnPropertyChanged(); } } - private async void LoadBluetoothDevices() + public async Task OnGoHome() { - // Logic to load available Bluetooth devices - // This is a placeholder for your Bluetooth device discovery logic - BluetoothDevices.Add(new BluetoothDevice { Name = "Device 1" }); - BluetoothDevices.Add(new BluetoothDevice { Name = "Device 2" }); + await Application.Current.MainPage.Navigation.PushAsync(new MainPage()); + } + + private async void ScanDevices() + { + // Clear the current list of devices before scanning + BluetoothDevices.Clear(); + + try + { + if (!_bluetoothLE.IsAvailable) + { + await Application.Current.MainPage.DisplayAlert("Bluetooth", "Bluetooth is not available.", "OK"); + return; + } + + if (!_bluetoothLE.IsOn) + { + await Application.Current.MainPage.DisplayAlert("Bluetooth", "Please turn on Bluetooth.", "OK"); + return; + } + + _adapter.DeviceDiscovered += (s, a) => + { + // Add discovered devices to the list + BluetoothDevices.Add(new BluetoothDevice + { + Name = a.Device.Name ?? "Unknown Device", + MacAddress = a.Device.Id.ToString() + }); + }; + + // Start scanning for devices + await _adapter.StartScanningForDevicesAsync(); + } + catch (Exception ex) + { + await Application.Current.MainPage.DisplayAlert("Error", $"Failed to scan for devices: {ex.Message}", "OK"); + } } private async void OnConnect() @@ -47,12 +91,29 @@ namespace RobobinApp.ViewModels // Logic to connect to the selected Bluetooth device await Application.Current.MainPage.DisplayAlert("Connection", $"Connecting to {SelectedDevice.Name}...", "OK"); - // Implement actual connection logic here + + try + { + // Stop scanning before attempting connection + await _adapter.StopScanningForDevicesAsync(); + + // Find the device using the MAC address + var device = await _adapter.ConnectToKnownDeviceAsync(Guid.Parse(SelectedDevice.MacAddress)); + + // Display successful connection + await Application.Current.MainPage.DisplayAlert("Connected", $"Connected to {SelectedDevice.Name}.", "OK"); + } + catch (DeviceConnectionException ex) + { + // Handle connection failure + await Application.Current.MainPage.DisplayAlert("Connection Error", $"Failed to connect: {ex.Message}", "OK"); + } } } - public class BluetoothDevice // Define this class to represent a Bluetooth device + public class BluetoothDevice { public string Name { get; set; } + public string MacAddress { get; set; } } } diff --git a/App/RobobinApp/ViewModels/MainPageViewModel.cs b/App/RobobinApp/ViewModels/MainPageViewModel.cs index d2387784a0e14eed25d5602d06b4f41951c9b65f..8665557a0fd8f7db1b5f3df628bd0300c238fe2d 100644 --- a/App/RobobinApp/ViewModels/MainPageViewModel.cs +++ b/App/RobobinApp/ViewModels/MainPageViewModel.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using System.Windows.Input; using Microsoft.Maui.Controls; using RobobinApp.Views; +using Shiny.BluetoothLE; namespace RobobinApp.ViewModels @@ -11,11 +12,12 @@ namespace RobobinApp.ViewModels { private bool _isBusy; private string _statusMessage; - + public ICommand ConnectToRobobinCommand { get; } public MainPageViewModel() { + ConnectToRobobinCommand = new Command(async () => await OnConnectToRobobin()); }