MOBILE-4470 choice: Fix messages shown on the app

main
Pau Ferrer Ocaña 2024-05-14 14:55:06 +02:00
parent f8e022c1fd
commit 8f461adf74
9 changed files with 158 additions and 104 deletions

View File

@ -524,15 +524,13 @@
"addon.mod_choice.cannotsubmit": "choice",
"addon.mod_choice.choiceoptions": "choice",
"addon.mod_choice.errorgetchoice": "local_moodlemobileapp",
"addon.mod_choice.expired": "choice",
"addon.mod_choice.full": "choice",
"addon.mod_choice.limita": "choice",
"addon.mod_choice.modulenameplural": "choice",
"addon.mod_choice.noresultsviewable": "choice",
"addon.mod_choice.notopenyet": "choice",
"addon.mod_choice.numberofuser": "choice",
"addon.mod_choice.numberofuserinpercentage": "choice",
"addon.mod_choice.previewonly": "choice",
"addon.mod_choice.previewing": "choice",
"addon.mod_choice.publishinfoanonafter": "choice",
"addon.mod_choice.publishinfoanonclose": "choice",
"addon.mod_choice.publishinfofullafter": "choice",

View File

@ -22,13 +22,13 @@ import { CoreCourseModulePrefetchDelegate } from '@features/course/services/modu
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
import { CoreCronDelegate } from '@services/cron';
import { CORE_SITE_SCHEMAS } from '@services/sites';
import { AddonModChoiceProvider } from './services/choice';
import { OFFLINE_SITE_SCHEMA } from './services/database/choice';
import { AddonModChoiceIndexLinkHandler } from './services/handlers/index-link';
import { AddonModChoiceListLinkHandler } from './services/handlers/list-link';
import { AddonModChoiceModuleHandler, AddonModChoiceModuleHandlerService } from './services/handlers/module';
import { AddonModChoicePrefetchHandler } from './services/handlers/prefetch';
import { AddonModChoiceSyncCronHandler } from './services/handlers/sync-cron';
import { ADDON_MOD_CHOICE_COMPONENT } from './constants';
const routes: Routes = [
{
@ -57,7 +57,7 @@ const routes: Routes = [
CoreContentLinksDelegate.registerHandler(AddonModChoiceIndexLinkHandler.instance);
CoreContentLinksDelegate.registerHandler(AddonModChoiceListLinkHandler.instance);
CoreCourseHelper.registerModuleReminderClick(AddonModChoiceProvider.COMPONENT);
CoreCourseHelper.registerModuleReminderClick(ADDON_MOD_CHOICE_COMPONENT);
},
},
],

View File

