From b48a27e656ddef892ddca935931a8b2e2fec024b Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 3 Jun 2020 11:28:22 +0200 Subject: [PATCH] MOBILE-3413 h5pactivity: Implement viewing attempt results --- scripts/langindex.json | 27 +++ src/addon/mod/h5pactivity/lang/en.json | 13 ++ .../attempt-results/attempt-results.html | 140 ++++++++++++ .../attempt-results/attempt-results.module.ts | 35 +++ .../attempt-results/attempt-results.scss | 55 +++++ .../pages/attempt-results/attempt-results.ts | 133 ++++++++++++ .../pages/user-attempts/user-attempts.html | 14 +- .../pages/user-attempts/user-attempts.ts | 4 +- .../mod/h5pactivity/providers/h5pactivity.ts | 199 +++++++++++++++++- src/assets/lang/en.json | 13 ++ src/components/icon/icon.scss | 4 +- 11 files changed, 621 insertions(+), 16 deletions(-) create mode 100644 src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.html create mode 100644 src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.module.ts create mode 100644 src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.scss create mode 100644 src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.ts diff --git a/scripts/langindex.json b/scripts/langindex.json index b1f7cff39..c6dc699fe 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -659,12 +659,39 @@ "addon.mod_glossary.noentriesfound": "local_moodlemobileapp", "addon.mod_glossary.searchquery": "local_moodlemobileapp", "addon.mod_glossary.tagarea_glossary_entries": "glossary", + "addon.mod_h5pactivity.all_attempts": "h5pactivity", + "addon.mod_h5pactivity.answer_checked": "h5pactivity", + "addon.mod_h5pactivity.answer_correct": "h5pactivity", + "addon.mod_h5pactivity.answer_fail": "h5pactivity", + "addon.mod_h5pactivity.answer_incorrect": "h5pactivity", + "addon.mod_h5pactivity.answer_pass": "h5pactivity", + "addon.mod_h5pactivity.attempt": "h5pactivity", + "addon.mod_h5pactivity.attempt_completion_no": "h5pactivity", + "addon.mod_h5pactivity.attempt_completion_yes": "h5pactivity", + "addon.mod_h5pactivity.attempt_success_fail": "h5pactivity", + "addon.mod_h5pactivity.attempt_success_pass": "h5pactivity", + "addon.mod_h5pactivity.attempt_success_unknown": "h5pactivity", + "addon.mod_h5pactivity.attempts_none": "h5pactivity", + "addon.mod_h5pactivity.completion": "h5pactivity", "addon.mod_h5pactivity.downloadh5pfile": "local_moodlemobileapp", + "addon.mod_h5pactivity.duration": "h5pactivity", "addon.mod_h5pactivity.errorgetactivity": "local_moodlemobileapp", "addon.mod_h5pactivity.filestatenotdownloaded": "local_moodlemobileapp", "addon.mod_h5pactivity.filestateoutdated": "local_moodlemobileapp", + "addon.mod_h5pactivity.maxscore": "h5pactivity", "addon.mod_h5pactivity.modulenameplural": "h5pactivity", + "addon.mod_h5pactivity.myattempts": "h5pactivity", + "addon.mod_h5pactivity.no_compatible_track": "h5pactivity", "addon.mod_h5pactivity.offlinedisabledwarning": "local_moodlemobileapp", + "addon.mod_h5pactivity.outcome": "h5pactivity", + "addon.mod_h5pactivity.result_fill-in": "h5pactivity", + "addon.mod_h5pactivity.result_other": "h5pactivity", + "addon.mod_h5pactivity.review_my_attempts": "h5pactivity", + "addon.mod_h5pactivity.score": "h5pactivity", + "addon.mod_h5pactivity.score_out_of": "h5pactivity", + "addon.mod_h5pactivity.startdate": "h5pactivity", + "addon.mod_h5pactivity.totalscore": "h5pactivity", + "addon.mod_h5pactivity.viewattempt": "local_moodlemobileapp", "addon.mod_imscp.deploymenterror": "imscp", "addon.mod_imscp.modulenameplural": "imscp", "addon.mod_imscp.showmoduledescription": "local_moodlemobileapp", diff --git a/src/addon/mod/h5pactivity/lang/en.json b/src/addon/mod/h5pactivity/lang/en.json index 7e1619d3b..21bb9eecd 100644 --- a/src/addon/mod/h5pactivity/lang/en.json +++ b/src/addon/mod/h5pactivity/lang/en.json @@ -1,5 +1,11 @@ { "all_attempts": "All user attempts", + "answer_checked": "Answer checked", + "answer_correct": "Your answer is correct", + "answer_fail": "Incorrect answer", + "answer_incorrect": "Your answer is incorrect", + "answer_pass": "Correct answer", + "attempt": "Attempt", "attempt_completion_no": "This attempt is not marked as completed", "attempt_completion_yes": "This attempt is completed", "attempts_none": "This user has no attempts to display.", @@ -15,8 +21,15 @@ "maxscore": "Max score", "modulenameplural": "H5P", "myattempts": "My attempts", + "no_compatible_track": "This interaction ({{$a}}) does not provide tracking information or the tracking provided is not compatible with the current activity version.", "offlinedisabledwarning": "You will need to be online to view the H5P package.", + "outcome": "Outcome", + "result_fill-in": "Fill-in text", + "result_other": "Unkown interaction type", "review_my_attempts": "View my attempts", "score": "Score", + "score_out_of": "{{$a.rawscore}} out of {{$a.maxscore}}", + "startdate": "Start date", + "totalscore": "Total score", "viewattempt": "View attempt {{$a}}" } \ No newline at end of file diff --git a/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.html b/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.html new file mode 100644 index 000000000..4ff03aa34 --- /dev/null +++ b/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.html @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + +

