Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check for Duplicates In Mining Mode #109

Merged
merged 11 commits into from
Dec 12, 2024
2 changes: 2 additions & 0 deletions JL.Core/Config/CoreConfigManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public sealed class CoreConfigManager
public bool AnkiIntegration { get; set; } // = false;
public bool ForceSyncAnki { get; private set; } // = false;
public bool AllowDuplicateCards { get; private set; } // = false;
public bool CheckForDuplicateCards { get; private set; } // = false;
public double LookupRate { get; private set; } // = 0;
public bool CaptureTextFromClipboard { get; set; } = true;
public bool CaptureTextFromWebSocket { get; set; } // = false;
Expand Down Expand Up @@ -95,6 +96,7 @@ public void ApplyPreferences(SqliteConnection connection)
AnkiIntegration = ConfigDBManager.GetValueFromConfig(connection, AnkiIntegration, nameof(AnkiIntegration), bool.TryParse);
ForceSyncAnki = ConfigDBManager.GetValueFromConfig(connection, ForceSyncAnki, nameof(ForceSyncAnki), bool.TryParse);
AllowDuplicateCards = ConfigDBManager.GetValueFromConfig(connection, AllowDuplicateCards, nameof(AllowDuplicateCards), bool.TryParse);
CheckForDuplicateCards = ConfigDBManager.GetValueFromConfig(connection, CheckForDuplicateCards, nameof(CheckForDuplicateCards), bool.TryParse);
LookupRate = ConfigDBManager.GetNumberWithDecimalPointFromConfig(connection, LookupRate, nameof(LookupRate), double.TryParse);
TextBoxTrimWhiteSpaceCharacters = ConfigDBManager.GetValueFromConfig(connection, TextBoxTrimWhiteSpaceCharacters, nameof(TextBoxTrimWhiteSpaceCharacters), bool.TryParse);
TextBoxRemoveNewlines = ConfigDBManager.GetValueFromConfig(connection, TextBoxRemoveNewlines, nameof(TextBoxRemoveNewlines), bool.TryParse);
Expand Down
7 changes: 2 additions & 5 deletions JL.Core/Mining/Anki/AnkiConnect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,12 @@ internal static class AnkiConnect
return Send(req);
}

public static ValueTask<Response?> GetCanAddNotesResponse(Note note)
public static ValueTask<Response?> GetCanAddNotesResponse(List<Note> notes)
{
Request req = new("canAddNotes", 6, new Dictionary<string, object>(1, StringComparer.Ordinal)
{
{
"notes", new[]
{
note
}
"notes", notes
}
});

Expand Down
12 changes: 11 additions & 1 deletion JL.Core/Mining/Anki/AnkiUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,21 @@ public static class AnkiUtils

internal static async Task<bool?> CanAddNote(Note note)
{
Response? response = await AnkiConnect.GetCanAddNotesResponse(note).ConfigureAwait(false);
Response? response = await AnkiConnect.GetCanAddNotesResponse([note]).ConfigureAwait(false);
string? resultString = response?.Result?.ToString() ?? null;

return resultString is not null
? JsonSerializer.Deserialize<List<bool>>(resultString)![0]
: null;
}

internal static async ValueTask<List<bool>?> CanAddNotes(List<Note> notes)
{
Response? response = await AnkiConnect.GetCanAddNotesResponse(notes).ConfigureAwait(false);
string? resultString = response?.Result?.ToString() ?? null;

return resultString is not null
? JsonSerializer.Deserialize<List<bool>>(resultString)!
bpwhelan marked this conversation as resolved.
Show resolved Hide resolved
: null;
}
}
316 changes: 316 additions & 0 deletions JL.Core/Mining/MiningUtils.cs

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions JL.Windows/ConfigManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,7 @@ public void LoadPreferenceWindow(PreferencesWindow preferenceWindow)
preferenceWindow.WebSocketUriTextBox.Text = coreConfigManager.WebSocketUri.OriginalString;
preferenceWindow.ForceSyncAnkiCheckBox.IsChecked = coreConfigManager.ForceSyncAnki;
preferenceWindow.AllowDuplicateCardsCheckBox.IsChecked = coreConfigManager.AllowDuplicateCards;
preferenceWindow.CheckForDuplicateCardsCheckBox.IsChecked = coreConfigManager.CheckForDuplicateCards;
preferenceWindow.LookupRateNumericUpDown.Value = coreConfigManager.LookupRate;
preferenceWindow.KanjiModeCheckBox.IsChecked = coreConfigManager.KanjiMode;
preferenceWindow.AutoAdjustFontSizesOnResolutionChangeCheckBox.IsChecked = AutoAdjustFontSizesOnResolutionChange;
Expand Down Expand Up @@ -1205,6 +1206,9 @@ public async Task SavePreferences(PreferencesWindow preferenceWindow)
ConfigDBManager.UpdateSetting(connection, nameof(CoreConfigManager.AllowDuplicateCards),
preferenceWindow.AllowDuplicateCardsCheckBox.IsChecked.ToString()!);

