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

v1.3 #6

Merged
merged 49 commits into from
Nov 4, 2021
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
91c72c6
Remove tag checking
MakeshVineeth Jul 13, 2021
a8d5799
Add logo
MakeshVineeth Jul 13, 2021
951a0fc
Fix SearchTagOnly can't be disabled.
MakeshVineeth Jul 15, 2021
9f23718
Improve code and add copy contents operation
MakeshVineeth Aug 24, 2021
1fcb9a7
Use Custom Control - 1
MakeshVineeth Sep 6, 2021
ae9fcc4
Use OnFocusLoad
MakeshVineeth Sep 7, 2021
a5e7a39
Add ScrollViewer
MakeshVineeth Sep 7, 2021
9e50293
Hide scrollbar
MakeshVineeth Sep 8, 2021
de41d7c
Rounded Corners Image
MakeshVineeth Sep 8, 2021
1472183
Revert "Rounded Corners Image"
MakeshVineeth Sep 8, 2021
5cd9d3c
Revert "Revert "Rounded Corners Image""
MakeshVineeth Sep 8, 2021
d9881d7
Fix Rounded Corners Image
MakeshVineeth Sep 8, 2021
daadbbe
Fix copy contents operation
MakeshVineeth Sep 8, 2021
34012cc
Use CustomPreview
MakeshVineeth Sep 12, 2021
4311024
Use double line breaks for better reading
MakeshVineeth Sep 12, 2021
4a3265f
Custom Preview - 1
MakeshVineeth Sep 12, 2021
fad5086
Custom Preview - 2
MakeshVineeth Sep 12, 2021
5d47dc2
Improve spacing
MakeshVineeth Sep 12, 2021
52ca12a
Custom Preview - 3
MakeshVineeth Sep 12, 2021
0567963
Custom Preview - 4
MakeshVineeth Sep 12, 2021
7644b69
Improve buttons bg
MakeshVineeth Sep 12, 2021
eefeb8f
EXPERIMENTAL Global Preview
MakeshVineeth Sep 12, 2021
9905625
Implement Singleton
MakeshVineeth Sep 17, 2021
97bc11a
Improve checking
MakeshVineeth Sep 17, 2021
6b40596
Add bitmap checking
MakeshVineeth Sep 17, 2021
44bf59a
Use DockPanel
MakeshVineeth Sep 19, 2021
f95989d
Improvements
MakeshVineeth Sep 19, 2021
435ff7d
Improve error checking
MakeshVineeth Sep 19, 2021
5adb813
Improving Valid URLs checking
MakeshVineeth Sep 19, 2021
698feb3
Add settings
MakeshVineeth Sep 20, 2021
dfd8dd4
Add more settings
MakeshVineeth Sep 20, 2021
6e34588
Give default property values
MakeshVineeth Oct 2, 2021
f2a8557
Upgrade to .NET 6.0
MakeshVineeth Oct 2, 2021
8e25fb5
ImageSize option without restart
MakeshVineeth Oct 10, 2021
70f3d6b
Verify resultName is null or empty.
MakeshVineeth Oct 10, 2021
e7e2d9a
Use static implementation instead of lazy
MakeshVineeth Oct 26, 2021
2509796
Upgrade nugets
MakeshVineeth Oct 26, 2021
d07875f
Rename CustomPreview to WikiResultPreviewControlBuilder
MakeshVineeth Oct 26, 2021
42d7cbd
Code Improvements
MakeshVineeth Oct 26, 2021
f731566
Code Improvements
MakeshVineeth Oct 26, 2021
0cdd2b6
Code Improvements
MakeshVineeth Oct 26, 2021
89fff3c
Null safety
MakeshVineeth Oct 26, 2021
d80cb5f
Improve overall readability.
MakeshVineeth Oct 26, 2021
c27c695
Improve preview eligible checking.
MakeshVineeth Oct 26, 2021
bc0ab50
Enable loading images for chromium Wiki URLs.
MakeshVineeth Oct 31, 2021
5603964
Improve Readablity
MakeshVineeth Oct 31, 2021
3e8f1aa
Improve image loading
MakeshVineeth Oct 31, 2021
a02c617
Improve image loading - 1
MakeshVineeth Oct 31, 2021
8127bf8
Improve code
MakeshVineeth Nov 4, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 218 additions & 0 deletions WikiPreview.Fluent.Plugin/CustomPreview.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Blast.API.Core.Processes;
using Blast.API.Graphics;
using Blast.API.Processes;
using Blast.Core.Interfaces;
using TextCopy;
using static WikiPreview.Fluent.Plugin.WikiPreviewSearchResult;
using static System.Environment;
using static WikiPreview.Fluent.Plugin.WikiPreviewSearchApp;
using static WikiPreview.Fluent.Plugin.ResultGenerator;

