Merge branch 'claude/vault-creation-sharing-62c0b6'
ci / build and test (push) Successful in 1m38s
ci / android head (push) Failing after 9s
ci / api image (push) Successful in 28s

# Conflicts:
#	README.md
This commit is contained in:
2026-08-04 10:10:40 +02:00
13 changed files with 1035 additions and 63 deletions
@@ -217,6 +217,70 @@ public sealed class TransferQueueingTests : IDisposable
Queued().ShouldHaveSingleItem();
}
/// <remarks>
/// The phone's way in, and it has to obey the same rules as every other: a document chosen in the system
/// picker is copied into the cache and the copy is queued, which is an upload with one extra property —
/// that this application made the file and will delete it again. Everything about *what may be queued*
/// is the same, and this says so rather than leaving a second path free to drift.
/// </remarks>
[Fact]
public void StagedUploads_QueueUnderTheSameRulesAsAnyOther()
{
Connected();
var folder = Path.Combine(directory, "a-folder");
Directory.CreateDirectory(folder);
transfers.QueueStagedUploads([File("picked.txt"), folder]);
Queued().ShouldHaveSingleItem();
transfers.Status.ShouldContain("1 file");
transfers.Status.ShouldContain("1 folder was skipped");
}
/// <remarks>
/// <para>
/// The phone's way out. The delivery itself — copying the finished file into the document the save
/// picker made — needs a transfer that actually runs and a picker to have made something, so it is
/// checked by hand in <c>docs/manual-checks.md</c> phase 14. What is worth pinning here is the pair of
/// refusals in front of it, because both would otherwise be discovered as an empty file sitting in
/// somebody's Downloads: the picker creates the destination the moment it is dismissed, so anything
/// this method turns away after that point has already cost a visible artefact.
/// </para>
/// </remarks>
[Fact]
public void ADeliveredDownload_QueuesTheFileAndRefusesADirectory()
{
var delivered = 0;
Connected();
transfers.QueueDeliveredDownload(
RemoteFile("one.log"),
Path.Combine(directory, "staged", "one.log"),
_ =>
{
delivered++;
return Task.CompletedTask;
});
Queued().ShouldHaveSingleItem();
transfers.Status.ShouldContain("one.log");
// A directory has nothing to fetch, and the message is the same one every other path on this screen
// gives for the same mistake.
transfers.QueueDeliveredDownload(
RemoteDirectory("logs"),
Path.Combine(directory, "staged", "logs"),
_ => Task.CompletedTask);
Queued().Count.ShouldBe(1);
transfers.Status.ShouldContain("Only files");
// Nothing is delivered by queueing. The callback runs when the bytes are there and not before.
delivered.ShouldBe(0);
}
/// <summary>The queue's rows, once the posts that create them have been let run.</summary>
/// <remarks>
/// <c>TransfersViewModel</c> adds a row from the transfer queue's own <c>Changed</c> event, which it