Add settings, cloud places, and optional archive-content indexing.

Keep official clients in charge of sync while Explorer can group locations, persist UI prefs, and list zip/rar/7z members without extracting them.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-23 12:16:09 +02:00
parent e9aba73552
commit 09a8cfafa3
57 changed files with 3130 additions and 119 deletions

View File

@@ -90,6 +90,68 @@ public class SourceManagerTests
var found = await mgr.FindByPathAsync(@"Z:\");
Assert.Equal(source.Id, found!.Id);
}
[Fact]
public async Task Forget_removes_disconnected_source_and_index_rows()
{
var db = Path.Combine(Path.GetTempPath(), "ew-app", Guid.NewGuid().ToString("N"), "index.db");
await using var store = new SqliteIndexStore(db, NullLogger<SqliteIndexStore>.Instance);
await store.OpenAsync();
var volumes = new FakeVolumes
{
Online =
[
new VolumeFingerprint
{
Kind = SourceKind.Smb,
RootPath = @"Z:\",
DisplayName = "Z: (Network)",
Filesystem = "SMB"
}
]
};
var env = new FakeEnv(Path.GetDirectoryName(db)!);
var mgr = new SourceManager(store, volumes, env, new SystemClock(), NullLogger<SourceManager>.Instance);
await mgr.InitializeAsync();
var source = (await store.Sources.GetAllAsync()).Single();
await store.Entries.UpsertAsync(new IndexEntry
{
SourceId = source.Id,
Name = "Photos",
NameNorm = "photos",
IsDirectory = true,
PathRel = "Photos",
LastSeenUtc = DateTimeOffset.UtcNow
});
Assert.False(mgr.CanForget(source));
Assert.False(await mgr.ForgetDisconnectedAsync(@"Z:\"));
volumes.Online = [];
await mgr.RefreshOnlineStateAsync();
source = (await store.Sources.GetAllAsync()).Single();
Assert.True(mgr.CanForget(source));
Assert.True(await mgr.ForgetDisconnectedAsync(@"Z:\"));
Assert.Empty(await store.Sources.GetAllAsync());
Assert.Null(await store.Entries.GetRootAsync(source.Id));
}
[Fact]
public async Task Forget_removes_unc_from_recents()
{
var dir = Path.Combine(Path.GetTempPath(), "ew-app", Guid.NewGuid().ToString("N"));
var db = Path.Combine(dir, "index.db");
await using var store = new SqliteIndexStore(db, NullLogger<SqliteIndexStore>.Instance);
var volumes = new FakeVolumes();
var env = new FakeEnv(dir);
File.WriteAllLines(Path.Combine(dir, "recents.txt"), [@"\\old-server\share"]);
var mgr = new SourceManager(store, volumes, env, new SystemClock(), NullLogger<SourceManager>.Instance);
await mgr.InitializeAsync();
Assert.Single(await store.Sources.GetAllAsync());
Assert.True(await mgr.ForgetDisconnectedAsync(@"\\old-server\share"));
Assert.Empty(await store.Sources.GetAllAsync());
Assert.Empty(File.ReadAllLines(Path.Combine(dir, "recents.txt")));
}
}
file sealed class FakeVolumes : IVolumeService