MOBILE-2348 core: Implement and apply core-timer
parent
20395c1eba
commit
d5c3523023
|
@ -11,7 +11,7 @@
|
|||
</ion-header>
|
||||
<ion-content>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<!-- Navigation arrows -->
|
||||
<!-- Navigation arrows and time left. -->
|
||||
<div *ngIf="questions && questions.length && !quizAborted && !showSummary">
|
||||
<ion-row align-items-center>
|
||||
<ion-col col-2>
|
||||
|
@ -19,8 +19,8 @@
|
|||
<ion-icon name="arrow-back" md="ios-arrow-back"></ion-icon>
|
||||
</a>
|
||||
</ion-col>
|
||||
<ion-col col-8>
|
||||
<!-- @todo <core-timer *ngIf="endTime" end-time="endTime" finished="timeUp()" timer-text="{{ 'mma.mod_quiz.timeleft' | translate }}"></core-timer> -->
|
||||
<ion-col col-8 text-center>
|
||||
<core-timer *ngIf="endTime" [endTime]="endTime" (finished)="timeUp()" [timerText]="'addon.mod_quiz.timeleft' | translate" align="center"></core-timer>
|
||||
</ion-col>
|
||||
<ion-col col-2 text-right>
|
||||
<a ion-button icon-only color="light" *ngIf="nextPage >= -1" (click)="changePage(nextPage)" [title]="'core.next' | translate">
|
||||
|
@ -101,7 +101,8 @@
|
|||
<ion-item text-wrap *ngIf="attempt.dueDateWarning">
|
||||
{{ attempt.dueDateWarning }}
|
||||
</ion-item>
|
||||
<!-- @todo <core-timer ng-if="endTime" end-time="endTime" finished="timeUp()" timer-text="{{ 'mma.mod_quiz.timeleft' | translate }}"></core-timer> -->
|
||||
<!-- Time left (if quiz is timed). -->
|
||||
<core-timer *ngIf="endTime" [endTime]="endTime" (finished)="timeUp()" [timerText]="'addon.mod_quiz.timeleft' | translate"></core-timer>
|
||||
<!-- List of messages explaining why the quiz cannot be submitted. -->
|
||||
<ion-item text-wrap *ngIf="preventSubmitMessages.length">
|
||||
<p class="item-heading">{{ 'addon.mod_quiz.cannotsubmitquizdueto' | translate }}</p>
|
||||
|
|
|
@ -40,6 +40,7 @@ import { CoreRichTextEditorComponent } from './rich-text-editor/rich-text-editor
|
|||
import { CoreNavBarButtonsComponent } from './navbar-buttons/navbar-buttons';
|
||||
import { CoreDynamicComponent } from './dynamic-component/dynamic-component';
|
||||
import { CoreSendMessageFormComponent } from './send-message-form/send-message-form';
|
||||
import { CoreTimerComponent } from './timer/timer';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -65,7 +66,8 @@ import { CoreSendMessageFormComponent } from './send-message-form/send-message-f
|
|||
CoreRichTextEditorComponent,
|
||||
CoreNavBarButtonsComponent,
|
||||
CoreDynamicComponent,
|
||||
CoreSendMessageFormComponent
|
||||
CoreSendMessageFormComponent,
|
||||
CoreTimerComponent
|
||||
],
|
||||
entryComponents: [
|
||||
CoreContextMenuPopoverComponent,
|
||||
|
@ -98,7 +100,8 @@ import { CoreSendMessageFormComponent } from './send-message-form/send-message-f
|
|||
CoreRichTextEditorComponent,
|
||||
CoreNavBarButtonsComponent,
|
||||
CoreDynamicComponent,
|
||||
CoreSendMessageFormComponent
|
||||
CoreSendMessageFormComponent,
|
||||
CoreTimerComponent
|
||||
]
|
||||
})
|
||||
export class CoreComponentsModule {}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<ion-item #container class="core-timer" [attr.text-center]="align == 'center' ? true : null" [attr.text-right]="align == 'right' ? true : null">
|
||||
<ion-icon name="timer" item-start></ion-icon>
|
||||
<label *ngIf="timeLeft > 0 && timerText">{{ timerText }}</label>
|
||||
<span *ngIf="timeLeft > 0">{{ timeLeft | coreSecondsToHMS }}</span>
|
||||
<span class="core-timesup" *ngIf="timeLeft <= 0">{{ 'core.timesup' | translate }}</span>
|
||||
</ion-item>
|
|
@ -0,0 +1,21 @@
|
|||
core-timer {
|
||||
.core-timer {
|
||||
background-color: $core-timer-color;
|
||||
|
||||
span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
// Create the timer warning colors. Go from $core-timer-color to $core-timer-warn-color.
|
||||
@for $i from 0 through $core-timer-iterations {
|
||||
&.core-timer-timeleft-#{$i} {
|
||||
background-color: mix($core-timer-color, $core-timer-warn-color, ($i / $core-timer-iterations) * 100);
|
||||
@if $i <= $core-timer-iterations / 2 {
|
||||
label, span, ion-icon {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, ElementRef, ViewChild } from '@angular/core';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
|
||||
/**
|
||||
* This directive shows a timer in format HH:MM:SS. When the countdown reaches 0, a function is called.
|
||||
*
|
||||
* Usage:
|
||||
* <core-timer [endTime]="endTime" (finished)="timeUp()" [timerText]="'addon.mod_quiz.timeleft' | translate"></core-timer>
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-timer',
|
||||
templateUrl: 'timer.html'
|
||||
})
|
||||
export class CoreTimerComponent implements OnInit, OnDestroy {
|
||||
@Input() endTime: string | number; // Timestamp (in seconds) when the timer should end.
|
||||
@Input() timerText: string; // Text to show next to the timer. If not defined, no text shown.
|
||||
@Input() timeLeftClass: string; // Name of the class to apply with each second. By default, 'core-timer-timeleft-'.
|
||||
@Input() align: string; // Where to align the time and text. Defaults to 'left'. Other values: 'center', 'right'.
|
||||
@Output() finished: EventEmitter<void>; // Will emit an event when the timer reaches 0.
|
||||
|
||||
@ViewChild('container', { read: ElementRef }) containerRef: ElementRef;
|
||||
|
||||
timeLeft: number; // Seconds left to end.
|
||||
|
||||
protected timeInterval;
|
||||
protected container: HTMLElement;
|
||||
|
||||
constructor(protected timeUtils: CoreTimeUtilsProvider) {
|
||||
this.finished = new EventEmitter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
const timeLeftClass = this.timeLeftClass || 'core-timer-timeleft-',
|
||||
endTime = Math.round(Number(this.endTime)),
|
||||
container: HTMLElement = this.containerRef && this.containerRef.nativeElement;
|
||||
|
||||
if (!endTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check time left every 200ms.
|
||||
this.timeInterval = setInterval(() => {
|
||||
this.timeLeft = endTime - this.timeUtils.timestamp();
|
||||
|
||||
if (this.timeLeft < 0) {
|
||||
// Time is up! Stop the timer and call the finish function.
|
||||
clearInterval(this.timeInterval);
|
||||
this.finished.emit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the time has nearly expired, change the color.
|
||||
if (this.timeLeft < 100 && !container.classList.contains(timeLeftClass + this.timeLeft)) {
|
||||
// Time left has changed. Remove previous classes and add the new one.
|
||||
container.classList.remove(timeLeftClass + (this.timeLeft + 1));
|
||||
container.classList.remove(timeLeftClass + (this.timeLeft + 2));
|
||||
container.classList.add(timeLeftClass + this.timeLeft);
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
clearInterval(this.timeInterval);
|
||||
}
|
||||
}
|
|
@ -208,6 +208,11 @@ $core-rte-min-height: 80px;
|
|||
|
||||
$core-toolbar-button-image-width: 32px;
|
||||
|
||||
// Timer variables.
|
||||
$core-timer-warn-color: $red !default;
|
||||
$core-timer-color: $white !default;
|
||||
$core-timer-iterations: 15 !default;
|
||||
|
||||
// Mixins
|
||||
// -------------------------
|
||||
@mixin core-transition($where: all, $time: 500ms) {
|
||||
|
|
Loading…
Reference in New Issue