Skip to content

Commit

Permalink
web app: Support overrides and add tooltips
Browse files Browse the repository at this point in the history
- Upcoming list has an icon added for creating and updating override
  rules
- All program and recording lists now have episode description that
  shows when hovering over subtitle.
  • Loading branch information
bennettpeter committed Jul 8, 2023
1 parent 093dafa commit 55ef522
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 40 deletions.
5 changes: 4 additions & 1 deletion mythtv/html/assets/i18n/en_US.json
Expand Up @@ -67,7 +67,9 @@
"seas_ep": "Seas Ep",
"season": "Season",
"subtitle": "Subtitle",
"title": "Title"
"title": "Title",
"edit_rule": "Edit Recording Rule",
"override_rule": "Add or Edit Override Rule"
},
"recrule": {
"type": "Type"
Expand Down Expand Up @@ -347,6 +349,7 @@
"weekHeader": "Wk"
},
"recrule": {
"DonotRecord": "Do not Record",
"NotRecording": "Not Recording",
"OverrideRecording": "Override Recording",
"RecordAll": "Record All",
Expand Down
Expand Up @@ -48,7 +48,7 @@ <h2>{{ 'settings.chanedit.title' | translate }}</h2>
<th style="flex-basis: 6%">
<!-- These are disabled buttons to ensure the spacing of the heading
matches the spacing of the rows -->
<button pButton pRipple icon="pi pi-pencil" class="p-button-text p-button-success"
<button pButton pRipple icon="pi pi-pencil" class="p-button-text"
disabled="true"></button>
<button pButton pRipple icon="pi pi-trash" class="p-button-text p-button-danger"
*ngIf="setupService.pageType == 'S'" disabled="true"></button>
Expand All @@ -71,13 +71,15 @@ <h2>{{ 'settings.chanedit.title' | translate }}</h2>
<td style="flex-basis: 10%">{{ getVisibility(channel) }}</td>
<td style="flex-basis: 6%">{{ channel.UseEIT ? 'Y' : 'N' }}</td>
<td style="flex-basis: 6%">
<button pButton pRipple icon="pi pi-pencil" class="p-button-text p-button-success"
<button pButton pRipple icon="pi pi-pencil" class="p-button-text"
(click)="editChannel(channel)" [disabled]="channel.ChanId < 0
|| (setupService.pageType == 'S' && setupService.schedulingEnabled)"
pTooltip="{{ 'settings.chanedit.updatechan' | translate }}"></button>
pTooltip="{{ 'settings.chanedit.updatechan' | translate }}"
tooltipPosition="left"></button>
<button pButton pRipple icon="pi pi-trash" class="p-button-text p-button-danger"
*ngIf="setupService.pageType == 'S'" (click)="deleteRequest(channel)"
pTooltip="{{ 'settings.chanedit.deletechan' | translate }}"
tooltipPosition="left"
[disabled]="channel.ChanId < 0 || setupService.schedulingEnabled"></button>
</td>
</tr>
Expand Down
Expand Up @@ -25,6 +25,10 @@
{{ 'dashboard.recordings.recgrp' | translate }} </th>
<th style="flex-basis: 7%" class="p-1">
{{ 'dashboard.upcoming.status' | translate }} </th>
<th style="flex-basis: 2%" class="p-1" *ngIf="usage == 'UPCOMING'">
<button pButton pRipple icon="pi pi-paperclip" [disabled]="true"
class="p-button-text p-button-primary"></button>
</th>
<th style="flex-basis: 2%" class="p-1"> <button pButton pRipple icon="pi pi-pencil" [disabled]="true"
class="p-button-text p-button-primary"></button>
</th>
Expand All @@ -41,7 +45,8 @@
<td style="flex-basis: 8%" class="p-1" *ngIf="usage == 'UPCOMING'">{{program.Recording.EncoderName}}
</td>
<td style="flex-basis: 12%" class="p-1 overflow-hidden"> {{program.Title}}</td>
<td style="flex-basis: 18%" class="p-1 overflow-hidden">
<td style="flex-basis: 18%" class="p-1 overflow-hidden" pTooltip="{{program.Description}}"
tooltipPosition="top">
{{program.SubTitle.slice(0,50)}}</td>
<td style="flex-basis: 4%" class="p-1">
<div *ngIf="program.Season>0 || program.Episode>0"> {{program.Season}}x{{program.Episode}}</div>
Expand All @@ -57,9 +62,15 @@
{{dataService.recStatusText[program.Recording.StatusName]}}
</div>
</td>
<td style="flex-basis: 2%" class="p-1" *ngIf="usage == 'UPCOMING'">
<button pButton pRipple icon="pi pi-paperclip" class="p-button-text p-button-primary"
(click)="override(program)" pTooltip="{{ 'dashboard.recordings.override_rule' | translate }}"
tooltipPosition="left"></button>
</td>
<td style="flex-basis: 2%" class="p-1">
<button pButton pRipple icon="pi pi-pencil" class="p-button-text p-button-primary"
(click)="updateRecRule(program)"></button>
(click)="updateRecRule(program)" pTooltip="{{ 'dashboard.recordings.edit_rule' | translate }}"
tooltipPosition="left" [disabled]="program.Recording && program.Recording.RecType == 7"></button>
</td>
</tr>
</ng-template>
Expand Down
Expand Up @@ -2,6 +2,7 @@ import { Component, Input, OnInit } from '@angular/core';
import { ScheduleLink } from 'src/app/schedule/schedule.component';
import { DataService } from 'src/app/services/data.service';
import { ScheduleOrProgram } from 'src/app/services/interfaces/program.interface';
import { RecRule } from 'src/app/services/interfaces/recording.interface';

@Component({
selector: 'app-programs',
Expand All @@ -14,8 +15,6 @@ export class ProgramsComponent implements OnInit {
// Usage: GUIDE, UPCOMING
@Input() usage: string = '';

// programs!: ProgramList;
editingProgram?: ScheduleOrProgram;
displayUpdateDlg = false;
displayUnsaved = false;
successCount = 0;
Expand Down Expand Up @@ -75,9 +74,17 @@ export class ProgramsComponent implements OnInit {
}

updateRecRule(program: ScheduleOrProgram) {
let copyProgram = Object.assign({}, program);
if (this.inter.sched)
this.inter.sched.open(copyProgram);
this.inter.sched.open(program);
}

override(program: ScheduleOrProgram) {
if (this.inter.sched) {
if (program.Recording.RecType == 7) // If already an override
this.inter.sched.open(program);
else
this.inter.sched.open(program, undefined, <RecRule>{ Type: 'Override Recording' });
}
}

}
Expand Up @@ -4,7 +4,8 @@
</div>
<h2>{{ 'dashboard.recordings.heading' | translate }}</h2>
<div class="block card w-full" style="height: 90vh" *ngIf="recordings else loading">
<p-slideMenu #menu [popup]="true" [model]="menuToShow" [viewportHeight]="360" [backLabel]="translate.instant('common.back')"></p-slideMenu>
<p-slideMenu #menu [popup]="true" [model]="menuToShow" [viewportHeight]="360"
[backLabel]="translate.instant('common.back')"></p-slideMenu>
<p-table [value]="recordings.Programs" scrollHeight="flex" [scrollable]="true" styleClass="p-datatable-striped"
[rowHover]="true" responsiveLayout="scroll">
<ng-template pTemplate="caption">
Expand Down Expand Up @@ -61,7 +62,8 @@ <h2>{{ 'dashboard.recordings.heading' | translate }}</h2>
<td style="flex-basis: 2%" class="p-1">
<i class="pi pi-eye" *ngIf="program.ProgramFlagNames.indexOf('WATCHED') > -1"></i>
</td>
<td style="flex-basis: 18%" class="p-1 overflow-hidden">
<td style="flex-basis: 18%" class="p-1 overflow-hidden" pTooltip="{{program.Description}}"
tooltipPosition="top">
{{program.SubTitle}}</td>
<td style="flex-basis: 4%" class="p-1">
<div *ngIf="program.Season>0 || program.Episode>0"> {{program.Season}}x{{program.Episode}}
Expand Down Expand Up @@ -111,9 +113,8 @@ <h2>{{ 'dashboard.recordings.heading' | translate }}</h2>
<div class="form-group field">
<label for="Description" class="label block">{{ 'dashboard.recordings.description' | translate
}}</label>
<textarea pInputTextarea [rows]="5" [cols]="30" id="Description"
[(ngModel)]="program.Description" name="Description" #Description="ngModel"
class="mb-2 form-control w-full"></textarea>
<textarea pInputTextarea [rows]="5" [cols]="30" id="Description" [(ngModel)]="program.Description"
name="Description" #Description="ngModel" class="mb-2 form-control w-full"></textarea>
</div>

<div class="form-group field">
Expand Down
Expand Up @@ -5,7 +5,7 @@ <h2>{{ 'dashboard.recrules.heading' | translate }}</h2>
<ng-template pTemplate="caption">
<button pButton pRipple label="{{ 'dashboard.recrules.new_recrule' | translate }}" icon="pi pi-plus"
class="p-button-success mr-2" (click)="newRecRule()"></button>
<button pButton pRipple label="{{ 'dashboard.recrules.new_teplate' | translate }}"
<button pButton pRipple label="{{ 'dashboard.recrules.new_teplate' | translate }}"
class="p-button-success p-button-outlined mr-2" (click)="newTemplate()" icon="pi pi-plus"></button>
</ng-template>
<ng-template pTemplate="header">
Expand Down Expand Up @@ -56,7 +56,8 @@ <h2>{{ 'dashboard.recrules.heading' | translate }}</h2>
</td>
<td style="flex-basis: 5%" class="p-1">
<button pButton pRipple icon="pi pi-pencil" class="p-button-text p-button-primary"
(click)="updateRecRule(recrule)"></button>
(click)="updateRecRule(recrule)" pTooltip="{{ 'dashboard.recordings.edit_rule' | translate }}"
tooltipPosition="left"></button>
</td>
</tr>
</ng-template>
Expand Down
Expand Up @@ -29,18 +29,21 @@ export class RecrulesComponent implements OnInit, SchedulerSummary {
"Record Daily": "",
"Record Weekly": "",
"Override Recording": "",
"Do not Record": "",
"Recording Template": "",
"Not Recording": ""
};

deSpacer = new RegExp(/ /g);

rulesLoaded = false;
errorCount = 0;

constructor(private dvrService: DvrService, private translate: TranslateService,
public utility: UtilityService) {
// translations
for (const [key, value] of Object.entries(this.typeValue)) {
const label = 'recrule.' + key.replace(' ', '');
const label = 'recrule.' + key.replace(this.deSpacer, '');
this.translate.get(label).subscribe(data => {
Object.defineProperty(this.typeValue, key, { value: data });
});
Expand Down
28 changes: 14 additions & 14 deletions mythtv/html/backend/src/app/dashboard/videos/videos.component.html
Expand Up @@ -22,12 +22,12 @@ <h2>{{ 'dashboard.videos.heading' | translate }}</h2>
</p-button>
</div>
<div *ngIf="refreshing else refreshBn"><p-progressSpinner
[style]="{width: '30px', height: '30px'}"></p-progressSpinner></div>
<ng-template #refreshBn>
<button pButton pRipple icon="pi pi-refresh" class="p-button-text .p-button-success"
(click)="refreshing=true;loadVideos()"
pTooltip="{{ 'common.refresh' | translate }}"></button>
</ng-template>
[style]="{width: '30px', height: '30px'}"></p-progressSpinner></div>
<ng-template #refreshBn>
<button pButton pRipple icon="pi pi-refresh" class="p-button-text .p-button-success"
(click)="refreshing=true;loadVideos()"
pTooltip="{{ 'common.refresh' | translate }}"></button>
</ng-template>

</th>
</tr>
Expand Down Expand Up @@ -65,7 +65,9 @@ <h2>{{ 'dashboard.videos.heading' | translate }}</h2>
<td style="flex-basis: 3%" class="p-1">
<i class="pi pi-eye" *ngIf="video.Watched"></i>
</td>
<td style="flex-basis: 30%" class="p-1 overflow-hidden"> {{video.SubTitle}}</td>
<td style="flex-basis: 30%" class="p-1 overflow-hidden" pTooltip="{{video.Description}}"
tooltipPosition="top">
{{video.SubTitle}}</td>
<td style="flex-basis: 6%" class="p-1">
<div *ngIf="video.Season>0 || video.Episode>0"> {{video.Season}}x{{video.Episode}} </div>
</td>
Expand All @@ -76,8 +78,8 @@ <h2>{{ 'dashboard.videos.heading' | translate }}</h2>
</td>
<td style="flex-basis: 3%" class="p-1">
<div *ngIf="video.ContentType != 'D'">
<button pButton pRipple icon="pi pi-ellipsis-v"
class="p-button-text p-button-primary" (click)="showMenu(video,$event)"></button>
<button pButton pRipple icon="pi pi-ellipsis-v" class="p-button-text p-button-primary"
(click)="showMenu(video,$event)"></button>
</div>
</td>
</tr>
Expand Down Expand Up @@ -110,9 +112,8 @@ <h2>{{ 'dashboard.videos.heading' | translate }}</h2>
<div class="form-group field">
<label for="Description" class="label block">{{ 'dashboard.recordings.description' | translate
}}</label>
<textarea pInputTextarea [rows]="5" [cols]="30" id="Description"
[(ngModel)]="video.Description" name="Description" #Description="ngModel"
class="mb-2 form-control w-full"></textarea>
<textarea pInputTextarea [rows]="5" [cols]="30" id="Description" [(ngModel)]="video.Description"
name="Description" #Description="ngModel" class="mb-2 form-control w-full"></textarea>
</div>

<div class="form-group field">
Expand Down Expand Up @@ -147,8 +148,7 @@ <h2>{{ 'dashboard.videos.heading' | translate }}</h2>
styleClass="p-button-warning">
</p-button>
<p-button icon="pi pi-check-circle" (onClick)="saveVideo();" label="{{ 'common.save' | translate }}"
styleClass="p-button-success"
[disabled]="!vidsform.dirty || video.Title.trim() == '' "></p-button>
styleClass="p-button-success" [disabled]="!vidsform.dirty || video.Title.trim() == '' "></p-button>
</ng-template>

</p-dialog>
Expand Down
5 changes: 3 additions & 2 deletions mythtv/html/backend/src/app/schedule/schedule.component.html
Expand Up @@ -2,7 +2,7 @@
<div *ngIf="recRule">
<p-dialog header="{{ 'dashboard.sched.heading' | translate }}" [(visible)]="displayDlg" [modal]="true"
[style]="{height: '90vw', width: '700px'}" [closable]="false" [closeOnEscape]="false">
<p> {{ channel?.ChanNum }} {{ channel?.CallSign }}</p>
<p> {{ recRule.CallSign }}</p>
<p> {{ utility.formatDate(recRule.StartTime) }} {{ utility.formatTime(recRule.StartTime) }} -
{{ utility.formatTime(recRule.EndTime )}}
</p>
Expand Down Expand Up @@ -111,7 +111,8 @@
<div class="form-group field">
<p-checkbox inputId="Active" [(ngModel)]="recRule.Inactive" name="Active" #Active="ngModel"
class="label mb-2 w-full" [binary]="true" label="{{ 'dashboard.sched.active_label' | translate }}"
[trueValue]="false" [falseValue]="true">
[trueValue]="false" [falseValue]="true"
[disabled]="override">
</p-checkbox>
</div>

Expand Down
31 changes: 25 additions & 6 deletions mythtv/html/backend/src/app/schedule/schedule.component.ts
Expand Up @@ -55,6 +55,7 @@ export class ScheduleComponent implements OnInit {
titleRows = 1;
subTitleRows = 1;
descriptionRows = 5;
override = false;
program?: ScheduleOrProgram;
channel?: Channel;
recRule?: RecRule;
Expand Down Expand Up @@ -249,9 +250,20 @@ export class ScheduleComponent implements OnInit {
}

setupData() {
let newOverride = false;
this.program = this.reqProgram;
let ruleType = '';
if (this.reqRecRule)
this.recRule = Object.assign({}, this.reqRecRule);
ruleType = this.reqRecRule.Type;
if (this.reqRecRule) {
if (['Override Recording', 'Do not Record'].indexOf(ruleType) > -1 && !this.reqRecRule.Id) {
newOverride = true;
this.recRule = undefined;
}
else
// This works because RecRule only has elementary items.
this.recRule = Object.assign({}, this.reqRecRule);
}
else
this.recRule = undefined;
this.channel = this.reqChannel;
Expand All @@ -262,12 +274,9 @@ export class ScheduleComponent implements OnInit {

var recId = 0;
this.typeList = [];
let ruleType: string = '';
if (this.reqRecRule)
ruleType = this.reqRecRule.Type;
this.templates = [<RecRule>{ Id: 0, Title: '' }];
this.defaultTemplate = undefined;
if (this.program && this.program.Recording)
if (this.program && this.program.Recording && !newOverride)
recId = this.program.Recording.RecordId;
this.recRules.forEach((entry, index) => {
if (entry.Id == recId) {
Expand Down Expand Up @@ -296,6 +305,9 @@ export class ScheduleComponent implements OnInit {
if (this.program && this.channel && this.recRule.SearchType == 'None')
this.mergeProgram(this.recRule, this.program, this.channel);

if (newOverride)
this.recRule.ParentId = this.program!.Recording.RecordId;

if (!ruleType)
ruleType = 'Not Recording';

Expand All @@ -314,6 +326,10 @@ export class ScheduleComponent implements OnInit {

if (!this.srchTypeDisabled)
this.onSearchTypeChange();

if (this.override)
this.recRule.Inactive = false;

setTimeout(() => {
if (this.recRule)
this.recRule.Type = ruleType;
Expand All @@ -324,6 +340,7 @@ export class ScheduleComponent implements OnInit {
setupTypeList(recRule: RecRule) {
let ruleType = recRule.Type;
this.typeList.length = 0;
this.override = false;
if (ruleType == 'Recording Template') {
this.typeList.push(
{
Expand All @@ -340,7 +357,8 @@ export class ScheduleComponent implements OnInit {
);
}
}
else if (ruleType == 'Override Recording')
else if (['Override Recording', 'Do not Record'].indexOf(ruleType) > -1) {
this.override = true;
this.typeList.push(
{
prompt: this.translate.instant('dashboard.sched.type.del_override'),
Expand All @@ -355,6 +373,7 @@ export class ScheduleComponent implements OnInit {
value: 'Do not Record'
}
);
}
else {
const isManual = (recRule.SearchType == 'Manual Search');
const isSearch = (recRule.SearchType != 'None');
Expand Down

0 comments on commit 55ef522

Please sign in to comment.