diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b6b07c..4b3e366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ The long form, with what was wrong before and how it was found, is in ### Added - Keyboard shortcuts after Feedly's: j and k through items, Shift-J and Shift-K through feeds, - g and a letter to go to a place, o to play, s to keep, and more. Press ? for the whole list. + g and a letter to go to a place, o to play, s to pin, and more. Press ? for the whole list. - Directory can be filtered to Podcasts or Blogs, and by each show's own iTunes category as a row of chips, the narrower one where a show gives two (Games, not Leisure). The two combine, and both filter in place. @@ -22,6 +22,8 @@ The long form, with what was wrong before and how it was found, is in - Directory shows each feed as its cover art in a grid, title and subscriber count underneath, instead of a list. Popular and the Add a feed dialog keep their rows. +- Keeping an item is now pinning it: a thumbtack in place of the flag, and Pin, Pinned and Unpin + in place of Keep, Kept and Stop keeping. A pinned item is still never deleted. - Currently Listening is its own place in the feed list, below Popular, instead of a section at the bottom of the Popular page. - The first scan after upgrading fetches every feed in full once, on its usual schedule, so each diff --git a/README.md b/README.md index 33f6260..b143bfd 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ behind iPodderX (2004-2008, Ray Slakinski & August Trometer). - **The web UI.** It has a toolbar, and a feed list that opens with Directory, Popular and All Subscriptions. Items sit in a sortable table with a Files pane, and there is a player bar. It comes in Dark, Light and Classic themes, and works on a phone. -- **Several people, one copy.** Each person has their own subscriptions and their own read, kept +- **Several people, one copy.** Each person has their own subscriptions and their own read, pinned and playback state. There is one file on disk per episode, however many people want it. People sign in with a password or through a proxy (Cloudflare Zero Trust or Authentik), and admins manage accounts and settings. @@ -21,7 +21,7 @@ behind iPodderX (2004-2008, Ray Slakinski & August Trometer). on new downloads per scan. - **Downloads.** Files come over HTTP or BitTorrent and are filed into a folder per feed. Retention deletes the oldest files to stay under a disk quota or an age limit, and never touches - an item someone has kept. + an item someone has pinned. - **OPML.** You can import and export your own subscriptions. You can also subscribe to an OPML URL, which keeps a whole list in step as a folder. diff --git a/docs/users.md b/docs/users.md index a126b7a..a151088 100644 --- a/docs/users.md +++ b/docs/users.md @@ -8,7 +8,7 @@ fetch, one parse and one file. | Yours alone | The same for everyone | |---|---| -| Read, kept, playback position | The feed's URL | +| Read, pinned, playback position | The feed's URL | | Which feeds you see at all | Its download folder | | Keywords, auto-download, explicit, per-scan cap | When it is scanned | | | The file on disk | @@ -34,10 +34,10 @@ is shared. Deleting a file deletes everyone's copy. A feed with other subscribers labels the button **Delete for everyone** and names them in the confirmation, and the server has the last word: if anyone else -has kept the item or not played it yet, `DELETE /api/enclosures/{id}` answers `409` with the +has pinned the item or not played it yet, `DELETE /api/enclosures/{id}` answers `409` with the reason, and only `?force=true` goes through. -Retention follows the same rule: an item anyone kept keeps its file, and it counts as read only once +Retention follows the same rule: an item anyone pinned keeps its file, and it counts as read only once every subscriber has read it. ## Signing in diff --git a/src/web.rs b/src/web.rs index 1a1ac09..3bb251f 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1259,9 +1259,9 @@ async fn delete_file( let complaint = match (starred, unread) { (0, 0) => None, (0, u) => Some(format!("{} subscribed to this feed {} not played it yet", people(u), if u == 1 { "has" } else { "have" })), - (st, 0) => Some(format!("another {} kept it", people(st))), + (st, 0) => Some(format!("another {} pinned it", people(st))), (st, u) => Some(format!( - "another {} kept it, and {} not played it yet", + "another {} pinned it, and {} not played it yet", people(st), if u == 1 { "one person has".to_string() } else { format!("{u} have") } )), diff --git a/tests/ui/app.spec.js b/tests/ui/app.spec.js index c2c43f4..1576936 100644 --- a/tests/ui/app.spec.js +++ b/tests/ui/app.spec.js @@ -197,7 +197,7 @@ test('the filter tabs change what is listed', async ({ page }) => { await page.locator('.tabs button', { hasText: 'Unread' }).first().click(); expect(await page.locator('.ep').count()).toBeLessThanOrEqual(all); - await page.locator('.tabs button', { hasText: 'Kept' }).first().click(); + await page.locator('.tabs button', { hasText: 'Pinned' }).first().click(); await expect(page.locator('#count')).toContainText('0 items'); }); @@ -787,13 +787,14 @@ test('a deleted file looks as if it was never downloaded', async ({ page }) => { }); test('one action, one icon: the toolbar, the page and every dialog agree', async ({ page }) => { - const icon = loc => loc.locator('svg path').first().getAttribute('d'); + // The whole glyph, not just its path: pinned and not pinned share one outline and differ in fill. + const icon = loc => loc.locator('svg').first().innerHTML(); await page.locator('#feedlist .feed', { hasText: 'Test Show' }).first().click(); // Unsubscribe is a minus in the toolbar and the feed header, never the x that closes things. expect(await icon(page.locator('#content .acts [data-a="rm"]'))).toBe(await icon(page.locator('#tbRemove'))); - // The toolbar's read and keep show the selected item's state, as its own buttons do, and follow + // The toolbar's read and pin show the selected item's state, as its own buttons do, and follow // a change made from the toolbar. await page.locator('.ep').first().click(); const pair = async a => [await icon(page.locator(a === 'read' ? '#tbRead' : '#tbFlag')), diff --git a/web/index.html b/web/index.html index 044c4ec..bb50001 100644 --- a/web/index.html +++ b/web/index.html @@ -626,7 +626,7 @@ input[type=range]::-moz-range-thumb{width:12px;height:12px;border:0;border-radiu