|
1 | 1 | <link rel="stylesheet" href="course.page.scss">
|
2 | 2 | <ion-header>
|
3 |
| - <ion-toolbar> |
4 |
| - <ion-buttons slot="start" [routerLink]="'/home/'+year"> |
5 |
| - <ion-back-button [defaultHref]="'/home/'+year"></ion-back-button> |
6 |
| - </ion-buttons> |
7 |
| - <ion-title> |
8 |
| - {{ course ?? 'Course' }} |
9 |
| - @if (courseProgress.duration > 0) { |
10 |
| - <small>{{ (courseProgress.duration - courseProgress.viewed) / 3600 | number:'1.0-1' }} hours left</small> |
11 |
| - } |
12 |
| - </ion-title> |
13 |
| - </ion-toolbar> |
| 3 | + <ion-toolbar> |
| 4 | + <ion-buttons slot="start" [routerLink]="'/home/'+year"> |
| 5 | + <ion-back-button [defaultHref]="'/home/'+year"></ion-back-button> |
| 6 | + </ion-buttons> |
| 7 | + <ion-title> |
| 8 | + {{ course ?? 'Course' }} |
| 9 | + @if (courseProgress.duration > 0) { |
| 10 | + <small>{{ (courseProgress.duration - courseProgress.viewed) / 3600 | number:'1.0-1' }} hours left</small> |
| 11 | + } |
| 12 | + </ion-title> |
| 13 | + </ion-toolbar> |
14 | 14 | </ion-header>
|
15 | 15 |
|
16 | 16 | <ion-content>
|
17 |
| - <ion-grid> |
18 |
| - <ion-row> |
19 |
| - <ion-col size="12" size-lg [hidden]="!currentVideo"> |
20 |
| - <video #videoPlayer class="video-js vjs-default-skin fullwidth" controls preload="metadata" |
21 |
| - data-setup='{"aspectRatio":"1280:640", "playbackRates": [0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 3]}' |
22 |
| - [hidden]="currentVideo && currentVideo.sources.length === 0" |
23 |
| - (contextmenu)="preventMouseEvent($event)" tabindex="1"> |
24 |
| - Your browser does not support the video tag. |
25 |
| - </video> |
26 |
| - @if (currentVideo) { |
27 |
| - <ion-text color="medium"> |
28 |
| - <p> |
29 |
| - {{ currentVideo.title }}@if (currentVideo.lecturer) { |
30 |
| - <span> - {{ currentVideo.lecturer }}</span> |
31 |
| - }<br/> |
32 |
| - <ion-button (click)="setPlaybackSpeed()" (keyup)="setPlaybackSpeed()" fill="outline" size="small" tabindex="0" class="set-playback-speed-button">Set playback speed</ion-button> |
33 |
| - @if (currentVideo.sourceExternal?.includes('1.mp4')) { |
34 |
| - <span> |
| 17 | + <ion-grid> |
| 18 | + <ion-row> |
| 19 | + <ion-col size="12" size-lg [hidden]="!currentVideo"> |
| 20 | + <video #videoPlayer class="video-js vjs-default-skin fullwidth" controls preload="metadata" |
| 21 | + data-setup='{"aspectRatio":"1280:640", "playbackRates": [0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 3]}' |
| 22 | + [hidden]="currentVideo && currentVideo.sources.length === 0" |
| 23 | + (contextmenu)="preventMouseEvent($event)" tabindex="1"> |
| 24 | + Your browser does not support the video tag. |
| 25 | + </video> |
| 26 | + @if (progressTimedOut) { |
| 27 | + <ion-card color="danger"> |
| 28 | + <ion-card-header> |
| 29 | + <ion-card-title>Session timed out.</ion-card-title> |
| 30 | + </ion-card-header> |
| 31 | + <ion-card-content> |
| 32 | + Cannot save your progress. Please refresh the page to continue watching. |
| 33 | + You're currently at {{ progressTimedOut }}. |
| 34 | + </ion-card-content> |
| 35 | + </ion-card> |
| 36 | + } |
| 37 | + @if (progressNetworkError) { |
| 38 | + <ion-card color="danger"> |
| 39 | + <ion-card-header> |
| 40 | + <ion-card-title>Network Error.</ion-card-title> |
| 41 | + </ion-card-header> |
| 42 | + <ion-card-content> |
| 43 | + Cannot save your progress. Please check your internet connection. |
| 44 | + </ion-card-content> |
| 45 | + </ion-card> |
| 46 | + } |
| 47 | + @if (currentVideo) { |
| 48 | + <ion-text color="medium"> |
| 49 | + <p> |
| 50 | + {{ currentVideo.title }}@if (currentVideo.lecturer) { |
| 51 | + <span> - {{ currentVideo.lecturer }}</span> |
| 52 | + }<br/> |
| 53 | + <ion-button (click)="setPlaybackSpeed()" (keyup)="setPlaybackSpeed()" fill="outline" |
| 54 | + size="small" tabindex="0" class="set-playback-speed-button"> |
| 55 | + Set playback speed |
| 56 | + </ion-button> |
| 57 | + @if (currentVideo.sourceExternal?.includes('1.mp4')) { |
| 58 | + <span> |
35 | 59 | | <a [href]="sanitize('//player.docchula.com/?url='+currentVideo.sourceExternal)" rel="noreferrer" target="_blank">
|
36 | 60 | Play with Docchula Player</a>
|
37 | 61 | </span>
|
38 |
| -} |
| 62 | + } |
39 | 63 | @if (isAndroid && currentVideo.sourceExternal) {
|
40 |
| -<span> |
| 64 | + <span> |
41 | 65 | | <a [href]="sanitize('intent:'+currentVideo.sourceExternal+'#Intent;S.title='+encodeURIComponent(currentVideo.title)+';package=com.mxtech.videoplayer.ad;end')" rel="noreferrer">Play with MX Player</a>
|
42 | 66 | </span>
|
43 |
| -} |
| 67 | + } |
44 | 68 | @if ((isIos || isAndroid) && currentVideo.sourceExternal) {
|
45 |
| -<span> |
| 69 | + <span> |
46 | 70 | | <a [href]="sanitize('vlc://'+currentVideo.sourceExternal)" rel="noreferrer">Play with VLC</a>
|
47 | 71 | </span>
|
48 |
| -} |
| 72 | + } |
49 | 73 | </p>
|
50 | 74 | <p class="ion-hide-md-down small-text">
|
51 | 75 | <strong>Hotkeys</strong>   Space: Pause, ▲/▼: Volume, ◄/►: Seek, F: Fullscreen
|
52 | 76 | </p>
|
53 | 77 | </ion-text>
|
54 | 78 | @if (currentVideo.sources.length === 0) {
|
55 |
| -<ion-card color="warning"> |
56 |
| - <ion-card-header> |
57 |
| - <ion-card-title>Format not supported</ion-card-title> |
58 |
| - </ion-card-header> |
59 |
| - <ion-card-content> |
60 |
| - Your browser can't play this video. Please try again using Google Chrome or Mozilla Firefox on Windows/Linux/macOS/Android. |
61 |
| - </ion-card-content> |
62 |
| - </ion-card> |
63 |
| - } |
64 |
| - @if (currentVideo.attachments.length !== 0) { |
65 |
| - <ion-list> |
66 |
| - <ion-list-header lines="inset"> |
67 |
| - <ion-label>Attachments</ion-label> |
68 |
| - </ion-list-header> |
69 |
| - @for (attachment of currentVideo.attachments; track attachment.src) { |
70 |
| - <ion-item> |
71 |
| - <ion-label>{{ attachment.name }}</ion-label> |
72 |
| - <a [href]="attachment.src" download target="_blank"> |
73 |
| - <ion-icon name="download" size="small" slot="end"></ion-icon> |
74 |
| - </a> |
75 |
| - </ion-item> |
76 |
| - } |
77 |
| - </ion-list> |
78 |
| - } |
79 |
| - } |
80 |
| - </ion-col> |
81 |
| - <ion-col size="12" size-lg [ngClass]="currentVideo ? 'scroll-area' : ''"> |
82 |
| - @if (list$ | async; as list) { |
83 |
| - <ion-list> |
84 |
| - @for (lecture of list; track lecture.id) { |
85 |
| - <ion-item button (click)="viewVideo(lecture)" |
86 |
| - [color]="(currentVideo && currentVideo.id && currentVideo.id === lecture.id) ? 'secondary' : ((lastPlayedVideoKey === lecture.id && !currentVideo) ? 'tertiary' : '')"> |
87 |
| - <ion-label class="ion-text-wrap"> |
88 |
| - @if (lecture.date) { |
89 |
| - <span class="date">{{ lecture.date | date:"dd MMM y" }}</span> |
90 |
| - } |
91 |
| - @if (lecture.date) { |
92 |
| - <span class="date-divider"> | </span> |
| 79 | + <ion-card color="warning"> |
| 80 | + <ion-card-header> |
| 81 | + <ion-card-title>Format not supported</ion-card-title> |
| 82 | + </ion-card-header> |
| 83 | + <ion-card-content> |
| 84 | + Your browser can't play this video. Please try again using Google Chrome or Mozilla Firefox on Windows/Linux/macOS/Android. |
| 85 | + </ion-card-content> |
| 86 | + </ion-card> |
| 87 | + } |
| 88 | + @if (currentVideo.attachments.length !== 0) { |
| 89 | + <ion-list> |
| 90 | + <ion-list-header lines="inset"> |
| 91 | + <ion-label>Attachments</ion-label> |
| 92 | + </ion-list-header> |
| 93 | + @for (attachment of currentVideo.attachments; track attachment.src) { |
| 94 | + <ion-item> |
| 95 | + <ion-label>{{ attachment.name }}</ion-label> |
| 96 | + <a [href]="attachment.src" download target="_blank"> |
| 97 | + <ion-icon name="download" size="small" slot="end"></ion-icon> |
| 98 | + </a> |
| 99 | + </ion-item> |
| 100 | + } |
| 101 | + </ion-list> |
| 102 | + } |
93 | 103 | }
|
94 |
| - {{ lecture.title }} |
95 |
| - <small> |
96 |
| - {{ lecture.lecturer}} |
97 |
| - @if (lecture.durationInMin) { |
98 |
| - <span class="time-info">- {{ lecture.durationInMin}} min </span> |
99 |
| - } |
100 |
| - @if (lecture.history.end_time && lecture.history.end_time > 3) { |
101 |
| - <span class="time-info"> |
| 104 | + </ion-col> |
| 105 | + <ion-col size="12" size-lg [ngClass]="currentVideo ? 'scroll-area' : ''"> |
| 106 | + @if (list$ | async; as list) { |
| 107 | + <ion-list> |
| 108 | + @for (lecture of list; track lecture.id) { |
| 109 | + <ion-item button (click)="viewVideo(lecture)" |
| 110 | + [color]="(currentVideo && currentVideo.id && currentVideo.id === lecture.id) ? 'secondary' : ((lastPlayedVideoKey === lecture.id && !currentVideo) ? 'tertiary' : '')"> |
| 111 | + <ion-label class="ion-text-wrap"> |
| 112 | + @if (lecture.date) { |
| 113 | + <span class="date">{{ lecture.date | date:"dd MMM y" }}</span> |
| 114 | + } |
| 115 | + @if (lecture.date) { |
| 116 | + <span class="date-divider"> | </span> |
| 117 | + } |
| 118 | + {{ lecture.title }} |
| 119 | + <small> |
| 120 | + {{ lecture.lecturer }} |
| 121 | + @if (lecture.durationInMin) { |
| 122 | + <span class="time-info">- {{ lecture.durationInMin }} min </span> |
| 123 | + } |
| 124 | + @if (lecture.history.end_time && lecture.history.end_time > 3) { |
| 125 | + <span class="time-info"> |
102 | 126 | @if (!lecture.duration) {
|
103 |
| - <span> |
104 |
| - - {{ (lecture.history.end_time) / 60 | number:'1.0-0'}} min played |
| 127 | + <span> |
| 128 | + - {{ (lecture.history.end_time) / 60 | number:'1.0-0' }} min played |
105 | 129 | </span>
|
106 | 130 | }
|
107 |
| - @if (lecture.duration && lecture.history.end_time/lecture.duration < 0.995) { |
108 |
| - <span> |
109 |
| - - {{ (lecture.duration - lecture.history.end_time) / 60 | number:'1.0-0'}} min left |
| 131 | + @if (lecture.duration && lecture.history.end_time / lecture.duration < 0.995) { |
| 132 | + <span> |
| 133 | + - {{ (lecture.duration - lecture.history.end_time) / 60 | number:'1.0-0' }} min left |
110 | 134 | </span>
|
111 |
| - } |
| 135 | + } |
112 | 136 | </span>
|
113 |
| - } |
114 |
| - @if (lecture.attachments.length !== 0) { |
115 |
| - <ion-icon name="document-attach-outline" size="small" color="medium"></ion-icon> |
116 |
| - } |
117 |
| - </small> |
118 |
| - @if (lecture.history.end_time && lecture.duration && lecture.history.end_time > 3 && (lecture.history.end_time/lecture.duration < 0.995)) { |
119 |
| - <ion-progress-bar |
120 |
| - [value]="lecture.history.end_time/lecture.duration"></ion-progress-bar> |
| 137 | + } |
| 138 | + @if (lecture.attachments.length !== 0) { |
| 139 | + <ion-icon name="document-attach-outline" size="small" color="medium"></ion-icon> |
| 140 | + } |
| 141 | + </small> |
| 142 | + @if (lecture.history.end_time && lecture.duration && lecture.history.end_time > 3 && (lecture.history.end_time / lecture.duration < 0.995)) { |
| 143 | + <ion-progress-bar |
| 144 | + [color]="(currentVideo && currentVideo.id && currentVideo.id === lecture.id) || (lastPlayedVideoKey === lecture.id && !currentVideo) ? 'light' : 'primary'" |
| 145 | + [value]="lecture.history.end_time/lecture.duration" /> |
| 146 | + } |
| 147 | + </ion-label> |
| 148 | + @if (lecture.history.end_time && lecture.duration && (lecture.history.end_time / lecture.duration >= 0.995)) { |
| 149 | + <ion-icon |
| 150 | + class="check-icon" |
| 151 | + name="checkmark-outline" |
| 152 | + slot="end" |
| 153 | + color="success"></ion-icon> |
| 154 | + } |
| 155 | + @if (lecture.sources.length === 0) { |
| 156 | + <ion-icon |
| 157 | + name="close-outline" |
| 158 | + slot="end" |
| 159 | + color="danger"></ion-icon> |
| 160 | + } |
| 161 | + @if (lastPlayedVideoKey === lecture.id) { |
| 162 | + <ion-icon |
| 163 | + name="pause-circle-outline" |
| 164 | + slot="end" |
| 165 | + color="medium"></ion-icon> |
| 166 | + } |
| 167 | + </ion-item> |
| 168 | + } |
| 169 | + </ion-list> |
121 | 170 | }
|
122 |
| - </ion-label> |
123 |
| - @if (lecture.history.end_time && lecture.duration && (lecture.history.end_time/lecture.duration >= 0.995)) { |
124 |
| - <ion-icon |
125 |
| - class="check-icon" |
126 |
| - name="checkmark-outline" |
127 |
| - slot="end" |
128 |
| - color="success"></ion-icon> |
129 |
| - } |
130 |
| - @if (lecture.sources.length === 0) { |
131 |
| - <ion-icon |
132 |
| - name="close-outline" |
133 |
| - slot="end" |
134 |
| - color="danger"></ion-icon> |
135 |
| - } |
136 |
| - @if (lastPlayedVideoKey === lecture.id) { |
137 |
| - <ion-icon |
138 |
| - name="pause-circle-outline" |
139 |
| - slot="end" |
140 |
| - color="medium"></ion-icon> |
141 |
| - } |
142 |
| - </ion-item> |
143 |
| - } |
144 |
| - </ion-list> |
145 |
| - } |
146 |
| - </ion-col> |
147 |
| - </ion-row> |
148 |
| -</ion-grid> |
| 171 | + </ion-col> |
| 172 | + </ion-row> |
| 173 | + </ion-grid> |
149 | 174 | </ion-content>
|
0 commit comments