Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/Devnull/Stash.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
/**
* What you wrote and didn't send, per user, as the web's useStash keeps it.
*
* Drafts go by the web's names: 'commit' for the Log's composer, which its
* sheet shares, 'quote-{id}' for a quote of a commit and 'reply-{id}' for a
* Drafts go by the web's names: 'commit' for a new commit, from the compose
* sheet, 'quote-{id}' for a quote of a commit and 'reply-{id}' for a
* reply to one. A screen keeps a draft as its field changes, and forgets it
* once it's sent or the field is emptied. Signing out forgets them all (see
* Account::forget).
Expand Down
21 changes: 3 additions & 18 deletions app/NativeComponents/Concerns/OpensCommitSheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
* your new commits puts it in place (see showCommitted()).
*
* What you write in it is stashed as you type, as on the web (see Stash): a
* quote per commit quoted, and a new commit as the Log's composer's draft,
* which the sheet shares, as the web's dialog does. Opened again, it starts
* from the draft, marked as restored. It's forgotten once it's sent.
* quote per commit quoted, and a new commit under the web's composer draft.
* Opened again, it starts from the draft, marked as restored. It's forgotten
* once it's sent.
*
* The sheet keeps its commit while it slides away, so it doesn't empty on the
* way down, and lets go of it once iOS says it's gone, however it was closed.
Expand Down Expand Up @@ -202,22 +202,7 @@ public function hideCommitSheet(): void
*/
public function commitSheetClosed(): void
{
$composed = $this->sheetView === 'compose';

$this->forgetCommitSheet();

if ($composed) {
$this->composeSheetClosed();
}
}

/**
* The sheet's new commit has gone, sent or stashed. The Log's composer shares its draft, so it takes it as the
* sheet left it.
*/
protected function composeSheetClosed(): void
{
//
}

/**
Expand Down
148 changes: 9 additions & 139 deletions app/NativeComponents/Log.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,19 @@

/**
* The log: the web's three of them, Following (you and the people you follow),
* Latest (everyone, newest first) and Trending (ranked by stars and replies),
* under a composer you type into where it is, as on the web.
* Latest (everyone, newest first) and Trending (ranked by stars and replies).
*
* EDGE tells PHP nothing about focus, and gives PHP no way to focus a field
* or scroll a list. So a touch on the field is taken as being in it, and a new
* key on the list is how it gets back to the top.
* EDGE gives PHP no way to scroll a list, so a new key on the list is how it
* gets back to the top.
*
* Nor does it say where a list is scrolled, so the nav bar's compose button
* can't tell whether the composer is on screen. It always opens the composer
* in a sheet (see OpensCommitSheet), which leaves the log where you were in
* it, and the commit goes on top as one from the composer does.
*
* The composer's draft is stashed as you type, as on the web (see Stash), so
* it's there again when the Log opens, marked as restored. The sheet shares
* it, as the web's dialog does, and the composer takes what the sheet left.
* The Log has no composer of its own. The nav bar's compose button opens one
* in a sheet (see OpensCommitSheet), which leaves the log where you were in it,
* and the commit goes on top. A field in the list was redrawn with the whole
* log every time it synced, and fast typing lost and reordered letters.
*
* It opens on the log as it was last time, then asks devnull again in the
* background, and every 30 seconds while it's showing, as the web polls.
* Commits newer than anything showing wait under the composer in the new
* Commits newer than anything showing wait at the top of the list in the new
* commits pill (see HoldsNewCommits), which says how many devnull counted
* since the newest one showing (?since=). Scrolled down, it pins under the tabs.
*
Expand Down Expand Up @@ -144,31 +138,8 @@ class Log extends NativeComponent
*/
public ?string $lastVisitAt = null;

/**
* The commit you're writing. It stays when the keyboard goes, until it's committed.
*/
public string $body = '';

/**
* Whether the composer shows its budget and Commit button: from the moment you're
* in it until you commit, or leave it empty and the log reloads.
*/
public bool $composing = false;

/**
* Mounts a fresh field when it changes, so a committed field starts clean.
*/
public int $composerKey = 0;

/**
* Whether the draft in the composer was stashed when it opened, which it marks until you empty it or drop it.
*/
public bool $draftRestored = false;