{{ 'addon.mod_h5pactivity.attempt' | translate }} #{{attempt.attempt}}: {{user.fullname}}

+
+ + +

{{ 'addon.mod_h5pactivity.attempt' | translate }} #{{attempt.attempt}}

+
+ + + + + +

{{ 'addon.mod_h5pactivity.startdate' | translate }}

+

{{ attempt.timecreated | coreFormatDate:'strftimedatetime' }}

+
+ +

{{ 'addon.mod_h5pactivity.completion' | translate }}

+

+ + {{ 'addon.mod_h5pactivity.attempt_completion_yes' | translate }} +

+

+ + {{ 'addon.mod_h5pactivity.attempt_completion_no' | translate }} +

+
+ +

{{ 'addon.mod_h5pactivity.duration' | translate }}

+

{{ attempt.durationReadable }}

+
+ +

{{ 'addon.mod_h5pactivity.outcome' | translate }}

+

+ + {{ 'addon.mod_h5pactivity.attempt_success_pass' | translate }} +

+

+ + {{ 'addon.mod_h5pactivity.attempt_success_fail' | translate }} +

+

+ {{ 'addon.mod_h5pactivity.attempt_success_unknown' | translate }} +

+
+ +

{{ 'addon.mod_h5pactivity.totalscore' | translate }}

+

{{ 'addon.mod_h5pactivity.score_out_of' | translate:{$a: attempt} }}

+
+
+
+ + + + + + + + + + + + + + + + {{ result.optionslabel }} + {{ result.correctlabel }} + {{ result.answerlabel }} + + + + + + + + + + + + + + + + + + + + + + +

{{ 'addon.mod_h5pactivity.score' | translate }}: {{ 'addon.mod_h5pactivity.score_out_of' | translate:{$a: result} }}

+
+
+ + + + {{ 'addon.mod_h5pactivity.no_compatible_track' | translate:{$a: result.interactiontype} }} + +
+
+
+
+
+ + + +

+ + {{ answer.answer }} +

+

+ + {{ answer.answer }} +

+

+ {{ answer.answer }} +

+

+ +

+

+ +

+

+ +