namespace WikiPreview.Fluent.Plugin
{
public class CustomPreview : IResultPreviewControlBuilder
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to follow the interface name WikiResultPreviewControlBuilder

{
private const string GoogleStr = "Search Google";
private const string WikipediaStr = "Wikipedia";
private const string CopyStr = "Copy Text";

public CustomPreview()
{
PreviewBuilderDescriptor = new PreviewBuilderDescriptor
{
Name = "Wikipedia Preview",
Description = "Displays the Wikipedia Article Information within Fluent Search.",
ShowPreviewAutomatically = true
};
}

public bool CanBuildPreviewForResult(ISearchResult searchResult)
{
if (string.IsNullOrWhiteSpace(searchResult.SearchApp)) return false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition is redundant since you do Equals below, if it was empty the Equals will return false


if (searchResult.SearchApp.Equals(SearchAppName,
StringComparison.OrdinalIgnoreCase)) return true;

string host = searchResult.Context;
if (string.IsNullOrWhiteSpace(host)) return false;

bool result = Uri.TryCreate(host, UriKind.Absolute, out Uri uri)
&& uri.Scheme == Uri.UriSchemeHttps;

if (!result) return false;

host = uri.Host[3..];
return host.StartsWith("wikipedia.org") && uri.Segments.Length == 3 && uri.Fragment.Length == 0;
}

public ValueTask<Control> CreatePreviewControl(ISearchResult searchResult)
{
if (searchResult is WikiPreviewSearchResult result)
{
Control control = GeneratePreview(result);
return new ValueTask<Control>(control);
}

string pageName = searchResult.Context.Split('/').Last();
return GenerateElement(pageName);
}

public PreviewBuilderDescriptor PreviewBuilderDescriptor { get; }

private static async ValueTask<Control> GenerateElement(string pageName)
{
WikiPreviewSearchResult searchResult = await Instance.GenerateOnDemand(pageName, true, false);

if (searchResult == null || string.IsNullOrWhiteSpace(searchResult.ResultName)) return default;

Control control = GeneratePreview(searchResult);
return control;
}

private static Control GeneratePreview(WikiPreviewSearchResult searchResult)
{
string text = searchResult.ResultName;

// double the new lines for better reading.
text = Regex.Replace(text, @"\r\n?|\n", NewLine + NewLine);

// StackPanel to store image and text.
var wikiDetails = new DockPanel();

// creates image control.
if (searchResult.PreviewImage is { IsEmpty: false })
{
Bitmap bitmap = searchResult.PreviewImage.ConvertToAvaloniaBitmap();

if (!bitmap.Dpi.IsDefault & !bitmap.Size.IsDefault)
{
var imageControl = new Border
{
Background = new ImageBrush(bitmap)
{
Stretch = Stretch.UniformToFill
},
CornerRadius = new CornerRadius(5.0),
BorderThickness = new Thickness(5.0),
Height = bitmap.Size.Height,
Width = bitmap.Size.Width,
MaxHeight = Instance.GetImageSize(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use static import then the property need to have better name, this is really not clear

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed the methods to GetImageSizePrefs which will return the image size preferences that user has set in FS Plugin Settings and SetImageSizePrefs for changing the image size value inside the static class if at all user changes values in FS Plugin Settings. Kindly let me know on this.

MaxWidth = Instance.GetImageSize()
};

wikiDetails.Children.Add(imageControl);
imageControl.SetValue(DockPanel.DockProperty, Dock.Top);
}
}

// creates article content.
var wikiDescription = new TextBlock
{
Text = text, Padding = new Thickness(5, 10, 5, 0), TextWrapping = TextWrapping.Wrap,
TextTrimming = TextTrimming.WordEllipsis
};

wikiDetails.Children.Add(wikiDescription);

var scrollViewer = new ScrollViewer
{
Content = wikiDetails,
VerticalScrollBarVisibility = ScrollBarVisibility.Hidden,
Margin = new Thickness(0, 0, 0, 5)
};

scrollViewer.PointerEnter += ScrollViewerOnPointerEnter;
scrollViewer.PointerLeave += ScrollViewerOnPointerLeave;

// Create Parent Grid.
var grid = new Grid
{
Margin = new Thickness(10.0, 0, 10, 10)
};

grid.RowDefinitions.Add(new RowDefinition());
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.Children.Add(scrollViewer);

Button openWiki = CreateButton(WikipediaStr, searchResult.Url);
Button searchGoogle = CreateButton(GoogleStr, searchResult.DisplayedName);
Button copyContents = CreateButton(CopyStr, text);

var uniformGrid = new UniformGrid
{
Columns = 3,
Rows = 0
};

uniformGrid.Children.Add(openWiki);
uniformGrid.Children.Add(searchGoogle);
uniformGrid.Children.Add(copyContents);

// add buttons grid to the bottom row.
Grid.SetRow(uniformGrid, 1);
grid.Children.Add(uniformGrid);

return grid;
}

private static void ScrollViewerOnPointerLeave(object sender, PointerEventArgs e)
{
if (sender is ScrollViewer scrollViewer)
scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
}

private static void ScrollViewerOnPointerEnter(object sender, PointerEventArgs e)
{
if (sender is ScrollViewer scrollViewer)
scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
}

private static Button CreateButton(string text, string tag)
{
var button = new Button
{
Content = text,
Margin = new Thickness(0, 0, 5, 0),
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
Tag = tag,
[!TemplatedControl.BackgroundProperty] = new DynamicResourceExtension("TextControlBackground")
};

button.Click += ButtonOnClick;
return button;
}

private static void ButtonOnClick(object sender, RoutedEventArgs e)
{
var button = sender as Button;
string buttonContent = button?.Content.ToString();

if (string.IsNullOrWhiteSpace(buttonContent)) return;

string buttonTag = button.Tag?.ToString();

if (string.IsNullOrWhiteSpace(buttonTag)) return;

IProcessManager managerInstance = ProcessUtils.GetManagerInstance();
if (buttonContent.Contains(WikipediaStr))
managerInstance.StartNewProcess(WikiRootUrl + buttonTag);
else if (buttonContent.Contains(GoogleStr))
managerInstance.StartNewProcess(GoogleSearchUrl + buttonTag);
else if (buttonContent.Contains(CopyStr)) Clipboard.SetText(buttonTag);
}
}
}
1 change: 1 addition & 0 deletions WikiPreview.Fluent.Plugin/QueryConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ public class QueryConfiguration
public int WikiNameSpace { get; set; }
public int ResultsCount { get; set; }
public int ImageSize { get; set; }
public bool LoadImage { get; set; }
}
}
105 changes: 105 additions & 0 deletions WikiPreview.Fluent.Plugin/ResultGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Reflection;
using System.Threading.Tasks;
using Blast.API.Search;
using Blast.Core.Results;
using static WikiPreview.Fluent.Plugin.WikiPreviewSearchApp;
using static WikiPreview.Fluent.Plugin.WikiResult;

