Skip to content

Commit 3f9bfbb

Browse files
authored
Merge pull request #8 from dtwk2/development_2
Development 2
2 parents 935b6dc + 77666b2 commit 3f9bfbb

File tree

75 files changed

+2721
-3507
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+2721
-3507
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net5.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="LiteDB" Version="5.0.11" />
10+
</ItemGroup>
11+
12+
<ItemGroup>
13+
<ProjectReference Include="..\..\Infrastructure\Infrastructure.csproj" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
6+
namespace CachedPathSuggest.Infrastructure
7+
{
8+
public static class DirectoryHelper
9+
{
10+
public static IEnumerable<(string path, string? label)>? EnumerateSubDirectories(string input)
11+
{
12+
var subDirs = EnumerateLogicalDriveOrSubDirectories(input);
13+
14+
// ReSharper disable PossibleMultipleEnumeration
15+
return subDirs != null
16+
? subDirs.Any()
17+
? subDirs.Select(a => (a, (string?)null)) : EnumerateChildren(input)
18+
: new[] { (input, (string?)"Unauthorized Access") };
19+
20+
// Find last separator and list directories underneath with * search-pattern
21+
static IEnumerable<(string, string?)> EnumerateChildren(string input)
22+
{
23+
var sepIdx = input.LastIndexOf('\\');
24+
25+
if (sepIdx >= input.Length)
26+
return EnumerateLogicalDrives();
27+
28+
string folder = input.Substring(0, sepIdx + 1);
29+
string searchPattern = input.Substring(sepIdx + 1) + "*";
30+
try
31+
{
32+
return Directory
33+
.GetDirectories(folder, searchPattern)
34+
.Select(a => (a, (string?)null)).ToList();
35+
}
36+
catch
37+
{
38+
// Catch invalid path exceptions here ...
39+
return Array.Empty<(string, string?)>();
40+
}
41+
}
42+
43+
static IEnumerable<string>? EnumerateLogicalDriveOrSubDirectories(string testDrive)
44+
{
45+
if (testDrive.Length < 3) return Enumerate(testDrive);
46+
47+
return Directory.Exists(testDrive) ? TryGetDirectories(testDrive) : Array.Empty<string>();
48+
49+
static string[]? TryGetDirectories(string testDrive)
50+
{
51+
try
52+
{
53+
return Directory.GetDirectories(testDrive);
54+
}
55+
catch (UnauthorizedAccessException)
56+
{
57+
return null;
58+
}
59+
}
60+
61+
static IEnumerable<string>? Enumerate(string input)
62+
{
63+
return (input.Length, input.TryGetUpper(0), input.TryGetUpper(1), input.TryGetUpper(2)) switch
64+
{
65+
(1, >= 'A' and <= 'Z', _, _) => new[] { input + ":\\" }.Concat(EnumerateLogicalDriveOrSubDirectories(input + ":\\") ?? Array.Empty<string>()),
66+
(2, >= 'A' and <= 'Z', ':', _) => new[] { input + ":\\" }.Concat(EnumerateLogicalDriveOrSubDirectories(input + "\\") ?? Array.Empty<string>()),
67+
(3, >= 'A' and <= 'Z', ':', '\\') => EnumerateLogicalDriveOrSubDirectories(input),
68+
_ => Array.Empty<string>()
69+
};
70+
}
71+
}
72+
}
73+
74+
public static IEnumerable<(string path, string? label)> EnumerateLogicalDrives()
75+
{
76+
foreach (var driveName in Environment.GetLogicalDrives())
77+
{
78+
if (string.IsNullOrEmpty(driveName))
79+
continue;
80+
81+
string? volumeLabel = null;
82+
83+
try
84+
{
85+
if (new DriveInfo(driveName) is { IsReady: true } driveInfo)
86+
volumeLabel = driveInfo.VolumeLabel;
87+
}
88+
catch (IOException)
89+
{
90+
// network path not found
91+
}
92+
catch (UnauthorizedAccessException)
93+
{
94+
// can't access path
95+
}
96+
97+
yield return (driveName, volumeLabel);
98+
}
99+
}
100+
}
101+
102+
internal static class StringHelper
103+
{
104+
public static char TryGetUpper(this string value, int index)
105+
{
106+
return char.ToUpper(value.ElementAtOrDefault(index));
107+
}
108+
}
109+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#nullable enable
2+
3+
using System;
4+
using System.Collections.Generic;
5+
using System.IO;
6+
using System.Linq;
7+
using LiteDB;
8+
9+
namespace CachedPathSuggest.Infrastructure
10+
{
11+
/// <summary>
12+
/// Implements a static service provider for searching and editing a LiteDB file.
13+
/// </summary>
14+
public class LiteRepository
15+
{
16+
private const string DbPath = @"..\..\..\Data\KeyValue.litedb";
17+
18+
// Collection needs a name because object, keyvaluepair<string,string> is generic.
19+
private const string CollectionName = "collection";
20+
21+
/// <summary>
22+
/// Class constructor
23+
/// </summary>
24+
public LiteRepository()
25+
{
26+
(Directory.GetParent(DbPath) ?? throw new Exception("Can't create directory")).Create();
27+
BsonMapper.Global.Entity<KeyValuePair<string, DateTime>>().Id(x => x.Key);
28+
}
29+
30+
public event Action? Change;
31+
32+
/// <summary>
33+
/// Inserts a new string into the collection of bookmarked strings.
34+
/// </summary>
35+
/// <param name="key"></param>
36+
/// <param name="collectionName"></param>
37+
public void Insert(string key, string? collectionName = null)
38+
{
39+
using var db = new LiteDatabase(DbPath);
40+
var col = db.GetCollection<KeyValuePair<string, DateTime>>(collectionName ?? CollectionName);
41+
col.Upsert(new KeyValuePair<string, DateTime>(key, DateTime.Now));
42+
Change?.Invoke();
43+
}
44+
45+
/// <summary>
46+
/// Inserts a new string into the collection of bookmarked strings.
47+
/// </summary>
48+
/// <param name="key"></param>
49+
/// <param name="collectionName"></param>
50+
public void Remove(string key, string? collectionName = null)
51+
{
52+
using var db = new LiteDatabase(DbPath);
53+
var col = db.GetCollection<KeyValuePair<string, DateTime>>(collectionName ?? CollectionName);
54+
55+
// Make sure string is already present
56+
if (col.FindOne(x => x.Key == key) is { } one)
57+
col.Delete(key);
58+
59+
Change?.Invoke();
60+
}
61+
62+
/// <summary>
63+
/// </summary>
64+
public KeyValuePair<string, DateTime>? Find(string key, string? collectionName = null)
65+
{
66+
using var db = new LiteDatabase(DbPath);
67+
var col = db.GetCollection<KeyValuePair<string, DateTime>>(collectionName ?? CollectionName);
68+
var one = col.FindOne(x => x.Key == key);
69+
return one;
70+
}
71+
72+
/// <summary>
73+
/// Filters the collection of bookmark strings by the given string and
74+
/// returns the resulting collection.
75+
/// </summary>
76+
public IEnumerable<KeyValuePair<string, DateTime>> Filter(string key, string? collectionName = null)
77+
{
78+
using var db = new LiteDatabase(DbPath);
79+
var col = db.GetCollection<KeyValuePair<string, DateTime>>(collectionName ?? CollectionName);
80+
return string.IsNullOrWhiteSpace(key)
81+
? col.Query().ToArray()
82+
: col.Find(Query.Contains(nameof(KeyValuePair<string, DateTime>.Key), key)).ToArray();
83+
}
84+
}
85+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using Infrastructure;
2+
3+
namespace CachedPathSuggest.ViewModels
4+
{
5+
/// <summary>
6+
/// This class is the parent root class of other lsit item related classes.
7+
/// It exists simple for methods to produce something like IEnumerable{<see cref="BaseItem" />}
8+
/// where 'BaseItem' cen be any class inheriting from <see cref="BaseItem" />.
9+
/// This enables us to use Converters, DataTemplates or other tools in WPF to display different
10+
/// UI bits for different types of classes.
11+
/// </summary>
12+
public class BaseItem : ViewModelBase
13+
{
14+
private bool isHitTestVisible;
15+
16+
public BaseItem(string value)
17+
{
18+
Value = value;
19+
IsHitTestVisible = true;
20+
}
21+
22+
public string Value { get; }
23+
24+
/// <summary>
25+
/// Gets/sets a property that indicates to the UI whether the resulting list item
26+
/// should be click-able to process data or not (a separator is part of the list but should not be clicked).
27+
/// </summary>
28+
public bool IsHitTestVisible
29+
{
30+
get => isHitTestVisible;
31+
set
32+
{
33+
isHitTestVisible = value;
34+
NotifyPropertyChanged();
35+
}
36+
}
37+
}
38+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace CachedPathSuggest.ViewModels
2+
{
3+
/// <summary>
4+
/// Implements a simple viewmodel for an item that should act as separator
5+
/// between 2 sub-sequent blocks of 2 different types of items.
6+
/// This type of item is usually useful in a WPF list of items where quickly
7+
/// different types of items appear with a need for displaying their content
8+
/// with a different UI (eg.: using a Converter or DataTemplate).
9+
/// </summary>
10+
public class ItemSeparator : BaseItem
11+
{
12+
/// <summary>
13+
/// Class constructor
14+
/// </summary>
15+
public ItemSeparator() : base(string.Empty)
16+
{
17+
// a separator is part of the list but should not be clicked
18+
IsHitTestVisible = false;
19+
}
20+
}
21+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace CachedPathSuggest.ViewModels
5+
{
6+
public class CachedPathInformation : PathInformation
7+
{
8+
public CachedPathInformation(DateTime storageDate, string path) : base(path)
9+
{
10+
StorageDate = storageDate;
11+
}
12+
13+
public DateTime StorageDate { get; }
14+
15+
public TimeSpan StorageLength => StorageDate - DateTime.Now;
16+
}
17+
18+
/// <summary>
19+
/// Implements a simple path information object to keep track of its full name and path etc.
20+
/// </summary>
21+
public class PathInformation : BaseItem, IEquatable<PathInformation>
22+
{
23+
/// <summary>
24+
/// Class constructor
25+
/// </summary>
26+
/// <param name="path"></param>
27+
/// <param name="information"></param>
28+
public PathInformation(string path, string? information = null) : base(path)
29+
{
30+
Parent = new DirectoryInfo(path).Parent == null ? path :
31+
path.EndsWith("\\") ? Path.GetDirectoryName(path) ?? string.Empty :
32+
string.Empty;
33+
34+
FullName = path;
35+
Information = information;
36+
}
37+
38+
/// <summary>
39+
/// Gets the name of a directory (without the path)
40+
/// </summary>
41+
public string Parent { get; }
42+
43+
/// <summary>
44+
/// Gets the full name (including path) for a directory
45+
/// </summary>
46+
public string FullName { get; }
47+
48+
/// <summary>
49+
/// Any other information e.g volume-information
50+
/// </summary>
51+
public string? Information { get; }
52+
53+
public bool Equals(PathInformation? other)
54+
{
55+
if (other is null) return false;
56+
if (ReferenceEquals(this, other)) return true;
57+
return Parent == other.Parent && FullName == other.FullName;
58+
}
59+
60+
public override bool Equals(object? obj)
61+
{
62+
if (obj is null) return false;
63+
if (ReferenceEquals(this, obj)) return true;
64+
return obj.GetType() == GetType() && Equals((PathInformation) obj);
65+
}
66+
67+
public override int GetHashCode()
68+
{
69+
return HashCode.Combine(Parent, FullName);
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)