@ -12,32 +12,17 @@
[courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()" />
<!-- Activity availability messages -->
<ion-card class="core-info-card" *ngIf="choiceNotOpenYet">
<ion-card class="core-info-card" *ngIf="showPreview && options.length">
<ion-item>
<ion-icon name="fas-circle-info" slot="start" aria-hidden="true" />
<ion-label>
<p *ngIf="options.length">{{ 'addon.mod_choice.previewonly' | translate:{$a: openTimeReadable} }}</p>
<p *ngIf="!options.length">{{ 'addon.mod_choice.notopenyet' | translate:{$a: openTimeReadable} }}</p>
</ion-label>
</ion-item>
</ion-card>
<ion-card class="core-info-card" *ngIf="choiceClosed">
<ion-item>
<ion-icon name="fas-circle-info" slot="start" aria-hidden="true" />
<ion-label>
<p *ngIf="options.length">
{{ 'addon.mod_choice.yourselection' | translate }}
<core-format-text [text]="options[0].text" contextLevel="module" [contextInstanceId]="module.id"
[courseId]="courseId" />
</p>
<p>{{ 'addon.mod_choice.expired' | translate:{$a: closeTimeReadable} }}</p>
<p>{{ 'addon.mod_choice.previewing' | translate }}</p>
</ion-label>
</ion-item>
</ion-card>
<!-- Inform what will happen with the choices. -->
<ion-card class="core-info-card" *ngIf="canEdit && publishInfo && options.length">
<ion-card class="core-info-card" *ngIf="publishInfo && options.length">
<ion-item>
<ion-icon name="fas-circle-info" slot="start" aria-hidden="true" />
<ion-label>{{ publishInfo | translate }}</ion-label>
@ -45,24 +30,40 @@
</ion-card>
<!-- Choice options -->
<ion-card *ngIf="options.length && choice">
<ion-card *ngIf="options.length && choice && (canEdit || showPreview)">
<ng-container *ngIf="choice.allowmultiple">
<ion-item class="ion-text-wrap" *ngFor="let option of options">
<ion-checkbox [(ngModel)]="option.checked" [disabled]="option.disabled || !canEdit">
<ion-checkbox [(ngModel)]="option.checked" [disabled]="option.disabled || showPreview">
<ng-container *ngTemplateOutlet="optionLabelTemplate; context: {option: option}" />
</ion-checkbox>
</ion-item>
</ng-container>
<ion-radio-group *ngIf="!choice.allowmultiple" [(ngModel)]="selectedOption.id">
<ion-item class="ion-text-wrap" *ngFor="let option of options">
<ion-radio [value]="option.id" [disabled]="option.disabled || !canEdit">
<ion-radio [value]="option.id" [disabled]="option.disabled || showPreview">
<ng-container *ngTemplateOutlet="optionLabelTemplate; context: {option: option}" />
</ion-radio>
</ion-item>
</ion-radio-group>
</ion-card>
<ion-card *ngIf="options.length && choice && !canEdit && !showPreview">
<ion-item-divider>
<ion-label>
<h2>{{ 'addon.mod_choice.yourselection' | translate }}</h2>
</ion-label>
</ion-item-divider>
<ng-container *ngFor="let option of options">
<ion-item class="ion-text-wrap" *ngIf="option.checked">
<ion-label>
<core-format-text [text]="option.text" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" />
</ion-label>
</ion-item>
</ng-container>
</ion-card>
<!-- Choice results -->
<div *ngIf="canSeeResults && choice">
<ng-container *ngIf="canSeeResults && choice">
<ion-item-divider>
<ion-label>
<h2>{{ 'addon.mod_choice.responses' | translate }}</h2>
@ -115,9 +116,9 @@
</ion-col>
</ion-row>
</ion-grid>
</div>
</ng-container>
<ion-card class="core-info-card" *ngIf="!canSeeResults && !choiceNotOpenYet">
<ion-card class="core-info-card" *ngIf="!canSeeResults && showResultsMessage">
<ion-item>
<ion-icon name="fas-circle-info" slot="start" aria-hidden="true" />
<ion-label>

View File

@ -26,7 +26,6 @@ import {
AddonModChoice,
AddonModChoiceChoice,
AddonModChoiceOption,
AddonModChoiceProvider,
AddonModChoiceResult,
} from '../../services/choice';
import { AddonModChoiceOffline } from '../../services/choice-offline';
@ -37,6 +36,7 @@ import {
AddonModChoiceSyncResult,
} from '../../services/choice-sync';
import { AddonModChoicePrefetchHandler } from '../../services/handlers/prefetch';
import { ADDON_MOD_CHOICE_COMPONENT, ADDON_MOD_CHOICE_PUBLISH_ANONYMOUS, AddonModChoiceShowResults } from '../../constants';
/**
* Component that displays a choice.
@ -47,14 +47,14 @@ import { AddonModChoicePrefetchHandler } from '../../services/handlers/prefetch'
})
export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityComponent implements OnInit {
component = AddonModChoiceProvider.COMPONENT;
component = ADDON_MOD_CHOICE_COMPONENT;
pluginName = 'choice';
choice?: AddonModChoiceChoice;
options: AddonModChoiceOption[] = [];
selectedOption: {id: number} = { id: -1 };
choiceNotOpenYet = false;
choiceClosed = false;
showPreview = false;
showResultsMessage = false;
canEdit = false;
canDelete = false;
canSeeResults = false;
@ -62,13 +62,11 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
labels: string[] = [];
results: AddonModChoiceResultFormatted[] = [];
publishInfo?: string; // Message explaining the user what will happen with his choices.
openTimeReadable?: string;
closeTimeReadable?: string;
protected userId?: number;
protected syncEventName = AddonModChoiceSyncProvider.AUTO_SYNCED;
protected hasAnsweredOnline = false;
protected now = Date.now();
protected now = CoreTimeUtils.timestamp();
constructor(
protected content?: IonContent,
@ -121,7 +119,7 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
* @inheritdoc
*/
protected async fetchContent(refresh?: boolean, sync = false, showErrors = false): Promise<void> {
this.now = Date.now();
this.now = CoreTimeUtils.timestamp();
this.choice = await AddonModChoice.getChoice(this.courseId, this.module.id);
@ -135,14 +133,7 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
}
}
this.choice.timeopen = (this.choice.timeopen || 0) * 1000;
this.choice.timeclose = (this.choice.timeclose || 0) * 1000;
this.openTimeReadable = CoreTimeUtils.userDate(this.choice.timeopen);
this.closeTimeReadable = CoreTimeUtils.userDate(this.choice.timeclose);
this.description = this.choice.intro;
this.choiceNotOpenYet = !!this.choice.timeopen && this.choice.timeopen > this.now;
this.choiceClosed = !!this.choice.timeclose && this.choice.timeclose <= this.now;
this.dataRetrieved.emit(this.choice);
@ -171,7 +162,8 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
options = await this.getOfflineResponses(choice, options);
}
const isOpen = this.isChoiceOpen(choice);
const isOpen = AddonModChoice.choiceHasBeenOpened(choice, this.now) &&
!AddonModChoice.choiceHasBeenClosed(choice, this.now);
this.selectedOption = { id: -1 }; // Single choice model.
const hasAnswered = options.some((option) => {
@ -186,30 +178,49 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
return true;
});
this.canEdit = isOpen && (choice.allowupdate! || !hasAnswered);
this.canDelete = isOpen && choice.allowupdate! && hasAnswered;
this.canEdit = isOpen && (!!choice.allowupdate || !hasAnswered);
this.canDelete = isOpen && !!choice.allowupdate && hasAnswered;
this.options = options;
if (!this.canEdit) {
this.setPublishInfo(choice, hasAnswered);
}
/**
* Set publish info message.
*
* @param choice Choice data.
*/
protected setPublishInfo(choice: AddonModChoiceChoice, hasAnswered: boolean): void {
const choiceOpen = !AddonModChoice.choiceHasBeenOpened(choice, this.now) &&
!AddonModChoice.choiceHasBeenClosed(choice, this.now);
if ((!choice.allowupdate && hasAnswered) || !choiceOpen) {
this.showPreview = false;
this.showResultsMessage = true;
this.publishInfo = '';
return;
}
this.showResultsMessage = false;
this.showPreview = !!choice.showpreview;
// Calculate the publish info message.
switch (choice.showresults) {
case AddonModChoiceProvider.RESULTS_NOT:
case AddonModChoiceShowResults.SHOWRESULTS_NOT:
this.publishInfo = 'addon.mod_choice.publishinfonever';
break;
case AddonModChoiceProvider.RESULTS_AFTER_ANSWER:
if (choice.publish == AddonModChoiceProvider.PUBLISH_ANONYMOUS) {
case AddonModChoiceShowResults.SHOWRESULTS_AFTER_ANSWER:
if (choice.publish === ADDON_MOD_CHOICE_PUBLISH_ANONYMOUS) {
this.publishInfo = 'addon.mod_choice.publishinfoanonafter';
} else {
this.publishInfo = 'addon.mod_choice.publishinfofullafter';
}
break;
case AddonModChoiceProvider.RESULTS_AFTER_CLOSE:
if (choice.publish == AddonModChoiceProvider.PUBLISH_ANONYMOUS) {
case AddonModChoiceShowResults.SHOWRESULTS_AFTER_CLOSE:
if (choice.publish === ADDON_MOD_CHOICE_PUBLISH_ANONYMOUS) {
this.publishInfo = 'addon.mod_choice.publishinfoanonclose';
} else {
this.publishInfo = 'addon.mod_choice.publishinfofullclose';
@ -288,7 +299,7 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
* @returns Resolved when done.
*/
protected async fetchResults(choice: AddonModChoiceChoice): Promise<void> {
if (this.choiceNotOpenYet) {
if (!AddonModChoice.choiceHasBeenOpened(choice, this.now)) {
// Cannot see results yet.
this.canSeeResults = false;
@ -310,7 +321,8 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
return Object.assign(result, { percentageamountfixed: result.percentageamount.toFixed(1) });
});
this.canSeeResults = hasVotes || AddonModChoice.canStudentSeeResults(choice, this.hasAnsweredOnline);
this.canSeeResults = hasVotes || AddonModChoice.canStudentSeeResults(choice, this.hasAnsweredOnline, this.now);
}
/**
@ -326,16 +338,6 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
this.analyticsLogEvent('mod_choice_view_choice');
}
/**
* Check if a choice is open.
*
* @param choice Choice data.
* @returns True if choice is open, false otherwise.
*/
protected isChoiceOpen(choice: AddonModChoiceChoice): boolean {
return (!choice.timeopen || choice.timeopen <= this.now) && (!choice.timeclose || choice.timeclose > this.now);
}
/**
* Return true if the user has selected at least one option.
*
@ -357,15 +359,17 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
* Save options selected.
*/
async save(): Promise<void> {
const choice = this.choice!;
if (!this.choice) {
return;
}
// Only show confirm if choice doesn't allow update.
if (!choice.allowupdate) {
if (!this.choice.allowupdate) {
await CoreDomUtils.showConfirm(Translate.instant('core.areyousure'));
}
const responses: number[] = [];
if (choice.allowmultiple) {
if (this.choice.allowmultiple) {
this.options.forEach((option) => {
if (option.checked) {
responses.push(option.id);
@ -378,7 +382,7 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
try {
const online = await AddonModChoice.submitResponse(choice.id, choice.name, this.courseId, responses);
const online = await AddonModChoice.submitResponse(this.choice.id, this.choice.name, this.courseId, responses);
this.content?.scrollToTop();
@ -402,6 +406,10 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
* Delete options selected.
*/
async delete(): Promise<void> {
if (!this.choice) {
return;
}
try {
await CoreDomUtils.showDeleteConfirm();
} catch {
@ -412,7 +420,7 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
try {
await AddonModChoice.deleteResponses(this.choice!.id, this.choice!.name, this.courseId);
await AddonModChoice.deleteResponses(this.choice.id, this.choice.name, this.courseId);
this.content?.scrollToTop();

View File

@ -0,0 +1,29 @@
// (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.
export const ADDON_MOD_CHOICE_COMPONENT = 'mmaModChoice';
/**
* Possible show results values.
*/
export const enum AddonModChoiceShowResults {
SHOWRESULTS_NOT = 0,
SHOWRESULTS_AFTER_ANSWER = 1,
SHOWRESULTS_AFTER_CLOSE = 2,
SHOWRESULTS_ALWAYS = 3,
}
// Possible choice publish values.
export const ADDON_MOD_CHOICE_PUBLISH_ANONYMOUS = false;
export const ADDON_MOD_CHOICE_PUBLISH_NAMES = true;

View File

@ -2,15 +2,13 @@
"cannotsubmit": "Sorry, there was a problem submitting your choice. Please try again.",
"choiceoptions": "Choice options",
"errorgetchoice": "Error getting choice data.",
"expired": "This activity closed on {{$a}}.",
"full": "(Full)",
"limita": "Limit: {{$a}}",
"modulenameplural": "Choices",
"noresultsviewable": "The results are not currently viewable.",
"notopenyet": "This activity is not available until {{$a}}.",
"numberofuser": "Number of responses",
"numberofuserinpercentage": "Percentage of responses",
"previewonly": "This is just a preview of the available options for this activity. You will not be able to submit your choice until {{$a}}.",
"previewing": "This is just a preview of the available options for this activity. You will be able to make a choice when it opens.",
"publishinfoanonafter": "Anonymous results will be published after you answer.",
"publishinfoanonclose": "Anonymous results will be published after the activity is closed.",
"publishinfofullafter": "Full results, showing everyone's choices, will be published after you answer.",

View File

@ -23,9 +23,10 @@ import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { AddonModChoice, AddonModChoiceProvider } from './choice';
import { AddonModChoice } from './choice';
import { AddonModChoiceOffline } from './choice-offline';
import { AddonModChoicePrefetchHandler } from './handlers/prefetch';
import { ADDON_MOD_CHOICE_COMPONENT } from '../constants';
/**
* Service to sync choices.
@ -150,7 +151,7 @@ export class AddonModChoiceSyncProvider extends CoreCourseActivitySyncBaseProvid
};
// Sync offline logs.
await CoreUtils.ignoreErrors(CoreCourseLogHelper.syncActivity(AddonModChoiceProvider.COMPONENT, choiceId, siteId));
await CoreUtils.ignoreErrors(CoreCourseLogHelper.syncActivity(ADDON_MOD_CHOICE_COMPONENT, choiceId, siteId));
const data = await CoreUtils.ignoreErrors(AddonModChoiceOffline.getResponse(choiceId, siteId, userId));

View File

@ -27,8 +27,7 @@ import { makeSingleton, Translate } from '@singletons';
import { AddonModChoiceOffline } from './choice-offline';
import { AddonModChoiceAutoSyncData, AddonModChoiceSyncProvider } from './choice-sync';
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
const ROOT_CACHE_KEY = 'mmaModChoice:';
import { ADDON_MOD_CHOICE_COMPONENT, AddonModChoiceShowResults } from '../constants';
/**
* Service that provides some features for choices.
@ -36,15 +35,7 @@ const ROOT_CACHE_KEY = 'mmaModChoice:';
@Injectable({ providedIn: 'root' })
export class AddonModChoiceProvider {
static readonly COMPONENT = 'mmaModChoice';
static readonly RESULTS_NOT = 0;
static readonly RESULTS_AFTER_ANSWER = 1;
static readonly RESULTS_AFTER_CLOSE = 2;
static readonly RESULTS_ALWAYS = 3;
static readonly PUBLISH_ANONYMOUS = false;
static readonly PUBLISH_NAMES = true;
protected static readonly ROOT_CACHE_KEY = 'mmaModChoice:';
/**
* Check if results can be seen by a student. The student can see the results if:
@ -54,14 +45,41 @@ export class AddonModChoiceProvider {
*
* @param choice Choice to check.
* @param hasAnswered True if user has answered the choice, false otherwise.
* @param timeNow Current time in seconds.
* @returns True if the students can see the results.
*/
canStudentSeeResults(choice: AddonModChoiceChoice, hasAnswered: boolean): boolean {
const now = Date.now();
canStudentSeeResults(choice: AddonModChoiceChoice, hasAnswered: boolean, timeNow: number): boolean {
if (!this.choiceHasBeenOpened(choice, timeNow)) {
return false;
}
return choice.showresults === AddonModChoiceProvider.RESULTS_ALWAYS ||
choice.showresults === AddonModChoiceProvider.RESULTS_AFTER_CLOSE && choice.timeclose && choice.timeclose <= now ||
choice.showresults === AddonModChoiceProvider.RESULTS_AFTER_ANSWER && hasAnswered;
const choiceClosed = this.choiceHasBeenClosed(choice, timeNow);
return choice.showresults === AddonModChoiceShowResults.SHOWRESULTS_ALWAYS ||
choice.showresults === AddonModChoiceShowResults.SHOWRESULTS_AFTER_ANSWER && hasAnswered ||
choice.showresults === AddonModChoiceShowResults.SHOWRESULTS_AFTER_CLOSE && choiceClosed;
}
/**
* Check if a choice has been opened.
*
* @param choice Choice to check.
* @param timeNow Current time in seconds.
* @returns True if the choice open dated has passed, false otherwise.
*/
choiceHasBeenOpened(choice: AddonModChoiceChoice, timeNow: number): boolean {
return !choice.timeopen || timeNow > choice.timeopen;
}
/**
* Check if a choice has been closed.
*
* @param choice Choice to check.
* @param timeNow Current time in seconds.
* @returns True if the choice close dated has passed, false otherwise.
*/
choiceHasBeenClosed(choice: AddonModChoiceChoice, timeNow: number): boolean {
return !!choice.timeclose && timeNow > choice.timeclose;
}
/**
@ -154,7 +172,7 @@ export class AddonModChoiceProvider {
* @returns Cache key.
*/
protected getChoiceDataCacheKey(courseId: number): string {
return ROOT_CACHE_KEY + 'choice:' + courseId;
return AddonModChoiceProvider.ROOT_CACHE_KEY + 'choice:' + courseId;
}
/**
@ -164,7 +182,7 @@ export class AddonModChoiceProvider {
* @returns Cache key.
*/
protected getChoiceOptionsCacheKey(choiceId: number): string {
return ROOT_CACHE_KEY + 'options:' + choiceId;
return AddonModChoiceProvider.ROOT_CACHE_KEY + 'options:' + choiceId;
}
/**
@ -174,7 +192,7 @@ export class AddonModChoiceProvider {
* @returns Cache key.
*/
protected getChoiceResultsCacheKey(choiceId: number): string {
return ROOT_CACHE_KEY + 'results:' + choiceId;
return AddonModChoiceProvider.ROOT_CACHE_KEY + 'results:' + choiceId;
}
/**
@ -200,7 +218,7 @@ export class AddonModChoiceProvider {
const preSets: CoreSiteWSPreSets = {
cacheKey: this.getChoiceDataCacheKey(courseId),
updateFrequency: CoreSite.FREQUENCY_RARELY,
component: AddonModChoiceProvider.COMPONENT,
component: ADDON_MOD_CHOICE_COMPONENT,
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
};
@ -259,7 +277,7 @@ export class AddonModChoiceProvider {
const preSets: CoreSiteWSPreSets = {
cacheKey: this.getChoiceOptionsCacheKey(choiceId),
updateFrequency: CoreSite.FREQUENCY_RARELY,
component: AddonModChoiceProvider.COMPONENT,
component: ADDON_MOD_CHOICE_COMPONENT,
componentId: options.cmId,
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
};
@ -288,7 +306,7 @@ export class AddonModChoiceProvider {
};
const preSets: CoreSiteWSPreSets = {
cacheKey: this.getChoiceOptionsCacheKey(choiceId),
component: AddonModChoiceProvider.COMPONENT,
component: ADDON_MOD_CHOICE_COMPONENT,
componentId: options.cmId,
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
};
@ -332,7 +350,7 @@ export class AddonModChoiceProvider {
this.invalidateChoiceData(courseId),
this.invalidateOptions(choice.id),
this.invalidateResults(choice.id),
CoreFilepool.invalidateFilesByComponent(siteId, AddonModChoiceProvider.COMPONENT, moduleId),
CoreFilepool.invalidateFilesByComponent(siteId, ADDON_MOD_CHOICE_COMPONENT, moduleId),
]);
}
@ -377,7 +395,7 @@ export class AddonModChoiceProvider {
return CoreCourseLogHelper.log(
'mod_choice_view_choice',
params,
AddonModChoiceProvider.COMPONENT,
ADDON_MOD_CHOICE_COMPONENT,
id,
siteId,
);
@ -482,7 +500,7 @@ export type AddonModChoiceChoice = {
introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
introfiles?: CoreWSExternalFile[];
publish?: boolean; // If choice is published.
showresults?: number; // 0 never, 1 after answer, 2 after close, 3 always.
showresults?: AddonModChoiceShowResults; // 0 never, 1 after answer, 2 after close, 3 always.
display?: number; // Display mode (vertical, horizontal).
allowupdate?: boolean; // Allow update.
allowmultiple?: boolean; // Allow multiple choices.
@ -531,7 +549,7 @@ export type AddonModChoiceOption = {
id: number; // Option id.
text: string; // Text of the choice.
maxanswers: number; // Maximum number of answers.
displaylayout: boolean; // True for orizontal, otherwise vertical.
displaylayout: boolean; // True for horizontal, otherwise vertical.
countanswers: number; // Number of answers.
checked: boolean; // We already answered.
disabled: boolean; // Option disabled.

View File

@ -21,8 +21,9 @@ import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import { AddonModChoice, AddonModChoiceProvider } from '../choice';
import { AddonModChoice } from '../choice';
import { AddonModChoiceSync, AddonModChoiceSyncResult } from '../choice-sync';
import { ADDON_MOD_CHOICE_COMPONENT } from '../../constants';
/**
* Handler to prefetch choices.
@ -32,7 +33,7 @@ export class AddonModChoicePrefetchHandlerService extends CoreCourseActivityPref
name = 'AddonModChoice';
modName = 'choice';
component = AddonModChoiceProvider.COMPONENT;
component = ADDON_MOD_CHOICE_COMPONENT;
updatesNames = /^configuration$|^.*files$|^answers$/;
/**
@ -74,7 +75,7 @@ export class AddonModChoicePrefetchHandlerService extends CoreCourseActivityPref
await Promise.all([
AddonModChoice.getOptions(choice.id, modOptions),
this.prefetchResults(choice.id, courseId, modOptions),
CoreFilepool.addFilesToQueue(siteId, introFiles, AddonModChoiceProvider.COMPONENT, module.id),
CoreFilepool.addFilesToQueue(siteId, introFiles, ADDON_MOD_CHOICE_COMPONENT, module.id),
]);
}