+
diff --git a/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.module.ts b/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.module.ts new file mode 100644 index 000000000..a692f5b14 --- /dev/null +++ b/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.module.ts @@ -0,0 +1,35 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// 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 { NgModule } from '@angular/core'; +import { IonicPageModule } from 'ionic-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { CorePipesModule } from '@pipes/pipes.module'; +import { AddonModH5PActivityAttemptResultsPage } from './attempt-results'; + +@NgModule({ + declarations: [ + AddonModH5PActivityAttemptResultsPage, + ], + imports: [ + CoreComponentsModule, + CoreDirectivesModule, + CorePipesModule, + IonicPageModule.forChild(AddonModH5PActivityAttemptResultsPage), + TranslateModule.forChild(), + ], +}) +export class AddonModH5PActivityAttemptResultsPageModule {} diff --git a/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.scss b/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.scss new file mode 100644 index 000000000..04b50c7d4 --- /dev/null +++ b/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.scss @@ -0,0 +1,55 @@ +ion-app.app-root page-addon-mod-h5pactivity-attempt-results { + + .addon-mod_h5pactivity-attempt-result-summary { + img { + width: 16px; + height: 16px; + display: inline; + @include margin-horizontal(0, 4px); + } + + .icon { + font-size: 1.4em; + } + } + + .addon-mod_h5pactivity-result-table-header .item-inner { + font-size: 0.9em; + font-weight: bold; + + .col[text-center] { + @include padding-horizontal(0); + } + } + + .addon-mod_h5pactivity-result-table-header, .addon-mod_h5pactivity-result-table-row { + + .item-inner ion-label { + @include margin(null, 0, null, null); + } + + .item { + @include padding(null, null, null, 0); + } + + .label { + margin-top: 0; + margin-bottom: 0; + } + + .icon { + font-size: 1.2em; + } + } + + .addon-mod_h5pactivity-result-table-row.item:nth-child(even) { + background-color: $gray-lighter; + @include darkmode() { + background-color: $core-dark-item-divider-bg-color; + } + } + + .addon-mod_h5pactivity-result-score { + border-top: 1px solid black; + } +} diff --git a/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.ts b/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.ts new file mode 100644 index 000000000..fdd495c7b --- /dev/null +++ b/src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.ts @@ -0,0 +1,133 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// 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, OnInit } from '@angular/core'; +import { IonicPage, NavParams } from 'ionic-angular'; +import { CoreDomUtils } from '@providers/utils/dom'; +import { CoreUser } from '@core/user/providers/user'; +import { + AddonModH5PActivity, AddonModH5PActivityProvider, AddonModH5PActivityData, AddonModH5PActivityAttemptResults +} from '../../providers/h5pactivity'; + +/** + * Page that displays results of an attempt. + */ +@IonicPage({ segment: 'addon-mod-h5pactivity-attempt-results' }) +@Component({ + selector: 'page-addon-mod-h5pactivity-attempt-results', + templateUrl: 'attempt-results.html', +}) +export class AddonModH5PActivityAttemptResultsPage implements OnInit { + loaded: boolean; + h5pActivity: AddonModH5PActivityData; + attempt: AddonModH5PActivityAttemptResults; + user: any; + component = AddonModH5PActivityProvider.COMPONENT; + + protected courseId: number; + protected h5pActivityId: number; + protected attemptId: number; + + constructor(navParams: NavParams) { + this.courseId = navParams.get('courseId'); + this.h5pActivityId = navParams.get('h5pActivityId'); + this.attemptId = navParams.get('attemptId'); + } + + /** + * Component being initialized. + * + * @return Promise resolved when done. + */ + async ngOnInit(): Promise { + try { + await this.fetchData(); + } catch (error) { + CoreDomUtils.instance.showErrorModalDefault(error, 'Error loading attempt.'); + } finally { + this.loaded = true; + } + } + + /** + * Refresh the data. + * + * @param refresher Refresher. + */ + doRefresh(refresher: any): void { + this.refreshData().finally(() => { + refresher.complete(); + }); + } + + /** + * Get quiz data and attempt data. + * + * @return Promise resolved when done. + */ + protected async fetchData(): Promise { + await Promise.all([ + this.fetchActivity(), + this.fetchAttempt(), + ]); + + await this.fetchUserProfile(); + } + + /** + * Get activity data. + * + * @return Promise resolved when done. + */ + protected async fetchActivity(): Promise { + this.h5pActivity = await AddonModH5PActivity.instance.getH5PActivityById(this.courseId, this.h5pActivityId); + } + + /** + * Get attempts. + * + * @return Promise resolved when done. + */ + protected async fetchAttempt(): Promise { + this.attempt = await AddonModH5PActivity.instance.getResults(this.h5pActivityId, this.attemptId); + } + + /** + * Get user profile. + * + * @return Promise resolved when done. + */ + protected async fetchUserProfile(): Promise { + this.user = await CoreUser.instance.getProfile(this.attempt.userid, this.courseId, true); + } + + /** + * Refresh the data. + * + * @return Promise resolved when done. + */ + protected async refreshData(): Promise { + + try { + await Promise.all([ + AddonModH5PActivity.instance.invalidateActivityData(this.courseId), + AddonModH5PActivity.instance.invalidateAttemptResults(this.h5pActivityId, this.attemptId), + ]); + } catch (error) { + // Ignore errors. + } + + await this.fetchData(); + } +} diff --git a/src/addon/mod/h5pactivity/pages/user-attempts/user-attempts.html b/src/addon/mod/h5pactivity/pages/user-attempts/user-attempts.html index 7712c6415..85822234a 100644 --- a/src/addon/mod/h5pactivity/pages/user-attempts/user-attempts.html +++ b/src/addon/mod/h5pactivity/pages/user-attempts/user-attempts.html @@ -9,13 +9,11 @@ - - - -

