From be27e47b87a554531e91989590f84b0e17eb6ef0 Mon Sep 17 00:00:00 2001 From: ethanmsmith Date: Wed, 12 Jul 2017 17:15:25 -0400 Subject: [PATCH 01/29] Redesigning UI. Includes refactoring pages. --- AnneProKeyboard/AnneProKeyboard.csproj | 7 + AnneProKeyboard/MainPage.xaml | 354 +++++++++---------------- AnneProKeyboard/MainPage.xaml.cs | 303 +-------------------- 3 files changed, 133 insertions(+), 531 deletions(-) diff --git a/AnneProKeyboard/AnneProKeyboard.csproj b/AnneProKeyboard/AnneProKeyboard.csproj index 9695768..5c2e69f 100644 --- a/AnneProKeyboard/AnneProKeyboard.csproj +++ b/AnneProKeyboard/AnneProKeyboard.csproj @@ -100,6 +100,9 @@ App.xaml + + LightingPage.xaml + @@ -131,6 +134,10 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + MSBuild:Compile Designer diff --git a/AnneProKeyboard/MainPage.xaml b/AnneProKeyboard/MainPage.xaml index 3d896db..e52637d 100644 --- a/AnneProKeyboard/MainPage.xaml +++ b/AnneProKeyboard/MainPage.xaml @@ -52,20 +52,8 @@ - - - - - - - - - - - - - + @@ -76,77 +64,77 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -31,19 +54,19 @@ - - - - + + --> diff --git a/AnneProKeyboard/LightingPage.xaml b/AnneProKeyboard/LightingPage.xaml index 8d42eb2..f8907c6 100644 --- a/AnneProKeyboard/LightingPage.xaml +++ b/AnneProKeyboard/LightingPage.xaml @@ -140,7 +140,7 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + - diff --git a/AnneProKeyboard/MainPage.xaml.cs b/AnneProKeyboard/MainPage.xaml.cs index 4b65c72..ecff991 100644 --- a/AnneProKeyboard/MainPage.xaml.cs +++ b/AnneProKeyboard/MainPage.xaml.cs @@ -31,12 +31,27 @@ namespace AnneProKeyboard /// public sealed partial class MainPage : Page { + private DeviceWatcher BluetoothDeviceWatcher; + private DeviceWatcher AllDevicesWatcher; + + private readonly Guid OAD_GUID = new Guid("f000ffc0-0451-4000-b000-000000000000"); + private readonly Guid WRITE_GATT_GUID = new Guid("f000ffc2-0451-4000-b000-000000000000"); + private readonly Guid READ_GATT_GUID = new Guid("f000ffc1-0451-4000-b000-000000000000"); + + private GattCharacteristic WriteGatt; + private GattCharacteristic ReadGatt; + private DeviceInformation KeyboardDeviceInformation; + private ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar; + private MainPage mainPage; + public MainPage() { this.InitializeComponent(); - _frame.Navigate(typeof(LayoutPage)); + _frame.Content = new LayoutPage(); + // Start up the background thread to find the keyboard + FindKeyboard(); CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true; titleBar = ApplicationView.GetForCurrentView().TitleBar; titleBar.ButtonInactiveBackgroundColor = Colors.White; @@ -46,6 +61,248 @@ public MainPage() Color systemAccentColor = (Color)App.Current.Resources["SystemAccentColor"]; } + private async void FindKeyboard() + { + string deviceSelectorInfo = BluetoothLEDevice.GetDeviceSelectorFromPairingState(true); + DeviceInformationCollection deviceInfoCollection = await DeviceInformation.FindAllAsync(deviceSelectorInfo, null); + + foreach (DeviceInformation device_info in deviceInfoCollection) + { + // Do not let the background task starve, check if we are paired then connect to the keyboard + if (device_info.Name.Contains("ANNE") + && device_info.Pairing.IsPaired) + { + ConnectToKeyboard(device_info); + + break; + } + } + + // if the device was never paired start doing the background check + // Make sure to disable Bluetooth listener + this.SetupBluetooth(); + } + + private void SetupBluetooth() + { + if (this.BluetoothDeviceWatcher == null) + { + BluetoothDeviceWatcher = DeviceInformation.CreateWatcher("System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\"", null, DeviceInformationKind.AssociationEndpoint); + + try + { + BluetoothDeviceWatcher.Added += BluetoothDeviceAdded; + BluetoothDeviceWatcher.Updated += BluetoothDeviceUpdated; + BluetoothDeviceWatcher.Start(); + } + catch + { + } + } + + if (AllDevicesWatcher == null) + { + AllDevicesWatcher = DeviceInformation.CreateWatcher(DeviceClass.All); + + try + { + AllDevicesWatcher.Updated += HIDDeviceUpdated; + AllDevicesWatcher.Start(); + } + catch + { + } + } + } + + private async void HIDDeviceUpdated(DeviceWatcher sender, DeviceInformationUpdate args) + { + DeviceInformation device_info = await DeviceInformation.CreateFromIdAsync(args.Id); + + if(device_info == null) + { + return; + } + + // Do not let the background task starve, check if we are paired then connect to the keyboard + if (device_info.Name.Contains("ANNE")) + { + if (device_info.IsEnabled) + { + FindKeyboard(); + } + else + { + await Dispatcher.RunAsync(CoreDispatcherPriority.High, () => + { + KeyboardDeviceInformation = null; + connectionStatusLabel.Text = "Not Connected"; + connectionStatusLabel.Foreground = new SolidColorBrush(Colors.Red); + if (Frame.Content.GetType() == typeof(LayoutPage)) + { + LayoutPage child = this.Frame.Content as LayoutPage; + child.LayoutSyncButton.IsEnabled = false; + } + if (Frame.Content.GetType() == typeof(LightingPage)) + { + LightingPage child = this.Frame.Content as LightingPage; + child.LightSyncButton.IsEnabled = false; + } + }); + } + } + } + + private void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e) + { + if (this.BluetoothDeviceWatcher != null) + { + BluetoothDeviceWatcher.Added -= BluetoothDeviceAdded; + BluetoothDeviceWatcher.Updated -= BluetoothDeviceUpdated; + + BluetoothDeviceWatcher.Stop(); + + this.BluetoothDeviceWatcher = null; + } + + if (this.AllDevicesWatcher != null) + { + AllDevicesWatcher.Updated -= HIDDeviceUpdated; + + AllDevicesWatcher.Stop(); + + this.AllDevicesWatcher = null; + } + } + + private void App_Resuming(object sender, object e) + { + this.SetupBluetooth(); + } + + private async void BluetoothDeviceAdded(DeviceWatcher watcher, DeviceInformation device) + { + if (device.Name.Contains("ANNE")) + { + if (device.Pairing.IsPaired) + { + ConnectToKeyboard(device); + } + else if (device.Pairing.CanPair) + { + var result = await device.Pairing.PairAsync(); + + if (result.Status == DevicePairingResultStatus.Paired) + { + ConnectToKeyboard(device); + } + } + } + } + + private void BluetoothDeviceUpdated(DeviceWatcher watcher, DeviceInformationUpdate device) + { + // Need this function for Bluetooth LE device watcher, otherwise it won't detect anything + } + + private async void ConnectToKeyboard(DeviceInformation device) + { + try + { + if (this.KeyboardDeviceInformation != null) + { + return; + } + + var keyboard = await BluetoothLEDevice.FromIdAsync(device.Id); + + if (keyboard == null) + { + return; + } + + if (keyboard.ConnectionStatus != BluetoothConnectionStatus.Connected) + { + return; + } + + var service = keyboard.GetGattService(OAD_GUID); + + if (service == null) + { + return; + } + + var write_gatt = service.GetCharacteristics(WRITE_GATT_GUID)[0]; + var read_gatt = service.GetCharacteristics(READ_GATT_GUID)[0]; + + if (write_gatt == null || read_gatt == null) + { + return; + } + + this.WriteGatt = write_gatt; + this.ReadGatt = read_gatt; + this.KeyboardDeviceInformation = device; + + await this.ReadGatt.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify); + this.ReadGatt.ValueChanged += ReadGatt_ValueChanged; + + // Sync up the profile data + this.RequestKeyboardSync(); + } + // We should actually catch errors here... + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + + private void ReadGatt_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args) + { + var data = args.CharacteristicValue.ToArray(); + + //TODO: handle the retrieved data + } + + private void RequestKeyboardSync() + { + // expect firmware version and mac address + byte[] device_id_meta_data = { 0x02, 0x01, 0x01 }; + + KeyboardWriter keyboard_writer = new KeyboardWriter(this.WriteGatt, device_id_meta_data, null); + keyboard_writer.WriteToKeyboard(); + + keyboard_writer.OnWriteFinished += (object_s, events) => + { + FinishSync(); + }; + } + + private async void FinishSync() + { + await Dispatcher.RunAsync(CoreDispatcherPriority.High, () => + { + this.connectionStatusLabel.Text = "Connected"; + this.connectionStatusLabel.Foreground = new SolidColorBrush(Colors.Green); + if (_frame.Content.GetType() == typeof(LayoutPage)) + { + LayoutPage child = _frame.Content as LayoutPage; + child.LayoutSyncButton.IsEnabled = true; + } + if (_frame.Content.GetType() == typeof(LightingPage)) + { + LightingPage child = _frame.Content as LightingPage; + child.LightSyncButton.IsEnabled = true; + } + }); + } + + public void SyncProfile(KeyboardProfileItem EditingProfile) + { + EditingProfile.SyncProfile(this.WriteGatt); + } + private void hamburgerHover(object sender, RoutedEventArgs e) { //HamburgerButton.Background = new SolidColorBrush(Colors.Red); @@ -84,9 +341,14 @@ private void HamburgerButton_Click(object sender, RoutedEventArgs e) private void LightingNav_Clicked(object sender, RoutedEventArgs e) { - if (!(_frame.CurrentSourcePageType == typeof(LightingPage))) + if (!(_frame.Content.GetType() == typeof(LightingPage))) { - _frame.Navigate(typeof(LightingPage)); + _frame.Content = new LightingPage(); + if (connectionStatusLabel.Text == "Connected") + { + LightingPage child = _frame.Content as LightingPage; + child.LightSyncButton.IsEnabled = true; + } pageHeader.Text = "Lighting"; LightingMenuButton.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); } @@ -94,9 +356,14 @@ private void LightingNav_Clicked(object sender, RoutedEventArgs e) private void LayoutNav_Clicked(object sender, RoutedEventArgs e) { - if (!(_frame.CurrentSourcePageType == typeof(LayoutPage))) + if (!(_frame.Content.GetType() == typeof(LayoutPage))) { - _frame.Navigate(typeof(LayoutPage)); + _frame.Content = new LayoutPage(); + if(connectionStatusLabel.Text == "Connected") + { + LayoutPage child = _frame.Content as LayoutPage; + child.LayoutSyncButton.IsEnabled = true; + } pageHeader.Text = "Layers"; LayoutMenuButton.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); } From c1e8ab12784225741b85dd65de8b8f270f6d6241 Mon Sep 17 00:00:00 2001 From: ethanmsmith Date: Tue, 25 Jul 2017 15:18:00 -0400 Subject: [PATCH 13/29] Syncing working as before (syncs lighting and layout at once). --- AnneProKeyboard/LayoutPage.xaml | 7 -- AnneProKeyboard/LayoutPage.xaml.cs | 30 +---- AnneProKeyboard/LightingPage.xaml | 2 - AnneProKeyboard/LightingPage.xaml.cs | 163 +-------------------------- AnneProKeyboard/MainPage.xaml | 2 +- AnneProKeyboard/MainPage.xaml.cs | 89 +++++++++++---- 6 files changed, 75 insertions(+), 218 deletions(-) diff --git a/AnneProKeyboard/LayoutPage.xaml b/AnneProKeyboard/LayoutPage.xaml index 8067690..c582cc4 100644 --- a/AnneProKeyboard/LayoutPage.xaml +++ b/AnneProKeyboard/LayoutPage.xaml @@ -289,12 +289,5 @@ - - - - - - + + + + @@ -46,11 +52,6 @@ - - - - - - - diff --git a/AnneProKeyboard/LayoutPage.xaml.cs b/AnneProKeyboard/LayoutPage.xaml.cs index b8d3544..3081ba8 100644 --- a/AnneProKeyboard/LayoutPage.xaml.cs +++ b/AnneProKeyboard/LayoutPage.xaml.cs @@ -78,7 +78,7 @@ public async void SaveProfiles() } } - private async void LoadProfiles() + public async void LoadProfiles() { try { @@ -115,6 +115,10 @@ private void CreateNewKeyboardProfile() private void ChangeSelectedProfile(KeyboardProfileItem profile) { + if(profile == null) + { + return; + } this.EditingProfile = profile; // set up the background colours for the keyboard lights @@ -182,8 +186,9 @@ private void ProfileNameChangedEvent_TextChanged(object sender, TextChangedEvent private void ProfileAddButton_Click(object sender, RoutedEventArgs e) { this.CreateNewKeyboardProfile(); - this.SaveProfiles(); + this.ChangeSelectedProfile(_keyboardProfiles[_keyboardProfiles.Count - 1]); + this.LayoutProfilesCombo.SelectedIndex = this.LayoutProfilesCombo.Items.Count - 1; } private void ProfileEditButton_Click(object sender, RoutedEventArgs e) @@ -211,6 +216,7 @@ private void ProfileDeleteButton_Click(object sender, RoutedEventArgs e) KeyboardProfileItem selected_profile = this._keyboardProfiles[(int)button.Tag]; this._keyboardProfiles.Remove(selected_profile); + //this.LayoutProfilesCombo.Items.Remove(selected_profile); // always make sure that the keyboard profiles list has 1 element in it if (this._keyboardProfiles.Count == 0) @@ -220,7 +226,8 @@ private void ProfileDeleteButton_Click(object sender, RoutedEventArgs e) // Change the chosen profile to the first element ChangeSelectedProfile(this._keyboardProfiles[0]); - + LayoutProfilesCombo.SelectedIndex = 0; + LayoutProfilesCombo.IsDropDownOpen = false; this.SaveProfiles(); } @@ -229,18 +236,10 @@ private void ProfileNameTextbox_LostFocus(object sender, RoutedEventArgs e) this.SaveProfiles(); TextBox textbox = (TextBox)sender; - textbox.IsEnabled = false; - textbox.Visibility = Visibility.Collapsed; - - FrameworkElement parent = (FrameworkElement)textbox.Parent; - TextBlock textblock = (TextBlock)parent.FindName("ProfileNameTextblock"); - textblock.Visibility = Visibility.Visible; this.RenamingProfile = null; } - - - + private void KeyboardProfiles_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if(e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Remove) @@ -288,9 +287,21 @@ private async void KeyboardLayoutButton_Click(object sender, RoutedEventArgs e) //add the combobox to relative panel and place it into the correct position RelativePanel parent = (RelativePanel)button.Parent; parent.Children.Add(keyboardLayoutSelection); - RelativePanel.SetRightOf(keyboardLayoutSelection, parent.Children[parent.Children.IndexOf(button) - 1]); - RelativePanel.SetRightOf(parent.Children[parent.Children.IndexOf(button) + 1], keyboardLayoutSelection); - keyboardLayoutSelection.Width = button.Width+1; //account for 1px between buttons + var button_idx = parent.Children.IndexOf(button); + var width = button.Width + 1; + if (button_idx != 0) + { + RelativePanel.SetRightOf(keyboardLayoutSelection, parent.Children[parent.Children.IndexOf(button) - 1]); + } else + { + RelativePanel.SetRightOf(keyboardLayoutSelection, null); + width += 1; + } + if (button_idx != parent.Children.Count - 2) //added combobox, account for it here + { + RelativePanel.SetRightOf(parent.Children[parent.Children.IndexOf(button) + 1], keyboardLayoutSelection); + } + keyboardLayoutSelection.Width = width; //account for 1px between buttons keyboardLayoutSelection.SelectedIndex = this.KeyboardKeyLabels.IndexOf((string)button.Content); button.Visibility = Visibility.Collapsed; @@ -353,18 +364,32 @@ private void KeyboardStandardLayout_DropDownClosed(object sender, object e) if (this.CurrentlyEditingFnKey != null) { - RelativePanel parent = (RelativePanel)CurrentlyEditingFnKey.Parent; - RelativePanel.SetRightOf(CurrentlyEditingFnKey, parent.Children[parent.Children.IndexOf(CurrentlyEditingFnKey) - 1]); - RelativePanel.SetRightOf(parent.Children[parent.Children.IndexOf(CurrentlyEditingFnKey) + 1], CurrentlyEditingFnKey); this.CurrentlyEditingFnKey.Visibility = Visibility.Visible; + RelativePanel parent = (RelativePanel)CurrentlyEditingFnKey.Parent; + var button_idx = parent.Children.IndexOf(CurrentlyEditingFnKey); + if (button_idx != 0) + { + RelativePanel.SetRightOf(CurrentlyEditingFnKey, parent.Children[parent.Children.IndexOf(CurrentlyEditingFnKey) - 1]); + } + if (button_idx != parent.Children.Count - 2) + { + RelativePanel.SetRightOf(parent.Children[parent.Children.IndexOf(CurrentlyEditingFnKey) + 1], CurrentlyEditingFnKey); + } } if (this.CurrentlyEditingStandardKey != null) { - RelativePanel parent = (RelativePanel)CurrentlyEditingStandardKey.Parent; - RelativePanel.SetRightOf(CurrentlyEditingStandardKey, parent.Children[parent.Children.IndexOf(CurrentlyEditingStandardKey) - 1]); - RelativePanel.SetRightOf(parent.Children[parent.Children.IndexOf(CurrentlyEditingStandardKey) + 1], CurrentlyEditingStandardKey); this.CurrentlyEditingStandardKey.Visibility = Visibility.Visible; + RelativePanel parent = (RelativePanel)CurrentlyEditingStandardKey.Parent; + var button_idx = parent.Children.IndexOf(CurrentlyEditingStandardKey); + if (button_idx != 0) + { + RelativePanel.SetRightOf(CurrentlyEditingStandardKey, parent.Children[parent.Children.IndexOf(CurrentlyEditingStandardKey) - 1]); + } + if (button_idx != parent.Children.Count - 2) + { + RelativePanel.SetRightOf(parent.Children[parent.Children.IndexOf(CurrentlyEditingStandardKey) + 1], CurrentlyEditingStandardKey); + } } this.keyboardLayoutSelection.Visibility = Visibility.Collapsed; @@ -380,7 +405,14 @@ private void LayoutProfilesCombo_SelectionChanged(object sender, SelectionChange private void LayoutProfilesCombo_Loaded(object sender, RoutedEventArgs e) { - LayoutProfilesCombo.SelectedIndex = 0; + try + { + LayoutProfilesCombo.SelectedIndex = 0; + } catch + { + //some occassions the load doesn't load correctly + //dont set any in combobox + } } } } diff --git a/AnneProKeyboard/LightingPage.xaml.cs b/AnneProKeyboard/LightingPage.xaml.cs index 51949cd..b2db5f8 100644 --- a/AnneProKeyboard/LightingPage.xaml.cs +++ b/AnneProKeyboard/LightingPage.xaml.cs @@ -69,7 +69,7 @@ public async void SaveProfiles() } } - private async void LoadProfiles() + public async void LoadProfiles() { try { @@ -495,8 +495,9 @@ private void ProfileNameChangedEvent_TextChanged(object sender, TextChangedEvent private void ProfileAddButton_Click(object sender, RoutedEventArgs e) { this.CreateNewKeyboardProfile(); - this.SaveProfiles(); + this.ChangeSelectedProfile(_keyboardProfiles[_keyboardProfiles.Count - 1]); + this.LightingProfilesCombo.SelectedIndex = this.LightingProfilesCombo.Items.Count - 1; } private void ProfileEditButton_Click(object sender, RoutedEventArgs e) @@ -533,6 +534,7 @@ private void ProfileDeleteButton_Click(object sender, RoutedEventArgs e) // Change the chosen profile to the first element ChangeSelectedProfile(this._keyboardProfiles[0]); + LightingProfilesCombo.SelectedIndex = 0; this.SaveProfiles(); } @@ -542,12 +544,6 @@ private void ProfileNameTextbox_LostFocus(object sender, RoutedEventArgs e) this.SaveProfiles(); TextBox textbox = (TextBox)sender; - textbox.IsEnabled = false; - textbox.Visibility = Visibility.Collapsed; - - FrameworkElement parent = (FrameworkElement)textbox.Parent; - TextBlock textblock = (TextBlock)parent.FindName("ProfileNameTextblock"); - textblock.Visibility = Visibility.Visible; this.RenamingProfile = null; } @@ -575,7 +571,13 @@ private void LightingProfilesCombo_SelectionChanged(object sender, SelectionChan private void LightingProfilesCombo_Loaded(object sender, RoutedEventArgs e) { - LightingProfilesCombo.SelectedIndex = 0; + try + { + LightingProfilesCombo.SelectedIndex = 0; + } catch + { + + } } private void colourPicker_SelectedColorChanged(object sender, EventArgs e) diff --git a/AnneProKeyboard/MainPage.xaml b/AnneProKeyboard/MainPage.xaml index 0413723..3d3701d 100644 --- a/AnneProKeyboard/MainPage.xaml +++ b/AnneProKeyboard/MainPage.xaml @@ -82,6 +82,7 @@ +