using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Threading; using AvaloniaApplication1.DataBase; using DaireApplication.Views; using ReactiveUI; using System; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace DaireApplication; public partial class Recipe : UserControl { Button recipeButton = new Button(); private bool _isLongPress; private MainWindow? _mainWindow; private UserTable? _currentUser; private RecipeTable _recipeTable=new RecipeTable(); private Process? _keyboardProcess; public Recipe() { InitializeComponent(); } public Recipe(MainWindow mainWindow,UserTable currentUser) { _currentUser = currentUser; _mainWindow = mainWindow; InitializeComponent(); nameBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true); updateBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true); setDefaultSettings(); addDynamicButtons(); } private async void OnRecipeClick(object? sender, RoutedEventArgs e) { if (_isLongPress) { // Reset the flag for future interactions. _isLongPress = false; // Ignore this click since a long press was detected. return; } if (sender is Button button) { if (_currentUser.CanEdit) { _mainWindow.FindControl("ContentArea").Content = new RecipeEdit(_mainWindow, _currentUser, _recipeTable.ReadRecipesById(button.Name)); } else { _mainWindow.FindControl("ContentArea").Content = new Settings(_mainWindow, _currentUser, _recipeTable.ReadRecipesById(button.Name)); _mainWindow.restBoard = true; } } } private async void deleteActionClick(object? sender, RoutedEventArgs e) { if (sender is Button button) { deleteMsg.Text = $"You are about to delete {button.Tag}"; DeletePopupOverlay.IsVisible = true; } } private async void UpdateActionClick(object? sender, RoutedEventArgs e) { if (sender is Button button) { var text = recipeButton.Content as TextBlock; updateInput.Text = $"{text.Text}"; updatePopupOverlay.IsVisible = true; } } private void OnLongRecipeClick(object? sender, RoutedEventArgs e) { if (e is HoldingRoutedEventArgs args) { if (args.HoldingState == HoldingState.Started) { _isLongPress = true; if (sender is Button button) { var targetText= button.Content as TextBlock; deleteActionBtn.Tag = targetText.Text; managePopupOverlay.IsVisible = true; recipeButton = button; //recipeButton = button; //if (button.Content is TextBlock targetText) //{ // deleteMsg.Text = $"You are about to delete {targetText.Text}"; //} } args.Handled = true; } else if (args.HoldingState == HoldingState.Completed) { _isLongPress = false; } } } private void CloseKeyboard() { try { if (_keyboardProcess != null) { // Kill the keyboard process _keyboardProcess.Kill(); _keyboardProcess.Dispose(); _keyboardProcess = null; // Force kill any remaining keyboard processes var processKill = new Process { StartInfo = new ProcessStartInfo { FileName = "killall", Arguments = "-9 onboard matchbox-keyboard florence", // Common Linux on-screen keyboards UseShellExecute = false, CreateNoWindow = true } }; processKill.Start(); processKill.WaitForExit(1000); processKill.Dispose(); } } catch (Exception ex) { Console.WriteLine($"Error closing keyboard: {ex.Message}"); } } public void AttachHandlers(Button button) { if (button != null) { button.Holding += OnLongRecipeClick; button.PointerPressed += (sender, e) => { // Simulate a long press on any pointer (mouse or touch) var point = e.GetPosition(button); OnLongRecipeClick(sender, new HoldingRoutedEventArgs(HoldingState.Started, point, e.Pointer.Type)); }; button.PointerReleased += (sender, e) => { // End simulated long press var point = e.GetPosition(button); OnLongRecipeClick(sender, new HoldingRoutedEventArgs(HoldingState.Completed, point, e.Pointer.Type)); }; } } private async void OnAddRecipeClick(object? sender, RoutedEventArgs e) { if (sender is Button button) { PopupOverlay.IsVisible = true; } } private async void OnPopupOverlayPointerPressed(object? sender, RoutedEventArgs e) { PopupOverlay.IsVisible = false; } private async void OnDeletePopupOverlayPointerPressed(object? sender, RoutedEventArgs e) { DeletePopupOverlay.IsVisible = false; managePopupOverlay.IsVisible = false; updatePopupOverlay.IsVisible = false; } private async void YesBtnClick(object? sender, RoutedEventArgs e) { var result = _recipeTable.DeleteRecipe(recipeButton.Name); if (result) { addDynamicButtons(); DeletePopupOverlay.IsVisible= false; managePopupOverlay.IsVisible = false; } else { } } private async void SaveUpdateClick(object? sender, RoutedEventArgs e) { if (!_recipeTable.DoesNameExist(updateInput.Text)) { var recipe = _recipeTable.ReadRecipesById(recipeButton.Name); recipe.Name = updateInput.Text; var result = _recipeTable.UpdateRecipe(recipe); if (result) { addDynamicButtons(); managePopupOverlay.IsVisible = false; updatePopupOverlay.IsVisible = false; CloseKeyboard(); } else { } } else { CloseKeyboard(); await MainWindow.MessageBox.Show(_mainWindow, "this name is already in use", "Error"); _mainWindow.Topmost = false; _mainWindow.Focus(); _mainWindow.Activate(); } } private void showPopUp(object? sender, RoutedEventArgs e) { if (sender is Button button) { recipeButton = button; button.Foreground = Brush.Parse("#A4275D"); PopupOverlay.IsVisible = true; // Append the button's content to the input box //InputTextBox.Text += button.Content?.ToString(); } } private async void saveRecipeClick(object? sender, RoutedEventArgs e) { if (sender is Button button) { if (!string.IsNullOrEmpty(NameInput.Text)) { if (!_recipeTable.DoesNameExist(NameInput.Text)) { RecipeTable data = new RecipeTable(); data.Name = NameInput.Text; data.Mixer = false; data.Fountain = false; data.MoldHeater = false; data.Vibration = false; data.VibHeater = false; data.Pedal = false; var result = _recipeTable.AddRecipe(data); if (result) { addDynamicButtons(); CloseKeyboard(); NameInput.Text = ""; PopupOverlay.IsVisible = false; } else { } } else { CloseKeyboard(); await MainWindow.MessageBox.Show(_mainWindow, "this name is already in use", "Error"); _mainWindow.Topmost = false; _mainWindow.Activate(); } } } } private (string? fileName, string args) GetKeyboardCommand() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return ("osk.exe", ""); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return ("onboard", ""); // or "florence", "matchbox-keyboard" return (null, ""); } private async void OnTextBoxFocused(object? sender, PointerPressedEventArgs e) { if (_keyboardProcess is { HasExited: false }) return; var (fileName, args) = GetKeyboardCommand(); if (fileName is null) return; _keyboardProcess = new Process { StartInfo = new ProcessStartInfo { FileName = fileName, Arguments = args, UseShellExecute = true }, EnableRaisingEvents = true }; try { _keyboardProcess.Start(); Dispatcher.UIThread.Post(() => { if (sender is Border border) { var textbox= border.Child as TextBox; textbox.SelectionStart = 0; textbox.SelectionEnd = textbox.Text?.Length ?? 0; } }); } catch { // fail silently if keyboard not found } } private void OnPopupOverlayPointerPressed(object sender, PointerPressedEventArgs e) { // Close the popup when clicking outside of it recipeButton.Foreground = Avalonia.Media.Brushes.Black; PopupOverlay.IsVisible = false; } private void setDefaultSettings() { //set recipe title if (_currentUser.CanEdit) { RecipeTitle.Content = "RECIPE EDIT/ADD PANEL"; } else { RecipeTitle.Content = "RECIPE SELECTION"; } //Set Track Up _mainWindow.HomeTrack.IsVisible = true; _mainWindow.RecipeSelTrack.IsVisible = false; _mainWindow.RecipePanelTrack.IsVisible = false; if (_currentUser.CanEdit) { _mainWindow.RecipePanelTrack.IsVisible = true; _mainWindow.RecipePanelPolygon.Stroke = Brush.Parse("#A4275D"); } else { _mainWindow.RecipeSelTrack.IsVisible = true; _mainWindow.RecipeSelPolygon.Stroke = Brush.Parse("#A4275D"); } //_mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black; _mainWindow.RecipeEditTrack.IsVisible = false; _mainWindow.RunInterfaceTrack.IsVisible = false; _mainWindow.SettingTrack.IsVisible = false; _mainWindow.TitleBtn.IsVisible = false; _mainWindow.DiagnosticsTrack.IsVisible = false; _mainWindow.SoftwareTrack.IsVisible = false; //Set Footer if (_currentUser.CanEdit) { _mainWindow.footerMsg.Text = "Long press to delete recipe"; _mainWindow.footerMsg.IsVisible = true; _mainWindow.chefBtns.IsVisible = true; } else { _mainWindow.footerMsg.Text = "Select a recipe to start"; _mainWindow.footerMsg.IsVisible = true; } _mainWindow.ManualControlTrack.IsVisible = false; _mainWindow.footerMsg.MaxWidth = 1000; _mainWindow.footer.Background = Avalonia.Media.Brushes.WhiteSmoke; _mainWindow.footerMsg.Foreground = Brush.Parse("#A4275D"); _mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy"); _mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt"); _mainWindow.footerDateContainer.IsVisible = true; _mainWindow.footerStartBtn.IsVisible = false; _mainWindow.adminBtns.IsVisible = false; } private void addDynamicButtons() { var recipes= _recipeTable.ReadRecipes(); var grid = this.FindControl("DynamicGrid"); grid.Children.Clear(); int lastRow = 0; int lastCol = 0; int colIndexForExtraData = 0; int recipeIndex = 0; try { if (recipes.Count<3) { // Add dynamic rows for (int i = 0; i < (int)Math.Ceiling((double)recipes.Count / 3); i++) // Example: 20 rows { lastRow = i; grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // Add content for each column for (int col = 0; col < recipes.Count; col++) { lastCol = col; var text = new TextBlock { Padding = new Thickness(10), Text = recipes[recipeIndex + col].Name, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, FontSize = 31, FontWeight=FontWeight.Normal, Foreground = Avalonia.Media.Brushes.Black }; var button = new Button { Width = 210, Height = 160, Margin = new Thickness(3), Content = text, Name = recipes[recipeIndex + col].Id.ToString(), CornerRadius = new CornerRadius(10), Background = Avalonia.Media.Brushes.White, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, }; button.Click += OnRecipeClick; if (_currentUser.CanEdit) { //button.Holding += OnLongRecipeClick; AttachHandlers(button); //button.DoubleTapped += OnDoubleRecipeClick; } grid.Children.Add(button); Grid.SetRow(button, i); Grid.SetColumn(button, col); } recipeIndex += 3; } if (_currentUser.CanEdit) { var Plus = new TextBlock { Padding = new Thickness(10), Text = "+", VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, FontSize = 100, Foreground = Brush.Parse("#A4275D") }; var AddButtun = new Button { Width = 210, Height = 160, Margin = new Thickness(3), Content = Plus, CornerRadius = new CornerRadius(10), Background = Avalonia.Media.Brushes.White, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center, Padding = new Thickness(0, 0, 0, 15), }; AddButtun.Click += OnAddRecipeClick; if (lastCol < 2) { grid.Children.Add(AddButtun); Grid.SetRow(AddButtun, lastRow); Grid.SetColumn(AddButtun, lastCol + 1); } else { grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); grid.Children.Add(AddButtun); Grid.SetRow(AddButtun, lastRow + 1); Grid.SetColumn(AddButtun, 0); } } } else { // Add dynamic rows for (int i = 0; i < (int)Math.Floor((double)recipes.Count / 3); i++) // Example: 20 rows { lastRow = i; grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // Add content for each column for (int col = 0; col < 3; col++) { lastCol = col; var text = new TextBlock { Padding = new Thickness(10), Text = recipes[recipeIndex + col].Name, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, FontSize = 31, FontWeight = FontWeight.Normal, Foreground = Avalonia.Media.Brushes.Black }; var button = new Button { Width = 210, Height = 160, Margin = new Thickness(3), Content = text, Name = recipes[recipeIndex + col].Id.ToString(), CornerRadius = new CornerRadius(10), Background = Avalonia.Media.Brushes.White, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, }; button.Click += OnRecipeClick; if (_currentUser.CanEdit) { //button.Holding += OnLongRecipeClick; AttachHandlers(button); //button.DoubleTapped += OnDoubleRecipeClick; } grid.Children.Add(button); Grid.SetRow(button, i); Grid.SetColumn(button, col); } recipeIndex += 3; } for (int i = 0; i < recipes.Count -recipeIndex; i++) { var text = new TextBlock { Padding = new Thickness(10), Text = recipes[recipeIndex + i].Name, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, FontSize = 31, FontWeight = FontWeight.Normal, Foreground = Avalonia.Media.Brushes.Black }; var button = new Button { Width = 210, Height = 160, Margin = new Thickness(3), Content = text, Name = recipes[recipeIndex + i].Id.ToString(), CornerRadius = new CornerRadius(10), Background = Avalonia.Media.Brushes.White, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, }; button.Click += OnRecipeClick; if (_currentUser.CanEdit) { //button.Holding += OnLongRecipeClick; AttachHandlers(button); //button.DoubleTapped += OnDoubleRecipeClick; } if (lastCol < 2) { lastCol += 1; grid.Children.Add(button); Grid.SetRow(button,lastRow); Grid.SetColumn(button, lastCol); } else { grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); grid.Children.Add(button); Grid.SetRow(button, lastRow + 1); Grid.SetColumn(button, colIndexForExtraData); colIndexForExtraData += 1; } } if (_currentUser.CanEdit) { var Plus = new TextBlock { Padding = new Thickness(10), Text = "+", VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, FontSize = 100, Foreground = Brush.Parse("#A4275D"), }; var AddButtun = new Button { Width = 210, Height = 160, Margin = new Thickness(3), Content = Plus, CornerRadius = new CornerRadius(10), Background = Avalonia.Media.Brushes.White, VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, Padding = new Thickness(0,0,0,15), }; AddButtun.Click += OnAddRecipeClick; if (lastCol < 2) { grid.Children.Add(AddButtun); Grid.SetRow(AddButtun, lastRow); Grid.SetColumn(AddButtun, lastCol + 1); } else { grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); grid.Children.Add(AddButtun); Grid.SetRow(AddButtun, lastRow + 1); Grid.SetColumn(AddButtun, colIndexForExtraData); } } } } catch (Exception) { } } }