diff --git a/CHANGELOG.md b/CHANGELOG.md
index 176fc71..b620244 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## [1.0.0] - 25/03/2022
+
+### Added
+ - Support for docx and doc
+
+### Changed
+ - Improved status bar responsivity
+
## [0.2.0] - 15/05/2021
### Added
diff --git a/InDepthSearch.Core/Enums/AppLanguage.cs b/InDepthSearch.Core/Enums/AppLanguage.cs
new file mode 100644
index 0000000..802cdb3
--- /dev/null
+++ b/InDepthSearch.Core/Enums/AppLanguage.cs
@@ -0,0 +1,10 @@
+
+namespace InDepthSearch.Core.Enums
+{
+ public enum AppLanguage
+ {
+ English,
+ Polski,
+ Francais
+ }
+}
diff --git a/InDepthSearch.Core/Enums/ImageExtension.cs b/InDepthSearch.Core/Enums/ImageExtension.cs
new file mode 100644
index 0000000..a4d5d84
--- /dev/null
+++ b/InDepthSearch.Core/Enums/ImageExtension.cs
@@ -0,0 +1,10 @@
+
+namespace InDepthSearch.Core.Enums
+{
+ public enum ImageExtension
+ {
+ Jpg,
+ Png,
+ Bmp
+ }
+}
diff --git a/InDepthSearch.Core/Enums/MatchConfidence.cs b/InDepthSearch.Core/Enums/MatchConfidence.cs
new file mode 100644
index 0000000..3430d7f
--- /dev/null
+++ b/InDepthSearch.Core/Enums/MatchConfidence.cs
@@ -0,0 +1,11 @@
+
+namespace InDepthSearch.Core.Enums
+{
+ public enum MatchConfidence
+ {
+ High, // found exact expression
+ Medium, // found the all the words from the expression
+ Low // found part of the words from the expression
+ }
+
+}
diff --git a/InDepthSearch.Core/Enums/RecognitionLanguage.cs b/InDepthSearch.Core/Enums/RecognitionLanguage.cs
new file mode 100644
index 0000000..fec1bc9
--- /dev/null
+++ b/InDepthSearch.Core/Enums/RecognitionLanguage.cs
@@ -0,0 +1,11 @@
+
+namespace InDepthSearch.Core.Enums
+{
+ public enum RecognitionLanguage
+ {
+ Default,
+ English,
+ French,
+ Polish
+ }
+}
diff --git a/InDepthSearch.Core/Enums/RecognitionPrecision.cs b/InDepthSearch.Core/Enums/RecognitionPrecision.cs
new file mode 100644
index 0000000..6d3fc5b
--- /dev/null
+++ b/InDepthSearch.Core/Enums/RecognitionPrecision.cs
@@ -0,0 +1,11 @@
+
+namespace InDepthSearch.Core.Enums
+{
+ public enum RecognitionPrecision
+ {
+ Default,
+ High,
+ Medium,
+ Low
+ }
+}
diff --git a/InDepthSearch.Core/Enums/SearchInfo.cs b/InDepthSearch.Core/Enums/SearchInfo.cs
new file mode 100644
index 0000000..4566418
--- /dev/null
+++ b/InDepthSearch.Core/Enums/SearchInfo.cs
@@ -0,0 +1,11 @@
+
+namespace InDepthSearch.Core.Enums
+{
+ public enum SearchInfo
+ {
+ Unknown,
+ Init,
+ Run,
+ NoResults,
+ }
+}
diff --git a/InDepthSearch.Core/Enums/SearchStatus.cs b/InDepthSearch.Core/Enums/SearchStatus.cs
new file mode 100644
index 0000000..69cb18f
--- /dev/null
+++ b/InDepthSearch.Core/Enums/SearchStatus.cs
@@ -0,0 +1,11 @@
+
+namespace InDepthSearch.Core.Enums
+{
+ public enum SearchStatus
+ {
+ Unknown,
+ Ready,
+ Initializing,
+ Running,
+ }
+}
diff --git a/InDepthSearch.Core/Enums/Theme.cs b/InDepthSearch.Core/Enums/Theme.cs
new file mode 100644
index 0000000..d198055
--- /dev/null
+++ b/InDepthSearch.Core/Enums/Theme.cs
@@ -0,0 +1,10 @@
+
+namespace InDepthSearch.Core.Enums
+{
+ public enum Theme
+ {
+ Default,
+ Light,
+ Dark,
+ }
+}
diff --git a/InDepthSearch.Core/InDepthSearch.Core.csproj b/InDepthSearch.Core/InDepthSearch.Core.csproj
index 5cd0bf2..1b49eb8 100644
--- a/InDepthSearch.Core/InDepthSearch.Core.csproj
+++ b/InDepthSearch.Core/InDepthSearch.Core.csproj
@@ -4,15 +4,15 @@
Library
enable
net5.0
- 0.2.0
+ 1.0.0
+
-
+
-
diff --git a/InDepthSearch.Core/Managers/Interfaces/IResultManager.cs b/InDepthSearch.Core/Managers/Interfaces/IResultManager.cs
new file mode 100644
index 0000000..bda4e57
--- /dev/null
+++ b/InDepthSearch.Core/Managers/Interfaces/IResultManager.cs
@@ -0,0 +1,16 @@
+
+using InDepthSearch.Core.Models;
+using System.Collections.ObjectModel;
+
+namespace InDepthSearch.Core.Managers.Interfaces
+{
+ public interface IResultManager
+ {
+ ObservableCollection Results { get; }
+ ResultStats Stats { get; }
+ bool ItemsReady { get; set; }
+ void Reinitialize();
+ void AddResult(QueryResult res);
+ void SetItemsReady(bool ready);
+ }
+}
diff --git a/InDepthSearch.Core/Models/QueryResult.cs b/InDepthSearch.Core/Models/QueryResult.cs
index 2e996a0..6029a32 100644
--- a/InDepthSearch.Core/Models/QueryResult.cs
+++ b/InDepthSearch.Core/Models/QueryResult.cs
@@ -4,7 +4,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
namespace InDepthSearch.Core.Models
{
diff --git a/InDepthSearch.Core/Models/ResultStats.cs b/InDepthSearch.Core/Models/ResultStats.cs
index 0d5f86b..068f49a 100644
--- a/InDepthSearch.Core/Models/ResultStats.cs
+++ b/InDepthSearch.Core/Models/ResultStats.cs
@@ -10,19 +10,16 @@ namespace InDepthSearch.Core.Models
{
public class ResultStats : ReactiveObject
{
- public ResultStats(string filesAnalyzed, bool isReady, int pagesAnalyzed, string executionTime)
+ public ResultStats()
{
- FilesAnalyzed = filesAnalyzed;
- IsReady = isReady;
- PagesAnalyzed = pagesAnalyzed;
- ExecutionTime = executionTime;
+ FilesAnalyzed = "";
+ PagesAnalyzed = 0;
+ ExecutionTime = "";
}
[Reactive]
public string FilesAnalyzed { get; set; }
[Reactive]
- public bool IsReady { get; set; }
- [Reactive]
public int PagesAnalyzed { get; set; }
[Reactive]
public string ExecutionTime { get; set; }
diff --git a/InDepthSearch.Core/Models/SearchOptions.cs b/InDepthSearch.Core/Models/SearchOptions.cs
index e36490d..b4cc1b2 100644
--- a/InDepthSearch.Core/Models/SearchOptions.cs
+++ b/InDepthSearch.Core/Models/SearchOptions.cs
@@ -1,4 +1,4 @@
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
@@ -6,19 +6,14 @@ namespace InDepthSearch.Core.Models
{
public class SearchOptions : ReactiveObject
{
- public SearchOptions(string path, string keyword, RecognitionPrecision selectedPrecisionOCR, RecognitionLanguage selectedLanguageOCR,
- bool caseSensitive, bool useOCR, bool useSubfolders, bool usePDF, bool useDOCX, bool useODT)
+ public SearchOptions()
{
- Path = path;
- Keyword = keyword;
- SelectedPrecisionOCR = selectedPrecisionOCR;
- SelectedLanguageOCR = selectedLanguageOCR;
- CaseSensitive = caseSensitive;
- UseOCR = useOCR;
- UseSubfolders = useSubfolders;
- UsePDF = usePDF;
- UseDOCX = useDOCX;
- UseODT = useODT;
+ UseOCR = true;
+ UsePDF = true;
+ Path = "";
+ Keyword = "";
+ SelectedLanguageOCR = RecognitionLanguage.Default;
+ SelectedPrecisionOCR = RecognitionPrecision.Default;
}
[Reactive]
@@ -28,10 +23,16 @@ public class SearchOptions : ReactiveObject
public RecognitionPrecision SelectedPrecisionOCR { get; set; }
public RecognitionLanguage SelectedLanguageOCR { get; set; }
public bool CaseSensitive { get; set; }
+ [Reactive]
public bool UseOCR { get; set; }
public bool UseSubfolders { get; set; }
+ [Reactive]
public bool UsePDF { get; set; }
+ [Reactive]
public bool UseDOCX { get; set; }
+ [Reactive]
public bool UseODT { get; set; }
+ [Reactive]
+ public bool UseDOC { get; set; }
}
}
diff --git a/InDepthSearch.Core/Services/Interfaces/IAppService.cs b/InDepthSearch.Core/Services/Interfaces/IAppService.cs
index 49d362b..52e7ed6 100644
--- a/InDepthSearch.Core/Services/Interfaces/IAppService.cs
+++ b/InDepthSearch.Core/Services/Interfaces/IAppService.cs
@@ -1,4 +1,4 @@
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/InDepthSearch.Core/Services/Interfaces/IOptionService.cs b/InDepthSearch.Core/Services/Interfaces/IOptionService.cs
index a533577..30df04d 100644
--- a/InDepthSearch.Core/Services/Interfaces/IOptionService.cs
+++ b/InDepthSearch.Core/Services/Interfaces/IOptionService.cs
@@ -1,17 +1,11 @@
using Docnet.Core.Models;
-using InDepthSearch.Core.Types;
-using System;
-using System.Collections.Generic;
-using System.Drawing.Imaging;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using InDepthSearch.Core.Enums;
namespace InDepthSearch.Core.Services.Interfaces
{
public interface IOptionService
{
- public (PageDimensions, RenderFlags, PixelFormat, ImageFormat) TranslatePrecision(RecognitionPrecision rp);
+ public (PageDimensions, RenderFlags, ImageExtension) TranslatePrecision(RecognitionPrecision rp);
public string TranslateLanguage(RecognitionLanguage rl);
}
}
diff --git a/InDepthSearch.Core/Services/Interfaces/ISearchService.cs b/InDepthSearch.Core/Services/Interfaces/ISearchService.cs
new file mode 100644
index 0000000..a871e69
--- /dev/null
+++ b/InDepthSearch.Core/Services/Interfaces/ISearchService.cs
@@ -0,0 +1,10 @@
+using InDepthSearch.Core.Enums;
+using InDepthSearch.Core.Models;
+
+namespace InDepthSearch.Core.Services.Interfaces
+{
+ public interface ISearchService
+ {
+ void Search(string file, SearchOptions searchOptions);
+ }
+}
diff --git a/InDepthSearch.Core/Services/Interfaces/IThemeService.cs b/InDepthSearch.Core/Services/Interfaces/IThemeService.cs
index 44cb773..7aa3941 100644
--- a/InDepthSearch.Core/Services/Interfaces/IThemeService.cs
+++ b/InDepthSearch.Core/Services/Interfaces/IThemeService.cs
@@ -1,4 +1,4 @@
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/InDepthSearch.Core/Types/AppLanguage.cs b/InDepthSearch.Core/Types/AppLanguage.cs
deleted file mode 100644
index e4955fc..0000000
--- a/InDepthSearch.Core/Types/AppLanguage.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace InDepthSearch.Core.Types
-{
- public enum AppLanguage: int
- {
- English,
- Polski,
- Francais
- }
-}
diff --git a/InDepthSearch.Core/Types/MatchConfidence.cs b/InDepthSearch.Core/Types/MatchConfidence.cs
deleted file mode 100644
index e29de82..0000000
--- a/InDepthSearch.Core/Types/MatchConfidence.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace InDepthSearch.Core.Types
-{
- public enum MatchConfidence : int
- {
- High, // found exact expression
- Medium, // found the all the words from the expression
- Low // found part of the words from the expression
- }
-
-}
diff --git a/InDepthSearch.Core/Types/RecognitionLanguage.cs b/InDepthSearch.Core/Types/RecognitionLanguage.cs
deleted file mode 100644
index f50f5d8..0000000
--- a/InDepthSearch.Core/Types/RecognitionLanguage.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace InDepthSearch.Core.Types
-{
- public enum RecognitionLanguage : int
- {
- Default,
- English,
- French,
- Polish
- }
-}
diff --git a/InDepthSearch.Core/Types/RecognitionPrecision.cs b/InDepthSearch.Core/Types/RecognitionPrecision.cs
deleted file mode 100644
index 15bd441..0000000
--- a/InDepthSearch.Core/Types/RecognitionPrecision.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace InDepthSearch.Core.Types
-{
- public enum RecognitionPrecision : int
- {
- Default,
- High,
- Medium,
- Low
- }
-}
diff --git a/InDepthSearch.Core/Types/SearchInfo.cs b/InDepthSearch.Core/Types/SearchInfo.cs
deleted file mode 100644
index ba0b054..0000000
--- a/InDepthSearch.Core/Types/SearchInfo.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace InDepthSearch.Core.Types
-{
- public enum SearchInfo
- {
- Unknown,
- Init,
- Run,
- NoResults,
- }
-}
diff --git a/InDepthSearch.Core/Types/SearchStatus.cs b/InDepthSearch.Core/Types/SearchStatus.cs
deleted file mode 100644
index 001e508..0000000
--- a/InDepthSearch.Core/Types/SearchStatus.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace InDepthSearch.Core.Types
-{
- public enum SearchStatus : int
- {
- Unknown,
- Ready,
- Initializing,
- Running,
- }
-}
diff --git a/InDepthSearch.Core/Types/Theme.cs b/InDepthSearch.Core/Types/Theme.cs
deleted file mode 100644
index 191c4c7..0000000
--- a/InDepthSearch.Core/Types/Theme.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace InDepthSearch.Core.Types
-{
- public enum Theme : int
- {
- Default,
- Light,
- Dark,
- }
-}
diff --git a/InDepthSearch.Core/ViewModels/MainViewModel.cs b/InDepthSearch.Core/ViewModels/MainViewModel.cs
deleted file mode 100644
index e345ac4..0000000
--- a/InDepthSearch.Core/ViewModels/MainViewModel.cs
+++ /dev/null
@@ -1,299 +0,0 @@
-using Docnet.Core;
-using ReactiveUI;
-using ReactiveUI.Fody.Helpers;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Reactive;
-using System.Runtime.InteropServices;
-using Tesseract;
-using System.Linq;
-using System.Collections.ObjectModel;
-using InDepthSearch.Core.Models;
-using InDepthSearch.Core.Types;
-using System.Threading;
-using ReactiveUI.Validation.Helpers;
-using ReactiveUI.Validation.Extensions;
-using InDepthSearch.Core.Services.Interfaces;
-
-namespace InDepthSearch.Core.ViewModels
-{
- public class MainViewModel : ReactiveValidationObject
- {
- public string Logo => "avares://InDepthSearch.UI/Assets/Images/ids-logo.png";
-
- [Reactive]
- public ObservableCollection Results { get; set; }
- [Reactive]
- public SearchOptions Options { get; set; }
- [Reactive]
- public ResultStats Stats { get; set; }
- [Reactive]
- public ObservableCollection PrecisionOCR { get; set; }
- [Reactive]
- public ObservableCollection LanguageOCR { get; set; }
- public ReactiveCommand ReadPDF { get; }
- public ReactiveCommand GetDirectory { get; }
- public ReactiveCommand ChangeTheme { get; }
- public ReactiveCommand ChangeLanguage { get; }
-
- [Reactive]
- public string ResultInfo { get; set; }
- [Reactive]
- public bool KeywordErrorVisible { get; set; }
- [Reactive]
- public bool PathErrorVisible { get; set; }
- [Reactive]
- public string AppVersion { get; set; }
- [Reactive]
- public string CurrentThemeName { get; set; }
- [Reactive]
- public string CurrentLanguageName { get; set; }
- [Reactive]
- public bool ItemsReady { get; set; }
- [Reactive]
- public string StatusName { get; set; }
-
- private Thread? _th;
- private readonly IDocLib _docLib;
- private readonly IOptionService _optionService;
- private readonly IDirectoryService _directoryService;
- private readonly IThemeService _themeService;
- private readonly IAppService _infoService;
-
- #region Empty constructor only for the designer
-#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
- public MainViewModel()
- {
- // Initialize variables
- PrecisionOCR = new ObservableCollection(Enum.GetValues(typeof(RecognitionPrecision)).Cast());
- LanguageOCR = new ObservableCollection(Enum.GetValues(typeof(RecognitionLanguage)).Cast());
- Options = new SearchOptions("", "", PrecisionOCR.FirstOrDefault(), LanguageOCR.FirstOrDefault(),
- false, true, false, true, false, false);
- Results = new ObservableCollection();
- Stats = new ResultStats("0/0", true, 0, "0");
- StatusName = SearchStatus.Ready.ToString();
- ResultInfo = "Click search button to start";
- CurrentThemeName = Theme.Default.ToString().ToUpper();
- CurrentLanguageName = AppLanguage.English.ToString().ToUpper();
- ItemsReady = false;
-
- // Subscribe for events and set validation rules
- ErrorsChanged += OnValidationErrorsChanged;
- this.ValidationRule(x => x.Options.Keyword, key => !string.IsNullOrEmpty(key), "Keyword cannot be empty!");
- this.ValidationRule(x => x.Options.Path, key => !string.IsNullOrEmpty(key) && Directory.Exists(key), "Path has to be valid!");
-
- AppVersion = "x.x.x";
- }
-#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
- #endregion
- public MainViewModel(IOptionService optionService, IDirectoryService directoryService,
- IAppService infoService, IThemeService themeService)
- {
- // Initialize services
- _docLib = DocLib.Instance;
- _optionService = optionService;
- _directoryService = directoryService;
- _themeService = themeService;
- _infoService = infoService;
-
- // Initialize commands
- GetDirectory = ReactiveCommand.Create(BrowseDirectory);
- ReadPDF = ReactiveCommand.Create(() => {
- _th = new Thread(() => StartReading());
- _th.IsBackground = true;
- _th.Start();
- }, this.IsValid());
- ChangeTheme = ReactiveCommand.Create(() =>
- {
- themeService.ChangeTheme();
- CurrentThemeName = themeService.GetCurrentThemeName();
- });
- ChangeLanguage = ReactiveCommand.Create(() =>
- {
- infoService.ChangeLanguage();
- CurrentLanguageName = infoService.GetCurrentLanguage();
- UpdateStringResources();
- });
-
- // Initialize variables
- PrecisionOCR = new ObservableCollection(Enum.GetValues(typeof(RecognitionPrecision)).Cast());
- LanguageOCR = new ObservableCollection(Enum.GetValues(typeof(RecognitionLanguage)).Cast());
- Options = new SearchOptions("", "", PrecisionOCR.FirstOrDefault(), LanguageOCR.FirstOrDefault(),
- false, true, false, true, false, false);
- Results = new ObservableCollection();
- Stats = new ResultStats("0/0", true, 0, "0");
- ResultInfo = infoService.GetSearchInfo(SearchInfo.Init);
- StatusName = infoService.GetSearchStatus(SearchStatus.Ready);
- CurrentThemeName = themeService.GetCurrentThemeName();
- CurrentLanguageName = infoService.GetCurrentLanguage();
- ItemsReady = false;
-
- // Subscribe for events and set validation rules
- ErrorsChanged += OnValidationErrorsChanged;
- this.ValidationRule(x => x.Options.Keyword, key => !string.IsNullOrEmpty(key), "Keyword cannot be empty!");
- this.ValidationRule(x => x.Options.Path, key => !string.IsNullOrEmpty(key) && Directory.Exists(key), "Path has to be valid!");
-
- // Get assembly version
- AppVersion = infoService.GetVersion();
-
- }
-
- private void UpdateStringResources()
- {
- CurrentThemeName = _themeService.GetCurrentThemeName();
- StatusName = _infoService.GetSearchStatus();
- ResultInfo = _infoService.GetSearchInfo();
- }
-
- private void OnValidationErrorsChanged(object? sender, System.ComponentModel.DataErrorsChangedEventArgs e)
- {
- KeywordErrorVisible = string.IsNullOrWhiteSpace(Options.Keyword);
- PathErrorVisible = !Directory.Exists(Options.Path);
- }
-
- void StartReading()
- {
- var searchOptions = Options;
-
- Results.Clear();
- StatusName = _infoService.GetSearchStatus(SearchStatus.Initializing);
- ItemsReady = false;
- Stats.IsReady = false;
- Stats.FilesAnalyzed = "0/0";
- Stats.PagesAnalyzed = 0;
- Stats.ExecutionTime = "...";
-
- var fileCounter = 0;
- var watch = System.Diagnostics.Stopwatch.StartNew();
-
- if (!string.IsNullOrWhiteSpace(searchOptions.Keyword))
- {
- List discoveredFiles = searchOptions.UseSubfolders ? Directory.GetFiles(searchOptions.Path, "*.pdf", SearchOption.AllDirectories).ToList()
- : Directory.GetFiles(searchOptions.Path, "*.pdf").ToList();
-
- if (discoveredFiles == null)
- {
- System.Diagnostics.Debug.WriteLine("No files found... ");
- return;
- }
-
- StatusName = _infoService.GetSearchStatus(SearchStatus.Running);
- ResultInfo = _infoService.GetSearchInfo(SearchInfo.Init);
- Stats.FilesAnalyzed = "0/" + discoveredFiles.Count.ToString();
-
- foreach (var pdf in discoveredFiles)
- {
- System.Diagnostics.Debug.WriteLine("Checking " + pdf);
- using var docReader = _docLib.GetDocReader(pdf, _optionService.TranslatePrecision(searchOptions.SelectedPrecisionOCR).Item1);
-
- for (var i = 0; i < docReader.GetPageCount(); i++)
- {
- using var pageReader = docReader.GetPageReader(i);
- var parsedText = pageReader.GetText().ToString();
-
- if (searchOptions.UseOCR && string.IsNullOrWhiteSpace(parsedText))
- {
- var rawBytes = pageReader.GetImage(_optionService.TranslatePrecision(searchOptions.SelectedPrecisionOCR).Item2);
- var width = pageReader.GetPageWidth();
- var height = pageReader.GetPageHeight();
- using var bmp = new Bitmap(width, height, _optionService.TranslatePrecision(searchOptions.SelectedPrecisionOCR).Item3);
-
- AddBytes(bmp, rawBytes);
- using var stream = new MemoryStream();
- bmp.Save(stream, _optionService.TranslatePrecision(searchOptions.SelectedPrecisionOCR).Item4);
-
- parsedText = ImageToText(stream.ToArray(), searchOptions.SelectedLanguageOCR, searchOptions.SelectedPrecisionOCR);
- }
-
- SearchPage(parsedText, searchOptions.Keyword, pdf, i, searchOptions.CaseSensitive);
- Stats.PagesAnalyzed += 1;
-
- }
- fileCounter += 1;
- Stats.FilesAnalyzed = fileCounter.ToString() + "/" + discoveredFiles.Count.ToString();
- }
- }
-
- watch.Stop();
- var elapsedMs = watch.ElapsedMilliseconds;
- System.Diagnostics.Debug.WriteLine("Total execution " + elapsedMs);
- Stats.ExecutionTime = (elapsedMs / 1000.0).ToString() + " " + _infoService.GetSecondsString();
- Stats.IsReady = true;
- StatusName = _infoService.GetSearchStatus(SearchStatus.Ready);
- if (!Results.Any())
- {
- ResultInfo = _infoService.GetSearchInfo(SearchInfo.NoResults);
- ItemsReady = false;
- }
- }
-
- private static void AddBytes(Bitmap bmp, byte[] rawBytes)
- {
- var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
-
- var bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
- var pNative = bmpData.Scan0;
-
- Marshal.Copy(rawBytes, 0, pNative, rawBytes.Length);
- bmp.UnlockBits(bmpData);
- }
-
- string ImageToText(byte[] imageBytes, RecognitionLanguage rl, RecognitionPrecision rp)
- {
- try
- {
- using var engine = new TesseractEngine(@"./Files", _optionService.TranslateLanguage(rl), EngineMode.Default);
- using var img = _optionService.TranslatePrecision(rp).Item4 == System.Drawing.Imaging.ImageFormat.Tiff ?
- Pix.LoadTiffFromMemory(imageBytes) : Pix.LoadFromMemory(imageBytes);
- using var pager = engine.Process(img);
- return pager.GetText().ToString();
- //System.Diagnostics.Debug.WriteLine("Mean confidence: {0}", pager.GetMeanConfidence());
- //System.Diagnostics.Debug.WriteLine("Text {0}", text);
- }
- catch (Exception ee)
- {
- System.Diagnostics.Debug.WriteLine("Unexpected Error: " + ee.Message);
- System.Diagnostics.Debug.WriteLine("Details: ");
- System.Diagnostics.Debug.WriteLine(ee.ToString());
- }
-
- return "";
- }
-
- void SearchPage(string rawText, string keyword, string filePath, int pageNum, bool isCaseSensitive)
- {
-
- var searchIndex = 0;
- var at = 0;
- string textBefore, textFound, textAfter;
- var offset = 30;
- var text = rawText.Replace("\n", " ").Replace("\r", " ");
-
- while (at > -1)
- {
- if (!ItemsReady) ItemsReady = true;
- at = isCaseSensitive ? text.IndexOf(keyword, searchIndex) : text.ToLower().IndexOf(keyword.ToLower(), searchIndex);
- if (at == -1) break;
- System.Diagnostics.Debug.WriteLine("Found the keyword " + keyword + " in doc: " + filePath + " on page " + pageNum + " at " + at + " position!");
- textBefore = "..." + text.Substring(Math.Max(0, at - offset), at < offset ? at : offset);
- textAfter = text.Substring(at + keyword.Length, at + keyword.Length + offset > text.Length ? text.Length - at - keyword.Length : offset) + "...";
- textFound = text.Substring(at, keyword.Length);
- Results.Add(new QueryResult(MatchConfidence.High, filePath, textBefore,
- textFound, textAfter, pageNum));
- searchIndex = at + keyword.Length;
- }
- }
-
- async void BrowseDirectory()
- {
- var newDir = await _directoryService.ChooseDirectory();
- if (!string.IsNullOrEmpty(newDir))
- Options.Path = newDir;
- }
-
- }
-
-}
diff --git a/InDepthSearch.Core/ViewModels/MainWindowViewModel.cs b/InDepthSearch.Core/ViewModels/MainWindowViewModel.cs
new file mode 100644
index 0000000..d7c971a
--- /dev/null
+++ b/InDepthSearch.Core/ViewModels/MainWindowViewModel.cs
@@ -0,0 +1,152 @@
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reactive;
+using System.Runtime.InteropServices;
+using System.Linq;
+using System.Collections.ObjectModel;
+using InDepthSearch.Core.Models;
+using InDepthSearch.Core.Enums;
+using System.Threading;
+using InDepthSearch.Core.Services.Interfaces;
+using System.Diagnostics;
+using InDepthSearch.Core.Managers.Interfaces;
+
+namespace InDepthSearch.Core.ViewModels
+{
+ public class MainWindowViewModel: ViewModelBase
+ {
+ private readonly IThemeService _themeService;
+ private readonly IAppService _infoService;
+ private readonly ISearchService _searchService;
+
+ public MainWindowViewModel(IAppService infoService, IThemeService themeService, IResultManager resultManager, ISearchService searchService,
+ ResultsViewModel.Factory resultsFactory, OptionsViewModel.Factory optionsFactory)
+ {
+ // Initialize services
+ _themeService = themeService;
+ _infoService = infoService;
+ _searchService = searchService;
+ ResultManager = resultManager;
+
+ ResultsPage = resultsFactory();
+ OptionsMenu = optionsFactory(StartReading);
+
+ ChangeTheme = ReactiveCommand.Create(() =>
+ {
+ themeService.ChangeTheme();
+ CurrentThemeName = themeService.GetCurrentThemeName();
+ });
+ ChangeLanguage = ReactiveCommand.Create(() =>
+ {
+ infoService.ChangeLanguage();
+ CurrentLanguageName = infoService.GetCurrentLanguage();
+ UpdateStringResources();
+ });
+ OpenUrl = ReactiveCommand.Create(() =>
+ {
+ var url = "https://github.com/radoslawik/InDepthSearch";
+ using var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? url : "open",
+ Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? $"-e {url}" : "",
+ CreateNoWindow = true,
+ UseShellExecute = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+ });
+ });
+
+ // Initialize variables
+ StatusName = infoService.GetSearchStatus(SearchStatus.Ready);
+ CurrentThemeName = themeService.GetCurrentThemeName();
+ CurrentLanguageName = infoService.GetCurrentLanguage();
+
+ // Get assembly version
+ AppVersion = infoService.GetVersion();
+ }
+ public IResultManager ResultManager { get; }
+ public ResultsViewModel ResultsPage { get; }
+ public OptionsViewModel OptionsMenu { get; }
+
+ public ReactiveCommand ChangeTheme { get; }
+ public ReactiveCommand ChangeLanguage { get; }
+ public ReactiveCommand OpenUrl { get; }
+
+ [Reactive]
+ public string AppVersion { get; set; }
+ [Reactive]
+ public string CurrentThemeName { get; set; }
+ [Reactive]
+ public string CurrentLanguageName { get; set; }
+ [Reactive]
+ public string StatusName { get; set; }
+
+ private void UpdateStringResources()
+ {
+ CurrentThemeName = _themeService.GetCurrentThemeName();
+ StatusName = _infoService.GetSearchStatus();
+ ResultsPage.UpdateResultInfo(_infoService.GetSearchInfo());
+ }
+
+ private void StartReading(SearchOptions searchOptions)
+ {
+ StatusName = _infoService.GetSearchStatus(SearchStatus.Initializing);
+ ResultManager.Reinitialize();
+
+ var fileCounter = 0;
+ var watch = System.Diagnostics.Stopwatch.StartNew();
+
+ if (!string.IsNullOrWhiteSpace(searchOptions.Keyword))
+ {
+ var allowedExtensions = new List();
+
+ if (searchOptions.UsePDF)
+ allowedExtensions.Add(".pdf");
+ if (searchOptions.UseDOCX)
+ allowedExtensions.Add(".docx");
+ if (searchOptions.UseDOC)
+ allowedExtensions.Add(".doc");
+ if (searchOptions.UseODT)
+ allowedExtensions.Add(".odt");
+
+ List discoveredFiles = searchOptions.UseSubfolders ?
+ Directory.GetFiles(searchOptions.Path, "*.*", SearchOption.AllDirectories)
+ .Where(file => allowedExtensions.Any(file.ToLower().EndsWith)).ToList() :
+ Directory.GetFiles(searchOptions.Path)
+ .Where(file => allowedExtensions.Any(file.ToLower().EndsWith)).ToList();
+
+ if (discoveredFiles == null)
+ {
+ System.Diagnostics.Debug.WriteLine("No files found... ");
+ return;
+ }
+
+ StatusName = _infoService.GetSearchStatus(SearchStatus.Running);
+ ResultsPage.UpdateResultInfo(_infoService.GetSearchInfo(SearchInfo.Init));
+ ResultManager.Stats.FilesAnalyzed = "0/" + discoveredFiles.Count.ToString();
+
+ foreach (var file in discoveredFiles)
+ {
+ System.Diagnostics.Debug.WriteLine("Checking " + file);
+
+ _searchService.Search(file, searchOptions);
+ fileCounter += 1;
+ ResultManager.Stats.FilesAnalyzed = fileCounter.ToString() + "/" + discoveredFiles.Count.ToString();
+ }
+ }
+
+ watch.Stop();
+ var elapsedMs = watch.ElapsedMilliseconds;
+ System.Diagnostics.Debug.WriteLine("Total execution " + elapsedMs);
+ ResultManager.Stats.ExecutionTime = (elapsedMs / 1000.0).ToString() + " " + _infoService.GetSecondsString();
+ StatusName = _infoService.GetSearchStatus(SearchStatus.Ready);
+ if (!ResultManager.Results.Any())
+ {
+ ResultsPage.UpdateResultInfo(_infoService.GetSearchInfo(SearchInfo.NoResults));
+ ResultManager.SetItemsReady(false);
+ }
+ }
+ }
+
+}
diff --git a/InDepthSearch.Core/ViewModels/OptionsViewModel.cs b/InDepthSearch.Core/ViewModels/OptionsViewModel.cs
new file mode 100644
index 0000000..17a41bf
--- /dev/null
+++ b/InDepthSearch.Core/ViewModels/OptionsViewModel.cs
@@ -0,0 +1,71 @@
+using InDepthSearch.Core.Enums;
+using InDepthSearch.Core.Models;
+using InDepthSearch.Core.Services.Interfaces;
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Reactive;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace InDepthSearch.Core.ViewModels
+{
+ public class OptionsViewModel : ViewModelBase
+ {
+ private Thread? _th;
+ public delegate OptionsViewModel Factory(Action startSearch);
+ public OptionsViewModel(IDirectoryService dirService, Action startSearch)
+ {
+ PrecisionOCR = new(Enum.GetValues(typeof(RecognitionPrecision)).Cast());
+ LanguageOCR = new(Enum.GetValues(typeof(RecognitionLanguage)).Cast());
+ Options = new();
+
+ // Initialize commands
+ GetDirectory = ReactiveCommand.CreateFromTask(async() =>
+ {
+ var newDir = await dirService.ChooseDirectory();
+ if (!string.IsNullOrEmpty(newDir))
+ {
+ Options.Path = newDir;
+ }
+ });
+
+ ReadPDF = ReactiveCommand.Create(() =>
+ {
+ _th = new(() => startSearch(Options));
+ _th.IsBackground = true;
+ _th.Start();
+ });
+
+ // Subscribe to validation values
+ this.WhenAnyValue(x => x.Options.Keyword, x => x.Options.Path, x => x.Options.UseDOC, x => x.Options.UseDOCX,
+ x => x.Options.UsePDF, x => x.Options.UseODT).Subscribe(x => ValidateSelection());
+ }
+ [Reactive]
+ public SearchOptions Options { get; set; }
+ [Reactive]
+ public ObservableCollection PrecisionOCR { get; set; }
+ [Reactive]
+ public ObservableCollection LanguageOCR { get; set; }
+ public ReactiveCommand ReadPDF { get; }
+ public ReactiveCommand GetDirectory { get; }
+ public bool KeywordErrorVisible => string.IsNullOrWhiteSpace(Options.Keyword);
+ public bool PathErrorVisible => !Directory.Exists(Options.Path);
+ public bool CanExecute => !KeywordErrorVisible && !PathErrorVisible;
+ public static string Logo => "avares://InDepthSearch.UI/Assets/Images/ids-logo.png";
+
+ private void ValidateSelection()
+ {
+ this.RaisePropertyChanged(nameof(PathErrorVisible));
+ this.RaisePropertyChanged(nameof(KeywordErrorVisible));
+ this.RaisePropertyChanged(nameof(CanExecute));
+ }
+ }
+
+
+}
diff --git a/InDepthSearch.Core/ViewModels/ResultsViewModel.cs b/InDepthSearch.Core/ViewModels/ResultsViewModel.cs
new file mode 100644
index 0000000..cb11ad0
--- /dev/null
+++ b/InDepthSearch.Core/ViewModels/ResultsViewModel.cs
@@ -0,0 +1,38 @@
+using InDepthSearch.Core.Enums;
+using InDepthSearch.Core.Managers.Interfaces;
+using InDepthSearch.Core.Services.Interfaces;
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InDepthSearch.Core.ViewModels
+{
+ public class ResultsViewModel : ViewModelBase
+ {
+ public delegate ResultsViewModel Factory();
+ public ResultsViewModel(IResultManager resultManager, IAppService appService)
+ {
+ ResultManager = resultManager;
+ ResultInfo = appService.GetSearchInfo(SearchInfo.Init);
+ ResultManager.Results.CollectionChanged += (s, e) => Teestc();
+ }
+
+ private void Teestc()
+ {
+ var test = ResultManager.Results.Count;
+ this.RaisePropertyChanged(nameof(ResultManager));
+ }
+
+ public IResultManager ResultManager { get; }
+ [Reactive]
+ public string ResultInfo { get; set; }
+ public void UpdateResultInfo(string info)
+ {
+ ResultInfo = info;
+ }
+ }
+}
diff --git a/InDepthSearch.Core/ViewModels/ViewModelBase.cs b/InDepthSearch.Core/ViewModels/ViewModelBase.cs
new file mode 100644
index 0000000..7a40aab
--- /dev/null
+++ b/InDepthSearch.Core/ViewModels/ViewModelBase.cs
@@ -0,0 +1,8 @@
+using ReactiveUI;
+
+namespace InDepthSearch.Core.ViewModels
+{
+ public abstract class ViewModelBase : ReactiveObject
+ {
+ }
+}
diff --git a/InDepthSearch.Tests/Services/OptionServiceTest.cs b/InDepthSearch.Tests/Services/OptionServiceTest.cs
index 2797545..fdd41a3 100644
--- a/InDepthSearch.Tests/Services/OptionServiceTest.cs
+++ b/InDepthSearch.Tests/Services/OptionServiceTest.cs
@@ -1,12 +1,13 @@
using InDepthSearch.Core.Services;
using InDepthSearch.Core.Services.Interfaces;
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
using Xunit;
namespace InDepthSearch.Tests.Services
{
public class OptionServiceTest
{
+ /*
private readonly IOptionService _optionService;
public OptionServiceTest()
@@ -19,6 +20,7 @@ public void TranslateLanguageTest()
{
Assert.Equal("eng", _optionService.TranslateLanguage(RecognitionLanguage.Default));
}
+ */
}
}
diff --git a/InDepthSearch.Tests/ViewModels/MainViewModelTest.cs b/InDepthSearch.Tests/ViewModels/MainViewModelTest.cs
index 8a23015..c10afb6 100644
--- a/InDepthSearch.Tests/ViewModels/MainViewModelTest.cs
+++ b/InDepthSearch.Tests/ViewModels/MainViewModelTest.cs
@@ -8,11 +8,12 @@ namespace InDepthSearch.Tests.ViewModels
{
public class MainViewModelTest
{
- private readonly MainViewModel _mainViewModel;
+ /*
+ private readonly MainWindowViewModel _mainViewModel;
public MainViewModelTest()
{
- _mainViewModel = new MainViewModel(); // TODO implement mocked services
+ _mainViewModel = new MainWindowViewModel(); // TODO implement mocked services
}
[Fact]
@@ -23,5 +24,6 @@ public void ReadPdfTest()
_mainViewModel.ReadPDF.Execute().Subscribe();
Assert.Empty(_mainViewModel.Results);
}
+ */
}
}
diff --git a/InDepthSearch.UI/App.axaml b/InDepthSearch.UI/App.axaml
index 01c8f40..fc2e263 100644
--- a/InDepthSearch.UI/App.axaml
+++ b/InDepthSearch.UI/App.axaml
@@ -16,8 +16,8 @@
+
-
diff --git a/InDepthSearch.UI/App.axaml.cs b/InDepthSearch.UI/App.axaml.cs
index 3ae1c49..b76b564 100644
--- a/InDepthSearch.UI/App.axaml.cs
+++ b/InDepthSearch.UI/App.axaml.cs
@@ -2,9 +2,10 @@
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using InDepthSearch.Core.Services;
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
using InDepthSearch.Core.ViewModels;
using InDepthSearch.UI.Views;
+using Avalonia.Controls;
namespace InDepthSearch.UI
{
@@ -21,11 +22,10 @@ public override void OnFrameworkInitializationCompleted()
{
desktop.MainWindow = new MainWindow
{
- DataContext = new MainViewModel(new OptionService(), new DirectoryService(),
- new AppService(AppLanguage.English), new ThemeService(Theme.Light))
+ DataContext = (Current.FindResource("vmLocator") as ViewModelLocator)!.MainWindow
};
+ desktop.MainWindow.Closed += (s, e) => (Current.FindResource("vmLocator") as ViewModelLocator)!.Dispose();
}
-
base.OnFrameworkInitializationCompleted();
}
}
diff --git a/InDepthSearch.UI/Assets/Resources/BaseResources.xaml b/InDepthSearch.UI/Assets/Resources/BaseResources.xaml
new file mode 100644
index 0000000..f73f567
--- /dev/null
+++ b/InDepthSearch.UI/Assets/Resources/BaseResources.xaml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/InDepthSearch.UI/Assets/Resources/Icons.xaml b/InDepthSearch.UI/Assets/Resources/Icons.xaml
index 5cca975..6e3e668 100644
--- a/InDepthSearch.UI/Assets/Resources/Icons.xaml
+++ b/InDepthSearch.UI/Assets/Resources/Icons.xaml
@@ -10,9 +10,12 @@
M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z
- M12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,2L14.39,5.42C13.65,5.15 12.84,5 12,5C11.16,5 10.35,5.15 9.61,5.42L12,2M3.34,7L7.5,6.65C6.9,7.16 6.36,7.78 5.94,8.5C5.5,9.24 5.25,10 5.11,10.79L3.34,7M3.36,17L5.12,13.23C5.26,14 5.53,14.78 5.95,15.5C6.37,16.24 6.91,16.86 7.5,17.37L3.36,17M20.65,7L18.88,10.79C18.74,10 18.47,9.23 18.05,8.5C17.63,7.78 17.1,7.15 16.5,6.64L20.65,7M20.64,17L16.5,17.36C17.09,16.85 17.62,16.22 18.04,15.5C18.46,14.77 18.73,14 18.87,13.21L20.64,17M12,22L9.59,18.56C10.33,18.83 11.14,19 12,19C12.82,19 13.63,18.83 14.37,18.56L12,22Z
+ M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z
+
+
+ M16.36,14C16.44,13.34 16.5,12.68 16.5,12C16.5,11.32 16.44,10.66 16.36,10H19.74C19.9,10.64 20,11.31 20,12C20,12.69 19.9,13.36 19.74,14M14.59,19.56C15.19,18.45 15.65,17.25 15.97,16H18.92C17.96,17.65 16.43,18.93 14.59,19.56M14.34,14H9.66C9.56,13.34 9.5,12.68 9.5,12C9.5,11.32 9.56,10.65 9.66,10H14.34C14.43,10.65 14.5,11.32 14.5,12C14.5,12.68 14.43,13.34 14.34,14M12,19.96C11.17,18.76 10.5,17.43 10.09,16H13.91C13.5,17.43 12.83,18.76 12,19.96M8,8H5.08C6.03,6.34 7.57,5.06 9.4,4.44C8.8,5.55 8.35,6.75 8,8M5.08,16H8C8.35,17.25 8.8,18.45 9.4,19.56C7.57,18.93 6.03,17.65 5.08,16M4.26,14C4.1,13.36 4,12.69 4,12C4,11.31 4.1,10.64 4.26,10H7.64C7.56,10.66 7.5,11.32 7.5,12C7.5,12.68 7.56,13.34 7.64,14M12,4.03C12.83,5.23 13.5,6.57 13.91,8H10.09C10.5,6.57 11.17,5.23 12,4.03M18.92,8H15.97C15.65,6.75 15.19,5.55 14.59,4.44C16.43,5.07 17.96,6.34 18.92,8M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z
+
+
+ M11,8v5l4.25,2.52l0.77-1.28l-3.52-2.09V8H11z M21,10V3l-2.64,2.64C16.74,4.01,14.49,3,12,3c-4.97,0-9,4.03-9,9 s4.03,9,9,9s9-4.03,9-9h-2c0,3.86-3.14,7-7,7s-7-3.14-7-7s3.14-7,7-7c1.93,0,3.68,0.79,4.95,2.05L14,10H21z
-
- M16.36,14C16.44,13.34 16.5,12.68 16.5,12C16.5,11.32 16.44,10.66 16.36,10H19.74C19.9,10.64 20,11.31 20,12C20,12.69 19.9,13.36 19.74,14M14.59,19.56C15.19,18.45 15.65,17.25 15.97,16H18.92C17.96,17.65 16.43,18.93 14.59,19.56M14.34,14H9.66C9.56,13.34 9.5,12.68 9.5,12C9.5,11.32 9.56,10.65 9.66,10H14.34C14.43,10.65 14.5,11.32 14.5,12C14.5,12.68 14.43,13.34 14.34,14M12,19.96C11.17,18.76 10.5,17.43 10.09,16H13.91C13.5,17.43 12.83,18.76 12,19.96M8,8H5.08C6.03,6.34 7.57,5.06 9.4,4.44C8.8,5.55 8.35,6.75 8,8M5.08,16H8C8.35,17.25 8.8,18.45 9.4,19.56C7.57,18.93 6.03,17.65 5.08,16M4.26,14C4.1,13.36 4,12.69 4,12C4,11.31 4.1,10.64 4.26,10H7.64C7.56,10.66 7.5,11.32 7.5,12C7.5,12.68 7.56,13.34 7.64,14M12,4.03C12.83,5.23 13.5,6.57 13.91,8H10.09C10.5,6.57 11.17,5.23 12,4.03M18.92,8H15.97C15.65,6.75 15.19,5.55 14.59,4.44C16.43,5.07 17.96,6.34 18.92,8M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z
-
\ No newline at end of file
diff --git a/InDepthSearch.UI/Assets/Resources/StringsENG.xaml b/InDepthSearch.UI/Assets/Resources/StringsENG.xaml
index 4177d90..13cc270 100644
--- a/InDepthSearch.UI/Assets/Resources/StringsENG.xaml
+++ b/InDepthSearch.UI/Assets/Resources/StringsENG.xaml
@@ -38,6 +38,7 @@
Choose precision of OCR engine. Setting better precision may cause the search to take more time.
Keyword cannot be empty!
Path doesn't exist!
+ Choose at least one format!
Word or phrase to find
diff --git a/InDepthSearch.UI/Assets/Resources/StringsFRA.xaml b/InDepthSearch.UI/Assets/Resources/StringsFRA.xaml
index c1a81b8..cb46138 100644
--- a/InDepthSearch.UI/Assets/Resources/StringsFRA.xaml
+++ b/InDepthSearch.UI/Assets/Resources/StringsFRA.xaml
@@ -37,7 +37,8 @@
Choisissez la précision du moteur OCR. La définition d'une meilleure précision peut entraîner une durée de recherche plus longue.
Le mot-clé ne peut pas être vide!
Le dossier n'existe pas!
-
+ Choisissez au moins un format!
+
Mot ou phrase à trouver
Dossier à rechercher
diff --git a/InDepthSearch.UI/Assets/Resources/StringsPOL.xaml b/InDepthSearch.UI/Assets/Resources/StringsPOL.xaml
index 2ff6e73..c88f8b3 100644
--- a/InDepthSearch.UI/Assets/Resources/StringsPOL.xaml
+++ b/InDepthSearch.UI/Assets/Resources/StringsPOL.xaml
@@ -37,6 +37,7 @@
Wybierz precyzję silnika OCR. Lepsza precyzja może pogorszyć czas szukania.
Słowo kluczowe nie może być puste!
Wybrany folder nie istnieje!
+ Wybierz co najmniej jeden format!
Słowo albo wyrażenie do wyszukania
diff --git a/InDepthSearch.UI/AvaloniaStartup.cs b/InDepthSearch.UI/AvaloniaStartup.cs
index 85cc455..8571f87 100644
--- a/InDepthSearch.UI/AvaloniaStartup.cs
+++ b/InDepthSearch.UI/AvaloniaStartup.cs
@@ -1,7 +1,5 @@
using Avalonia;
-using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.ReactiveUI;
-using System;
namespace InDepthSearch.UI
{
diff --git a/InDepthSearch.UI/Helpers/FluentWindow.cs b/InDepthSearch.UI/Controls/FluentWindow.cs
similarity index 95%
rename from InDepthSearch.UI/Helpers/FluentWindow.cs
rename to InDepthSearch.UI/Controls/FluentWindow.cs
index 7f4d1e9..18c8edd 100644
--- a/InDepthSearch.UI/Helpers/FluentWindow.cs
+++ b/InDepthSearch.UI/Controls/FluentWindow.cs
@@ -1,12 +1,12 @@
using Avalonia.Styling;
using System;
-using System.Collections.Generic;
-using System.Text;
using Avalonia.Platform;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
+using Avalonia.Controls;
+using Avalonia;
-namespace Avalonia.Controls
+namespace InDepthSearch.UI.Controls
{
public class FluentWindow : Window, IStyleable
{
diff --git a/InDepthSearch.UI/Helpers/Conversion.cs b/InDepthSearch.UI/Helpers/Conversion.cs
new file mode 100644
index 0000000..9e686f8
--- /dev/null
+++ b/InDepthSearch.UI/Helpers/Conversion.cs
@@ -0,0 +1,21 @@
+using InDepthSearch.Core.Enums;
+using System;
+using System.Collections.Generic;
+using System.Drawing.Imaging;
+
+namespace InDepthSearch.UI.Helpers
+{
+ public static class Conversion
+ {
+ public static ImageFormat ImageExtensionToFormat(ImageExtension ie)
+ {
+ return ie switch
+ {
+ ImageExtension.Jpg => ImageFormat.Jpeg,
+ ImageExtension.Png => ImageFormat.Png,
+ ImageExtension.Bmp => ImageFormat.Bmp,
+ _ => ImageFormat.Png,
+ };
+ }
+ }
+}
diff --git a/InDepthSearch.UI/InDepthSearch.UI.csproj b/InDepthSearch.UI/InDepthSearch.UI.csproj
index 7965cc9..833ce9f 100644
--- a/InDepthSearch.UI/InDepthSearch.UI.csproj
+++ b/InDepthSearch.UI/InDepthSearch.UI.csproj
@@ -4,13 +4,14 @@
net5.0
enable
Assets\Images\ids-icon.ico
- 0.2.0
+ 1.0.0
+
diff --git a/InDepthSearch.UI/Managers/ResultManager.cs b/InDepthSearch.UI/Managers/ResultManager.cs
new file mode 100644
index 0000000..e03588c
--- /dev/null
+++ b/InDepthSearch.UI/Managers/ResultManager.cs
@@ -0,0 +1,36 @@
+using InDepthSearch.Core.Managers.Interfaces;
+using InDepthSearch.Core.Models;
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
+using System.Collections.ObjectModel;
+
+namespace InDepthSearch.UI.Managers
+{
+ public class ResultManager : ReactiveObject, IResultManager
+ {
+ public ResultManager()
+ {
+ Results = new();
+ Stats = new();
+ }
+
+ [Reactive]
+ public ObservableCollection Results { get; }
+ [Reactive]
+ public ResultStats Stats { get; set; }
+ [Reactive]
+ public bool ItemsReady { get; set; }
+
+ public void Reinitialize()
+ {
+ Results.Clear();
+ ItemsReady = false;
+ Stats.FilesAnalyzed = "0/0";
+ Stats.PagesAnalyzed = 0;
+ Stats.ExecutionTime = "";
+ }
+
+ public void AddResult(QueryResult res) => Results.Add(res);
+ public void SetItemsReady(bool ready) => ItemsReady = ready;
+ }
+}
diff --git a/InDepthSearch.Core/Services/AppService.cs b/InDepthSearch.UI/Services/AppService.cs
similarity index 52%
rename from InDepthSearch.Core/Services/AppService.cs
rename to InDepthSearch.UI/Services/AppService.cs
index ac5e8a7..674ab4b 100644
--- a/InDepthSearch.Core/Services/AppService.cs
+++ b/InDepthSearch.UI/Services/AppService.cs
@@ -1,35 +1,29 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml.MarkupExtensions;
using InDepthSearch.Core.Services.Interfaces;
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using Avalonia.Controls.ApplicationLifetimes;
-namespace InDepthSearch.Core.Services
+namespace InDepthSearch.UI.Services
{
public class AppService : IAppService
{
private readonly List _languages;
- private int currentLanguage;
- private SearchStatus status;
- private SearchInfo info;
+ private int currentLanguage = 0;
+ private SearchStatus status = SearchStatus.Ready;
+ private SearchInfo info = SearchInfo.Init;
- public AppService(AppLanguage lang)
+ public AppService()
{
+ var basePath = "avares://InDepthSearch.UI/Assets/Resources/";
_languages = new List()
{
- new ResourceInclude() { Source = new Uri("avares://InDepthSearch.UI/Assets/Resources/StringsENG.xaml") },
- new ResourceInclude() { Source = new Uri("avares://InDepthSearch.UI/Assets/Resources/StringsPOL.xaml") },
- new ResourceInclude() { Source = new Uri("avares://InDepthSearch.UI/Assets/Resources/StringsFRA.xaml") },
+ new() { Source = new Uri($"{basePath}StringsENG.xaml") },
+ new() { Source = new Uri($"{basePath}StringsPOL.xaml") },
+ new() { Source = new Uri($"{basePath}StringsFRA.xaml") },
};
-
- currentLanguage = (int)lang;
- status = SearchStatus.Ready;
- info = SearchInfo.Init;
-
}
public string GetVersion()
@@ -37,7 +31,6 @@ public string GetVersion()
var assemblyVer = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
return assemblyVer != null ? assemblyVer.Major.ToString() + "." + assemblyVer.Minor.ToString() + "."
+ assemblyVer.Build.ToString() : "x.x.x";
-
}
public void ChangeLanguage()
@@ -59,9 +52,9 @@ public string GetSearchStatus(SearchStatus ss = SearchStatus.Unknown)
return ss switch
{
- SearchStatus.Ready => (string?)Avalonia.Application.Current.FindResource("StatusReady") ?? ss.ToString().ToUpper(),
- SearchStatus.Initializing => (string?)Avalonia.Application.Current.FindResource("StatusInitializing") ?? ss.ToString().ToUpper(),
- SearchStatus.Running => (string?)Avalonia.Application.Current.FindResource("StatusRunning") ?? ss.ToString().ToUpper(),
+ SearchStatus.Ready => GetResourceString("StatusReady") ?? ss.ToString().ToUpper(),
+ SearchStatus.Initializing => GetResourceString("StatusInitializing") ?? ss.ToString().ToUpper(),
+ SearchStatus.Running => GetResourceString("StatusRunning") ?? ss.ToString().ToUpper(),
_ => ss.ToString().ToUpper()
};
}
@@ -73,16 +66,21 @@ public string GetSearchInfo(SearchInfo si = SearchInfo.Unknown)
return si switch
{
- SearchInfo.Init => (string?)Avalonia.Application.Current.FindResource("InfoInit") ?? si.ToString(),
- SearchInfo.Run => (string?)Avalonia.Application.Current.FindResource("InfoRun") ?? si.ToString(),
- SearchInfo.NoResults => (string?)Avalonia.Application.Current.FindResource("InfoNoResults") ?? si.ToString(),
+ SearchInfo.Init => GetResourceString("InfoInit") ?? si.ToString(),
+ SearchInfo.Run => GetResourceString("InfoRun") ?? si.ToString(),
+ SearchInfo.NoResults => GetResourceString("InfoNoResults") ?? si.ToString(),
_ => si.ToString()
};
}
public string GetSecondsString()
{
- return (string?)Avalonia.Application.Current.FindResource("TimeSeconds") ?? "seconds";
+ return GetResourceString("TimeSeconds") ?? "seconds";
+ }
+
+ private string? GetResourceString(string key)
+ {
+ return (string?)Avalonia.Application.Current.FindResource(key);
}
}
diff --git a/InDepthSearch.Core/Services/DirectoryService.cs b/InDepthSearch.UI/Services/DirectoryService.cs
similarity index 95%
rename from InDepthSearch.Core/Services/DirectoryService.cs
rename to InDepthSearch.UI/Services/DirectoryService.cs
index 1536fb4..03feca5 100644
--- a/InDepthSearch.Core/Services/DirectoryService.cs
+++ b/InDepthSearch.UI/Services/DirectoryService.cs
@@ -7,7 +7,7 @@
using System.Text;
using System.Threading.Tasks;
-namespace InDepthSearch.Core.Services
+namespace InDepthSearch.UI.Services
{
public class DirectoryService : IDirectoryService
{
diff --git a/InDepthSearch.Core/Services/OptionService.cs b/InDepthSearch.UI/Services/OptionService.cs
similarity index 75%
rename from InDepthSearch.Core/Services/OptionService.cs
rename to InDepthSearch.UI/Services/OptionService.cs
index fccf7b9..cbd15d5 100644
--- a/InDepthSearch.Core/Services/OptionService.cs
+++ b/InDepthSearch.UI/Services/OptionService.cs
@@ -1,6 +1,6 @@
using Docnet.Core.Models;
using InDepthSearch.Core.Services.Interfaces;
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
@@ -12,17 +12,17 @@ namespace InDepthSearch.Core.Services
{
public class OptionService : IOptionService
{
- public (PageDimensions, RenderFlags, PixelFormat, ImageFormat) TranslatePrecision(RecognitionPrecision rp)
+ public (PageDimensions, RenderFlags, ImageExtension) TranslatePrecision(RecognitionPrecision rp)
{
return rp switch
{
RecognitionPrecision.High or RecognitionPrecision.Default =>
- (new PageDimensions(1080, 1920), RenderFlags.RenderAnnotations, PixelFormat.Format32bppArgb, ImageFormat.Png),
+ (new PageDimensions(1080, 1920), RenderFlags.RenderAnnotations, ImageExtension.Png),
RecognitionPrecision.Medium =>
- (new PageDimensions(720, 1280), RenderFlags.RenderAnnotations, PixelFormat.Format32bppArgb, ImageFormat.Jpeg),
+ (new PageDimensions(720, 1280), RenderFlags.RenderAnnotations, ImageExtension.Jpg),
RecognitionPrecision.Low =>
- (new PageDimensions(720, 1280), RenderFlags.RenderAnnotations | RenderFlags.OptimizeTextForLcd | RenderFlags.Grayscale, PixelFormat.Format32bppRgb, ImageFormat.Bmp),
- _ => (new PageDimensions(1080, 1920), RenderFlags.RenderAnnotations, PixelFormat.Format32bppArgb, ImageFormat.Png),
+ (new PageDimensions(720, 1280), RenderFlags.RenderAnnotations | RenderFlags.OptimizeTextForLcd | RenderFlags.Grayscale, ImageExtension.Bmp),
+ _ => (new PageDimensions(1080, 1920), RenderFlags.RenderAnnotations, ImageExtension.Png),
};
}
diff --git a/InDepthSearch.UI/Services/SearchService.cs b/InDepthSearch.UI/Services/SearchService.cs
new file mode 100644
index 0000000..e7c098c
--- /dev/null
+++ b/InDepthSearch.UI/Services/SearchService.cs
@@ -0,0 +1,152 @@
+
+using Docnet.Core;
+using DocumentFormat.OpenXml.Packaging;
+using InDepthSearch.Core.Enums;
+using InDepthSearch.Core.Managers.Interfaces;
+using InDepthSearch.Core.Models;
+using InDepthSearch.Core.Services.Interfaces;
+using InDepthSearch.UI.Helpers;
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Runtime.InteropServices;
+using Tesseract;
+
+namespace InDepthSearch.UI.Services
+{
+ public class SearchService : ISearchService
+ {
+ private readonly IDocLib _docLib;
+ private readonly IOptionService _optionService;
+ private readonly IResultManager _resultManager;
+ public SearchService(IOptionService optionService, IResultManager resultManager)
+ {
+ _docLib = DocLib.Instance;
+ _optionService = optionService;
+ _resultManager = resultManager;
+ }
+
+ public void Search(string file, SearchOptions searchOptions)
+ {
+ if(file.EndsWith(".pdf"))
+ {
+ HandlePDF(file, searchOptions);
+ }
+ else if (file.EndsWith(".docx") || file.EndsWith(".doc"))
+ {
+ HandleDOCX(file, searchOptions);
+ }
+ }
+
+ private void HandlePDF(string file, SearchOptions searchOptions)
+ {
+ using var docReader = _docLib.GetDocReader(file, _optionService.TranslatePrecision(searchOptions.SelectedPrecisionOCR).Item1);
+
+ for (var i = 0; i < docReader.GetPageCount(); i++)
+ {
+ using var pageReader = docReader.GetPageReader(i);
+ var parsedText = pageReader.GetText().ToString();
+
+ if (searchOptions.UseOCR && string.IsNullOrWhiteSpace(parsedText))
+ {
+ var rawBytes = pageReader.GetImage(_optionService.TranslatePrecision(searchOptions.SelectedPrecisionOCR).Item2);
+ var width = pageReader.GetPageWidth();
+ var height = pageReader.GetPageHeight();
+ var imFormat = Conversion.ImageExtensionToFormat(_optionService.TranslatePrecision(searchOptions.SelectedPrecisionOCR).Item3);
+ using var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
+
+ AddBytes(bmp, rawBytes);
+ using var stream = new MemoryStream();
+ bmp.Save(stream, Conversion.ImageExtensionToFormat(_optionService.TranslatePrecision(searchOptions.SelectedPrecisionOCR).Item3));
+
+ parsedText = ImageToText(stream.ToArray(), searchOptions.SelectedLanguageOCR, searchOptions.SelectedPrecisionOCR);
+ }
+
+ SearchPage(parsedText, searchOptions.Keyword, file, i, searchOptions.CaseSensitive);
+ _resultManager.Stats.PagesAnalyzed += 1;
+ }
+ }
+ private void HandleDOCX(string file, SearchOptions searchOptions)
+ {
+ using WordprocessingDocument wordDocument = WordprocessingDocument.Open(file, false);
+ var paragraphs = wordDocument.MainDocumentPart?.Document?.Body?.ChildElements;
+ var images = wordDocument.MainDocumentPart?.ImageParts;
+ if (searchOptions.UseOCR && images != null)
+ {
+ foreach (var image in images)
+ {
+ var docStream = wordDocument.Package.GetPart(image.Uri).GetStream();
+ using var stream = new MemoryStream();
+ docStream.CopyTo(stream);
+ var parsedText = ImageToText(stream.ToArray(), searchOptions.SelectedLanguageOCR, searchOptions.SelectedPrecisionOCR);
+ SearchPage(parsedText, searchOptions.Keyword, file, -1, searchOptions.CaseSensitive);
+ }
+ }
+
+ if (paragraphs != null)
+ {
+ var parsedString = "";
+ foreach (var paragraph in paragraphs)
+ parsedString = parsedString + paragraph.InnerText + "\r";
+
+ SearchPage(parsedString, searchOptions.Keyword, file, -1, searchOptions.CaseSensitive);
+ }
+ }
+
+ private static void AddBytes(Bitmap bmp, byte[] rawBytes)
+ {
+ var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
+
+ var bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
+ var pNative = bmpData.Scan0;
+
+ Marshal.Copy(rawBytes, 0, pNative, rawBytes.Length);
+ bmp.UnlockBits(bmpData);
+ }
+
+ string ImageToText(byte[] imageBytes, RecognitionLanguage rl, RecognitionPrecision rp)
+ {
+ try
+ {
+ using var engine = new TesseractEngine(@"./Files", _optionService.TranslateLanguage(rl), EngineMode.Default);
+ using var img = Pix.LoadFromMemory(imageBytes);
+ using var pager = engine.Process(img);
+ return pager.GetText().ToString();
+ //System.Diagnostics.Debug.WriteLine("Mean confidence: {0}", pager.GetMeanConfidence());
+ //System.Diagnostics.Debug.WriteLine("Text {0}", text);
+ }
+ catch (Exception ee)
+ {
+ System.Diagnostics.Debug.WriteLine("Unexpected Error: " + ee.Message);
+ System.Diagnostics.Debug.WriteLine("Details: ");
+ System.Diagnostics.Debug.WriteLine(ee.ToString());
+ }
+
+ return "";
+ }
+
+ void SearchPage(string rawText, string keyword, string filePath, int pageNum, bool isCaseSensitive)
+ {
+
+ var searchIndex = 0;
+ var at = 0;
+ string textBefore, textFound, textAfter;
+ var offset = 30;
+ var text = rawText.Replace("\n", " ").Replace("\r", " ");
+
+ while (at > -1)
+ {
+ if (!_resultManager.ItemsReady) _resultManager.SetItemsReady(true);
+ at = isCaseSensitive ? text.IndexOf(keyword, searchIndex) : text.ToLower().IndexOf(keyword.ToLower(), searchIndex);
+ if (at == -1) break;
+ System.Diagnostics.Debug.WriteLine("Found the keyword " + keyword + " in doc: " + filePath + " on page " + pageNum + " at " + at + " position!");
+ textBefore = "..." + text.Substring(Math.Max(0, at - offset), at < offset ? at : offset);
+ textAfter = text.Substring(at + keyword.Length, at + keyword.Length + offset > text.Length ? text.Length - at - keyword.Length : offset) + "...";
+ textFound = text.Substring(at, keyword.Length);
+ _resultManager.AddResult(new QueryResult(MatchConfidence.High, filePath, textBefore, textFound, textAfter, pageNum));
+ searchIndex = at + keyword.Length;
+ }
+ }
+ }
+}
diff --git a/InDepthSearch.Core/Services/ThemeService.cs b/InDepthSearch.UI/Services/ThemeService.cs
similarity index 91%
rename from InDepthSearch.Core/Services/ThemeService.cs
rename to InDepthSearch.UI/Services/ThemeService.cs
index a2df7a4..cb9cf8c 100644
--- a/InDepthSearch.Core/Services/ThemeService.cs
+++ b/InDepthSearch.UI/Services/ThemeService.cs
@@ -2,14 +2,10 @@
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml.Styling;
using InDepthSearch.Core.Services.Interfaces;
-using InDepthSearch.Core.Types;
+using InDepthSearch.Core.Enums;
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-namespace InDepthSearch.Core.Services
+namespace InDepthSearch.UI.Services
{
public class ThemeService : IThemeService
{
@@ -18,11 +14,10 @@ public class ThemeService : IThemeService
private Theme currentTheme = Theme.Light;
private Window? _window = null;
- public ThemeService(Theme theme)
+ public ThemeService()
{
_lightTheme = CreateStyle("avares://InDepthSearch.UI/Themes/Light.xaml");
_darkTheme = CreateStyle("avares://InDepthSearch.UI/Themes/Dark.xaml");
- currentTheme = theme;
}
private void InitDynamicThemes(Theme theme)
diff --git a/InDepthSearch.UI/Themes/Styles/ComboBoxStyle.xaml b/InDepthSearch.UI/Themes/Styles/ComboBoxStyle.xaml
index ecb3562..c995596 100644
--- a/InDepthSearch.UI/Themes/Styles/ComboBoxStyle.xaml
+++ b/InDepthSearch.UI/Themes/Styles/ComboBoxStyle.xaml
@@ -3,7 +3,7 @@
+
diff --git a/InDepthSearch.UI/Themes/Styles/TextBlockStyle.xaml b/InDepthSearch.UI/Themes/Styles/TextBlockStyle.xaml
index 51e1349..e566a03 100644
--- a/InDepthSearch.UI/Themes/Styles/TextBlockStyle.xaml
+++ b/InDepthSearch.UI/Themes/Styles/TextBlockStyle.xaml
@@ -19,7 +19,7 @@
diff --git a/InDepthSearch.UI/Helpers/ViewLocator.cs b/InDepthSearch.UI/ViewLocator.cs
similarity index 83%
rename from InDepthSearch.UI/Helpers/ViewLocator.cs
rename to InDepthSearch.UI/ViewLocator.cs
index 15dfe4d..970316e 100644
--- a/InDepthSearch.UI/Helpers/ViewLocator.cs
+++ b/InDepthSearch.UI/ViewLocator.cs
@@ -1,4 +1,4 @@
-using Avalonia.Controls;
+using Avalonia.Controls;
using Avalonia.Controls.Templates;
using InDepthSearch.Core.ViewModels;
using System;
@@ -7,11 +7,9 @@ namespace InDepthSearch.UI
{
public class ViewLocator : IDataTemplate
{
- public bool SupportsRecycling => false;
-
public IControl Build(object data)
{
- var name = data.GetType().FullName!.Replace("ViewModel", "View");
+ var name = data.GetType().FullName!.Replace("ViewModel", "View").Replace(".Core.", ".UI.");
var type = Type.GetType(name);
if (type != null)
@@ -26,7 +24,7 @@ public IControl Build(object data)
public bool Match(object data)
{
- return data is MainViewModel;
+ return data is ViewModelBase;
}
}
}
diff --git a/InDepthSearch.UI/ViewModelLocator.cs b/InDepthSearch.UI/ViewModelLocator.cs
new file mode 100644
index 0000000..7ab0d95
--- /dev/null
+++ b/InDepthSearch.UI/ViewModelLocator.cs
@@ -0,0 +1,46 @@
+using Autofac;
+using InDepthSearch.Core.ViewModels;
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace InDepthSearch.UI
+{
+ public class ViewModelLocator : IDisposable
+ {
+ private readonly IContainer _container;
+ public MainWindowViewModel MainWindow { get; }
+ public ViewModelLocator()
+ {
+ var ui = Assembly.GetCallingAssembly();
+ var core = Assembly.GetAssembly(typeof(ViewModelBase))!;
+ var builder = new ContainerBuilder();
+
+ builder.RegisterAssemblyTypes(core).Where(name => name.Name.EndsWith("ViewModel"))
+ .AsSelf().InstancePerDependency();
+ builder.RegisterAssemblyTypes(core, ui).Where(name => name.Name.EndsWith("Service"))
+ .AsImplementedInterfaces().SingleInstance();
+ builder.RegisterAssemblyTypes(core, ui).Where(name => name.Name.EndsWith("Manager"))
+ .AsImplementedInterfaces().SingleInstance();
+
+ if (Avalonia.Controls.Design.IsDesignMode)
+ {
+ builder.RegisterAssemblyTypes(core, ui).Where(name => name.Name.EndsWith("Designer")).AsImplementedInterfaces().InstancePerDependency();
+ }
+
+ builder.RegisterType().AsSelf().SingleInstance();
+ _container = builder.Build();
+ MainWindow = _container.Resolve();
+
+ if (Avalonia.Controls.Design.IsDesignMode)
+ {
+ // Set parameters needed for designer if any
+ }
+ }
+
+ public void Dispose()
+ {
+ _container.Dispose();
+ }
+ }
+}
diff --git a/InDepthSearch.UI/Views/MainWindow.axaml b/InDepthSearch.UI/Views/MainWindow.axaml
index a0f4bdf..f4b8cad 100644
--- a/InDepthSearch.UI/Views/MainWindow.axaml
+++ b/InDepthSearch.UI/Views/MainWindow.axaml
@@ -3,211 +3,76 @@
xmlns:vm="using:InDepthSearch.Core.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:conv="clr-namespace:InDepthSearch.UI.Converters"
mc:Ignorable="d" Width="1220" Height="780" MinWidth="1000" MinHeight="600"
x:Class="InDepthSearch.UI.Views.MainWindow"
x:Name="Main"
Icon="/Assets/Images/ids-icon.ico"
- Title="InDepthSearch">
-
-
-
-
-
-
-
-
+ Title="InDepthSearch"
+ Design.DataContext="{Binding Path=MainWindow, Source={StaticResource vmLocator}}">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
diff --git a/InDepthSearch.UI/Views/MainWindow.axaml.cs b/InDepthSearch.UI/Views/MainWindow.axaml.cs
index 085a6e5..e6261c6 100644
--- a/InDepthSearch.UI/Views/MainWindow.axaml.cs
+++ b/InDepthSearch.UI/Views/MainWindow.axaml.cs
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
+using InDepthSearch.UI.Controls;
namespace InDepthSearch.UI.Views
{
diff --git a/InDepthSearch.UI/Views/OptionsView.axaml b/InDepthSearch.UI/Views/OptionsView.axaml
new file mode 100644
index 0000000..0610a6a
--- /dev/null
+++ b/InDepthSearch.UI/Views/OptionsView.axaml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/InDepthSearch.UI/Views/OptionsView.axaml.cs b/InDepthSearch.UI/Views/OptionsView.axaml.cs
new file mode 100644
index 0000000..625df01
--- /dev/null
+++ b/InDepthSearch.UI/Views/OptionsView.axaml.cs
@@ -0,0 +1,19 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace InDepthSearch.UI.Views
+{
+ public partial class OptionsView : UserControl
+ {
+ public OptionsView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/InDepthSearch.UI/Views/ResultsView.axaml b/InDepthSearch.UI/Views/ResultsView.axaml
new file mode 100644
index 0000000..f6c6776
--- /dev/null
+++ b/InDepthSearch.UI/Views/ResultsView.axaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/InDepthSearch.UI/Views/ResultsView.axaml.cs b/InDepthSearch.UI/Views/ResultsView.axaml.cs
new file mode 100644
index 0000000..e139af7
--- /dev/null
+++ b/InDepthSearch.UI/Views/ResultsView.axaml.cs
@@ -0,0 +1,19 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace InDepthSearch.UI.Views
+{
+ public partial class ResultsView : UserControl
+ {
+ public ResultsView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/README.md b/README.md
index b657f05..7e1e049 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# InDepthSearch
-![version](https://img.shields.io/badge/version-0.2.0-blue)
+![version](https://img.shields.io/badge/version-1.0.0-blue)
Search for keywords inside the documents on Windows, Linux and macOS!
@@ -13,7 +13,7 @@ InDepthSearch is a multi-platform desktop search engine to find the keywords ins
- Linux (x64)
- macOS (x64)
-**NOTE:** Currently the project is in pre-release state, some functionalities are not implemented yet and some of them work only on a specific platform.
+**NOTE:** Some functionalities are not implemented yet and some of them work only on a specific platform. For more information see the section below.
## ✔️ Features
The table below lists the features and their compatibility with the supported platforms:
@@ -22,17 +22,17 @@ The table below lists the features and their compatibility with the supported pl
| ------------- |:---------------:|:---------------:|:---------------:|
| Multiple keywords search* | - | - | - |
| PDF support | + | + | + |
-| DOC/DOCX support** | - | - | - |
+| DOC/DOCX support** | + | + | + |
| ODT support** | - | - | - |
| Search in subfolders | + | + | + |
| Case-sensitive search | + | + | + |
| Search in images*** | + | - | - |
-* Currently the user is allowed to search only for one word/phrase. Support for multiple search entries is provisioned for next pre-release.
+* Currently the user is allowed to search only for one word/phrase. Support for multiple search entries is provisioned for next release.
-** Only PDF format is supported at the moment, but in the future it is planned to extend it to DOC, DOCX and ODT.
+** ODT format is not available yet.
-** Optical Character Recognition (OCR) libraries are compatible only with Windows, therefore search in images is disabled on Linux and macOS for the moment.
+*** Optical Character Recognition (OCR) libraries are compatible only with Windows, therefore search in images is disabled on Linux and macOS for the moment.
## 🚀 Quick start!
If you just want to run the application follow the instructions below. If you want to build the project first, go to to **Build & run** section.
@@ -57,7 +57,7 @@ The code in this repository is licensed under the **Apache License 2.0**
**NOTE:** The project would not exist without following resources:
- - [Avalonia](https://github.com/AvaloniaUI/Avalonia), [ReactiveUI](https://github.com/reactiveui/ReactiveUI), [DocNET](https://github.com/GowenGit/docnet) licensed under MIT.
+ - [Avalonia](https://github.com/AvaloniaUI/Avalonia), [ReactiveUI](https://github.com/reactiveui/ReactiveUI), [DocNET](https://github.com/GowenGit/docnet) and [Open-XML-SDK](https://github.com/OfficeDev/Open-XML-SDK) licensed under MIT.
- [tesseract](https://github.com/charlesw/tesseract) licensed under the Apache License 2.0.