diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index c957232..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,4 +0,0 @@
-[submodule "Odotocodot.OneNote.Linq"]
- path = Odotocodot.OneNote.Linq
- url = https://github.com/Odotocodot/Odotocodot.OneNote.Linq
- branch = flow-plugin
diff --git a/Changelog.md b/Changelog.md
new file mode 100644
index 0000000..180487f
--- /dev/null
+++ b/Changelog.md
@@ -0,0 +1,97 @@
+# Changelog
+
+## 2.1.0 - 2024-6-24
+
+### Added
+
+- New and improved icons.
+- New preview panel for creating pages ([#20](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/issues/20))
+- New setting for icon theme: FL Default (matches Flow Launcher's theme), light, dark and color.
+- Opening a hierarchy item from the plugin now always brings OneNote to the front.
+- New Hotkey (Ctrl + ⏎ Enter) to create new items without opening them in OneNote.
+
+### Changed
+
+- Refactored icon generation.
+- Refactored settings view.
+- Changed Linq2OneNote library reference from submodule to NuGet package.
+- Updated tooltips for notebooks, section groups, sections and pages.
+
+### Fixes
+
+- Fixed incorrect autocomplete text for creating new items.
+
+## 2.0.1 - 2023-10-09
+
+### Added
+
+- OneNote is now opened asynchronously to prevent blocking UI ([#15](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/issues/15))
+
+## 2.0.0 - 2023-10-05
+
+### **Breaking Changes**
+
+- Now requires Flow Launcher version 1.16 or later.
+
+### Added
+
+- **[Created custom OneNote parser/library](https://github.com/Odotocodot/Linq2OneNote)**, adding the ability for several new features.
+- Support for section groups when using the notebook explorer.
+- Support for displaying unread results.
+- Support for showing locked sections in results (you still can't see inside them unless they are unlocked).
+- The ability to search by only title.
+- The ability to do a scoped search (e.g. search in one section only).
+- **Settings!** You can change these options:
+ - Show unread icons.
+ - Show encrypted sections.
+ - Show recycle bin items.
+ - Created coloured icons for notebook and sections.
+ - Default number of recent pages
+ - **Customisable keywords!**
+
+### Changed
+
+- Compressed images.
+- Reduced the calls to create a OneNote COM object, this should lead to an overall smoother experience.
+- Updated to .NET 7 (update Flow Launcher if an error persists).
+- Refactored the majority of code and project structure.
+
+### Removed
+
+- [Scipbe.Common.Office.OneNote](https://github.com/scipbe/ScipBe-Common-Office) package reference.
+
+## 1.1.1 - 2023-03-05
+
+### Fixes
+
+- Fixed crash on search ([#7](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/issues/7))
+
+## 1.1.0 - 2023-03-04
+
+### Added
+
+- Added the ability to create notebooks, sections and pages.
+
+### Changes
+
+- Improved the readme
+
+### Fixes
+
+- Fixed typos
+
+## 1.0.2 - 2023-02-28
+
+### Fixes
+
+- Fixed crash due to encrypted sections ([#3](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/issues/3), [#4](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/issues/4))
+
+## 1.0.1 - 2023-01-15
+
+### Fixes
+
+- Fixed crash on invalid search ([#1](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/issues/1))
+
+## 1.0.0 - 2022-12-16
+
+Initial Release
diff --git a/Flow.Launcher.Plugin.OneNote.sln b/Flow.Launcher.Plugin.OneNote.sln
index 7c6236a..35ab3f3 100644
--- a/Flow.Launcher.Plugin.OneNote.sln
+++ b/Flow.Launcher.Plugin.OneNote.sln
@@ -11,10 +11,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
LICENSE = LICENSE
Readme.md = Readme.md
release.ps1 = release.ps1
+ Changelog.md = Changelog.md
EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Odotocodot.OneNote.Linq", "Odotocodot.OneNote.Linq\Odotocodot.OneNote.Linq\Odotocodot.OneNote.Linq.csproj", "{AB2CEDD9-15DB-4EAF-A675-10928E83918D}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -25,10 +24,6 @@ Global
{3801047C-BEF0-4774-91DB-B64EEE874BB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3801047C-BEF0-4774-91DB-B64EEE874BB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3801047C-BEF0-4774-91DB-B64EEE874BB2}.Release|Any CPU.Build.0 = Release|Any CPU
- {AB2CEDD9-15DB-4EAF-A675-10928E83918D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AB2CEDD9-15DB-4EAF-A675-10928E83918D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AB2CEDD9-15DB-4EAF-A675-10928E83918D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AB2CEDD9-15DB-4EAF-A675-10928E83918D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Flow.Launcher.Plugin.OneNote/Flow.Launcher.Plugin.OneNote.csproj b/Flow.Launcher.Plugin.OneNote/Flow.Launcher.Plugin.OneNote.csproj
index d40de89..0633013 100644
--- a/Flow.Launcher.Plugin.OneNote/Flow.Launcher.Plugin.OneNote.csproj
+++ b/Flow.Launcher.Plugin.OneNote/Flow.Launcher.Plugin.OneNote.csproj
@@ -11,6 +11,7 @@
false
true
true
+ true
@@ -26,8 +27,10 @@
+
-
+
+
@@ -35,8 +38,4 @@
Always
-
-
-
-
diff --git a/Flow.Launcher.Plugin.OneNote/Icons.cs b/Flow.Launcher.Plugin.OneNote/Icons.cs
deleted file mode 100644
index e118d92..0000000
--- a/Flow.Launcher.Plugin.OneNote/Icons.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-using Odotocodot.OneNote.Linq;
-using System;
-using System.IO;
-
-namespace Flow.Launcher.Plugin.OneNote
-{
- public class Icons : BaseModel
- {
- public const string Logo = "Images/logo.png";
- public const string Sync = "Images/refresh.png";
- public const string Warning = "Images/warning.png";
- public const string Search = Logo;
- public const string RecycleBin = "Images/recycle_bin.png";
- public const string Recent = "Images/recent.png";
- public const string RecentPage = "Images/recent_page.png";
-
- public const string Page = Logo;
- public const string Section = "Images/section.png";
- public const string SectionGroup = "Images/section_group.png";
- public const string Notebook = "Images/notebook.png";
-
- public const string NewPage = "Images/new_page.png";
- public const string NewSection = "Images/new_section.png";
- public const string NewSectionGroup = "Images/new_section_group.png";
- public const string NewNotebook = "Images/new_notebook.png";
-
- private OneNoteItemIcons notebookIcons;
- private OneNoteItemIcons sectionIcons;
- private Settings settings;
-
- public int CachedIconCount => notebookIcons.IconCount + sectionIcons.IconCount;
- public string CachedIconsFileSize => GetBytesReadable(notebookIcons.IconsFileSize + sectionIcons.IconsFileSize);
- public static string NotebookIconDirectory { get; private set; }
- public static string SectionIconDirectory { get; private set; }
-
-
- private static readonly Lazy lazy = new();
- public static Icons Instance => lazy.Value;
-
- public static void Init(PluginInitContext context, Settings settings)
- {
- NotebookIconDirectory = Path.Combine(context.CurrentPluginMetadata.PluginDirectory, "Images", "NotebookIcons");
- SectionIconDirectory = Path.Combine(context.CurrentPluginMetadata.PluginDirectory, "Images", "SectionIcons");
-
- Instance.notebookIcons = new OneNoteItemIcons(NotebookIconDirectory, Path.Combine(context.CurrentPluginMetadata.PluginDirectory, Notebook));
- Instance.sectionIcons = new OneNoteItemIcons(SectionIconDirectory, Path.Combine(context.CurrentPluginMetadata.PluginDirectory, Section));
-
-
- Instance.notebookIcons.PropertyChanged += Instance.IconCountChanged;
- Instance.sectionIcons.PropertyChanged += Instance.IconCountChanged;
-
- Instance.settings = settings;
- }
-
- public static void Close()
- {
- Instance.notebookIcons.PropertyChanged -= Instance.IconCountChanged;
- Instance.sectionIcons.PropertyChanged -= Instance.IconCountChanged;
- }
- private void IconCountChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
- {
- OnPropertyChanged(nameof(CachedIconCount));
- OnPropertyChanged(nameof(CachedIconsFileSize));
- }
-
- public static string GetIcon(IOneNoteItem item)
- {
- return item switch
- {
- OneNoteNotebook notebook => Instance.settings.CreateColoredIcons && notebook.Color.HasValue
- ? Instance.notebookIcons.GetIcon(notebook.Color.Value)
- : Notebook,
- OneNoteSectionGroup sectionGroup => sectionGroup.IsRecycleBin
- ? RecycleBin
- : SectionGroup,
- OneNoteSection section => Instance.settings.CreateColoredIcons && section.Color.HasValue
- ? Instance.sectionIcons.GetIcon(section.Color.Value)
- : Section,
- OneNotePage => Page,
- _ => Warning,
- };
- }
-
- public void ClearCachedIcons()
- {
- notebookIcons.ClearCachedIcons();
- sectionIcons.ClearCachedIcons();
- }
-
- // Returns the human-readable file size for an arbitrary, 64-bit file size
- // The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB"
- private static string GetBytesReadable(long i)
- {
- // Get absolute value
- long absolute_i = Math.Abs(i);
- // Determine the suffix and readable value
- string suffix;
- double readable;
- switch (absolute_i)
- {
- case >= 0x40000000: // Gigabyte
- suffix = "GB";
- readable = i >> 20;
- break;
- case >= 0x100000: // Megabyte
- suffix = "MB";
- readable = i >> 10;
- break;
- case >= 0x400:
- suffix = "KB"; // Kilobyte
- readable = i;
- break;
- default:
- return i.ToString("0 B"); // Byte
- }
- // Divide by 1024 to get fractional value
- readable /= 1024;
- // Return formatted number with suffix
- return readable.ToString("0.## ") + suffix;
- }
-
- }
-}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Icons/IconConstants.cs b/Flow.Launcher.Plugin.OneNote/Icons/IconConstants.cs
new file mode 100644
index 0000000..8dd61b1
--- /dev/null
+++ b/Flow.Launcher.Plugin.OneNote/Icons/IconConstants.cs
@@ -0,0 +1,26 @@
+namespace Flow.Launcher.Plugin.OneNote.Icons
+{
+ public static class IconConstants
+ {
+ public const string ImagesDirectory = "Images/";
+ public const string GeneratedImagesDirectory = $"{ImagesDirectory}Generated/";
+
+ public const string Logo = "logo";
+
+ public const string Notebook = "notebook";
+ public const string SectionGroup = "section_group";
+ public const string RecycleBin = "recycle_bin";
+ public const string Section = "section";
+ public const string Page = "page";
+
+ public const string Sync = "sync";
+ public const string Search = "search";
+ public const string Recent = "page_recent";
+ public const string NotebookExplorer = "notebook_explorer";
+ public const string NewPage = "page_new";
+ public const string NewSection = "section_new";
+ public const string NewSectionGroup = "section_group_new";
+ public const string NewNotebook = "notebook_new";
+ public const string Warning = "warning";
+ }
+}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Icons/IconGeneratorInfo.cs b/Flow.Launcher.Plugin.OneNote/Icons/IconGeneratorInfo.cs
new file mode 100644
index 0000000..dfe0df2
--- /dev/null
+++ b/Flow.Launcher.Plugin.OneNote/Icons/IconGeneratorInfo.cs
@@ -0,0 +1,30 @@
+using System.Drawing;
+using Odotocodot.OneNote.Linq;
+
+namespace Flow.Launcher.Plugin.OneNote.Icons
+{
+ public record struct IconGeneratorInfo
+ {
+ public string Prefix { get; }
+ public Color? Color { get; }
+
+ public IconGeneratorInfo(OneNoteNotebook notebook)
+ {
+ Prefix = IconConstants.Notebook;
+ Color = notebook.Color;
+ }
+ public IconGeneratorInfo(OneNoteSectionGroup sectionGroup)
+ {
+ Prefix = sectionGroup.IsRecycleBin ? IconConstants.RecycleBin : IconConstants.SectionGroup;
+ }
+ public IconGeneratorInfo(OneNoteSection section)
+ {
+ Prefix = IconConstants.Section;
+ Color = section.Color;
+ }
+ public IconGeneratorInfo(OneNotePage page)
+ {
+ Prefix = IconConstants.Page;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Icons/IconProvider.cs b/Flow.Launcher.Plugin.OneNote/Icons/IconProvider.cs
new file mode 100644
index 0000000..2e12698
--- /dev/null
+++ b/Flow.Launcher.Plugin.OneNote/Icons/IconProvider.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Concurrent;
+using System.IO;
+using System.Linq;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using Color = System.Drawing.Color;
+using IC = Flow.Launcher.Plugin.OneNote.Icons.IconConstants;
+
+namespace Flow.Launcher.Plugin.OneNote.Icons
+{
+ public class IconProvider : BaseModel
+ {
+ public const string Logo = IC.ImagesDirectory + IC.Logo + ".png";
+ public string Sync => GetIconPath(IC.Sync);
+ public string Search => GetIconPath(IC.Search);
+ public string Recent => GetIconPath(IC.Recent);
+ public string NotebookExplorer => GetIconPath(IC.NotebookExplorer);
+ public string QuickNote => NewPage;
+ public string NewPage => GetIconPath(IC.NewPage);
+ public string NewSection => GetIconPath(IC.NewSection);
+ public string NewSectionGroup => GetIconPath(IC.NewSectionGroup);
+ public string NewNotebook => GetIconPath(IC.NewNotebook);
+ public string Warning => settings.IconTheme == IconTheme.Color
+ ? $"{IC.ImagesDirectory}{IC.Warning}.{GetIconThemeString(IconTheme.Dark)}.png"
+ : GetIconPath(IC.Warning);
+
+ private readonly Settings settings;
+ private readonly ConcurrentDictionary iconCache = new();
+ private readonly string imagesDirectory;
+
+ public DirectoryInfo GeneratedImagesDirectoryInfo { get; }
+ public int CachedIconCount => iconCache.Keys.Count(k => char.IsDigit(k.Split('.')[1][1]));
+
+ private readonly PluginInitContext context;
+
+ public IconProvider(PluginInitContext context, Settings settings)
+ {
+ imagesDirectory = $"{context.CurrentPluginMetadata.PluginDirectory}/{IC.ImagesDirectory}";
+
+ GeneratedImagesDirectoryInfo = Directory.CreateDirectory($"{context.CurrentPluginMetadata.PluginDirectory}/{IC.GeneratedImagesDirectory}");
+
+ this.context = context;
+ this.settings = settings;
+
+ foreach (var image in GeneratedImagesDirectoryInfo.EnumerateFiles())
+ {
+ var imageSource = BitmapImageFromPath(image.FullName);
+ imageSource.Freeze();
+ iconCache.TryAdd(image.Name, imageSource);
+ }
+ }
+
+ private string GetIconPath(string icon) => $"{IC.ImagesDirectory}{icon}.{GetIconThemeString(settings.IconTheme)}.png";
+
+ private static string GetIconThemeString(IconTheme iconTheme)
+ {
+ if (iconTheme == IconTheme.System)
+ {
+ iconTheme = FlowLauncherThemeToIconTheme();
+ }
+ return Enum.GetName(iconTheme).ToLower();
+ }
+
+ private static IconTheme FlowLauncherThemeToIconTheme()
+ {
+ var color05B = (SolidColorBrush)Application.Current.TryFindResource("Color05B"); //Alt key "SystemControlPageTextBaseHighBrush"
+ if (color05B == null)
+ return IconTheme.Light;
+
+ var color = color05B.Color;
+ return 5 * color.G + 2 * color.R + color.B > 8 * 128 //Is the color light?
+ ? IconTheme.Light
+ : IconTheme.Dark;
+ }
+
+ private static BitmapImage BitmapImageFromPath(string path) => new BitmapImage(new Uri(path));
+
+ public Result.IconDelegate GetIcon(IconGeneratorInfo info)
+ {
+ bool generate = (string.CompareOrdinal(info.Prefix, IC.Notebook) == 0
+ || string.CompareOrdinal(info.Prefix, IC.Section) == 0)
+ && settings.CreateColoredIcons
+ && info.Color.HasValue;
+
+ return generate ? GetIconGenerated : GetIconStatic;
+
+ ImageSource GetIconGenerated()
+ {
+ var imageSource = iconCache.GetOrAdd($"{info.Prefix}.{info.Color!.Value.ToArgb()}.png", ImageSourceFactory, info.Color.Value);
+ OnPropertyChanged(nameof(CachedIconCount));
+ return imageSource;
+ }
+
+ ImageSource GetIconStatic()
+ {
+ return iconCache.GetOrAdd($"{info.Prefix}.{GetIconThemeString(settings.IconTheme)}.png", key =>
+ {
+ var path = Path.Combine(imagesDirectory, key);
+ return BitmapImageFromPath(path);
+ });
+ }
+ }
+
+ private ImageSource ImageSourceFactory(string key, Color color)
+ {
+ var prefix = key.Split('.')[0];
+ var path = Path.Combine(imagesDirectory, $"{prefix}.dark.png");
+ var bitmap = BitmapImageFromPath(path);
+ var newBitmap = ChangeIconColor(bitmap, color);
+
+ path = $"{GeneratedImagesDirectoryInfo.FullName}{key}";
+
+ using var fileStream = new FileStream(path, FileMode.Create);
+ var encoder = new PngBitmapEncoder();
+ encoder.Frames.Add(BitmapFrame.Create(newBitmap));
+ encoder.Save(fileStream);
+ return newBitmap;
+ }
+
+ private static BitmapSource ChangeIconColor(BitmapImage bitmapImage, Color color)
+ {
+ var writeableBitmap = new WriteableBitmap(bitmapImage);
+
+ var stride = writeableBitmap.BackBufferStride;
+ var pixelHeight = writeableBitmap.PixelHeight;
+
+ var pixelData = new byte[stride * pixelHeight];
+ var bytesPerPixel = writeableBitmap.Format.BitsPerPixel / 8;
+
+ writeableBitmap.CopyPixels(pixelData, stride, 0);
+ for (int j = 0; j < pixelHeight; j++)
+ {
+ int line = j * stride;
+ for (int i = 0; i < stride; i += bytesPerPixel)
+ {
+ pixelData[line + i] = color.B;
+ pixelData[line + i + 1] = color.G;
+ pixelData[line + i + 2] = color.R;
+ }
+ }
+ writeableBitmap.WritePixels(new Int32Rect(0, 0, writeableBitmap.PixelWidth, pixelHeight),
+ pixelData, stride, 0);
+ writeableBitmap.Freeze();
+
+ return writeableBitmap;
+ }
+
+ public void ClearCachedIcons()
+ {
+ iconCache.Clear();
+ foreach (var file in GeneratedImagesDirectoryInfo.EnumerateFiles())
+ {
+ try
+ {
+ file.Delete();
+ }
+ catch (Exception e)
+ {
+ // context.API.ShowMsg("Failed to delete", $"Failed to delete {file.Name}");
+ context.API.LogException(nameof(IconProvider), "Failed to delete", e);
+ }
+
+ }
+ OnPropertyChanged(nameof(CachedIconCount));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Icons/IconTheme.cs b/Flow.Launcher.Plugin.OneNote/Icons/IconTheme.cs
new file mode 100644
index 0000000..38db369
--- /dev/null
+++ b/Flow.Launcher.Plugin.OneNote/Icons/IconTheme.cs
@@ -0,0 +1,11 @@
+namespace Flow.Launcher.Plugin.OneNote.Icons
+{
+ public enum IconTheme
+ {
+ System,
+ Light,
+ Dark,
+ Color
+ }
+}
+
diff --git a/Flow.Launcher.Plugin.OneNote/Images/new_notebook.png b/Flow.Launcher.Plugin.OneNote/Images/new_notebook.png
deleted file mode 100644
index 6eef320..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/new_notebook.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/new_page.png b/Flow.Launcher.Plugin.OneNote/Images/new_page.png
deleted file mode 100644
index aee4a9b..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/new_page.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/new_section.png b/Flow.Launcher.Plugin.OneNote/Images/new_section.png
deleted file mode 100644
index 0e46a95..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/new_section.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/new_section_group.png b/Flow.Launcher.Plugin.OneNote/Images/new_section_group.png
deleted file mode 100644
index 7219366..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/new_section_group.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook.color.png b/Flow.Launcher.Plugin.OneNote/Images/notebook.color.png
new file mode 100644
index 0000000..41c09e0
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook.dark.png b/Flow.Launcher.Plugin.OneNote/Images/notebook.dark.png
new file mode 100644
index 0000000..243267b
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook.light.png b/Flow.Launcher.Plugin.OneNote/Images/notebook.light.png
new file mode 100644
index 0000000..0b7aa0f
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook.png b/Flow.Launcher.Plugin.OneNote/Images/notebook.png
deleted file mode 100644
index b9f296d..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/notebook.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.color.png b/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.color.png
new file mode 100644
index 0000000..50b77c2
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.dark.png b/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.dark.png
new file mode 100644
index 0000000..ccf8eae
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.light.png b/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.light.png
new file mode 100644
index 0000000..1cc20b2
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook_explorer.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook_new.color.png b/Flow.Launcher.Plugin.OneNote/Images/notebook_new.color.png
new file mode 100644
index 0000000..184e666
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook_new.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook_new.dark.png b/Flow.Launcher.Plugin.OneNote/Images/notebook_new.dark.png
new file mode 100644
index 0000000..044399e
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook_new.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/notebook_new.light.png b/Flow.Launcher.Plugin.OneNote/Images/notebook_new.light.png
new file mode 100644
index 0000000..7e45f31
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/notebook_new.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page.color.png b/Flow.Launcher.Plugin.OneNote/Images/page.color.png
new file mode 100644
index 0000000..475f806
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page.dark.png b/Flow.Launcher.Plugin.OneNote/Images/page.dark.png
new file mode 100644
index 0000000..b6ab349
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page.light.png b/Flow.Launcher.Plugin.OneNote/Images/page.light.png
new file mode 100644
index 0000000..d1e4c39
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page_new.color.png b/Flow.Launcher.Plugin.OneNote/Images/page_new.color.png
new file mode 100644
index 0000000..bd209be
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page_new.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page_new.dark.png b/Flow.Launcher.Plugin.OneNote/Images/page_new.dark.png
new file mode 100644
index 0000000..990c51d
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page_new.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page_new.light.png b/Flow.Launcher.Plugin.OneNote/Images/page_new.light.png
new file mode 100644
index 0000000..01400e4
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page_new.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page_recent.color.png b/Flow.Launcher.Plugin.OneNote/Images/page_recent.color.png
new file mode 100644
index 0000000..ed53432
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page_recent.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page_recent.dark.png b/Flow.Launcher.Plugin.OneNote/Images/page_recent.dark.png
new file mode 100644
index 0000000..68c9ea5
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page_recent.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/page_recent.light.png b/Flow.Launcher.Plugin.OneNote/Images/page_recent.light.png
new file mode 100644
index 0000000..400e969
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/page_recent.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/recent.png b/Flow.Launcher.Plugin.OneNote/Images/recent.png
deleted file mode 100644
index ee97336..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/recent.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/recent_page.png b/Flow.Launcher.Plugin.OneNote/Images/recent_page.png
deleted file mode 100644
index 9f7a5de..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/recent_page.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.color.png b/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.color.png
new file mode 100644
index 0000000..b79e0a8
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.dark.png b/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.dark.png
new file mode 100644
index 0000000..080cee6
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.light.png b/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.light.png
new file mode 100644
index 0000000..b032988
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.png b/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.png
deleted file mode 100644
index 879d0e0..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/recycle_bin.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/refresh.png b/Flow.Launcher.Plugin.OneNote/Images/refresh.png
deleted file mode 100644
index 98e70e3..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/refresh.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/search.color.png b/Flow.Launcher.Plugin.OneNote/Images/search.color.png
new file mode 100644
index 0000000..a8c3c76
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/search.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/search.dark.png b/Flow.Launcher.Plugin.OneNote/Images/search.dark.png
new file mode 100644
index 0000000..b960dea
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/search.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/search.light.png b/Flow.Launcher.Plugin.OneNote/Images/search.light.png
new file mode 100644
index 0000000..c64d7cd
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/search.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section.color.png b/Flow.Launcher.Plugin.OneNote/Images/section.color.png
new file mode 100644
index 0000000..2c5e320
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section.dark.png b/Flow.Launcher.Plugin.OneNote/Images/section.dark.png
new file mode 100644
index 0000000..f10d2cd
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section.light.png b/Flow.Launcher.Plugin.OneNote/Images/section.light.png
new file mode 100644
index 0000000..f2939d9
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section.png b/Flow.Launcher.Plugin.OneNote/Images/section.png
deleted file mode 100644
index e336883..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/section.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_group.color.png b/Flow.Launcher.Plugin.OneNote/Images/section_group.color.png
new file mode 100644
index 0000000..96586e9
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_group.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_group.dark.png b/Flow.Launcher.Plugin.OneNote/Images/section_group.dark.png
new file mode 100644
index 0000000..c20ca77
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_group.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_group.light.png b/Flow.Launcher.Plugin.OneNote/Images/section_group.light.png
new file mode 100644
index 0000000..4abcbb7
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_group.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_group.png b/Flow.Launcher.Plugin.OneNote/Images/section_group.png
deleted file mode 100644
index 9859d55..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/section_group.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_group_new.color.png b/Flow.Launcher.Plugin.OneNote/Images/section_group_new.color.png
new file mode 100644
index 0000000..3ab0ac7
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_group_new.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_group_new.dark.png b/Flow.Launcher.Plugin.OneNote/Images/section_group_new.dark.png
new file mode 100644
index 0000000..7275038
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_group_new.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_group_new.light.png b/Flow.Launcher.Plugin.OneNote/Images/section_group_new.light.png
new file mode 100644
index 0000000..ef4059b
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_group_new.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_new.color.png b/Flow.Launcher.Plugin.OneNote/Images/section_new.color.png
new file mode 100644
index 0000000..4d9edb8
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_new.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_new.dark.png b/Flow.Launcher.Plugin.OneNote/Images/section_new.dark.png
new file mode 100644
index 0000000..193ba21
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_new.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/section_new.light.png b/Flow.Launcher.Plugin.OneNote/Images/section_new.light.png
new file mode 100644
index 0000000..4e172bf
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/section_new.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/sync.color.png b/Flow.Launcher.Plugin.OneNote/Images/sync.color.png
new file mode 100644
index 0000000..e09b7a6
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/sync.color.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/sync.dark.png b/Flow.Launcher.Plugin.OneNote/Images/sync.dark.png
new file mode 100644
index 0000000..30d68e5
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/sync.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/sync.light.png b/Flow.Launcher.Plugin.OneNote/Images/sync.light.png
new file mode 100644
index 0000000..39a3861
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/sync.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/warning.dark.png b/Flow.Launcher.Plugin.OneNote/Images/warning.dark.png
new file mode 100644
index 0000000..017f2a0
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/warning.dark.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/warning.light.png b/Flow.Launcher.Plugin.OneNote/Images/warning.light.png
new file mode 100644
index 0000000..ab87991
Binary files /dev/null and b/Flow.Launcher.Plugin.OneNote/Images/warning.light.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Images/warning.png b/Flow.Launcher.Plugin.OneNote/Images/warning.png
deleted file mode 100644
index da4f218..0000000
Binary files a/Flow.Launcher.Plugin.OneNote/Images/warning.png and /dev/null differ
diff --git a/Flow.Launcher.Plugin.OneNote/Main.cs b/Flow.Launcher.Plugin.OneNote/Main.cs
index 1e4f456..4bdb0b8 100644
--- a/Flow.Launcher.Plugin.OneNote/Main.cs
+++ b/Flow.Launcher.Plugin.OneNote/Main.cs
@@ -2,6 +2,9 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using System.Windows.Controls;
+using Flow.Launcher.Plugin.OneNote.Icons;
+using Flow.Launcher.Plugin.OneNote.UI.Views;
using Odotocodot.OneNote.Linq;
namespace Flow.Launcher.Plugin.OneNote
{
@@ -9,18 +12,25 @@ public class Main : IAsyncPlugin, IContextMenu, ISettingProvider, IDisposable
{
private PluginInitContext context;
+ private ResultCreator resultCreator;
private SearchManager searchManager;
private Settings settings;
+ private IconProvider iconProvider;
private static SemaphoreSlim semaphore;
+ private static Main instance;
+
+ private Query currentQuery;
public Task InitAsync(PluginInitContext context)
{
this.context = context;
settings = context.API.LoadSettingJsonStorage();
- Icons.Init(context, settings);
- searchManager = new SearchManager(context, settings, new ResultCreator(context, settings));
+ iconProvider = new IconProvider(context, settings);
+ resultCreator = new ResultCreator(context, settings, iconProvider);
+ searchManager = new SearchManager(context, settings, resultCreator);
semaphore = new SemaphoreSlim(1,1);
context.API.VisibilityChanged += OnVisibilityChanged;
+ instance = this;
return Task.CompletedTask;
}
@@ -38,42 +48,38 @@ private static async Task OneNoteInitAsync(CancellationToken token = default)
return;
await semaphore.WaitAsync(token);
- OneNoteApplication.Init();
+ OneNoteApplication.InitComObject();
semaphore.Release();
}
public async Task> QueryAsync(Query query, CancellationToken token)
{
+ currentQuery = query;
var init = OneNoteInitAsync(token);
if (string.IsNullOrEmpty(query.Search))
- return searchManager.EmptyQuery();
+ return resultCreator.EmptyQuery();
await init;
- return query.FirstSearch switch
- {
- string fs when fs.StartsWith(settings.Keywords.RecentPages) => searchManager.RecentPages(fs),
- string fs when fs.StartsWith(settings.Keywords.NotebookExplorer) => searchManager.NotebookExplorer(query),
- string fs when fs.StartsWith(settings.Keywords.TitleSearch) => searchManager.TitleSearch(string.Join(' ', query.SearchTerms), OneNoteApplication.GetNotebooks()),
- _ => searchManager.DefaultSearch(query.Search)
- };
+ return searchManager.Query(query);
}
+ public static void ForceReQuery() => instance.context.API.ChangeQuery(instance.currentQuery.RawQuery, true);
+
public List LoadContextMenus(Result selectedResult)
{
- return searchManager.ContextMenu(selectedResult);
+ return resultCreator.ContextMenu(selectedResult);
}
- public System.Windows.Controls.Control CreateSettingPanel()
+ public Control CreateSettingPanel()
{
- return new UI.Views.SettingsView(new UI.ViewModels.SettingsViewModel(context, settings));
+ return new SettingsView(context, settings, iconProvider);
}
public void Dispose()
{
context.API.VisibilityChanged -= OnVisibilityChanged;
semaphore.Dispose();
- Icons.Close();
OneNoteApplication.ReleaseComObject();
}
}
diff --git a/Flow.Launcher.Plugin.OneNote/OneNoteItemIcons.cs b/Flow.Launcher.Plugin.OneNote/OneNoteItemIcons.cs
deleted file mode 100644
index a4994da..0000000
--- a/Flow.Launcher.Plugin.OneNote/OneNoteItemIcons.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-
-namespace Flow.Launcher.Plugin.OneNote
-{
- public class OneNoteItemIcons : BaseModel
- {
- private readonly Dictionary icons;
- private readonly string iconDirectory;
- private readonly string baseIconPath;
-
- public OneNoteItemIcons(string folderPath, string baseIconPath)
- {
- icons = new Dictionary();
- iconDirectory = folderPath;
- this.baseIconPath = baseIconPath;
-
- Directory.CreateDirectory(iconDirectory);
- foreach (var imagePath in Directory.EnumerateFiles(iconDirectory))
- {
- if (int.TryParse(Path.GetFileNameWithoutExtension(imagePath), out int argb))
- icons.Add(Color.FromArgb(argb), imagePath);
- }
- }
- public int IconCount => icons.Count;
-
- public long IconsFileSize => new DirectoryInfo(iconDirectory).EnumerateFiles()
- .Select(file => file.Length)
- .Aggregate(0L, (a, b) => a + b);
- public void ClearCachedIcons()
- {
- icons.Clear();
- foreach (var img in new DirectoryInfo(iconDirectory).EnumerateFiles())
- {
- img.Delete();
- }
- OnPropertyChanged(nameof(IconCount));
- OnPropertyChanged(nameof(IconsFileSize));
- }
-
- public string GetIcon(Color color)
- {
- if (!icons.TryGetValue(color, out string path))
- {
- //Create Colored Image
- using var bitmap = new Bitmap(baseIconPath);
- BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
-
- int bytesPerPixel = Bitmap.GetPixelFormatSize(bitmap.PixelFormat) / 8;
- byte[] pixels = new byte[bitmapData.Stride * bitmap.Height];
- IntPtr pointer = bitmapData.Scan0;
- Marshal.Copy(pointer, pixels, 0, pixels.Length);
- int bytesWidth = bitmapData.Width * bytesPerPixel;
-
- for (int j = 0; j < bitmapData.Height; j++)
- {
- int line = j * bitmapData.Stride;
- for (int i = 0; i < bytesWidth; i += bytesPerPixel)
- {
- pixels[line + i] = color.B;
- pixels[line + i + 1] = color.G;
- pixels[line + i + 2] = color.R;
- }
- }
-
- Marshal.Copy(pixels, 0, pointer, pixels.Length);
- bitmap.UnlockBits(bitmapData);
- path = Path.Combine(iconDirectory, color.ToArgb() + ".png");
- bitmap.Save(path, ImageFormat.Png);
-
- icons.Add(color, path);
- OnPropertyChanged(nameof(IconCount));
- OnPropertyChanged(nameof(IconsFileSize));
-
- }
-
- return path;
- }
- }
-}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/ResultCreator.cs b/Flow.Launcher.Plugin.OneNote/ResultCreator.cs
index 5c9258b..b2d17aa 100644
--- a/Flow.Launcher.Plugin.OneNote/ResultCreator.cs
+++ b/Flow.Launcher.Plugin.OneNote/ResultCreator.cs
@@ -1,6 +1,11 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using System.Windows.Controls;
+using Flow.Launcher.Plugin.OneNote.Icons;
+using Flow.Launcher.Plugin.OneNote.UI.Views;
+using Humanizer;
using Odotocodot.OneNote.Linq;
namespace Flow.Launcher.Plugin.OneNote
@@ -9,253 +14,461 @@ public class ResultCreator
{
private readonly PluginInitContext context;
private readonly Settings settings;
+ private readonly IconProvider iconProvider;
private const string PathSeparator = " > ";
+ private const string BulletPoint = "\u2022 ";
+ private const string TrianglePoint = "\u2023 ";
- public ResultCreator(PluginInitContext context, Settings settings)
+ private string ActionKeyword => context.CurrentPluginMetadata.ActionKeyword;
+ public ResultCreator(PluginInitContext context, Settings settings, IconProvider iconProvider)
{
this.settings = settings;
+ this.iconProvider = iconProvider;
this.context = context;
}
- private static string GetNicePath(IOneNoteItem item, bool includeSelf = true, string separator = PathSeparator)
- {
- return item.RelativePath.Replace(OneNoteParser.RelativePathSeparator.ToString(), separator);
- }
+ private static string GetNicePath(IOneNoteItem item, string separator = PathSeparator) =>
+ item.RelativePath.Replace(OneNoteApplication.RelativePathSeparator.ToString(), separator);
private string GetTitle(IOneNoteItem item, List highlightData)
{
string title = item.Name;
- if (item.IsUnread && settings.ShowUnread)
- {
- string unread = "\u2022 ";
- title = title.Insert(0, unread);
+ if (!item.IsUnread || !settings.ShowUnread)
+ return title;
+
+ title = title.Insert(0, BulletPoint);
- if (highlightData != null)
- {
- for (int i = 0; i < highlightData.Count; i++)
- {
- highlightData[i] += unread.Length;
- }
- }
+ if (highlightData == null)
+ return title;
+
+ for (int i = 0; i < highlightData.Count; i++)
+ {
+ highlightData[i] += BulletPoint.Length;
}
return title;
}
+
+ private string GetAutoCompleteText(IOneNoteItem item)
+ => $"{ActionKeyword} {settings.Keywords.NotebookExplorer}{GetNicePath(item, Keywords.NotebookExplorerSeparator)}{Keywords.NotebookExplorerSeparator}";
+
- #region Create OneNote Item Results
- public Result CreatePageResult(OneNotePage page, string query = null)
+ public List EmptyQuery()
{
- return CreateOneNoteItemResult(page, false, string.IsNullOrWhiteSpace(query) ? null : context.API.FuzzySearch(query, page.Name).MatchData);
- }
+ return new List
+ {
+ new Result
+ {
+ Title = "Search OneNote pages",
+ SubTitle = "Try typing something!",
+ AutoCompleteText = ActionKeyword,
+ IcoPath = iconProvider.Search,
+ Score = 5000,
+ },
+ new Result
+ {
+ Title = "View notebook explorer",
+ SubTitle = $"Type \"{settings.Keywords.NotebookExplorer}\" or select this option to search by notebook structure ",
+ AutoCompleteText = $"{ActionKeyword} {settings.Keywords.NotebookExplorer}",
+ IcoPath = iconProvider.NotebookExplorer,
+ Score = 2000,
+ Action = _ =>
+ {
+ context.API.ChangeQuery($"{ActionKeyword} {settings.Keywords.NotebookExplorer}", true);
+ return false;
+ },
+ },
+ new Result
+ {
+ Title = "See recent pages",
+ SubTitle = $"Type \"{settings.Keywords.RecentPages}\" or select this option to see recently modified pages",
+ AutoCompleteText = $"{ActionKeyword} {settings.Keywords.RecentPages}",
+ IcoPath = iconProvider.Recent,
+ Score = -1000,
+ Action = _ =>
+ {
+ context.API.ChangeQuery($"{ActionKeyword} {settings.Keywords.RecentPages}", true);
+ return false;
+ },
+ },
+ new Result
+ {
+ Title = "New quick note",
+ IcoPath = iconProvider.QuickNote,
+ Score = -4000,
+ PreviewPanel = GetNewPagePreviewPanel(null, null),
+ Action = _ =>
+ {
+ OneNoteApplication.CreateQuickNote(true);
+ WindowHelper.FocusOneNote();
+ return true;
+ },
+ },
+ new Result
+ {
+ Title = "Open and sync notebooks",
+ IcoPath = iconProvider.Sync,
+ Score = int.MinValue,
+ Action = _ =>
+ {
+ var notebooks = OneNoteApplication.GetNotebooks();
+ foreach (var notebook in notebooks)
+ {
+ notebook.Sync();
+ }
+ notebooks.GetPages()
+ .Where(i => !i.IsInRecycleBin)
+ .OrderByDescending(pg => pg.LastModified)
+ .First()
+ .OpenInOneNote();
+
+ WindowHelper.FocusOneNote();
+ return true;
+ },
+ },
+ };
+ }
+
public Result CreateOneNoteItemResult(IOneNoteItem item, bool actionIsAutoComplete, List highlightData = null, int score = 0)
{
string title = GetTitle(item, highlightData);
- string titleToolTip = null;
- string subTitle = GetNicePath(item, true);
- string subTitleToolTip = null;
- string autoCompleteText = $"{context.CurrentPluginMetadata.ActionKeyword} {settings.Keywords.NotebookExplorer}{GetNicePath(item, true, Keywords.NotebookExplorerSeparator)}";
+ string toolTip = string.Empty;
+ string subTitle = GetNicePath(item);
+ string autoCompleteText = GetAutoCompleteText(item);
+ IconGeneratorInfo iconInfo;
+
switch (item)
{
case OneNoteNotebook notebook:
- titleToolTip = $"{notebook.Name}\n\n" +
- $"Last Modified:\t{notebook.LastModified:F}\n" +
- $"Sections:\t\t{notebook.Sections.Count()}\n" +
- $"Sections Groups:\t{notebook.SectionGroups.Count()}";
+ toolTip =
+ $"""
+ Last Modified:
+ {TrianglePoint}{notebook.LastModified:F}
+
+ Contains:
+ {TrianglePoint}{"section group".ToQuantity(notebook.SectionGroups.Count())}
+ {TrianglePoint}{"section".ToQuantity(notebook.Sections.Count())}
+ {TrianglePoint}{"page".ToQuantity(notebook.GetPages().Count())}
+ """;
subTitle = string.Empty;
- autoCompleteText += Keywords.NotebookExplorerSeparator;
+ iconInfo = new IconGeneratorInfo(notebook);
break;
case OneNoteSectionGroup sectionGroup:
- subTitleToolTip = $"{subTitle}\n\n" +
- $"Last Modified:\t{sectionGroup.LastModified:F}\n" +
- $"Sections:\t\t{sectionGroup.Sections.Count()}\n" +
- $"Sections Groups:\t{sectionGroup.SectionGroups.Count()}";
+ toolTip =
+ $"""
+ Last Modified:
+ {TrianglePoint}{sectionGroup.LastModified:F}
+
+ Contains:
+ {TrianglePoint}{"section group".ToQuantity(sectionGroup.SectionGroups.Count())}
+ {TrianglePoint}{"section".ToQuantity(sectionGroup.Sections.Count())}
+ {TrianglePoint}{"page".ToQuantity(sectionGroup.GetPages().Count())}
+ """;
- autoCompleteText += Keywords.NotebookExplorerSeparator;
+ iconInfo = new IconGeneratorInfo(sectionGroup);
break;
case OneNoteSection section:
if (section.Encrypted)
{
- title += " [Encrypted]";
- if (section.Locked)
- title += "[Locked]";
- else
- title += "[Unlocked]";
+ title += $" [Encrypted] {(section.Locked ? "[Locked]" : "[Unlocked]")}";
}
- subTitleToolTip = $"{subTitle}\n\n" +
- $"Last Modified:\t{section.LastModified}\n" +
- $"Pages:\t\t{section.Pages.Count()}";
-
- autoCompleteText += Keywords.NotebookExplorerSeparator;
+ toolTip =
+ $"""
+ Last Modified:
+ {TrianglePoint}{section.LastModified:F}
+
+ Contains:
+ {TrianglePoint}{"page".ToQuantity(section.GetPages().Count())}
+ """;
+
+ iconInfo = new IconGeneratorInfo(section);
break;
case OneNotePage page:
+ autoCompleteText = actionIsAutoComplete ? autoCompleteText[..^1] : string.Empty;
+
actionIsAutoComplete = false;
- subTitle = subTitle.Remove(subTitle.Length - (page.Name.Length + PathSeparator.Length));
- subTitleToolTip = $"{subTitle}\n\n" +
- $"Created:\t\t{page.Created:F}\n" +
- $"Last Modified:\t{page.LastModified:F}";
+
+ subTitle = subTitle[..^(page.Name.Length + PathSeparator.Length)];
+ toolTip =
+ $"Created:\t\t{page.Created:F}\n" +
+ $"Last Modified:\t{page.LastModified:F}";
+
+ iconInfo = new IconGeneratorInfo(page);
+ break;
+ default:
+ iconInfo = default;
break;
}
+
return new Result
{
Title = title,
- TitleToolTip = titleToolTip,
+ TitleToolTip = toolTip,
TitleHighlightData = highlightData,
- SubTitle = subTitle,
- SubTitleToolTip = subTitleToolTip,
AutoCompleteText = autoCompleteText,
+ SubTitle = subTitle,
Score = score,
- IcoPath = Icons.GetIcon(item),
+ Icon = iconProvider.GetIcon(iconInfo),
ContextData = item,
- AsyncAction = async c =>
+ AsyncAction = async _ =>
{
if (actionIsAutoComplete)
{
- context.API.ChangeQuery(autoCompleteText);
+ context.API.ChangeQuery($"{autoCompleteText}", true);
return false;
}
+
await Task.Run(() =>
{
- OneNoteApplication.SyncItem(item);
- OneNoteApplication.OpenInOneNote(item);
+ item.Sync();
+ item.OpenInOneNote();
});
+ WindowHelper.FocusOneNote();
return true;
- }
+ },
};
}
- #endregion
+
+ public Result CreatePageResult(OneNotePage page, string query)
+ => CreateOneNoteItemResult(page, false, string.IsNullOrWhiteSpace(query) ? null : context.API.FuzzySearch(query, page.Name).MatchData);
- #region Create New OneNote Item Results
- public static Result CreateNewPageResult(string pageTitle, OneNoteSection section)
+ public Result CreateRecentPageResult(OneNotePage page)
{
- pageTitle = pageTitle.Trim();
+ var result = CreateOneNoteItemResult(page, false, null);
+ result.SubTitle = $"{page.LastModified.Humanize()}\t{result.SubTitle}";
+ result.IcoPath = iconProvider.Recent;
+ return result;
+ }
+
+ public Result CreateNewPageResult(string newPageName, OneNoteSection section)
+ {
+ newPageName = newPageName.Trim();
return new Result
{
- Title = $"Create page: \"{pageTitle}\"",
- SubTitle = $"Path: {GetNicePath(section, true)} > {pageTitle}",
- IcoPath = Icons.NewPage,
+ Title = $"Create page: \"{newPageName}\"",
+ SubTitle = $"Path: {GetNicePath(section)}{PathSeparator}{newPageName}",
+ AutoCompleteText = $"{GetAutoCompleteText(section)}{newPageName}",
+ IcoPath = iconProvider.NewPage,
+ PreviewPanel = GetNewPagePreviewPanel(section, newPageName),
Action = c =>
{
- OneNoteApplication.CreatePage(section, pageTitle);
- return true;
- }
+ bool showOneNote = !c.SpecialKeyState.CtrlPressed;
+
+ OneNoteApplication.CreatePage(section, newPageName, showOneNote);
+ Main.ForceReQuery();
+
+ if(showOneNote)
+ WindowHelper.FocusOneNote();
+
+ return showOneNote;
+ },
};
}
- public Result CreateNewSectionResult(string sectionTitle, IOneNoteItem parent)
+ public Result CreateNewSectionResult(string newSectionName, IOneNoteItem parent)
{
- sectionTitle = sectionTitle.Trim();
- bool validTitle = OneNoteParser.IsSectionNameValid(sectionTitle);
+ newSectionName = newSectionName.Trim();
+ bool validTitle = OneNoteApplication.IsSectionNameValid(newSectionName);
return new Result
{
- Title = $"Create section: \"{sectionTitle}\"",
+ Title = $"Create section: \"{newSectionName}\"",
SubTitle = validTitle
- ? $"Path: {GetNicePath(parent, true)} > {sectionTitle}"
- : $"Section names cannot contain: {string.Join(' ', OneNoteParser.InvalidSectionChars)}",
- IcoPath = Icons.NewSection,
+ ? $"Path: {GetNicePath(parent)}{PathSeparator}{newSectionName}"
+ : $"Section names cannot contain: {string.Join(' ', OneNoteApplication.InvalidSectionChars)}",
+ AutoCompleteText = $"{GetAutoCompleteText(parent)}{newSectionName}",
+ IcoPath = iconProvider.NewSection,
Action = c =>
{
if (!validTitle)
+ {
return false;
+ }
+ bool showOneNote = !c.SpecialKeyState.CtrlPressed;
+
switch (parent)
{
case OneNoteNotebook notebook:
- OneNoteApplication.CreateSection(notebook, sectionTitle);
+ OneNoteApplication.CreateSection(notebook, newSectionName, showOneNote);
break;
case OneNoteSectionGroup sectionGroup:
- OneNoteApplication.CreateSection(sectionGroup, sectionTitle);
- break;
- default:
+ OneNoteApplication.CreateSection(sectionGroup, newSectionName, showOneNote);
break;
}
-
- context.API.ChangeQuery(context.CurrentPluginMetadata.ActionKeyword);
- return true;
-
- }
+
+ Main.ForceReQuery();
+ if(showOneNote)
+ WindowHelper.FocusOneNote();
+
+ return showOneNote;
+ },
};
}
- public Result CreateNewSectionGroupResult(string sectionGroupTitle, IOneNoteItem parent)
+
+ public Result CreateNewSectionGroupResult(string newSectionGroupName, IOneNoteItem parent)
{
- sectionGroupTitle = sectionGroupTitle.Trim();
- bool validTitle = OneNoteParser.IsSectionGroupNameValid(sectionGroupTitle);
+ newSectionGroupName = newSectionGroupName.Trim();
+ bool validTitle = OneNoteApplication.IsSectionGroupNameValid(newSectionGroupName);
return new Result
{
- Title = $"Create section group: \"{sectionGroupTitle}\"",
+ Title = $"Create section group: \"{newSectionGroupName}\"",
SubTitle = validTitle
- ? $"Path: {GetNicePath(parent, true)} > {sectionGroupTitle}"
- : $"Section group names cannot contain: {string.Join(' ', OneNoteParser.InvalidSectionGroupChars)}",
- IcoPath = Icons.NewSectionGroup,
+ ? $"Path: {GetNicePath(parent)}{PathSeparator}{newSectionGroupName}"
+ : $"Section group names cannot contain: {string.Join(' ', OneNoteApplication.InvalidSectionGroupChars)}",
+ AutoCompleteText = $"{GetAutoCompleteText(parent)}{newSectionGroupName}",
+ IcoPath = iconProvider.NewSectionGroup,
Action = c =>
{
if (!validTitle)
+ {
return false;
+ }
+ bool showOneNote = !c.SpecialKeyState.CtrlPressed;
+
switch (parent)
{
case OneNoteNotebook notebook:
- OneNoteApplication.CreateSectionGroup(notebook, sectionGroupTitle);
+ OneNoteApplication.CreateSectionGroup(notebook, newSectionGroupName, showOneNote);
break;
case OneNoteSectionGroup sectionGroup:
- OneNoteApplication.CreateSectionGroup(sectionGroup, sectionGroupTitle);
- break;
- default:
+ OneNoteApplication.CreateSectionGroup(sectionGroup, newSectionGroupName, showOneNote);
break;
}
- context.API.ChangeQuery(context.CurrentPluginMetadata.ActionKeyword);
- return true;
- }
+ Main.ForceReQuery();
+ if(showOneNote)
+ WindowHelper.FocusOneNote();
+
+ return showOneNote;
+ },
};
}
- public Result CreateNewNotebookResult(string notebookTitle)
+ public Result CreateNewNotebookResult(string newNotebookName)
{
- notebookTitle = notebookTitle.Trim();
- bool validTitle = OneNoteParser.IsNotebookNameValid(notebookTitle);
+ newNotebookName = newNotebookName.Trim();
+ bool validTitle = OneNoteApplication.IsNotebookNameValid(newNotebookName);
return new Result
{
- Title = $"Create notebook: \"{notebookTitle}\"",
+ Title = $"Create notebook: \"{newNotebookName}\"",
SubTitle = validTitle
? $"Location: {OneNoteApplication.GetDefaultNotebookLocation()}"
- : $"Notebook names cannot contain: {string.Join(' ', OneNoteParser.InvalidNotebookChars)}",
- IcoPath = Icons.NewNotebook,
+ : $"Notebook names cannot contain: {string.Join(' ', OneNoteApplication.InvalidNotebookChars)}",
+ AutoCompleteText = $"{ActionKeyword} {settings.Keywords.NotebookExplorer}{newNotebookName}",
+ IcoPath = iconProvider.NewNotebook,
Action = c =>
{
if (!validTitle)
+ {
return false;
+ }
+
+ bool showOneNote = !c.SpecialKeyState.CtrlPressed;
+
+ OneNoteApplication.CreateNotebook(newNotebookName, showOneNote);
+ Main.ForceReQuery();
+
+ if (showOneNote)
+ WindowHelper.FocusOneNote();
- OneNoteApplication.CreateNotebook(notebookTitle);
+ return showOneNote;
+ },
+ };
+ }
+
+ public List ContextMenu(Result selectedResult)
+ {
+ var results = new List();
+ if (selectedResult.ContextData is IOneNoteItem item)
+ {
+ var result = CreateOneNoteItemResult(item, false);
+ result.Title = $"Open and sync \"{item.Name}\"";
+ result.SubTitle = string.Empty;
+ result.ContextData = null;
+ results.Add(result);
- context.API.ChangeQuery(context.CurrentPluginMetadata.ActionKeyword);
- return true;
+ if (item is not OneNotePage)
+ {
+ results.Add(new Result
+ {
+ Title = "Show in Notebook Explorer",
+ SubTitle = result.AutoCompleteText,
+ Score = - 1000,
+ IcoPath = iconProvider.NotebookExplorer,
+ Action = _ =>
+ {
+ context.API.ChangeQuery(result.AutoCompleteText);
+ return false;
+ }
+ });
}
- };
+ }
+ return results;
+ }
+
+ public List NoItemsInCollection(List results, IOneNoteItem parent)
+ {
+ // parent can be null if the collection only contains notebooks.
+ switch (parent)
+ {
+ case OneNoteNotebook:
+ case OneNoteSectionGroup:
+ // Can create section/section group
+ results.Add(NoItemsInCollectionResult("section", iconProvider.NewSection, "(unencrypted) section"));
+ results.Add(NoItemsInCollectionResult("section group", iconProvider.NewSectionGroup));
+ break;
+ case OneNoteSection section:
+ // Can create page
+ if (!section.Locked)
+ {
+ results.Add(NoItemsInCollectionResult("page", iconProvider.NewPage, section: section));
+ }
+ break;
+ }
+
+ return results;
+
+ Result NoItemsInCollectionResult(string title, string iconPath, string subTitle = null, OneNoteSection section = null)
+ {
+ return new Result
+ {
+ Title = $"Create {title}: \"\"",
+ SubTitle = $"No {subTitle ?? title}s found. Type a valid title to create one",
+ IcoPath = iconPath,
+ PreviewPanel = section != null ? GetNewPagePreviewPanel(section, null) : null ,
+ };
+ }
}
- #endregion
+ private Lazy GetNewPagePreviewPanel(OneNoteSection section, string pageTitle) =>
+ new(() => new NewOneNotePagePreviewPanel(context, section, pageTitle));
- public static List NoMatchesFoundResult()
+ public static List NoMatchesFound()
{
return SingleResult("No matches found",
"Try searching something else, or syncing your notebooks.",
- Icons.Logo);
+ IconProvider.Logo);
}
- public static List InvalidQuery()
+ public List InvalidQuery()
{
return SingleResult("Invalid query",
"The first character of the search must be a letter or a digit",
- Icons.Warning);
+ iconProvider.Warning);
+ }
+ public List SearchingByTitle()
+ {
+ return SingleResult($"Now searching by title.", null, iconProvider.Search);
}
- public static List SingleResult(string title, string subTitle, string iconPath)
+ private static List SingleResult(string title, string subTitle, string iconPath)
{
return new List
{
@@ -267,5 +480,6 @@ public static List SingleResult(string title, string subTitle, string ic
}
};
}
+
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/SearchManager.cs b/Flow.Launcher.Plugin.OneNote/SearchManager.cs
index 1862b25..21ed884 100644
--- a/Flow.Launcher.Plugin.OneNote/SearchManager.cs
+++ b/Flow.Launcher.Plugin.OneNote/SearchManager.cs
@@ -9,339 +9,82 @@ public class SearchManager
{
private readonly PluginInitContext context;
private readonly Settings settings;
- private readonly ResultCreator rc;
+ private readonly ResultCreator resultCreator;
+ private readonly NotebookExplorer notebookExplorer;
public SearchManager(PluginInitContext context, Settings settings, ResultCreator resultCreator)
{
this.context = context;
this.settings = settings;
- rc = resultCreator;
+ this.resultCreator = resultCreator;
+ notebookExplorer = new NotebookExplorer(this, resultCreator);
}
- #region Notebook Explorer
- public List NotebookExplorer(Query query)
- {
- var results = new List();
-
- string fullSearch = query.Search.Remove(query.Search.IndexOf(settings.Keywords.NotebookExplorer), settings.Keywords.NotebookExplorer.Length);
-
- IOneNoteItem parent = null;
- IEnumerable collection = OneNoteApplication.GetNotebooks();
-
- string[] searches = fullSearch.Split(Keywords.NotebookExplorerSeparator, StringSplitOptions.None);
-
- for (int i = -1; i < searches.Length - 1; i++)
- {
- if (i < 0)
- continue;
-
- parent = collection.FirstOrDefault(item => item.Name == searches[i]);
- if (parent == null)
- return results;
-
- collection = parent.Children;
- }
- string lastSearch = searches[^1];
-
- results = lastSearch switch
+ internal List Query(Query query)
+ {
+ return query.Search switch
{
- //Empty search so show all in collection
- string ls when string.IsNullOrWhiteSpace(ls)
- => NotebookEmptySearch(parent, collection),
+ string s when s.StartsWith(settings.Keywords.RecentPages)
+ => RecentPages(s),
- //Search by title
- string ls when ls.StartsWith(settings.Keywords.TitleSearch) && parent is not OneNotePage
- => TitleSearch(ls, collection, parent),
+ string s when s.StartsWith(settings.Keywords.NotebookExplorer)
+ => notebookExplorer.Query(query),
- //scoped search
- string ls when ls.StartsWith(settings.Keywords.ScopedSearch) && (parent is OneNoteNotebook || parent is OneNoteSectionGroup)
- => ScopedSearch(ls, parent),
+ string s when s.StartsWith(settings.Keywords.TitleSearch)
+ => TitleSearch(s, null, OneNoteApplication.GetNotebooks()),
- //default search
- _ => NotebookDefaultSearch(parent, collection, lastSearch)
+ _ => DefaultSearch(query.Search),
};
-
- if (parent != null)
- {
- var result = rc.CreateOneNoteItemResult(parent, false, score: 4000);
- result.Title = $"Open \"{parent.Name}\" in OneNote";
- result.SubTitle = lastSearch switch
- {
- string ls when ls.StartsWith(settings.Keywords.TitleSearch)
- => $"Now search by title in \"{parent.Name}\"",
-
- string ls when ls.StartsWith(settings.Keywords.ScopedSearch)
- => $"Now searching all pages in \"{parent.Name}\"",
-
- _ => $"Use \'{settings.Keywords.ScopedSearch}\' to search this item. Use \'{settings.Keywords.TitleSearch}\' to search by title in this item",
- };
-
- results.Add(result);
- }
-
- return results;
- }
-
- private List NotebookDefaultSearch(IOneNoteItem parent, IEnumerable collection, string lastSearch)
- {
- List highlightData = null;
- int score = 0;
-
- var results = collection.Where(SettingsCheck)
- .Where(item => FuzzySearch(item.Name, lastSearch, out highlightData, out score))
- .Select(item => rc.CreateOneNoteItemResult(item, true, highlightData, score))
- .ToList();
-
- AddCreateNewOneNoteItemResults(results, parent, lastSearch);
- return results;
}
- private List NotebookEmptySearch(IOneNoteItem parent, IEnumerable collection)
+ private List DefaultSearch(string query)
{
- List results = collection.Where(SettingsCheck)
- .Select(item => rc.CreateOneNoteItemResult(item, true))
- .ToList();
- if (!results.Any())
- {
- switch (parent) //parent can be null if the collection contains notebooks.
- {
- case OneNoteNotebook:
- case OneNoteSectionGroup:
- //can create section/section group
- results.Add(NoItemsInCollectionResult("section", Icons.NewSection, "(unencrypted) section"));
- results.Add(NoItemsInCollectionResult("section group", Icons.NewSectionGroup));
- break;
- case OneNoteSection section:
- //can create page
- if (!section.Locked)
- results.Add(NoItemsInCollectionResult("page", Icons.NewPage));
- break;
- default:
- break;
- }
- }
-
- return results;
-
- static Result NoItemsInCollectionResult(string title, string iconPath, string subTitle = null)
+ // Check for invalid start of query i.e. symbols
+ if (!char.IsLetterOrDigit(query[0]))
{
- return new Result
- {
- Title = $"Create {title}: \"\"",
- SubTitle = $"No {subTitle ?? title}s found. Type a valid title to create one",
- IcoPath = iconPath,
- };
+ return resultCreator.InvalidQuery();
}
- }
-
- private List ScopedSearch(string query, IOneNoteItem parent)
- {
- if (query.Length == settings.Keywords.ScopedSearch.Length)
- return ResultCreator.NoMatchesFoundResult();
- if (!char.IsLetterOrDigit(query[settings.Keywords.ScopedSearch.Length]))
- return ResultCreator.InvalidQuery();
-
- string currentSearch = query[settings.Keywords.TitleSearch.Length..];
- var results = new List();
-
- results = OneNoteApplication.FindPages(parent, currentSearch)
- .Select(pg => rc.CreatePageResult(pg, currentSearch))
- .ToList();
-
- if (!results.Any())
- results = ResultCreator.NoMatchesFoundResult();
+ var results = OneNoteApplication.FindPages(query)
+ .Select(pg => resultCreator.CreatePageResult(pg, query));
- return results;
+ return results.Any() ? results.ToList() : ResultCreator.NoMatchesFound();
}
- private void AddCreateNewOneNoteItemResults(List results, IOneNoteItem parent, string query)
+ private List TitleSearch(string query, IOneNoteItem parent, IEnumerable currentCollection)
{
- if (!results.Any(result => string.Equals(query.Trim(), result.Title, StringComparison.OrdinalIgnoreCase)))
+ if (query.Length == settings.Keywords.TitleSearch.Length && parent == null)
{
- if (parent?.IsInRecycleBin() == true)
- return;
-
- switch (parent)
- {
- case null:
- results.Add(rc.CreateNewNotebookResult(query));
- break;
- case OneNoteNotebook:
- case OneNoteSectionGroup:
- results.Add(rc.CreateNewSectionResult(query, parent));
- results.Add(rc.CreateNewSectionGroupResult(query, parent));
- break;
- case OneNoteSection section:
- if (!section.Locked)
- results.Add(ResultCreator.CreateNewPageResult(query, section));
- break;
- default:
- break;
- }
+ return resultCreator.SearchingByTitle();
}
- }
- #endregion
-
- public List EmptyQuery()
- {
- return new List
- {
- new Result
- {
- Title = "Search OneNote pages",
- SubTitle = $"Type \"{settings.Keywords.NotebookExplorer}\" or select this option to search by notebook structure ",
- AutoCompleteText = $"{context.CurrentPluginMetadata.ActionKeyword} {settings.Keywords.NotebookExplorer}",
- IcoPath = Icons.Logo,
- Score = 2000,
- Action = c =>
- {
- context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeyword} {settings.Keywords.NotebookExplorer}");
- return false;
- },
- },
- new Result
- {
- Title = "See recent pages",
- SubTitle = $"Type \"{settings.Keywords.RecentPages}\" or select this option to see recently modified pages",
- AutoCompleteText = $"{context.CurrentPluginMetadata.ActionKeyword} {settings.Keywords.RecentPages}",
- IcoPath = Icons.Recent,
- Score = -1000,
- Action = c =>
- {
- context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeyword} {settings.Keywords.RecentPages}");
- return false;
- },
- },
- new Result
- {
- Title = "New quick note",
- IcoPath = Icons.NewPage,
- Score = -4000,
- Action = c =>
- {
- OneNoteApplication.CreateQuickNote();
- return true;
- }
- },
- new Result
- {
- Title = "Open and sync notebooks",
- IcoPath = Icons.Sync,
- Score = int.MinValue,
- Action = c =>
- {
- foreach (var notebook in OneNoteApplication.GetNotebooks())
- {
- notebook.Sync();
- }
- OneNoteApplication.GetNotebooks()
- .GetPages()
- .OrderByDescending(pg => pg.LastModified)
- .First()
- .OpenInOneNote();
- return true;
- }
- },
- };
- }
- public List DefaultSearch(string query)
- {
- //Check for invalid start of query i.e. symbols
- if (!char.IsLetterOrDigit(query[0]))
- return ResultCreator.InvalidQuery();
-
- var results = OneNoteApplication.FindPages(query)
- .Select(pg => rc.CreatePageResult(pg, query));
- if (results.Any())
- return results.ToList();
-
- return ResultCreator.NoMatchesFoundResult();
- }
- public List TitleSearch(string query, IEnumerable currentCollection, IOneNoteItem parent = null)
- {
- if (query.Length == settings.Keywords.TitleSearch.Length && parent == null)
- return ResultCreator.SingleResult($"Now searching by title.", null, Icons.Search);
List highlightData = null;
int score = 0;
var currentSearch = query[settings.Keywords.TitleSearch.Length..];
- var results = currentCollection.Traverse(item =>
- {
- if (!SettingsCheck(item))
- return false;
-
- return FuzzySearch(item.Name, currentSearch, out highlightData, out score);
- })
- .Select(item => rc.CreateOneNoteItemResult(item, false, highlightData, score))
- .ToList();
+ var results = currentCollection.Traverse(item => SettingsCheck(item) && FuzzySearch(item.Name, currentSearch, out highlightData, out score))
+ .Select(item => resultCreator.CreateOneNoteItemResult(item, false, highlightData, score))
+ .ToList();
- if (!results.Any())
- results = ResultCreator.NoMatchesFoundResult();
-
- return results;
+ return results.Any() ? results : ResultCreator.NoMatchesFound();
}
- public List RecentPages(string query)
+
+ private List RecentPages(string query)
{
int count = settings.DefaultRecentsCount;
+
if (query.Length > settings.Keywords.RecentPages.Length && int.TryParse(query[settings.Keywords.RecentPages.Length..], out int userChosenCount))
count = userChosenCount;
-
+
return OneNoteApplication.GetNotebooks()
.GetPages()
.Where(SettingsCheck)
.OrderByDescending(pg => pg.LastModified)
.Take(count)
- .Select(pg =>
- {
- Result result = rc.CreatePageResult(pg);
- result.SubTitleToolTip = result.SubTitle;
- result.SubTitle = $"{GetLastEdited(DateTime.Now - pg.LastModified)}\t{result.SubTitle}";
- result.IcoPath = Icons.RecentPage;
- return result;
- })
+ .Select(resultCreator.CreateRecentPageResult)
.ToList();
}
- public List ContextMenu(Result selectedResult)
- {
- var results = new List();
- if (selectedResult.ContextData is IOneNoteItem item)
- {
- var result = rc.CreateOneNoteItemResult(item, false);
- result.Title = $"Open and sync \"{item.Name}\"";
- result.SubTitle = string.Empty;
- result.ContextData = null;
- results.Add(result);
- }
- return results;
- }
- private static string GetLastEdited(TimeSpan diff)
- {
- string lastEdited = "Last edited ";
- if (PluralCheck(diff.TotalDays, "day", ref lastEdited)
- || PluralCheck(diff.TotalHours, "hour", ref lastEdited)
- || PluralCheck(diff.TotalMinutes, "min", ref lastEdited)
- || PluralCheck(diff.TotalSeconds, "sec", ref lastEdited))
- return lastEdited;
- else
- return lastEdited += "Now.";
-
- static bool PluralCheck(double totalTime, string timeType, ref string lastEdited)
- {
- var roundedTime = (int)Math.Round(totalTime);
- if (roundedTime > 0)
- {
- string plural = roundedTime == 1 ? "" : "s";
- lastEdited += $"{roundedTime} {timeType}{plural} ago.";
- return true;
- }
- else
- return false;
-
- }
- }
private bool FuzzySearch(string itemName, string search, out List highlightData, out int score)
{
var matchResult = context.API.FuzzySearch(search, itemName);
@@ -359,7 +102,166 @@ private bool SettingsCheck(IOneNoteItem item)
success = false;
return success;
}
+ private sealed class NotebookExplorer
+ {
+ private readonly SearchManager searchManager;
+ private readonly ResultCreator resultCreator;
- }
+ private Keywords Keywords => searchManager.settings.Keywords;
+ internal NotebookExplorer(SearchManager searchManager, ResultCreator resultCreator)
+ {
+ this.searchManager = searchManager;
+ this.resultCreator = resultCreator;
+ }
+
+ internal List Query(Query query)
+ {
+ var results = new List();
+
+ string fullSearch = query.Search[(query.Search.IndexOf(Keywords.NotebookExplorer, StringComparison.Ordinal) + Keywords.NotebookExplorer.Length)..];
+
+ IOneNoteItem parent = null;
+ IEnumerable collection = OneNoteApplication.GetNotebooks();
+
+ string[] searches = fullSearch.Split(Keywords.NotebookExplorerSeparator, StringSplitOptions.None);
+
+ for (int i = -1; i < searches.Length - 1; i++)
+ {
+ if (i < 0)
+ {
+ continue;
+ }
+
+ parent = collection.FirstOrDefault(item => item.Name.Equals(searches[i]));
+ if (parent == null)
+ {
+ return results;
+ }
+
+ collection = parent.Children;
+ }
+
+ string lastSearch = searches[^1];
+
+ results = lastSearch switch
+ {
+ // Empty search so show all in collection
+ string search when string.IsNullOrWhiteSpace(search)
+ => EmptySearch(parent, collection),
+
+ // Search by title
+ string search when search.StartsWith(Keywords.TitleSearch) && parent is not OneNotePage
+ => searchManager.TitleSearch(search, parent, collection),
+
+ // Scoped search
+ string search when search.StartsWith(Keywords.ScopedSearch) && parent is OneNoteNotebook or OneNoteSectionGroup
+ => ScopedSearch(search, parent),
+
+ // Default search
+ _ => Explorer(lastSearch, parent, collection),
+ };
+
+ if (parent != null)
+ {
+ var result = resultCreator.CreateOneNoteItemResult(parent, false, score: 4000);
+ result.Title = $"Open \"{parent.Name}\" in OneNote";
+ result.SubTitle = lastSearch switch
+ {
+ string search when search.StartsWith(Keywords.TitleSearch)
+ => $"Now search by title in \"{parent.Name}\"",
+
+ string search when search.StartsWith(Keywords.ScopedSearch)
+ => $"Now searching all pages in \"{parent.Name}\"",
+
+ _ => $"Use \'{Keywords.ScopedSearch}\' to search this item. Use \'{Keywords.TitleSearch}\' to search by title in this item",
+ };
+ results.Add(result);
+ }
+
+ return results;
+ }
+
+ private List EmptySearch(IOneNoteItem parent, IEnumerable collection)
+ {
+ List results = collection.Where(searchManager.SettingsCheck)
+ .Select(item => resultCreator.CreateOneNoteItemResult(item, true))
+ .ToList();
+ if (results.Any())
+ return results;
+ return resultCreator.NoItemsInCollection(results, parent);
+ }
+
+ private List ScopedSearch(string query, IOneNoteItem parent)
+ {
+ if (query.Length == Keywords.ScopedSearch.Length)
+ {
+ return ResultCreator.NoMatchesFound();
+ }
+
+ if (!char.IsLetterOrDigit(query[Keywords.ScopedSearch.Length]))
+ {
+ return resultCreator.InvalidQuery();
+ }
+
+ string currentSearch = query[Keywords.TitleSearch.Length..];
+ var results = new List();
+
+ results = OneNoteApplication.FindPages(currentSearch, parent)
+ .Select(pg => resultCreator.CreatePageResult(pg, currentSearch))
+ .ToList();
+
+ if (!results.Any())
+ {
+ results = ResultCreator.NoMatchesFound();
+ }
+
+ return results;
+ }
+#nullable enable
+ private List Explorer(string search, IOneNoteItem? parent, IEnumerable collection)
+ {
+ List? highlightData = null;
+ int score = 0;
+
+ var results = collection.Where(searchManager.SettingsCheck)
+ .Where(item => searchManager.FuzzySearch(item.Name, search, out highlightData, out score))
+ .Select(item => resultCreator.CreateOneNoteItemResult(item, true, highlightData, score))
+ .ToList();
+
+ AddCreateNewOneNoteItemResults(search, parent, results);
+ return results;
+ }
+
+ private void AddCreateNewOneNoteItemResults(string newItemName, IOneNoteItem? parent, List results)
+ {
+ if (!results.Any(result => string.Equals(newItemName.Trim(), result.Title, StringComparison.OrdinalIgnoreCase)))
+ {
+ if (parent?.IsInRecycleBin() == true)
+ {
+ return;
+ }
+
+ switch (parent)
+ {
+ case null:
+ results.Add(resultCreator.CreateNewNotebookResult(newItemName));
+ break;
+ case OneNoteNotebook:
+ case OneNoteSectionGroup:
+ results.Add(resultCreator.CreateNewSectionResult(newItemName, parent));
+ results.Add(resultCreator.CreateNewSectionGroupResult(newItemName, parent));
+ break;
+ case OneNoteSection section:
+ if (!section.Locked)
+ {
+ results.Add(resultCreator.CreateNewPageResult(newItemName, section));
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
}
diff --git a/Flow.Launcher.Plugin.OneNote/Settings.cs b/Flow.Launcher.Plugin.OneNote/Settings.cs
index ba823fc..86a4876 100644
--- a/Flow.Launcher.Plugin.OneNote/Settings.cs
+++ b/Flow.Launcher.Plugin.OneNote/Settings.cs
@@ -1,4 +1,6 @@
-namespace Flow.Launcher.Plugin.OneNote
+using Flow.Launcher.Plugin.OneNote.Icons;
+
+namespace Flow.Launcher.Plugin.OneNote
{
public class Settings : UI.Model
{
@@ -7,6 +9,7 @@ public class Settings : UI.Model
private bool showRecycleBin = true;
private bool showEncrypted = false;
private bool createColoredIcons = true;
+ private IconTheme iconTheme = IconTheme.Color;
public Keywords Keywords { get; init; } = new Keywords();
public bool ShowRecycleBin
@@ -34,5 +37,11 @@ public bool CreateColoredIcons
get => createColoredIcons;
set => SetProperty(ref createColoredIcons, value);
}
+
+ public IconTheme IconTheme
+ {
+ get => iconTheme;
+ set => SetProperty(ref iconTheme, value);
+ }
}
}
diff --git a/Flow.Launcher.Plugin.OneNote/UI/RelayCommand.cs b/Flow.Launcher.Plugin.OneNote/UI/RelayCommand.cs
new file mode 100644
index 0000000..e462b62
--- /dev/null
+++ b/Flow.Launcher.Plugin.OneNote/UI/RelayCommand.cs
@@ -0,0 +1,34 @@
+#nullable enable
+using System;
+using System.Windows.Input;
+
+namespace Flow.Launcher.Plugin.OneNote.UI
+{
+ public sealed class RelayCommand : ICommand
+ {
+ private readonly Action