namespace WikiPreview.Fluent.Plugin
{
public sealed class ResultGenerator
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What this class is doing, why it's holding the image and keep it's size, nothing is clear here

Copy link
Owner Author

@MakeshVineeth MakeshVineeth Oct 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's holding the placeholder image of Wiki logo, as it will be used for search results that doesn't have any images. Since I don't want the instance of image to be created every time, I'm using static class in the new code.

Coming to image size, I've given users an option to change the image size through FS Plugin Settings. Since this image size preferences required across multiple classes, I'm storing it inside this static class.

{
private static readonly Lazy<ResultGenerator> LazySingleton =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you using lazy to not create the instance of the image below? Are there any cases you search with Wiki and not load it?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it was mainly for loading the instance of the image and also store the image size preferences, also making it accessible across all classes. Earlier I thought lazy implementation can be more efficient. In the new code, I've achieved the same behavior that I wanted in a static way.

new(() => new ResultGenerator());

private readonly BitmapImageResult _bitmapLogo;

private ResultGenerator()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to load the image every time this class is created? Make it a static property

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a Singleton before where only same instance will be provided. Now I've made it into static class as per your suggestions.

{
var assembly = Assembly.GetExecutingAssembly();
const string resourceName = "WikiPreview.Fluent.Plugin.Wikipedia-logo.png";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to declare const if you only use it below

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reasons, IDE would keep on suggesting me to declare const. I'm directly giving the string literal now, let me know on this.

_bitmapLogo = new BitmapImageResult(assembly.GetManifestResourceStream(resourceName));
}

private int ImageSize { get; set; }

public static ResultGenerator Instance => LazySingleton.Value;

public int GetImageSize()
{
return ImageSize;
}

public void SetImageSize(int size)
{
ImageSize = size;
}

public async ValueTask<WikiPreviewSearchResult> GenerateSearchResult(PageView value,
string searchedText, bool loadImage = true)
{
string resultName = value.Extract;
string displayedName = value.Title;
double score = displayedName.SearchDistanceScore(searchedText);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better use SearchTokens as it better for titles, it searches even if the order of word in search is reversed (E.g. "world hello", "hello word")

string pageId = value.PageId.ToString();
string wikiUrl = displayedName.Replace(' ', '_');
BitmapImageResult bitmapImageResult;

if (value.Thumbnail != null && loadImage)
{
string imgUrl = value.Thumbnail.Source;
using var imageClient = new HttpClient();
imageClient.DefaultRequestHeaders.UserAgent.TryParseAdd(UserAgentString);
Stream stream = await imageClient.GetStreamAsync(imgUrl);
var bitmap = new Bitmap(stream);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you creating Bitmap since the Avalonia one does not support it?

Copy link
Owner Author

@MakeshVineeth MakeshVineeth Oct 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, AvaloniaBitmap is not working for some unknown reasons. In fact, it's breaking the plugin completely.

bitmapImageResult = new BitmapImageResult(bitmap);
}
else
{
bitmapImageResult = _bitmapLogo;
}

return new WikiPreviewSearchResult(resultName)
{
Url = wikiUrl,
PreviewImage = bitmapImageResult,
DisplayedName = displayedName,
SearchedText = searchedText,
Score = score,
SearchObjectId = pageId,
PinUniqueId = pageId
};
}

public async ValueTask<WikiPreviewSearchResult> GenerateOnDemand(string searchId, bool isCustomPreview = false,
bool loadImage = true)
{
if (string.IsNullOrWhiteSpace(searchId))
return default;

string searchType = isCustomPreview ? "titles=" : "pageids=";

string url = "https://en.wikipedia.org/w/api.php?action=query&prop=extracts|pageimages&" + searchType +
searchId +
"&explaintext&exintro&pilicense=any&pithumbsize=100&format=json";

using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.UserAgent.TryParseAdd(UserAgentString);
var wiki = await httpClient.GetFromJsonAsync<Wiki>(url, SerializerOptions);
if (wiki == null) return default;

Dictionary<string, PageView>.ValueCollection pages = wiki.Query.Pages.Values;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for null wiki?.Query?.Pages?.Values

if (pages is { Count: 0 }) return default;

PageView pageView = pages.First();
return await GenerateSearchResult(pageView, pageView?.Title, loadImage);
}
}
}
28 changes: 15 additions & 13 deletions WikiPreview.Fluent.Plugin/WikiPreview.Fluent.Plugin.csproj
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0-windows10.0.19041</TargetFramework>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
None
</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyVersion>1.2.0.0</AssemblyVersion>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyVersion>1.3.0.0</AssemblyVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
<PackageReference Include="Blast.API" Version="0.9.76.5-beta" />
<PackageReference Include="TextCopy" Version="1.5.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AsyncEnumerator" Version="4.0.2"/>
<PackageReference Include="Blast.API" Version="0.9.89.1-beta"/>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update NuGets

<PackageReference Include="TextCopy" Version="1.5.1"/>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant

</ItemGroup>

<ItemGroup>
<None Remove="Wikipedia-logo.png"/>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant

<EmbeddedResource Include="Wikipedia-logo.png"/>
</ItemGroup>

</Project>
Loading