public function mount(): void
{
$this->body = app(Stash::class)->get($this->me()?->id, 'commit');
$this->draftRestored = $this->body !== '';
$this->log = app(ShownTabs::class)->get($this->me()?->id, 'log', self::Logs, 'following');
$this->lastVisitAt = $this->lastVisitSeenAt();
$this->showKept();
Expand All @@ -181,7 +152,6 @@ public function mount(): void
public function onResume(): void
{
$this->forgetRefreshes();
$this->closeEmptyComposer();
$this->forgetDeleted();
$this->forgetHidden();
$this->showKept();
Expand Down Expand Up @@ -323,8 +293,6 @@ public function isRanked(): bool
*/
public function load(): void
{
$this->closeEmptyComposer();

if ($this->isRanked()) {
$this->rank();

Expand Down Expand Up @@ -432,88 +400,7 @@ public function followSuggested(string $username): void
}

/**
* A touch on the composer's field puts you in it.
*/
public function composerFocused(): void
{
$this->composing = true;
}

/**
* Stashes the draft as it changes. An empty field forgets it, and isn't restored any more.
*/
public function updatedBody(): void
{
app(Stash::class)->put($this->me()?->id, 'commit', $this->body);

if ($this->body === '') {
$this->draftRestored = false;
}
}

/**
* The web's drop, beside a restored draft: it's thrown away, and a fresh field takes its place.
*/
public function dropStash(): void
{
$this->body = '';
$this->updatedBody();
$this->composerKey++;
}

public function remaining(): int
{
return Commit::MaxLength - mb_strlen($this->body);
}

public function canCommit(): bool
{
$length = mb_strlen(trim($this->body));

return $length >= Commit::MinLength && $length <= Commit::MaxLength;
}

/**
* Commits the draft and puts it at the top of the log. Pressing Commit has
* already put the keyboard away. The draft stays if devnull says no.
*/
public function commit(): void
{
if (! $this->canCommit()) {
return;
}

$commit = $this->attempt(fn ($devnull) => $devnull->createCommit(trim($this->body)));

if ($commit === null) {
return;
}

$this->body = '';
$this->updatedBody();
$this->composing = false;
$this->composerKey++;
$this->showCommitted($commit);
}

/**
* The sheet wrote to the composer's stash, so the composer takes the draft as the sheet left it, in a fresh field.
*/
protected function composeSheetClosed(): void
{
$draft = app(Stash::class)->get($this->me()?->id, 'commit');

if ($draft === $this->body) {
return;
}

$this->body = $draft;
$this->draftRestored = $draft !== '';
$this->composerKey++;
}

/**
* Puts a commit you just made at the top of the log, from the composer or the sheet.
* Puts a commit you just made in the compose sheet at the top of the log.
*/
protected function showCommitted(Commit $commit): void
{
Expand Down Expand Up @@ -546,20 +433,6 @@ protected function updateShownCommits(Closure $update): void
$this->threads = array_map(fn (array $replies): array => array_map($update, $replies), $this->threads);
}

/**
* An empty composer you've left closes again. Nothing says when you leave it,
* so this waits for the log to reload: on returning to it, or pulling to refresh.
*/
private function closeEmptyComposer(): void
{
if (! $this->composing || $this->body !== '') {
return;
}

$this->composing = false;
$this->composerKey++;
}

/**
* The log as it was kept last time, if there is one. Coming back to it, it's
* laid over what's showing like any fresh page, so a change made elsewhere
Expand Down Expand Up @@ -772,9 +645,6 @@ public function render(): View
'myColour' => $this->myColour(),
'viewer' => $viewer,
'pasteis' => app(Account::class)->pasteis(),
'composerOpen' => $this->composing || $this->body !== '',
'remaining' => $this->remaining(),
'canCommit' => $this->canCommit(),
'stashed' => app(Stash::class)->names($viewer?->id),
'newCommitsLabel' => $this->newCommitsLabel(),
'pages' => $pages,
Expand Down
48 changes: 0 additions & 48 deletions resources/views/native/partials/composer.blade.php

This file was deleted.

4 changes: 0 additions & 4 deletions resources/views/native/partials/log-page.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ class="w-full flex-1 bg-theme-surface"
:on-end-reached="$page['showing'] ? 'loadMore' : null"
:end-reached-buffer="5"
>
@if ($viewer)
@include('native.partials.composer', ['me' => $viewer])
@endif

@include('native.partials.new-commits-pill', ['label' => $newCommitsLabel, 'press' => 'showNewCommits', 'shown' => $page['showing'] && $newCommits !== []])

@if (! $page['loaded'] && $page['error'] === null)
Expand Down
38 changes: 2 additions & 36 deletions tests/Feature/Screens/ComposeSheetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,8 @@ function sheetCommitDisabled(TestableComponent $screen): bool
'autofocus' => true,
'value' => '',
])
// The same list, so it stays scrolled where it was, and the composer at its top stays as it was.
->and(nodeByRef($screen, 'log')['id'])->toBe($list)
->and($screen->instance()->composing)->toBeFalse();
// The same list, so it stays scrolled where it was.
->and(nodeByRef($screen, 'log')['id'])->toBe($list);
});

it('keeps Commit disabled until the commit is long enough, and short enough', function () {
Expand Down Expand Up @@ -139,39 +138,6 @@ function sheetCommitDisabled(TestableComponent $screen): bool
Http::assertNotSent(fn (Request $request): bool => $request->method() === 'POST');
});

it('shares its draft with the composer at the top of the log, as the web dialog does', function () {
fakeApi([
'GET /api/v1/log/following' => [pageJson([])],
'POST /api/v1/commits' => [['data' => commitJson(['id' => 'mine', 'body' => 'Half a thought, shipped.'])], 201],
]);

$screen = Native::visit('/log', platform: 'ios')
->input('body', 'Half a thought')
->press('composeInSheet');

expect(nodeByRef($screen, 'sheet-body')['props']['value'])->toBe('Half a thought');

// Closed, the composer takes the draft as the sheet left it.
$screen->input('sheet-body', 'Half a thought, and more')
->dismissSheet('sheet');

expect(nodeByRef($screen, 'body')['props']['value'])->toBe('Half a thought, and more')
->and(nodeByRef($screen, 'stash'))->not->toBeEmpty();

// Sent from the sheet, it's gone from both.
$screen->press('composeInSheet')
->input('sheet-body', 'Half a thought, shipped.')
->tap('sheet-commit')
->dismissSheet('sheet')
->assertSet('body', '');

expect(nodeByRef($screen, 'body')['props']['value'])->toBe('');

$screen->press('composeInSheet');

expect(nodeByRef($screen, 'sheet-body')['props']['value'])->toBe('');
});

it('only commits from a sheet that has a composer in it', function () {
fakeApi(['GET /api/v1/log/following' => [pageJson([commitJson(['id' => 'c1', 'author' => userJson(['id' => 'u2', 'username' => 'ada'])])])]]);

Expand Down
Loading
Loading