Every play button for what is playing shows pause, and pauses it
Only the player bar's button changed; the files pane's, the row's and the toolbar's kept showing play while it played. play() now pauses when asked to play what is already playing, which makes each of them a toggle, and syncPlayButtons() repaints them on play, pause and ended and whenever the list or reader is drawn. Closes #34. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,8 @@ The long form, with what was wrong before and how it was found, is in
|
||||
higher than a downloaded one's.
|
||||
- Images in posts from sites that refuse images to other sites' pages, such as Jeff Geerling's,
|
||||
now show: ipx asks for them without saying it is the page showing them.
|
||||
- While an episode plays, its play buttons in the files pane, its row and the toolbar show
|
||||
pause, as the player bar's does, and pause it when pressed.
|
||||
- An item you open stays read. A list refresh that crossed with marking it read could put its
|
||||
unread dot back until the next refresh.
|
||||
- On the Unread tab, the item you were reading leaves the list as soon as you move to the next
|
||||
|
||||
@@ -182,6 +182,27 @@ test('the three panes are there and the item text lands in the bottom one', asyn
|
||||
await expect(page.locator('#files [data-a="play"]')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('while an episode plays, its play buttons all say pause, and pause it', async ({ page }) => {
|
||||
await page.locator('.feed', { hasText: 'Test Show' }).click();
|
||||
await page.locator('.tabs button', { hasText: 'All' }).first().click();
|
||||
const downloaded = page.locator('.ep', { has: page.locator('.kind.here') }).first();
|
||||
await expect(downloaded).toBeVisible({ timeout: 20_000 });
|
||||
await downloaded.click();
|
||||
await page.evaluate(() => { audio.muted = true; });
|
||||
const pane = page.locator('#files [data-a="play"]');
|
||||
await pane.click();
|
||||
await expect.poll(() => page.evaluate(() => !audio.paused)).toBe(true);
|
||||
// The files pane, the row and the toolbar all follow the player bar, not only the bar.
|
||||
await expect(pane).toHaveAttribute('title', 'Pause');
|
||||
await expect(downloaded.locator('[data-a="play"]')).toHaveAttribute('title', 'Pause');
|
||||
await expect(page.locator('#tbPlay')).toHaveAttribute('title', 'Pause');
|
||||
await pane.click(); // and pressing it pauses
|
||||
await expect.poll(() => page.evaluate(() => audio.paused)).toBe(true);
|
||||
await expect(pane).toHaveAttribute('title', 'Play');
|
||||
await expect(page.locator('#tbPlay')).toHaveAttribute('title', 'Play the selected item');
|
||||
await page.locator('#pclose').click();
|
||||
});
|
||||
|
||||
test('a downloaded file that is not audio gets no player', async ({ page }) => {
|
||||
// Regression: anything with a file got an <audio> element and a play button, so a blog's
|
||||
// header image rendered as a broken player.
|
||||
|
||||
@@ -41,6 +41,7 @@ function renderEntries(){
|
||||
return;
|
||||
}
|
||||
for(const e of S.entries) box.appendChild(epEl(e));
|
||||
syncPlayButtons();
|
||||
if(pane) pane.scrollTop=top;
|
||||
if(S.entries.length < S.total){
|
||||
const b=document.createElement('button');
|
||||
@@ -137,7 +138,7 @@ const feedName=id=>{ const f=S.feeds.find(x=>x.id===id); return f?(f.title||f.id
|
||||
/// Replaces one row with a fresh one, leaving the rest of the list and its scroll alone.
|
||||
function swapRow(e){
|
||||
const row=$(`#eps .ep[data-guid="${CSS.escape(e.guid)}"]`);
|
||||
if(row) row.replaceWith(epEl(e));
|
||||
if(row){ row.replaceWith(epEl(e)); syncPlayButtons(); }
|
||||
}
|
||||
|
||||
/// Read and unread as this page last set them, and when the server had it. A list asked for
|
||||
@@ -257,6 +258,7 @@ function showDetail(e){
|
||||
$('#dback').onclick=()=>showDetail(null);
|
||||
for(const root of [box,files]) if(root) $$('button[data-a]',root).forEach(b=>
|
||||
b.onclick=()=>epAction(b.dataset.a,e,null,b.dataset.enc?Number(b.dataset.enc):null));
|
||||
syncPlayButtons();
|
||||
}
|
||||
|
||||
/// One enclosure: a play button when the file is here, otherwise what it is and a way to get it.
|
||||
|
||||
@@ -22,6 +22,8 @@ function play(e,enc=e.enclosures.find(isPlayable)){
|
||||
}
|
||||
// The same file carries on where it was; another of the item's files starts from its top.
|
||||
const resuming = player.guid===e.guid && player.enc===enc.id;
|
||||
// Every play button is a pause button for what is playing, as the player bar's is.
|
||||
if(resuming && !audio.paused){ audio.pause(); return; }
|
||||
if(!resuming){
|
||||
player.guid=e.guid; player.feed=e.feed_id; player.entry=e; player.enc=enc.id; player.moved=false;
|
||||
document.body.classList.toggle('has-video', kindOf(enc)==='video');
|
||||
@@ -84,6 +86,22 @@ audio.addEventListener('ended',()=>{savePos();markPlayed();$('#pplay').innerHTML
|
||||
// body.playing is what sets the EQ bars moving.
|
||||
audio.addEventListener('play',()=>{ $('#pplay').innerHTML=ICON.pause; document.body.classList.add('playing'); });
|
||||
audio.addEventListener('pause',()=>{ $('#pplay').innerHTML=ICON.play; document.body.classList.remove('playing'); });
|
||||
for(const ev of ['play','pause','ended']) audio.addEventListener(ev,syncPlayButtons);
|
||||
|
||||
/// Every play button for what is playing shows pause, like the player bar's: a row's, the files
|
||||
/// pane's, the toolbar's. Only the bar's used to change, so the others said play while it played.
|
||||
function syncPlayButtons(){
|
||||
const on=(guid,enc?)=>!audio.paused&&player.guid===guid&&(enc==null||player.enc===enc);
|
||||
const paint=(b,now,idle)=>{
|
||||
const label=now?'Pause':idle;
|
||||
if(b.title===label) return;
|
||||
b.title=label; b.setAttribute('aria-label',label); b.innerHTML=now?ICON.pause:ICON.play;
|
||||
};
|
||||
for(const b of $$('#eps .ep [data-a=play]')) paint(b,on(b.closest('.ep').dataset.guid),'Play');
|
||||
for(const b of $$('#files [data-a=play][data-enc], #detail [data-a=play][data-enc]'))
|
||||
paint(b,on(S.sel,Number(b.dataset.enc)),'Play');
|
||||
const e=cur(); paint($('#tbPlay'),!!e&&on(e.guid),'Play the selected item');
|
||||
}
|
||||
for(const ev of ['play','pause','timeupdate']) audio.addEventListener(ev,syncListening);
|
||||
window.addEventListener('beforeunload',savePos);
|
||||
$('#pplay').onclick=()=>audio.paused?audio.play():audio.pause();
|
||||
|
||||
Reference in New Issue
Block a user