From 4efb23b301d75caeb992a6d0bf35be0e2a464d1f Mon Sep 17 00:00:00 2001 From: Paul-Winpenny <92634321+Paul-Winpenny@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:46:46 +0100 Subject: [PATCH] Wifi networks list is now present, also minor style changes. --- App/RobobinApp/Models/BluetoothDevice.cs | 21 +++ App/RobobinApp/Models/WifiNetwork.cs | 14 ++ App/RobobinApp/RobobinApp.csproj | 9 +- .../ViewModels/ConnectionPageViewModel.cs | 61 ++++---- App/RobobinApp/Views/ConnectionPage.xaml | 146 ++++++++++++------ 5 files changed, 174 insertions(+), 77 deletions(-) create mode 100644 App/RobobinApp/Models/BluetoothDevice.cs create mode 100644 App/RobobinApp/Models/WifiNetwork.cs diff --git a/App/RobobinApp/Models/BluetoothDevice.cs b/App/RobobinApp/Models/BluetoothDevice.cs new file mode 100644 index 00000000..c4a552e5 --- /dev/null +++ b/App/RobobinApp/Models/BluetoothDevice.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RobobinApp.Models +{ + public class BluetoothDevice + { + public string Name { get; set; } + public string MacAddress { get; set; } + + public BluetoothDevice(string name, string macAddress) + { + Name = name; + MacAddress = macAddress; + } + } +} + diff --git a/App/RobobinApp/Models/WifiNetwork.cs b/App/RobobinApp/Models/WifiNetwork.cs new file mode 100644 index 00000000..0e0e8303 --- /dev/null +++ b/App/RobobinApp/Models/WifiNetwork.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RobobinApp.Models +{ + public class WifiNetwork + { + public string SSID { get; set; } + public string SignalStrength { get; set; } + } +} diff --git a/App/RobobinApp/RobobinApp.csproj b/App/RobobinApp/RobobinApp.csproj index 421fce80..47ae3c5d 100644 --- a/App/RobobinApp/RobobinApp.csproj +++ b/App/RobobinApp/RobobinApp.csproj @@ -1,20 +1,19 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> + <TargetFrameworks>net8.0-ios;net8.0-maccatalyst</TargetFrameworks> <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks> <OutputType>Exe</OutputType> - <RootNamespace>MauiApp1</RootNamespace> + <RootNamespace>Robobin</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> - <ApplicationTitle>MauiApp1</ApplicationTitle> - <ApplicationId>com.companyname.mauiapp1</ApplicationId> + <ApplicationTitle>Robobin</ApplicationTitle> + <ApplicationId>com.companyname.robobin</ApplicationId> <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion> <ApplicationVersion>1</ApplicationVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion> - <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion> <TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion> diff --git a/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs b/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs index 8c08c32b..8a728f5b 100644 --- a/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs +++ b/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs @@ -9,6 +9,9 @@ using Plugin.BLE.Abstractions.Exceptions; using Plugin.BLE.Abstractions.EventArgs; using System.Threading.Tasks; using Plugin.BLE.Abstractions; +using RobobinApp.Models; +using System.Net.NetworkInformation; +using System.Collections.Generic; namespace RobobinApp.ViewModels { @@ -18,12 +21,16 @@ namespace RobobinApp.ViewModels private IDevice _connectedDevice; // Track the connected device public ICommand GoHomeCommand { get; } public ObservableCollection<BluetoothDevice> BluetoothDevices { get; } + public ObservableCollection<WifiNetwork> WifiNetworks { get; } + public ICommand ConnectCommand { get; } - public ICommand SendWifiInfoCommand { get; } - public ICommand DisconnectCommand { get; } // Command for disconnecting - private bool _isConnected; // Track connection state + public ICommand SendWifiInfoCommand { get; } + public ICommand DisconnectCommand { get; } + private bool _isConnected; private string ssid; private string password; + public bool IsBluetoothDeviceSelectionVisible => !IsWifiNetworkSelectionVisible; + public bool IsConnected { get => _isConnected; @@ -58,6 +65,17 @@ namespace RobobinApp.ViewModels private readonly IAdapter _adapter; private readonly IBluetoothLE _bluetoothLE; public string ConnectButtonText => IsConnected ? "Disconnect" : "Connect"; + private bool _isWifiNetworkSelectionVisible; + public bool IsWifiNetworkSelectionVisible + { + get => _isWifiNetworkSelectionVisible; + set + { + _isWifiNetworkSelectionVisible = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(IsBluetoothDeviceSelectionVisible)); + } + } public ConnectionPageViewModel() { @@ -70,6 +88,7 @@ namespace RobobinApp.ViewModels _bluetoothLE = CrossBluetoothLE.Current; _adapter = _bluetoothLE.Adapter; _adapter.DeviceDiscovered += OnDeviceDiscovered; + IsWifiNetworkSelectionVisible = false; Debug.WriteLine("Checking and requesting Bluetooth permissions."); CheckAndRequestBluetoothPermissions(); @@ -208,31 +227,20 @@ namespace RobobinApp.ViewModels private void OnDeviceDiscovered(object sender, DeviceEventArgs e) { - Debug.WriteLine($"Discovered device: ID={e.Device.Id}, Name={e.Device.Name}, State={e.Device.State}, RSSI={e.Device.Rssi}"); + Debug.WriteLine($"Discovered device: {e.Device.Name ?? e.Device.Id.ToString()}"); - // Filter out devices that are not in a ready state - //if (e.Device.State != DeviceState.Connected && e.Device.State != DeviceState.Disconnected) - //{ - // Debug.WriteLine($"Device {e.Device.Name} is not in a fully ready state (State: {e.Device.State}). Skipping."); - // return; - //} - - var bluetoothDevice = new BluetoothDevice - { - Name = string.IsNullOrWhiteSpace(e.Device.Name) ? e.Device.Id.ToString() : e.Device.Name, - MacAddress = e.Device.Id.ToString() - }; + var bluetoothDevice = new BluetoothDevice( + string.IsNullOrWhiteSpace(e.Device.Name) ? e.Device.Id.ToString() : e.Device.Name, + e.Device.Id.ToString() + ); if (!BluetoothDevices.Any(d => d.MacAddress == bluetoothDevice.MacAddress)) { - Device.BeginInvokeOnMainThread(() => - { - BluetoothDevices.Add(bluetoothDevice); - Debug.WriteLine($"Added device to list: {bluetoothDevice.Name} ({bluetoothDevice.MacAddress})"); - }); + Device.BeginInvokeOnMainThread(() => BluetoothDevices.Add(bluetoothDevice)); } } + private async Task<IDevice> TryConnectAsync(Guid deviceId, int retryCount = 3) { IDevice device = null; @@ -295,6 +303,7 @@ namespace RobobinApp.ViewModels if (characteristic.Id == Guid.Parse("6e400002-b5a3-f393-e0a9-e50e24dcca9e")) { + IsWifiNetworkSelectionVisible = true; Debug.WriteLine("Found RX characteristic (for writing data)"); // Convert the string to a byte array byte[] data = System.Text.Encoding.UTF8.GetBytes("Hello World"); @@ -338,9 +347,10 @@ namespace RobobinApp.ViewModels Debug.WriteLine($"Attempting to disconnect from {_connectedDevice.Name}"); await _adapter.DisconnectDeviceAsync(_connectedDevice); Debug.WriteLine("Disconnected successfully."); - + IsWifiNetworkSelectionVisible = false; // Dispose of the device reference - _connectedDevice.Dispose(); + if (_connectedDevice != null) + _connectedDevice.Dispose(); _connectedDevice = null; IsConnected = false; await Application.Current.MainPage.DisplayAlert("Disconnected", "Device disconnected successfully.", "OK"); @@ -356,11 +366,6 @@ namespace RobobinApp.ViewModels Debug.WriteLine("No device to disconnect."); } } - } - public class BluetoothDevice - { - public string Name { get; set; } - public string MacAddress { get; set; } } } diff --git a/App/RobobinApp/Views/ConnectionPage.xaml b/App/RobobinApp/Views/ConnectionPage.xaml index 7d7ae169..d7592573 100644 --- a/App/RobobinApp/Views/ConnectionPage.xaml +++ b/App/RobobinApp/Views/ConnectionPage.xaml @@ -3,6 +3,35 @@ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="RobobinApp.Views.ConnectionPage" Title="Connect to Robobin"> + <ContentPage.Resources> + <ResourceDictionary> + <Style x:Key="HeaderLabelStyle" TargetType="Label"> + <Setter Property="FontSize" Value="Medium" /> + <Setter Property="TextColor" Value="DarkSlateBlue" /> + <Setter Property="HorizontalOptions" Value="Center" /> + <Setter Property="VerticalOptions" Value="Start" /> + </Style> + + <Style x:Key="ButtonStyle" TargetType="Button"> + <Setter Property="BackgroundColor" Value="LightBlue" /> + <Setter Property="TextColor" Value="White" /> + <Setter Property="Padding" Value="10,5" /> + <Setter Property="CornerRadius" Value="5" /> + <Setter Property="FontAttributes" Value="Bold" /> + </Style> + + + + <Style x:Key="ListViewStyle" TargetType="ListView"> + <Setter Property="BackgroundColor" Value="White" /> + <Setter Property="SeparatorVisibility" Value="Default" /> + <Setter Property="SeparatorColor" Value="LightGray" /> + <Setter Property="SelectedItem" Value="Blue" /> + <Setter Property="VerticalScrollBarVisibility" Value="Always"/> + + </Style> + </ResourceDictionary> + </ContentPage.Resources> <ContentPage.MenuBarItems> <MenuBarItem Text="Menu"> @@ -11,56 +40,85 @@ </ContentPage.MenuBarItems> <StackLayout Padding="20"> - <Label Text="Select a Bluetooth Device" - FontSize="Medium" - HorizontalOptions="Center" - VerticalOptions="Start" /> - - <ListView x:Name="DeviceListView" - ItemsSource="{Binding BluetoothDevices}" - SelectedItem="{Binding SelectedDevice}" - VerticalOptions="FillAndExpand"> - <ListView.ItemTemplate> - <DataTemplate> - <TextCell Text="{Binding Name}" /> - </DataTemplate> - </ListView.ItemTemplate> - </ListView> - - <Button Text="{Binding ConnectButtonText}" - Command="{Binding ConnectCommand}" - IsEnabled="{Binding SelectedDevice, Converter={StaticResource NullToBooleanConverter}}" - HorizontalOptions="Center" - VerticalOptions="End" /> - - <!-- Section for SSID and Password - Initially Hidden --> - <StackLayout IsVisible="{Binding IsConnected}" - Padding="10" - BackgroundColor="LightGray" - HorizontalOptions="FillAndExpand" - VerticalOptions="Start"> - <Label Text="SSID:" + <StackLayout IsVisible="{Binding IsBluetoothDeviceSelectionVisible}"> + <Label Text="Select a Bluetooth Device" FontSize="Medium" - HorizontalOptions="Start" /> - <Entry x:Name="SSIDEntry" - Placeholder="Enter SSID" - Text="{Binding SSID}" - HorizontalOptions="Fill" /> + HorizontalOptions="Center" + VerticalOptions="Start" /> - <Label Text="Password:" - FontSize="Medium" - HorizontalOptions="Start" /> - <Entry x:Name="PasswordEntry" - Placeholder="Enter Password" - Text="{Binding Password}" - IsPassword="True" - HorizontalOptions="Fill" /> + <ListView x:Name="DeviceListView" + ItemsSource="{Binding BluetoothDevices}" + SelectedItem="{Binding SelectedDevice}" + VerticalOptions="FillAndExpand"> + <ListView.ItemTemplate> + <DataTemplate> + <TextCell Text="{Binding Name}" /> + </DataTemplate> + </ListView.ItemTemplate> + </ListView> - <Button Text="Send WiFi Information" - Command="{Binding SendWifiInfoCommand}" + <Button Text="{Binding ConnectButtonText}" + Command="{Binding ConnectCommand}" + IsEnabled="{Binding SelectedDevice, Converter={StaticResource NullToBooleanConverter}}" HorizontalOptions="Center" VerticalOptions="End" /> </StackLayout> + <StackLayout IsVisible="{Binding IsWifiNetworkSelectionVisible}"> + <Grid Padding="10" HorizontalOptions="FillAndExpand"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + + <Label Text="{Binding SelectedDevice.Name}" + FontSize="Medium" + HorizontalOptions="Start" + VerticalOptions="Center" + Grid.Column="0" /> + + <Button Text="Disconnect" + Command="{Binding DisconnectCommand}" + HorizontalOptions="End" + VerticalOptions="Center" + Grid.Column="1" /> + </Grid> + + <Label Text="Select a WiFi Network" + FontSize="Medium" + HorizontalOptions="Center" + VerticalOptions="Start" /> + + <ListView x:Name="WifiListView" + ItemsSource="{Binding AvailableWifiNetworks}" + SelectedItem="{Binding SelectedWifiNetwork}" + VerticalOptions="FillAndExpand"> + <ListView.ItemTemplate> + <DataTemplate> + <TextCell Text="{Binding SSID}" /> + </DataTemplate> + </ListView.ItemTemplate> + </ListView> + + <!-- Section for Password Input --> + <StackLayout Padding="10" + BackgroundColor="LightGray" + HorizontalOptions="FillAndExpand" + VerticalOptions="Start"> + <Label Text="Password:" + FontSize="Medium" + HorizontalOptions="Start" /> + <Entry x:Name="PasswordEntry" + Placeholder="Enter Password" + Text="{Binding Password}" + IsPassword="True" + HorizontalOptions="Fill" /> + + <Button Text="Send WiFi Information" + Command="{Binding SendWifiInfoCommand}" + HorizontalOptions="Center" + VerticalOptions="End" /> + </StackLayout> + </StackLayout> </StackLayout> </ContentPage> -- GitLab