{{ user.fullname }}

-

{{ 'addon.mod_h5pactivity.myattempts' | translate }}

-
-
+ + +

{{ user.fullname }}

+

{{ 'addon.mod_h5pactivity.myattempts' | translate }}

+
@@ -57,7 +55,7 @@ - + {{ attempt.attempt }} {{ attempt.timemodified | coreFormatDate:'strftimedatetimeshort' }} diff --git a/src/addon/mod/h5pactivity/pages/user-attempts/user-attempts.ts b/src/addon/mod/h5pactivity/pages/user-attempts/user-attempts.ts index 19bcd9878..7e33e03cd 100644 --- a/src/addon/mod/h5pactivity/pages/user-attempts/user-attempts.ts +++ b/src/addon/mod/h5pactivity/pages/user-attempts/user-attempts.ts @@ -31,13 +31,13 @@ import { }) export class AddonModH5PActivityUserAttemptsPage implements OnInit { loaded: boolean; + courseId: number; + h5pActivityId: number; h5pActivity: AddonModH5PActivityData; attemptsData: AddonModH5PActivityUserAttempts; user: any; isCurrentUser: boolean; - protected courseId: number; - protected h5pActivityId: number; protected userId: number; constructor(navParams: NavParams) { diff --git a/src/addon/mod/h5pactivity/providers/h5pactivity.ts b/src/addon/mod/h5pactivity/providers/h5pactivity.ts index 4ee07967f..b57500a5c 100644 --- a/src/addon/mod/h5pactivity/providers/h5pactivity.ts +++ b/src/addon/mod/h5pactivity/providers/h5pactivity.ts @@ -41,9 +41,32 @@ export class AddonModH5PActivityProvider { protected formatAttempt(attempt: AddonModH5PActivityWSAttempt): AddonModH5PActivityAttempt { const formattedAttempt: AddonModH5PActivityAttempt = attempt; + formattedAttempt.timecreated = attempt.timecreated * 1000; // Convert to milliseconds. formattedAttempt.timemodified = attempt.timemodified * 1000; // Convert to milliseconds. - formattedAttempt.durationReadable = CoreTimeUtils.instance.formatTime(attempt.duration); - formattedAttempt.durationCompact = CoreTimeUtils.instance.formatDurationShort(attempt.duration); + formattedAttempt.success = typeof formattedAttempt.success == 'undefined' ? null : formattedAttempt.success; + + if (!attempt.duration) { + formattedAttempt.durationReadable = '-'; + formattedAttempt.durationCompact = '-'; + } else { + formattedAttempt.durationReadable = CoreTimeUtils.instance.formatTime(attempt.duration); + formattedAttempt.durationCompact = CoreTimeUtils.instance.formatDurationShort(attempt.duration); + } + + return formattedAttempt; + } + + /** + * Format attempt data and results. + * + * @param attempt Attempt and results to format. + */ + protected formatAttemptResults(attempt: AddonModH5PActivityWSAttemptResults): AddonModH5PActivityAttemptResults { + const formattedAttempt: AddonModH5PActivityAttemptResults = this.formatAttempt(attempt); + + for (const i in formattedAttempt.results) { + formattedAttempt.results[i] = this.formatResult(formattedAttempt.results[i]); + } return formattedAttempt; } @@ -70,6 +93,17 @@ export class AddonModH5PActivityProvider { return formatted; } + /** + * Format an attempt's result. + * + * @param result Result to format. + */ + protected formatResult(result: AddonModH5PActivityWSResult): AddonModH5PActivityWSResult { + result.timecreated = result.timecreated * 1000; // Convert to milliseconds. + + return result; + } + /** * Get cache key for access information WS calls. * @@ -210,6 +244,61 @@ export class AddonModH5PActivityProvider { return this.getH5PActivityByField(courseId, 'id', id, forceCache, siteId); } + /** + * Get cache key for results WS calls. + * + * @param id Instance ID. + * @param attemptsIds Attempts IDs. + * @return Cache key. + */ + protected getResultsCacheKey(id: number, attemptsIds: number[]): string { + return this.getResultsCommonCacheKey(id) + ':' + JSON.stringify(attemptsIds); + } + + /** + * Get common cache key for results WS calls. + * + * @param id Instance ID. + * @return Cache key. + */ + protected getResultsCommonCacheKey(id: number): string { + return this.ROOT_CACHE_KEY + 'results:' + id; + } + + /** + * Get attempt results. + * + * @param id Activity ID. + * @param attemptId Attempt ID. + * @param options Other options. + * @return Promise resolved with the attempts of the user. + */ + async getResults(id: number, attemptId: number, options?: AddonModH5PActivityGetResultsOptions) + : Promise { + + options = options || {}; + + const site = await CoreSites.instance.getSite(options.siteId); + + const params = { + h5pactivityid: id, + attemptids: [attemptId], + }; + const preSets: CoreSiteWSPreSets = { + cacheKey: this.getResultsCacheKey(id, params.attemptids), + updateFrequency: CoreSite.FREQUENCY_SOMETIMES, + }; + + if (options.ignoreCache) { + preSets.getFromCache = false; + preSets.emergencyCache = false; + } + + const response: AddonModH5PActivityGetResultsResult = await site.read('mod_h5pactivity_get_results', params, preSets); + + return this.formatAttemptResults(response.attempts[0]); + } + /** * Get cache key for attemps WS calls. * @@ -290,6 +379,33 @@ export class AddonModH5PActivityProvider { await site.invalidateWsCacheForKey(this.getH5PActivityDataCacheKey(courseId)); } + /** + * Invalidates all attempts results for H5P activity. + * + * @param id Activity ID. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when the data is invalidated. + */ + async invalidateAllResults(id: number, siteId?: string): Promise { + const site = await CoreSites.instance.getSite(siteId); + + await site.invalidateWsCacheForKey(this.getResultsCommonCacheKey(id)); + } + + /** + * Invalidates results of a certain attempt for H5P activity. + * + * @param id Activity ID. + * @param attemptId Attempt ID. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when the data is invalidated. + */ + async invalidateAttemptResults(id: number, attemptId: number, siteId?: string): Promise { + const site = await CoreSites.instance.getSite(siteId); + + await site.invalidateWsCacheForKey(this.getResultsCacheKey(id, [attemptId])); + } + /** * Invalidates all users attempts for H5P activity. * @@ -416,7 +532,16 @@ export type AddonModH5PActivityGetAttemptsResult = { }; /** - * Attempts data for a user as returned by the WS. + * Result of WS mod_h5pactivity_get_results. + */ +export type AddonModH5PActivityGetResultsResult = { + activityid: number; // Activity course module ID. + attempts: AddonModH5PActivityWSAttemptResults[]; // The complete attempts list. + warnings?: CoreWSExternalWarning[]; +}; + +/** + * Attempts data for a user as returned by the WS mod_h5pactivity_get_attempts. */ export type AddonModH5PActivityWSUserAttempts = { userid: number; // The user id. @@ -429,7 +554,7 @@ export type AddonModH5PActivityWSUserAttempts = { }; /** - * Attempt data as returned by the WS. + * Attempt data as returned by the WS mod_h5pactivity_get_attempts. */ export type AddonModH5PActivityWSAttempt = { id: number; // ID of the context. @@ -447,7 +572,56 @@ export type AddonModH5PActivityWSAttempt = { }; /** - * Attempts data with some calculated data. + * Attempt and results data as returned by the WS mod_h5pactivity_get_results. + */ +export type AddonModH5PActivityWSAttemptResults = AddonModH5PActivityWSAttempt & { + results?: AddonModH5PActivityWSResult[]; // The results of the attempt. +}; + +/** + * Attempt result data as returned by the WS mod_h5pactivity_get_results. + */ +export type AddonModH5PActivityWSResult = { + id: number; // ID of the context. + attemptid: number; // ID of the H5P attempt. + subcontent: string; // Subcontent identifier. + timecreated: number; // Result creation. + interactiontype: string; // Interaction type. + description: string; // Result description. + content?: string; // Result extra content. + rawscore: number; // Result score value. + maxscore: number; // Result max score. + duration?: number; // Result duration in seconds. + completion?: number; // Result completion. + success?: number; // Result success. + optionslabel?: string; // Label used for result options. + correctlabel?: string; // Label used for correct answers. + answerlabel?: string; // Label used for user answers. + track?: boolean; // If the result has valid track information. + options?: { // The statement options. + description: string; // Option description. + id: number; // Option identifier. + correctanswer: AddonModH5PActivityWSResultAnswer; // The option correct answer. + useranswer: AddonModH5PActivityWSResultAnswer; // The option user answer. + }[]; +}; + +/** + * Result answer as returned by the WS mod_h5pactivity_get_results. + */ +export type AddonModH5PActivityWSResultAnswer = { + answer?: string; // Option text value. + correct?: boolean; // If has to be displayed as correct. + incorrect?: boolean; // If has to be displayed as incorrect. + text?: boolean; // If has to be displayed as simple text. + checked?: boolean; // If has to be displayed as a checked option. + unchecked?: boolean; // If has to be displayed as a unchecked option. + pass?: boolean; // If has to be displayed as passed. + fail?: boolean; // If has to be displayed as failed. +}; + +/** + * User attempts data with some calculated data. */ export type AddonModH5PActivityUserAttempts = { userid: number; // The user id. @@ -467,6 +641,13 @@ export type AddonModH5PActivityAttempt = AddonModH5PActivityWSAttempt & { durationCompact?: string; // Duration in a "short" human readable format. }; +/** + * Attempt and results data with some calculated data. + */ +export type AddonModH5PActivityAttemptResults = AddonModH5PActivityAttempt & { + results?: AddonModH5PActivityWSResult[]; // The results of the attempt. +}; + /** * Options to pass to getDeployedFile function. */ @@ -476,6 +657,14 @@ export type AddonModH5PActivityGetDeployedFileOptions = { siteId?: string; // Site ID. If not defined, current site. }; +/** + * Options to pass to getResults function. + */ +export type AddonModH5PActivityGetResultsOptions = { + ignoreCache?: boolean; // Whether to ignore cache. Will fail if offline or server down. + siteId?: string; // Site ID. If not defined, current site. +}; + /** * Options to pass to getAttempts function. */ diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 1f5a0268a..38dddb5cb 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -660,6 +660,12 @@ "addon.mod_glossary.searchquery": "Search query", "addon.mod_glossary.tagarea_glossary_entries": "Glossary entries", "addon.mod_h5pactivity.all_attempts": "All user attempts", + "addon.mod_h5pactivity.answer_checked": "Answer checked", + "addon.mod_h5pactivity.answer_correct": "Your answer is correct", + "addon.mod_h5pactivity.answer_fail": "Incorrect answer", + "addon.mod_h5pactivity.answer_incorrect": "Your answer is incorrect", + "addon.mod_h5pactivity.answer_pass": "Correct answer", + "addon.mod_h5pactivity.attempt": "Attempt", "addon.mod_h5pactivity.attempt_completion_no": "This attempt is not marked as completed", "addon.mod_h5pactivity.attempt_completion_yes": "This attempt is completed", "addon.mod_h5pactivity.attempt_success_fail": "Fail", @@ -675,9 +681,16 @@ "addon.mod_h5pactivity.maxscore": "Max score", "addon.mod_h5pactivity.modulenameplural": "H5P", "addon.mod_h5pactivity.myattempts": "My attempts", + "addon.mod_h5pactivity.no_compatible_track": "This interaction ({{$a}}) does not provide tracking information or the tracking provided is not compatible with the current activity version.", "addon.mod_h5pactivity.offlinedisabledwarning": "You will need to be online to view the H5P package.", + "addon.mod_h5pactivity.outcome": "Outcome", + "addon.mod_h5pactivity.result_fill-in": "Fill-in text", + "addon.mod_h5pactivity.result_other": "Unkown interaction type", "addon.mod_h5pactivity.review_my_attempts": "View my attempts", "addon.mod_h5pactivity.score": "Score", + "addon.mod_h5pactivity.score_out_of": "{{$a.rawscore}} out of {{$a.maxscore}}", + "addon.mod_h5pactivity.startdate": "Start date", + "addon.mod_h5pactivity.totalscore": "Total score", "addon.mod_h5pactivity.viewattempt": "View attempt {{$a}}", "addon.mod_imscp.deploymenterror": "Content package error!", "addon.mod_imscp.modulenameplural": "IMS content packages", diff --git a/src/components/icon/icon.scss b/src/components/icon/icon.scss index a80559c8e..f14ba848a 100644 --- a/src/components/icon/icon.scss +++ b/src/components/icon/icon.scss @@ -7,7 +7,9 @@ @each $color-name, $color-base, $color-contrast in get-colors($colors-dark) { .fa-#{$color-name} { - color: $color-base !important; + @include darkmode() { + color: $color-base !important; + } } }