ConfigDBManager.UpdateSetting(connection, nameof(CoreConfigManager.CheckForDuplicateCards),
preferenceWindow.CheckForDuplicateCardsCheckBox.IsChecked.ToString()!);

ConfigDBManager.UpdateSetting(connection, nameof(CoreConfigManager.LookupRate),
preferenceWindow.LookupRateNumericUpDown.Value.ToString(CultureInfo.InvariantCulture));

Expand Down
59 changes: 57 additions & 2 deletions JL.Windows/GUI/PopupWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,8 @@ private void UpdatePosition(double x, double y)

public void DisplayResults(bool generateAllResults)
{
ConfigManager configManager = ConfigManager.Instance;
CoreConfigManager coreConfigManager = CoreConfigManager.Instance;
_dictsWithResults.Clear();

PopupListView.Items.Filter = PopupWindowUtils.NoAllDictFilter;
Expand All @@ -497,6 +499,15 @@ public void DisplayResults(bool generateAllResults)
? LastLookupResults.Length
: Math.Min(LastLookupResults.Length, ConfigManager.Instance.MaxNumResultsNotInMiningMode);

bool checkForDuplicateCards = MiningMode
&& coreConfigManager.CheckForDuplicateCards
&& !configManager.MineToFileInsteadOfAnki
&& coreConfigManager.AnkiIntegration;

TextBlock[]? duplicateIcons = checkForDuplicateCards
? new TextBlock[LastLookupResults.Count]
bpwhelan marked this conversation as resolved.
Show resolved Hide resolved
: null;

StackPanel[] popupItemSource = new StackPanel[resultCount];

for (int i = 0; i < resultCount; i++)
Expand All @@ -508,10 +519,14 @@ public void DisplayResults(bool generateAllResults)
_dictsWithResults.Add(lookupResult.Dict);
}

popupItemSource[i] = PrepareResultStackPanel(lookupResult, i, resultCount, pitchDict, pitchDictIsActive, showPOrthographyInfo, showROrthographyInfo, showAOrthographyInfo, pOrthographyInfoFontSize);
popupItemSource[i] = PrepareResultStackPanel(lookupResult, i, resultCount, pitchDict, pitchDictIsActive, showPOrthographyInfo, showROrthographyInfo, showAOrthographyInfo, pOrthographyInfoFontSize, duplicateIcons);
}

PopupListView.ItemsSource = popupItemSource;
if (duplicateIcons is not null)
{
_ = CheckResultForDuplicates(duplicateIcons);
}
GenerateDictTypeButtons();
UpdateLayout();
}
Expand All @@ -536,7 +551,7 @@ private void AddEventHandlersToDefinitionsTextBox(TextBox textBox)
textBox.PreviewMouseLeftButtonDown += DefinitionsTextBox_PreviewMouseLeftButtonDown;
}

