using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; namespace AxCopilot.Views; public partial class ChatWindow { private async Task ShowInlineUserAskAsync(string question, List options, string defaultValue) { var tcs = new TaskCompletionSource(); await Dispatcher.InvokeAsync(() => { AddUserAskCard(question, options, defaultValue, tcs); }); var completed = await Task.WhenAny(tcs.Task, Task.Delay(TimeSpan.FromMinutes(5))); if (completed != tcs.Task) { await Dispatcher.InvokeAsync(RemoveUserAskCard); return null; } return await tcs.Task; } private void RemoveUserAskCard() { if (_userAskCard == null) return; MessagePanel.Children.Remove(_userAskCard); _userAskCard = null; } private void AddUserAskCard(string question, List options, string defaultValue, TaskCompletionSource tcs) { RemoveUserAskCard(); var accentBrush = TryFindResource("AccentColor") as Brush ?? Brushes.CornflowerBlue; var accentColor = ((SolidColorBrush)accentBrush).Color; var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White; var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray; var borderBrush = TryFindResource("BorderColor") as Brush ?? new SolidColorBrush(Color.FromArgb(0x24, accentColor.R, accentColor.G, accentColor.B)); var itemBg = TryFindResource("ItemBackground") as Brush ?? new SolidColorBrush(Color.FromArgb(0x10, accentColor.R, accentColor.G, accentColor.B)); var hoverBg = TryFindResource("ItemHoverBackground") as Brush ?? new SolidColorBrush(Color.FromArgb(0x16, 0xFF, 0xFF, 0xFF)); var okBrush = BrushFromHex("#10B981"); var dangerBrush = BrushFromHex("#EF4444"); var container = new Border { Margin = new Thickness(40, 4, 90, 8), HorizontalAlignment = HorizontalAlignment.Left, MaxWidth = Math.Max(420, GetMessageMaxWidth() - 36), Background = itemBg, BorderBrush = borderBrush, BorderThickness = new Thickness(1), CornerRadius = new CornerRadius(14), Padding = new Thickness(14, 12, 14, 12), }; var outer = new StackPanel(); outer.Children.Add(new TextBlock { Text = "의견 요청", FontSize = 12.5, FontWeight = FontWeights.SemiBold, Foreground = primaryText, }); outer.Children.Add(new TextBlock { Text = question, Margin = new Thickness(0, 4, 0, 10), FontSize = 12.5, Foreground = primaryText, TextWrapping = TextWrapping.Wrap, LineHeight = 20, }); Border? selectedOption = null; string selectedResponse = defaultValue; if (options.Count > 0) { var optionPanel = new WrapPanel { Margin = new Thickness(0, 0, 0, 10), ItemWidth = double.NaN, }; foreach (var option in options.Where(static option => !string.IsNullOrWhiteSpace(option))) { var optionLabel = option.Trim(); var optBorder = new Border { Background = Brushes.Transparent, BorderBrush = borderBrush, BorderThickness = new Thickness(1), CornerRadius = new CornerRadius(999), Padding = new Thickness(10, 6, 10, 6), Margin = new Thickness(0, 0, 8, 8), Cursor = Cursors.Hand, Child = new TextBlock { Text = optionLabel, FontSize = 12, Foreground = primaryText, }, }; optBorder.MouseEnter += (s, _) => { if (!ReferenceEquals(selectedOption, s)) ((Border)s).Background = hoverBg; }; optBorder.MouseLeave += (s, _) => { if (!ReferenceEquals(selectedOption, s)) ((Border)s).Background = Brushes.Transparent; }; optBorder.MouseLeftButtonUp += (_, _) => { if (selectedOption != null) { selectedOption.Background = Brushes.Transparent; selectedOption.BorderBrush = borderBrush; } selectedOption = optBorder; selectedOption.Background = new SolidColorBrush(Color.FromArgb(0x18, accentColor.R, accentColor.G, accentColor.B)); selectedOption.BorderBrush = accentBrush; selectedResponse = optionLabel; }; optionPanel.Children.Add(optBorder); } outer.Children.Add(optionPanel); } outer.Children.Add(new TextBlock { Text = "직접 입력", FontSize = 11.5, Foreground = secondaryText, Margin = new Thickness(0, 0, 0, 6), }); var inputBox = new TextBox { Text = defaultValue, AcceptsReturn = true, TextWrapping = TextWrapping.Wrap, MinHeight = 42, MaxHeight = 100, FontSize = 12.5, Padding = new Thickness(10, 8, 10, 8), Background = Brushes.Transparent, Foreground = primaryText, CaretBrush = primaryText, BorderBrush = borderBrush, BorderThickness = new Thickness(1), }; inputBox.TextChanged += (_, _) => { if (!string.IsNullOrWhiteSpace(inputBox.Text)) { selectedResponse = inputBox.Text.Trim(); if (selectedOption != null) { selectedOption.Background = Brushes.Transparent; selectedOption.BorderBrush = borderBrush; selectedOption = null; } } }; outer.Children.Add(inputBox); var buttonRow = new StackPanel { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Right, Margin = new Thickness(0, 12, 0, 0), }; Border BuildActionButton(string label, Brush bg, Brush fg) { return new Border { Background = bg, BorderBrush = bg, BorderThickness = new Thickness(1), CornerRadius = new CornerRadius(999), Padding = new Thickness(12, 7, 12, 7), Margin = new Thickness(8, 0, 0, 0), Cursor = Cursors.Hand, Child = new TextBlock { Text = label, FontSize = 12, FontWeight = FontWeights.SemiBold, Foreground = fg, }, }; } var cancelBtn = BuildActionButton("취소", Brushes.Transparent, dangerBrush); cancelBtn.BorderBrush = new SolidColorBrush(Color.FromArgb(0x40, 0xEF, 0x44, 0x44)); cancelBtn.MouseLeftButtonUp += (_, _) => { RemoveUserAskCard(); tcs.TrySetResult(null); }; buttonRow.Children.Add(cancelBtn); var submitBtn = BuildActionButton("전달", okBrush, Brushes.White); submitBtn.MouseLeftButtonUp += (_, _) => { var finalResponse = !string.IsNullOrWhiteSpace(inputBox.Text) ? inputBox.Text.Trim() : selectedResponse?.Trim(); if (string.IsNullOrWhiteSpace(finalResponse)) finalResponse = defaultValue?.Trim(); if (string.IsNullOrWhiteSpace(finalResponse)) return; RemoveUserAskCard(); tcs.TrySetResult(finalResponse); }; buttonRow.Children.Add(submitBtn); outer.Children.Add(buttonRow); container.Child = outer; _userAskCard = container; container.Opacity = 0; container.BeginAnimation(UIElement.OpacityProperty, new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(180))); MessagePanel.Children.Add(container); ForceScrollToEnd(); inputBox.Focus(); inputBox.CaretIndex = inputBox.Text.Length; } }