clone

a desktop tv and program guide for over-the-air broadcasts: what's on air, what your tuner gets, live tv, recordings

Record opens to this one, every episode or new only

FelineStateMachine committed 9633ca2
The guide's actions had three record buttons side by side. One Record
now opens, in its place, to the three choices, the first focused; Esc
or another program folds them back. A program without series
information keeps the plain Record. R, Shift R and N are as before.
commit
9633ca2e7b6a5c1e87223a037d485fc6a0029978
parent
b1832427144bb0a1813f8fc378b73fa1c9b6e867
author
FelineStateMachine <226808055+FelineStateMachine@users.noreply.github.com>
kind
feat risk score 1.8 of 3, Jev's estimate
2 files changed, +31 -6
MREADME.md2+-
Mfrontend/dist/app.js35++++++++++++++++++++++++++----
M README.md +1 -1
@@ -158,7 +158,7 @@ had.
158158 159159 | Key | Elsewhere |160160 | --- | --- |161-| G | Guide: arrows move, and Up and Down wrap round the channels. The filters (Favorites, Sports...; also `[` `]`) are Down from the top bar, which is Left from the earliest program. Enter watches what's on, or shows a program to come's actions; hold Enter, or I, for any program's: watch, record, series, new episodes only, favorite, hide. Home jumps to now, R / Shift R / N record, Shift F favorite, H hide (U undoes) |161+| G | Guide: arrows move, and Up and Down wrap round the channels. The filters (Favorites, Sports...; also `[` `]`) are Down from the top bar, which is Left from the earliest program. Enter watches what's on, or shows a program to come's actions; hold Enter, or I, for any program's: watch, record (which opens to this one, every episode or new only), favorite, hide. Home jumps to now, R / Shift R / N record, Shift F favorite, H hide (U undoes) |162162 | D | Recordings: Left (or `[` `]`) for Library, Coming up, Series. Enter shows a recording's actions: resume, from the start, watched, delete (press twice); for one recording now, watch from the start, 30 more minutes, stop (keeping it) and delete; Shift Enter starts over, W marks watched, Delete twice removes; on a series K sets how many to keep, N new episodes only |163163 | A | Reception: what the tuners measured, by RF channel (the ones the scan found first), with the transmitters licensed on each. Up and Down pick one, Enter watches its first channel; Left for the tuner, Measure now, which reads every RF channel on a free tuner and shows its progress, and Scan for channels (press twice) |164164 | W | Weather: current conditions, alerts, the next 24 hours, 7-day, radar loop and satellite; Up and Down move through them, Left to watch the weather channel |
M frontend/dist/app.js +30 -5
@@ -161,6 +161,7 @@ const state = {
161161 config: null, // location the lineup is built for162162 dvr: null, // recording state from the server163163 dvrKeys: new Map(), // "7.1@1791058239" -> upcoming item164+ recPick: '', // the airing whose Record is open to its choices164165 recording: null, // recording being played instead of live TV165166 captionsFor: null, // captions turned off or on for one program: { key, on }166167 recTab: 'library',
@@ -1556,6 +1557,7 @@ function restoreFocus() {
15561557 // recording's actions, the guide's filters): it goes to the view's main15571558 // part, and reports whether it did.15581559 function viewBack() {1560+ if (state.view === 'guide' && state.recPick) { closeRecordPick(); return true; }15591561 if (state.view === 'guide' && guideUI.zone !== 'grid') { guideZone('grid'); return true; }15601562 if (state.view === 'recordings' && recUI.zone === 'actions') { recZone('list'); return true; }15611563 return false;
@@ -1877,9 +1879,10 @@ function wireGuide() {
18771879 const ch = list[state.gRow];18781880 switch (b.dataset.act) {18791881 case 'watch': return watchChannel(ch);1880- case 'once': return recordSelected('once');1881- case 'series': return recordSelected('series', false);1882- case 'new': return recordSelected('series', true);1882+ case 'record': return openRecordPick(ch, selectedProgram(list));1883+ case 'once': state.recPick = ''; return recordSelected('once');1884+ case 'series': state.recPick = ''; return recordSelected('series', false);1885+ case 'new': state.recPick = ''; return recordSelected('series', true);18831886 case 'fav': return toggleFavorite(ch);18841887 case 'hide': guideZone('grid'); return hideChannel(ch);18851888 default: return null;
@@ -2180,13 +2183,18 @@ function renderGuideActions(ch, p) {
21802183 const label = { recording: 'Recording now', unavailable: 'Channel not available', conflict: 'Conflict: every tuner records then' }[it.status] || 'Recording scheduled';21812184 parts.push(`<span class="chip ${it.status === 'unavailable' || it.status === 'conflict' ? 'warn' : 'live'}">${label}</span>`);21822185 parts.push(act('once', it.status === 'recording' ? 'Stop recording' : 'Cancel'));2186+ } else if (!rule && p.seriesId) {2187+ // One Record, which opens to this airing, every episode or new ones;2188+ // another program closes it.2189+ if (state.recPick !== airingKey(ch, p)) state.recPick = '';2190+ parts.push(state.recPick === airingKey(ch, p)2191+ ? act('once', '<i></i>This one', 'rec') + act('series', 'Every episode') + act('new', 'New only')2192+ : act('record', '<i></i>Record', 'rec'));21832193 } else {21842194 parts.push(act('once', '<i></i>Record', 'rec'));21852195 }21862196 if (rule) {21872197 parts.push(`<span class="chip new">Series${rule.newOnly ? ', new only' : ''}</span>${act('series', 'Stop series')}`);2188- } else if (p.seriesId) {2189- parts.push(act('series', 'Record series') + act('new', 'New episodes only'));21902198 }21912199 }21922200 if (!airing) parts.push(act('watch', `Watch ${esc(ch.number)}`));
@@ -2219,6 +2227,23 @@ function fitGuideDetail() {
22192227 if (box.offsetHeight > room) box.classList.add('one-row');22202228 }22212229 2230+// openRecordPick opens Record into its three choices, the first focused.2231+function openRecordPick(ch, p) {2232+ if (!ch || !p) return;2233+ state.recPick = airingKey(ch, p);2234+ renderGuideActions(ch, p);2235+ focusEl(f($('#guide'), 'actions').querySelector('[data-act="once"]'));2236+}2237+2238+// closeRecordPick folds the choices back into Record, focused.2239+function closeRecordPick() {2240+ state.recPick = '';2241+ const list = guideChannels();2242+ renderGuideActions(list[state.gRow], selectedProgram(list));2243+ const rec = f($('#guide'), 'actions').querySelector('[data-act="record"]');2244+ if (rec && guideUI.zone === 'actions') focusEl(rec);2245+}2246+22222247 function recordSelected(kind, newOnly) {22232248 const list = guideChannels();22242249 return recordAiring(list[state.gRow], selectedProgram(list), kind, newOnly);