private StackPanel PrepareResultStackPanel(LookupResult result, int index, int resultCount, Dict? pitchDict, bool pitchDictIsActive, bool showPOrthographyInfo, bool showROrthographyInfo, bool showAOrthographyInfo, double pOrthographyInfoFontSize)
private StackPanel PrepareResultStackPanel(LookupResult result, int index, int resultCount, Dict? pitchDict, bool pitchDictIsActive, bool showPOrthographyInfo, bool showROrthographyInfo, bool showAOrthographyInfo, double pOrthographyInfoFontSize, TextBlock[]? duplicateIcons)
{
// top
WrapPanel top = new()
Expand All @@ -545,6 +560,7 @@ private StackPanel PrepareResultStackPanel(LookupResult result, int index, int r
};

ConfigManager configManager = ConfigManager.Instance;
CoreConfigManager coreConfigManager = CoreConfigManager.Instance;
bpwhelan marked this conversation as resolved.
Show resolved Hide resolved

TextBlock primarySpellingTextBlock = PopupWindowUtils.CreateTextBlock(nameof(result.PrimarySpelling),
result.PrimarySpelling,
Expand Down Expand Up @@ -797,6 +813,29 @@ private StackPanel PrepareResultStackPanel(LookupResult result, int index, int r
_ = top.Children.Add(dictTypeTextBlock);
}

// Keep this at the bottom
if (duplicateIcons is not null)
{
TextBlock duplicate = new()
{
Text = "⚠",
Name = nameof(duplicate),
FontSize = configManager.DictTypeFontSize,
Foreground = configManager.DefinitionsColor,
VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(7, 0, 0, 0),
HorizontalAlignment = HorizontalAlignment.Left,
Background = Brushes.Transparent,
Cursor = Cursors.Arrow,
Padding = new Thickness(0),
ToolTip = $"{result.PrimarySpelling} is already in the Anki deck.",
Visibility = Visibility.Hidden
};

_ = top.Children.Add(duplicate);
duplicateIcons[index] = duplicate;
}

// bottom
StackPanel bottom = new();

Expand Down Expand Up @@ -1071,6 +1110,22 @@ private StackPanel PrepareResultStackPanel(LookupResult result, int index, int r
return stackPanel;
}

private async Task CheckResultForDuplicates(TextBlock[] duplicateIcons)
{
bool[]? duplicateCard = await MiningUtils.CheckDuplicates(LastLookupResults, _currentText, _currentCharPosition).ConfigureAwait(false);

if (duplicateCard is not null)
{
for (int i = 0; i < duplicateCard.Length; i++)
{
if (duplicateCard[i])
{
await MainWindow.Instance.Dispatcher.InvokeAsync(() => { duplicateIcons[i].Visibility = Visibility.Visible; });
}
}
}
}

private int GetFirstVisibleListViewItemIndex()
{
StackPanel? firstVisibleStackPanel = PopupListView.Items.Cast<StackPanel>()
Expand Down
7 changes: 7 additions & 0 deletions JL.Windows/GUI/PreferencesWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,13 @@
<CheckBox x:Name="AllowDuplicateCardsCheckBox" HorizontalAlignment="Right" />
</DockPanel>

<DockPanel Margin="0,10,0,0">
<TextBlock HorizontalAlignment="Left" Text="Check for duplicate cards"
Style="{StaticResource TextBlockDefault}" VerticalAlignment="Center" TextWrapping="Wrap"
ToolTip="Checks Anki for Duplicate Expressions when entering Mining Mode" Cursor="Help"/>
<CheckBox x:Name="CheckForDuplicateCardsCheckBox" HorizontalAlignment="Right" />
</DockPanel>

<TabControl Margin="0,10,0,0">
<TabControl.Resources>
<Style TargetType="{x:Type TabPanel}">
Expand Down