using System; using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.VisualTree; using AdvancedCalculator.ViewModels; using AdvancedCalculator.Models; using Avalonia.Controls.Presenters; namespace AdvancedCalculator.Views; public partial class MainView : UserControl { public MainView() { InitializeComponent(); this.AttachedToVisualTree += OnAttachedToVisualTree; this.DetachedFromVisualTree += OnDetachedFromVisualTree; } private MainViewModel? _vm; private ListBox? _historyList; private Border? _functionsPanelRoot; private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e) { _vm = DataContext as MainViewModel; if (_vm is not null) { _vm.CopyRequested += OnCopyRequested; } _historyList = this.FindControl("HistoryList"); if (_historyList is not null) { // Handle taps anywhere in a history row to copy output text _historyList.AddHandler(InputElement.TappedEvent, OnHistoryTapped, RoutingStrategies.Tunnel | RoutingStrategies.Bubble); } // Functions flyout wiring is done via Opened/Closed events } private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e) { if (_vm is not null) { _vm.CopyRequested -= OnCopyRequested; } if (_historyList is not null) { _historyList.RemoveHandler(InputElement.TappedEvent, OnHistoryTapped); _historyList = null; } // Detach functions panel tap handler if still attached if (_functionsPanelRoot is not null) { _functionsPanelRoot.RemoveHandler(InputElement.TappedEvent, OnFunctionsItemTapped); _functionsPanelRoot = null; } _vm = null; } private async void OnCopyRequested(object? sender, string text) { var top = TopLevel.GetTopLevel(this); if (top?.Clipboard is null) return; try { await top.Clipboard.SetTextAsync(text); } catch { // Ignore clipboard errors; e.g., browser permission or missing gesture context } } private void OnHistoryTapped(object? sender, TappedEventArgs e) { // Find the ListBoxItem the tap originated from var source = e.Source as ContentPresenter; var container = source?.FindAncestorOfType(); if (container?.DataContext is not HistoryItem item) return; var vm = DataContext as MainViewModel; if (vm?.CopyHistoryOutputCommand.CanExecute(item) == true) { vm.CopyHistoryOutputCommand.Execute(item); // Mark handled to avoid unintended selection change on tap e.Handled = true; } } private void OnFunctionsItemTapped(object? sender, TappedEventArgs e) { if (sender is not IControl control) return; if (control.DataContext is not FunctionDefinitionItem item) { // If attached to panel root, walk up from the source to a ListBoxItem and use its DataContext if (sender is IVisual root && e.Source is IVisual src) { var lbi = src.FindAncestorOfType(); if (lbi?.DataContext is not FunctionDefinitionItem rowItem) return; item = rowItem; } else { return; } } var vm = DataContext as MainViewModel; if (vm?.InsertFunctionCommand.CanExecute(item) == true) { vm.InsertFunctionCommand.Execute(item); e.Handled = true; } } private void OnFunctionsFlyoutOpened(object? sender, EventArgs e) { // Flyout content is rendered in a popup; find by name at TopLevel var top = TopLevel.GetTopLevel(this); if (top is null) return; var panel = top.FindDescendantOfType(b => b.Name == "FunctionsPanelRoot"); if (panel is null) return; // Attach a single tap handler to the flyout content root panel.AddHandler(InputElement.TappedEvent, OnFunctionsItemTapped, RoutingStrategies.Tunnel | RoutingStrategies.Bubble); _functionsPanelRoot = panel; } private void OnFunctionsFlyoutClosed(object? sender, EventArgs e) { if (_functionsPanelRoot is not null) { _functionsPanelRoot.RemoveHandler(InputElement.TappedEvent, OnFunctionsItemTapped); _functionsPanelRoot = null; } } }