feat(avalonia): implement HighlightTextConverter with theme-aware styling

- Add gold foreground color (#FFD700) for highlighted search matches
- Update HighlightTextConverter to use theme resource with fallback
- Fix TextBlockHelper to preserve Foreground property when copying Runs
- Fix highlight update bug: sync TitleHighlightData/SubTitleHighlightData/Score
  for reused ResultViewModel instances when query changes
- Update migration checklist to mark HighlightTextConverter as done
This commit is contained in:
Shengkai Lin 2026-02-01 13:25:11 +08:00
parent 830023513f
commit 9c99c7c65a
5 changed files with 31 additions and 2 deletions

View file

@ -281,7 +281,7 @@
| Converter | Status | Description |
|-----------|--------|-------------|
| HighlightTextConverter | :yellow_circle: Stub | Returns plain text, needs highlighting |
| HighlightTextConverter | :white_check_mark: Done | Bold gold highlighting for matched characters |
| QuerySuggestionBoxConverter | :yellow_circle: Stub | Not implemented |
| BoolToVisibilityConverter | :white_check_mark: Done | Boolean to visibility |
| TextConverter | :x: Missing | Text transformations |

View file

@ -57,7 +57,18 @@ public class HighlightTextConverter : IMultiValueConverter
{
var run = new Run(text);
if (isHighlight)
{
run.FontWeight = FontWeight.Bold;
// Try to get from resources, fallback to gold
if (Application.Current != null && Application.Current.TryGetResource("HighlightForegroundBrush", null, out var brush) && brush is IBrush b)
{
run.Foreground = b;
}
else
{
run.Foreground = new SolidColorBrush(Colors.Gold);
}
}
return run;
}
}

View file

@ -42,7 +42,8 @@ public static class TextBlockHelper
{
var newRun = new Run(run.Text)
{
FontWeight = run.FontWeight
FontWeight = run.FontWeight,
Foreground = run.Foreground
};
textBlock.Inlines?.Add(newRun);
}

View file

@ -11,6 +11,7 @@
<Color x:Key="ResultSubTitleColor">#999999</Color>
<Color x:Key="SeparatorColor">#333333</Color>
<Color x:Key="SelectedItemBackgroundColor">#30FFFFFF</Color>
<Color x:Key="HighlightForegroundColor">#FFD700</Color>
<!-- Brushes -->
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="{StaticResource WindowBackgroundColor}" />
@ -19,5 +20,6 @@
<SolidColorBrush x:Key="ResultSubTitleBrush" Color="{StaticResource ResultSubTitleColor}" />
<SolidColorBrush x:Key="SeparatorBrush" Color="{StaticResource SeparatorColor}" />
<SolidColorBrush x:Key="SelectedItemBackgroundBrush" Color="{StaticResource SelectedItemBackgroundColor}" />
<SolidColorBrush x:Key="HighlightForegroundBrush" Color="{StaticResource HighlightForegroundColor}" />
</ResourceDictionary>

View file

@ -62,6 +62,21 @@ public partial class ResultsViewModel : ObservableObject, IDisposable
r.Settings = _settings;
}
// Update highlight data and score for items that will be kept by EditDiff.
// This is necessary because EditDiff reuses existing ResultViewModel instances
// based on Title+SubTitle equality, but highlight indices are query-specific.
// For example, "Chrome" highlighted for "chr" [0,1,2] vs "chrome" [0,1,2,3,4,5].
var existingItems = _sourceList.Items.ToDictionary(r => (r.Title, r.SubTitle));
foreach (var newItem in resultsList)
{
if (existingItems.TryGetValue((newItem.Title, newItem.SubTitle), out var existing))
{
existing.TitleHighlightData = newItem.TitleHighlightData;
existing.SubTitleHighlightData = newItem.SubTitleHighlightData;
existing.Score = newItem.Score;
}
}
// EditDiff calculates minimal changes needed - items with same Title+SubTitle are kept
_sourceList.EditDiff(resultsList, ResultViewModelComparer.Instance);