commit
6b3d39068c
|
@ -2162,6 +2162,7 @@
|
||||||
"core.settings.disableall": "message",
|
"core.settings.disableall": "message",
|
||||||
"core.settings.disabled": "lesson",
|
"core.settings.disabled": "lesson",
|
||||||
"core.settings.disabledfeatures": "tool_mobile",
|
"core.settings.disabledfeatures": "tool_mobile",
|
||||||
|
"core.settings.disallowed": "message",
|
||||||
"core.settings.displayformat": "local_moodlemobileapp",
|
"core.settings.displayformat": "local_moodlemobileapp",
|
||||||
"core.settings.enabledownloadsection": "local_moodlemobileapp",
|
"core.settings.enabledownloadsection": "local_moodlemobileapp",
|
||||||
"core.settings.enablefirebaseanalytics": "local_moodlemobileapp",
|
"core.settings.enablefirebaseanalytics": "local_moodlemobileapp",
|
||||||
|
@ -2176,6 +2177,7 @@
|
||||||
"core.settings.filesystemroot": "local_moodlemobileapp",
|
"core.settings.filesystemroot": "local_moodlemobileapp",
|
||||||
"core.settings.fontsize": "local_moodlemobileapp",
|
"core.settings.fontsize": "local_moodlemobileapp",
|
||||||
"core.settings.fontsizecharacter": "block_accessibility/char",
|
"core.settings.fontsizecharacter": "block_accessibility/char",
|
||||||
|
"core.settings.forced": "message",
|
||||||
"core.settings.forcedsetting": "local_moodlemobileapp",
|
"core.settings.forcedsetting": "local_moodlemobileapp",
|
||||||
"core.settings.forcesafeareamargins": "local_moodlemobileapp",
|
"core.settings.forcesafeareamargins": "local_moodlemobileapp",
|
||||||
"core.settings.general": "moodle",
|
"core.settings.general": "moodle",
|
||||||
|
@ -2186,7 +2188,6 @@
|
||||||
"core.settings.license": "moodle",
|
"core.settings.license": "moodle",
|
||||||
"core.settings.localnotifavailable": "local_moodlemobileapp",
|
"core.settings.localnotifavailable": "local_moodlemobileapp",
|
||||||
"core.settings.locationhref": "local_moodlemobileapp",
|
"core.settings.locationhref": "local_moodlemobileapp",
|
||||||
"core.settings.locked": "admin",
|
|
||||||
"core.settings.loggedin": "message",
|
"core.settings.loggedin": "message",
|
||||||
"core.settings.loggedoff": "message",
|
"core.settings.loggedoff": "message",
|
||||||
"core.settings.navigatorlanguage": "local_moodlemobileapp",
|
"core.settings.navigatorlanguage": "local_moodlemobileapp",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ion-item-divider sticky="true">
|
<ion-item-divider sticky="true">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.block_activitymodules.pluginname' | translate }}</h2>
|
<h2>{{ 'addon.block_activitymodules.pluginname' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<core-loading [hideUntil]="loaded" [fullscreen]="false">
|
<core-loading [hideUntil]="loaded" [fullscreen]="false">
|
||||||
|
|
|
@ -41,12 +41,12 @@
|
||||||
|
|
||||||
<core-spacer></core-spacer>
|
<core-spacer></core-spacer>
|
||||||
<ion-item *ngIf="options.show.favourite">
|
<ion-item *ngIf="options.show.favourite">
|
||||||
<ion-label>{{ 'addon.block_myoverview.favouritesonly' | translate }}</ion-label>
|
<ion-label>{{ 'addon.block_myoverview.favouritesonly' | translate }}</ion-label>
|
||||||
<ion-toggle [(ngModel)]="options.favouriteSelected"></ion-toggle>
|
<ion-toggle [(ngModel)]="options.favouriteSelected"></ion-toggle>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item *ngIf="options.show.hidden">
|
<ion-item *ngIf="options.show.hidden">
|
||||||
<ion-label>{{ 'addon.block_myoverview.aria:hiddencourses' | translate }}</ion-label>
|
<ion-label>{{ 'addon.block_myoverview.aria:hiddencourses' | translate }}</ion-label>
|
||||||
<ion-toggle [(ngModel)]="options.hiddenSelected"></ion-toggle>
|
<ion-toggle [(ngModel)]="options.hiddenSelected"></ion-toggle>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ion-item-divider sticky="true">
|
<ion-item-divider sticky="true">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.block_recentlyaccessedcourses.pluginname' | translate }}</h2>
|
<h2>{{ 'addon.block_recentlyaccessedcourses.pluginname' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<div slot="end" class="flex-row">
|
<div slot="end" class="flex-row">
|
||||||
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId">
|
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ion-item-divider sticky="true">
|
<ion-item-divider sticky="true">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.block_recentlyaccesseditems.pluginname' | translate }}</h2>
|
<h2>{{ 'addon.block_recentlyaccesseditems.pluginname' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<div slot="end">
|
<div slot="end">
|
||||||
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId">
|
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ion-item-divider sticky="true">
|
<ion-item-divider sticky="true">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.block_sitemainmenu.pluginname' | translate }}</h2>
|
<h2>{{ 'addon.block_sitemainmenu.pluginname' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<core-loading [hideUntil]="loaded" [fullscreen]="false">
|
<core-loading [hideUntil]="loaded" [fullscreen]="false">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ion-item-divider sticky="true">
|
<ion-item-divider sticky="true">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.block_starredcourses.pluginname' | translate }}</h2>
|
<h2>{{ 'addon.block_starredcourses.pluginname' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<div slot="end" class="flex-row">
|
<div slot="end" class="flex-row">
|
||||||
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId">
|
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ion-item-divider sticky="true">
|
<ion-item-divider sticky="true">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.block_timeline.pluginname' | translate }}</h2>
|
<h2>{{ 'addon.block_timeline.pluginname' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<core-loading [hideUntil]="loaded" [fullscreen]="false">
|
<core-loading [hideUntil]="loaded" [fullscreen]="false">
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<core-loading [hideUntil]="loaded">
|
<core-loading [hideUntil]="loaded">
|
||||||
<ion-item *ngIf="showMyEntriesToggle">
|
<ion-item *ngIf="showMyEntriesToggle">
|
||||||
<ion-label>{{ 'addon.blog.showonlyyourentries' | translate }}</ion-label>
|
<ion-label>{{ 'addon.blog.showonlyyourentries' | translate }}</ion-label>
|
||||||
<ion-toggle [(ngModel)]="onlyMyEntries" (ionChange)="onlyMyEntriesToggleChanged(onlyMyEntries)"></ion-toggle>
|
<ion-toggle [(ngModel)]="onlyMyEntries" (ionChange)="onlyMyEntriesToggleChanged(onlyMyEntries)"></ion-toggle>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<core-empty-box *ngIf="entries && entries.length == 0" icon="far-newspaper" [message]="'addon.blog.noentriesyet' | translate">
|
<core-empty-box *ngIf="entries && entries.length == 0" icon="far-newspaper" [message]="'addon.blog.noentriesyet' | translate">
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<ion-label position="stacked">
|
<ion-label position="stacked">
|
||||||
<p class="item-heading" [core-mark-required]="true">{{ 'core.date' | translate }}</p>
|
<p class="item-heading" [core-mark-required]="true">{{ 'core.date' | translate }}</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-datetime formControlName="timestart" [placeholder]="'core.date' | translate" [displayFormat]="dateFormat"
|
<ion-datetime formControlName="timestart" [placeholder]="'core.date' | translate" [displayFormat]="dateFormat"
|
||||||
[max]="maxDate" [min]="minDate" display-timezone="utc">
|
[max]="maxDate" [min]="minDate" display-timezone="utc">
|
||||||
</ion-datetime>
|
</ion-datetime>
|
||||||
<core-input-errors [control]="form.controls.timestart" [errorMessages]="errors"></core-input-errors>
|
<core-input-errors [control]="form.controls.timestart" [errorMessages]="errors"></core-input-errors>
|
||||||
|
@ -156,7 +156,7 @@
|
||||||
<ion-item *ngIf="form.controls.duration.value === 1">
|
<ion-item *ngIf="form.controls.duration.value === 1">
|
||||||
<ion-label position="stacked"></ion-label>
|
<ion-label position="stacked"></ion-label>
|
||||||
<ion-datetime formControlName="timedurationuntil" [max]="maxDate" [min]="minDate"
|
<ion-datetime formControlName="timedurationuntil" [max]="maxDate" [min]="minDate"
|
||||||
[placeholder]="'addon.calendar.durationuntil' | translate" [displayFormat]="dateFormat" display-timezone="utc">
|
[placeholder]="'addon.calendar.durationuntil' | translate" [displayFormat]="dateFormat" display-timezone="utc">
|
||||||
</ion-datetime>
|
</ion-datetime>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item lines="none">
|
<ion-item lines="none">
|
||||||
|
|
|
@ -40,10 +40,10 @@
|
||||||
<core-context-menu-item [hidden]="isSelf || !muteEnabled || !conversation" [priority]="600" [content]="(conversation && conversation.ismuted ? 'addon.messages.unmuteconversation' :
|
<core-context-menu-item [hidden]="isSelf || !muteEnabled || !conversation" [priority]="600" [content]="(conversation && conversation.ismuted ? 'addon.messages.unmuteconversation' :
|
||||||
'addon.messages.muteconversation') | translate" (action)="changeMute($event)" [closeOnClick]="false"
|
'addon.messages.muteconversation') | translate" (action)="changeMute($event)" [closeOnClick]="false"
|
||||||
[iconAction]="muteIcon"></core-context-menu-item>
|
[iconAction]="muteIcon"></core-context-menu-item>
|
||||||
<core-context-menu-item [hidden]="!canDelete || !messages || !messages.length" [priority]="400"
|
<core-context-menu-item [hidden]="!canDelete || !messages || !messages.length" [priority]="400"
|
||||||
[content]="'addon.messages.showdeletemessages' | translate" iconAction="toggle" [(toggle)]="showDelete">
|
[content]="'addon.messages.showdeletemessages' | translate" iconAction="toggle" [(toggle)]="showDelete">
|
||||||
</core-context-menu-item>
|
</core-context-menu-item>
|
||||||
<core-context-menu-item [hidden]="!groupMessagingEnabled || !conversationId || isGroup || !messages || !messages.length"
|
<core-context-menu-item [hidden]="!groupMessagingEnabled || !conversationId || isGroup || !messages || !messages.length"
|
||||||
[priority]="200" [content]="'addon.messages.deleteconversation' | translate" (action)="deleteConversation($event)"
|
[priority]="200" [content]="'addon.messages.deleteconversation' | translate" (action)="deleteConversation($event)"
|
||||||
[closeOnClick]="false" [iconAction]="deleteIcon"></core-context-menu-item>
|
[closeOnClick]="false" [iconAction]="deleteIcon"></core-context-menu-item>
|
||||||
<core-context-menu-item
|
<core-context-menu-item
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<!-- Contactable privacy. -->
|
<!-- Contactable privacy. -->
|
||||||
<ion-card>
|
<ion-card>
|
||||||
<ion-item *ngIf="!advancedContactable">
|
<ion-item *ngIf="!advancedContactable">
|
||||||
<ion-label>{{ 'addon.messages.blocknoncontacts' | translate }}</ion-label>
|
<ion-label>{{ 'addon.messages.blocknoncontacts' | translate }}</ion-label>
|
||||||
<ion-toggle [(ngModel)]="contactablePrivacy" (ngModelChange)="saveContactablePrivacy(contactablePrivacy)">
|
<ion-toggle [(ngModel)]="contactablePrivacy" (ngModelChange)="saveContactablePrivacy(contactablePrivacy)">
|
||||||
</ion-toggle>
|
</ion-toggle>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
@ -46,88 +46,12 @@
|
||||||
|
|
||||||
<!-- Notifications. -->
|
<!-- Notifications. -->
|
||||||
<ng-container *ngIf="preferences">
|
<ng-container *ngIf="preferences">
|
||||||
<div *ngFor="let component of preferences.components">
|
<ng-container *ngIf="!groupMessagingEnabled">
|
||||||
<ion-card list *ngFor="let notification of component.notifications">
|
<ng-container *ngTemplateOutlet="legacySettings; context: {preferences: preferences}"></ng-container>
|
||||||
<ion-item-divider class="ion-text-wrap">
|
</ng-container>
|
||||||
<ion-label>
|
<ng-container *ngIf="groupMessagingEnabled">
|
||||||
<ion-row class="ion-no-padding" *ngIf="!groupMessagingEnabled">
|
<ng-container *ngTemplateOutlet="settings; context: {preferences: preferences}"></ng-container>
|
||||||
<ion-col class="ion-no-padding">
|
</ng-container>
|
||||||
<h2>{{ notification.displayname }}</h2>
|
|
||||||
</ion-col>
|
|
||||||
<ion-col size="2" class="ion-text-center ion-no-padding ion-hide-md-down">
|
|
||||||
<h2>{{ 'core.settings.loggedin' | translate }}</h2>
|
|
||||||
</ion-col>
|
|
||||||
<ion-col *ngIf="!groupMessagingEnabled" size="2" class="ion-text-center ion-no-padding
|
|
||||||
ion-hide-md-down">
|
|
||||||
<h2>{{ 'core.settings.loggedoff' | translate }}</h2>
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
<h2 *ngIf="groupMessagingEnabled">{{ 'addon.notifications.notificationpreferences' | translate }}</h2>
|
|
||||||
</ion-label>
|
|
||||||
</ion-item-divider>
|
|
||||||
<ng-container *ngFor="let processor of notification.processors">
|
|
||||||
<!-- If group messaging is enabled, display a simplified view. -->
|
|
||||||
<ng-container *ngIf="groupMessagingEnabled">
|
|
||||||
<ion-item class="ion-text-wrap">
|
|
||||||
<ion-label>{{ processor.displayname }}</ion-label>
|
|
||||||
<core-button-with-spinner *ngIf="!preferences.disableall" [loading]="!!notification.updating" slot="end">
|
|
||||||
<ion-toggle *ngIf="!processor.locked" [(ngModel)]="processor.checked"
|
|
||||||
(ngModelChange)="changePreference(notification, '', processor)">
|
|
||||||
</ion-toggle>
|
|
||||||
<ion-note *ngIf="processor.locked">
|
|
||||||
{{ processor.lockedmessage }}
|
|
||||||
</ion-note>
|
|
||||||
</core-button-with-spinner>
|
|
||||||
<ion-note slot="end" *ngIf="preferences.disableall">
|
|
||||||
{{ 'core.settings.disabled' | translate }}
|
|
||||||
</ion-note>
|
|
||||||
</ion-item>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container *ngIf="!groupMessagingEnabled">
|
|
||||||
<!-- Tablet view -->
|
|
||||||
<ion-row class="ion-text-wrap ion-hide-md-down ion-align-items-center">
|
|
||||||
<ion-col class="ion-margin-horizontal">{{ processor.displayname }}</ion-col>
|
|
||||||
<ion-col size="2" class="ion-text-center" *ngFor="let state of ['loggedin', 'loggedoff']">
|
|
||||||
<core-button-with-spinner *ngIf="!preferences.disableall"
|
|
||||||
[loading]="notification.updating && notification.updating[state]">
|
|
||||||
<!-- If notifications not disabled, show toggle. -->
|
|
||||||
<ion-toggle *ngIf="!processor.locked" [(ngModel)]="processor[state].checked"
|
|
||||||
(ngModelChange)="changePreference(notification, state, processor)">
|
|
||||||
</ion-toggle>
|
|
||||||
<div class="ion-padding text-gray" *ngIf="processor.locked">
|
|
||||||
{{'core.settings.locked' | translate }}
|
|
||||||
</div>
|
|
||||||
</core-button-with-spinner>
|
|
||||||
<!-- If notifications are disabled, show "Disabled" instead of toggle. -->
|
|
||||||
<span *ngIf="preferences.disableall">{{ 'core.settings.disabled' | translate }}</span>
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
<!-- Phone view -->
|
|
||||||
<ion-list-header class="ion-text-wrap ion-hide-md-up">
|
|
||||||
<ion-label>{{ processor.displayname }}</ion-label>
|
|
||||||
</ion-list-header>
|
|
||||||
<!-- If notifications not disabled, show toggles.
|
|
||||||
If notifications are disabled, show "Disabled" instead of toggle. -->
|
|
||||||
<ion-item *ngFor="let state of ['loggedin', 'loggedoff']" class="ion-text-wrap ion-hide-md-up">
|
|
||||||
<ion-label>{{ 'core.settings.' + state | translate }}</ion-label>
|
|
||||||
<core-button-with-spinner slot="end" *ngIf="!preferences.disableall"
|
|
||||||
[loading]="notification.updating && notification.updating[state]">
|
|
||||||
<ion-toggle *ngIf="!processor.locked" [(ngModel)]="processor[state].checked"
|
|
||||||
(ngModelChange)="changePreference(notification, state, processor)">
|
|
||||||
</ion-toggle>
|
|
||||||
<ion-note *ngIf="processor.locked">
|
|
||||||
{{'core.settings.locked' | translate }}
|
|
||||||
</ion-note>
|
|
||||||
</core-button-with-spinner>
|
|
||||||
<ion-note slot="end" *ngIf="preferences.disableall">
|
|
||||||
{{ 'core.settings.disabled' | translate }}
|
|
||||||
</ion-note>
|
|
||||||
</ion-item>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</ion-card>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- General settings. -->
|
<!-- General settings. -->
|
||||||
|
@ -148,3 +72,77 @@
|
||||||
</ion-card>
|
</ion-card>
|
||||||
</core-loading>
|
</core-loading>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
|
<!-- Only 3.5 version -->
|
||||||
|
<ng-template #legacySettings let-preferences="preferences">
|
||||||
|
<ng-container *ngFor="let component of preferences.components">
|
||||||
|
<ion-card *ngFor="let notification of component.notifications">
|
||||||
|
<ion-card-header class="ion-no-padding">
|
||||||
|
<ion-item class="ion-text-wrap">
|
||||||
|
<ion-label>
|
||||||
|
<h2>{{ notification.displayname }}</h2>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-card-header>
|
||||||
|
<ion-card-content class="ion-no-padding">
|
||||||
|
<ng-container *ngFor="let processor of notification.processors">
|
||||||
|
<ion-item-divider class="ion-text-wrap">
|
||||||
|
<ion-label>
|
||||||
|
<p class="item-heading">{{ processor.displayname }}</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item-divider>
|
||||||
|
<!-- If notifications not disabled, show toggles.
|
||||||
|
If notifications are disabled, show "Disabled" instead of toggle. -->
|
||||||
|
<ion-item *ngFor="let state of ['loggedin', 'loggedoff']" class="ion-text-wrap">
|
||||||
|
<ion-label>{{ 'core.settings.' + state | translate }}</ion-label>
|
||||||
|
<ng-container *ngIf="!preferences.disableall">
|
||||||
|
<!-- If notifications enabled, show toggle. -->
|
||||||
|
<core-button-with-spinner *ngIf="!processor.locked" [loading]="notification['updating'+state]">
|
||||||
|
<ion-toggle [(ngModel)]="processor[state].checked"
|
||||||
|
(ngModelChange)="changePreferenceLegacy(notification, processor, state)">
|
||||||
|
</ion-toggle>
|
||||||
|
</core-button-with-spinner>
|
||||||
|
<span *ngIf="processor.locked && processor[state].checked" class="text-gray">
|
||||||
|
{{'core.settings.forced' | translate }}
|
||||||
|
</span>
|
||||||
|
<span *ngIf="processor.locked && !processor[state].checked" class="text-gray">
|
||||||
|
{{'core.settings.disallowed' | translate }}
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
<span *ngIf="preferences.disableall">{{ 'core.settings.disabled' | translate }}</span>
|
||||||
|
</ion-item>
|
||||||
|
</ng-container>
|
||||||
|
</ion-card-content>
|
||||||
|
</ion-card>
|
||||||
|
</ng-container>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
|
||||||
|
<ng-template #settings let-preferences="preferences">
|
||||||
|
<ng-container *ngFor="let component of preferences.components">
|
||||||
|
<ion-card *ngFor="let notification of component.notifications">
|
||||||
|
<ion-item-divider class="ion-text-wrap">
|
||||||
|
<ion-label>
|
||||||
|
<h2>{{ 'addon.notifications.notificationpreferences' | translate }}</h2>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item-divider>
|
||||||
|
<ng-container *ngFor="let processor of notification.processors">
|
||||||
|
<!-- If group messaging is enabled, display a simplified view. -->
|
||||||
|
<ion-item class="ion-text-wrap">
|
||||||
|
<ion-label>{{ processor.displayname }}</ion-label>
|
||||||
|
<ng-container *ngIf="!preferences.disableall">
|
||||||
|
<!-- If notifications enabled, show toggle. -->
|
||||||
|
<core-button-with-spinner *ngIf="!processor.locked" [loading]="notification.updating">
|
||||||
|
<ion-toggle [(ngModel)]="processor.enabled" (ngModelChange)="changePreference(notification, processor)">
|
||||||
|
</ion-toggle>
|
||||||
|
</core-button-with-spinner>
|
||||||
|
<span class="text-gray" *ngIf="processor.locked">
|
||||||
|
{{ processor.lockedmessage }}
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
<span *ngIf="preferences.disableall" class="text-gray">{{ 'core.settings.disabled' | translate }}</span>
|
||||||
|
</ion-item>
|
||||||
|
</ng-container>
|
||||||
|
</ion-card>
|
||||||
|
</ng-container>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreConstants } from '@/core/constants';
|
import { CoreConstants } from '@/core/constants';
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
|
import { AddonNotificationsPreferencesNotificationProcessorState } from '@addons/notifications/services/notifications';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the messages settings page.
|
* Page that displays the messages settings page.
|
||||||
|
@ -50,14 +51,16 @@ export class AddonMessagesSettingsPage implements OnInit, OnDestroy {
|
||||||
groupMessagingEnabled = false;
|
groupMessagingEnabled = false;
|
||||||
sendOnEnter = false;
|
sendOnEnter = false;
|
||||||
|
|
||||||
|
protected loggedInOffLegacyMode = false;
|
||||||
protected previousContactableValue?: number | boolean;
|
protected previousContactableValue?: number | boolean;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
const currentSite = CoreSites.getCurrentSite();
|
const currentSite = CoreSites.getRequiredCurrentSite();
|
||||||
this.advancedContactable = !!currentSite?.isVersionGreaterEqualThan('3.6');
|
this.advancedContactable = !!currentSite.isVersionGreaterEqualThan('3.6');
|
||||||
this.allowSiteMessaging = !!currentSite?.canUseAdvancedFeature('messagingallusers');
|
this.allowSiteMessaging = !!currentSite.canUseAdvancedFeature('messagingallusers');
|
||||||
this.groupMessagingEnabled = AddonMessages.isGroupMessagingEnabled();
|
this.groupMessagingEnabled = AddonMessages.isGroupMessagingEnabled();
|
||||||
|
this.loggedInOffLegacyMode = !currentSite.isVersionGreaterEqualThan('4.0');
|
||||||
|
|
||||||
this.asyncInit();
|
this.asyncInit();
|
||||||
}
|
}
|
||||||
|
@ -90,13 +93,16 @@ export class AddonMessagesSettingsPage implements OnInit, OnDestroy {
|
||||||
component.notifications = component.notifications.filter((notification) =>
|
component.notifications = component.notifications.filter((notification) =>
|
||||||
notification.preferencekey == AddonMessagesProvider.NOTIFICATION_PREFERENCES_KEY);
|
notification.preferencekey == AddonMessagesProvider.NOTIFICATION_PREFERENCES_KEY);
|
||||||
|
|
||||||
component.notifications.forEach((notification) => {
|
if (this.loggedInOffLegacyMode) {
|
||||||
notification.processors.forEach(
|
// Load enabled from loggedin / loggedoff values.
|
||||||
(processor: AddonMessagesMessagePreferencesNotificationProcessorFormatted) => {
|
component.notifications.forEach((notification) => {
|
||||||
processor.checked = processor.loggedin.checked || processor.loggedoff.checked;
|
notification.processors.forEach(
|
||||||
},
|
(processor) => {
|
||||||
);
|
processor.enabled = processor.loggedin.checked || processor.loggedoff.checked;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,74 +171,70 @@ export class AddonMessagesSettingsPage implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the value of a certain preference.
|
* Change the value of a certain preference. Versions 3.6 onwards.
|
||||||
*
|
*
|
||||||
* @param notification Notification object.
|
* @param notification Notification object.
|
||||||
* @param state State name, ['loggedin', 'loggedoff'].
|
|
||||||
* @param processor Notification processor.
|
* @param processor Notification processor.
|
||||||
*/
|
*/
|
||||||
async changePreference(
|
async changePreference(
|
||||||
notification: AddonMessagesMessagePreferencesNotificationFormatted,
|
notification: AddonMessagesMessagePreferencesNotificationFormatted,
|
||||||
state: string,
|
processor: AddonMessagesMessagePreferencesNotificationProcessor,
|
||||||
processor: AddonMessagesMessagePreferencesNotificationProcessorFormatted,
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
// Update both states at the same time.
|
||||||
|
let value = notification.processors
|
||||||
|
.filter((processor) => processor.enabled)
|
||||||
|
.map((processor) => processor.name)
|
||||||
|
.join(',');
|
||||||
|
|
||||||
const valueArray: string[] = [];
|
if (value == '') {
|
||||||
let value = 'none';
|
value = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
if (this.groupMessagingEnabled) {
|
notification.updating = true;
|
||||||
// Update both states at the same time.
|
|
||||||
const promises: Promise<void>[] = [];
|
|
||||||
|
|
||||||
notification.processors.forEach((processor: AddonMessagesMessagePreferencesNotificationProcessorFormatted) => {
|
|
||||||
if (processor.checked) {
|
|
||||||
valueArray.push(processor.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (value.length > 0) {
|
|
||||||
value = valueArray.join(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
notification.updating = true;
|
|
||||||
|
|
||||||
|
const promises: Promise<void>[] = [];
|
||||||
|
if (this.loggedInOffLegacyMode) {
|
||||||
promises.push(CoreUser.updateUserPreference(notification.preferencekey + '_loggedin', value));
|
promises.push(CoreUser.updateUserPreference(notification.preferencekey + '_loggedin', value));
|
||||||
promises.push(CoreUser.updateUserPreference(notification.preferencekey + '_loggedoff', value));
|
promises.push(CoreUser.updateUserPreference(notification.preferencekey + '_loggedoff', value));
|
||||||
|
} else {
|
||||||
try {
|
promises.push(CoreUser.updateUserPreference(notification.preferencekey + '_enabled', value));
|
||||||
await Promise.all(promises);
|
|
||||||
// Update the preferences since they were modified.
|
|
||||||
this.updatePreferencesAfterDelay();
|
|
||||||
} catch (error) {
|
|
||||||
// Show error and revert change.
|
|
||||||
CoreDomUtils.showErrorModal(error);
|
|
||||||
processor.checked = !processor.checked;
|
|
||||||
} finally {
|
|
||||||
notification.updating = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Promise.all(promises);
|
||||||
|
// Update the preferences since they were modified.
|
||||||
|
this.updatePreferencesAfterDelay();
|
||||||
|
} catch (error) {
|
||||||
|
// Show error and revert change.
|
||||||
|
CoreDomUtils.showErrorModal(error);
|
||||||
|
processor.enabled = !processor.enabled;
|
||||||
|
} finally {
|
||||||
|
notification.updating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the value of a certain preference. Only on version 3.5.
|
||||||
|
*
|
||||||
|
* @param notification Notification object.
|
||||||
|
* @param processor Notification processor.
|
||||||
|
* @param state State name, ['loggedin', 'loggedoff'].
|
||||||
|
*/
|
||||||
|
async changePreferenceLegacy(
|
||||||
|
notification: AddonMessagesMessagePreferencesNotificationFormatted,
|
||||||
|
processor: AddonMessagesMessagePreferencesNotificationProcessor,
|
||||||
|
state: 'loggedin' | 'loggedoff',
|
||||||
|
): Promise<void> {
|
||||||
// Update only the specified state.
|
// Update only the specified state.
|
||||||
const processorState = processor[state];
|
const processorState: AddonNotificationsPreferencesNotificationProcessorState = processor[state];
|
||||||
const preferenceName = notification.preferencekey + '_' + processorState.name;
|
const preferenceName = notification.preferencekey + '_' + processorState.name;
|
||||||
|
|
||||||
notification.processors.forEach((processor) => {
|
const value = notification.processors
|
||||||
if (processor[state].checked) {
|
.filter((processor) => processor[state].checked)
|
||||||
valueArray.push(processor.name);
|
.map((processor) => processor.name)
|
||||||
}
|
.join(',');
|
||||||
});
|
|
||||||
|
|
||||||
if (value.length > 0) {
|
notification['updating'+state] = true;
|
||||||
value = valueArray.join(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!notification.updating) {
|
|
||||||
notification.updating = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
notification.updating[state] = true;
|
|
||||||
try {
|
try {
|
||||||
await CoreUser.updateUserPreference(preferenceName, value);
|
await CoreUser.updateUserPreference(preferenceName, value);
|
||||||
// Update the preferences since they were modified.
|
// Update the preferences since they were modified.
|
||||||
|
@ -242,7 +244,7 @@ export class AddonMessagesSettingsPage implements OnInit, OnDestroy {
|
||||||
CoreDomUtils.showErrorModal(error);
|
CoreDomUtils.showErrorModal(error);
|
||||||
processorState.checked = !processorState.checked;
|
processorState.checked = !processorState.checked;
|
||||||
} finally {
|
} finally {
|
||||||
notification.updating[state] = false;
|
notification['updating'+state] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,12 +290,7 @@ export class AddonMessagesSettingsPage implements OnInit, OnDestroy {
|
||||||
* Message preferences notification with some caclulated data.
|
* Message preferences notification with some caclulated data.
|
||||||
*/
|
*/
|
||||||
type AddonMessagesMessagePreferencesNotificationFormatted = AddonMessagesMessagePreferencesNotification & {
|
type AddonMessagesMessagePreferencesNotificationFormatted = AddonMessagesMessagePreferencesNotification & {
|
||||||
updating?: boolean | {[state: string]: boolean}; // Calculated in the app. Whether the notification is being updated.
|
updating?: boolean; // Calculated in the app. Whether the notification is being updated.
|
||||||
};
|
updatingloggedin?: boolean; // Calculated in the app. Whether the notification is being updated.
|
||||||
|
updatingloggedoff?: boolean; // Calculated in the app. Whether the notification is being updated.
|
||||||
/**
|
|
||||||
* Message preferences notification processor with some caclulated data.
|
|
||||||
*/
|
|
||||||
type AddonMessagesMessagePreferencesNotificationProcessorFormatted = AddonMessagesMessagePreferencesNotificationProcessor & {
|
|
||||||
checked?: boolean; // Calculated in the app. Whether the processor is checked either for loggedin or loggedoff.
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { makeSingleton } from '@singletons';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
import { AddonMessagesSyncEvents, AddonMessagesSyncProvider } from './messages-sync';
|
import { AddonMessagesSyncEvents, AddonMessagesSyncProvider } from './messages-sync';
|
||||||
import { CoreWSError } from '@classes/errors/wserror';
|
import { CoreWSError } from '@classes/errors/wserror';
|
||||||
|
import { AddonNotificationsPreferencesNotificationProcessorState } from '@addons/notifications/services/notifications';
|
||||||
|
|
||||||
const ROOT_CACHE_KEY = 'mmaMessages:';
|
const ROOT_CACHE_KEY = 'mmaMessages:';
|
||||||
|
|
||||||
|
@ -3047,16 +3048,9 @@ export type AddonMessagesMessagePreferencesNotificationProcessor = {
|
||||||
locked: boolean; // Is locked by admin?.
|
locked: boolean; // Is locked by admin?.
|
||||||
lockedmessage?: string; // @since 3.6. Text to display if locked.
|
lockedmessage?: string; // @since 3.6. Text to display if locked.
|
||||||
userconfigured: number; // Is configured?.
|
userconfigured: number; // Is configured?.
|
||||||
loggedin: {
|
enabled?: boolean; // @since 4.0. Processor enabled.
|
||||||
name: string; // Name.
|
loggedin: AddonNotificationsPreferencesNotificationProcessorState; // @deprecated removed on 4.0.
|
||||||
displayname: string; // Display name.
|
loggedoff: AddonNotificationsPreferencesNotificationProcessorState; // @deprecated removed on 4.0.
|
||||||
checked: boolean; // Is checked?.
|
|
||||||
};
|
|
||||||
loggedoff: {
|
|
||||||
name: string; // Name.
|
|
||||||
displayname: string; // Display name.
|
|
||||||
checked: boolean; // Is checked?.
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="wordLimitEnabled && words >= 0">
|
<ion-item class="ion-text-wrap" *ngIf="wordLimitEnabled && words >= 0">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.mod_assign.wordlimit' | translate }}</h2>
|
<h2>{{ 'addon.mod_assign.wordlimit' | translate }}</h2>
|
||||||
<p>{{ 'core.numwords' | translate: {'$a': words + ' / ' + wordLimit} }}</p>
|
<p>{{ 'core.numwords' | translate: {'$a': words + ' / ' + wordLimit} }}</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="addon-mod_forum-post">
|
<div class="addon-mod_forum-post">
|
||||||
<ng-container *ngIf="!formData.isEditing || !showForm">
|
<ng-container *ngIf="!formData.isEditing || !showForm">
|
||||||
<ion-card-header class="ion-text-wrap ion-no-padding" id="addon-mod_forum-post-{{post.id}}">
|
<ion-card-header class="ion-text-wrap ion-no-padding" id="addon-mod_forum-post-{{post.id}}">
|
||||||
<ion-item class="ion-text-wrap" [class.highlight]="highlight" lines="none">
|
<ion-item class="ion-text-wrap" [class.highlight]="highlight" lines="none">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<ion-button *ngIf="isIOS && (!shouldOpenInBrowser || !isOnline)" expand="block" class="ion-margin"
|
<ion-button *ngIf="isIOS && (!shouldOpenInBrowser || !isOnline)" expand="block" class="ion-margin"
|
||||||
(click)="open(openFileAction.OPEN_WITH)">
|
(click)="open(openFileAction.OPEN_WITH)">
|
||||||
<ion-icon name="far-share-square" slot="start" aria-hidden="true"></ion-icon>
|
<ion-icon name="far-share-square" slot="start" aria-hidden="true"></ion-icon>
|
||||||
{{ 'core.openwith' | translate }}
|
{{ 'core.openwith' | translate }}
|
||||||
|
|
|
@ -35,75 +35,144 @@
|
||||||
</ion-card>
|
</ion-card>
|
||||||
|
|
||||||
<!-- Show processor selector. -->
|
<!-- Show processor selector. -->
|
||||||
<core-combobox *ngIf="preferences && preferences.processors && preferences.processors.length > 0"
|
<core-combobox *ngIf="preferences && preferences.processors && preferences.processors.length > 0" [selection]="currentProcessorName"
|
||||||
[selection]="currentProcessor!.name" (onChange)="changeProcessor($event)">
|
(onChange)="changeProcessor($event)">
|
||||||
<ion-select-option class="ion-text-wrap" *ngFor="let processor of preferences.processors" [value]="processor.name">
|
<ion-select-option class="ion-text-wrap" *ngFor="let processor of preferences.processors" [value]="processor.name">
|
||||||
{{ processor.displayname }}
|
{{ processor.displayname }}
|
||||||
</ion-select-option>
|
</ion-select-option>
|
||||||
</core-combobox>
|
</core-combobox>
|
||||||
|
|
||||||
<ion-card list *ngFor="let component of components" class="ion-margin-top">
|
<ng-container *ngIf="loggedInOffLegacyMode">
|
||||||
<ion-item-divider class="ion-text-wrap">
|
<ng-container *ngTemplateOutlet="legacySettings; context: {preferences: preferences}"></ng-container>
|
||||||
<ion-grid class="ion-no-padding">
|
</ng-container>
|
||||||
<ion-row class="ion-no-padding">
|
|
||||||
<ion-col class="ion-no-padding">{{ component.displayname }}</ion-col>
|
|
||||||
<ion-col size="2" class="ion-text-center ion-no-padding ion-hide-md-down">
|
|
||||||
{{ 'core.settings.loggedin' | translate }}
|
|
||||||
</ion-col>
|
|
||||||
<ion-col size="2" class="ion-text-center ion-no-padding ion-hide-md-down">
|
|
||||||
{{ 'core.settings.loggedoff' | translate }}
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
</ion-grid>
|
|
||||||
</ion-item-divider>
|
|
||||||
<ng-container *ngFor="let notification of component.notifications">
|
|
||||||
<!-- Tablet view -->
|
|
||||||
<ion-grid class="ion-text-wrap ion-hide-md-down addon-notifications-table-content">
|
|
||||||
<ion-row class="ion-align-items-center">
|
|
||||||
<ion-col class="ion-margin-horizontal">{{ notification.displayname }}</ion-col>
|
|
||||||
<ion-col size="2" class="ion-text-center" *ngFor="let state of ['loggedin', 'loggedoff']">
|
|
||||||
<!-- If notifications enabled, show toggle. -->
|
|
||||||
<ion-spinner [hidden]="!preferences!.enableall ||
|
|
||||||
!(notification.processorsByName[currentProcessor!.name][state] &&
|
|
||||||
notification.processorsByName[currentProcessor!.name][state].updating)">
|
|
||||||
</ion-spinner>
|
|
||||||
<ion-toggle *ngIf="preferences!.enableall && !notification.processorsByName[currentProcessor!.name].locked"
|
|
||||||
[(ngModel)]="notification.processorsByName[currentProcessor!.name][state].checked"
|
|
||||||
(ngModelChange)="changePreference(notification, state)"
|
|
||||||
[disabled]="notification.processorsByName[currentProcessor!.name][state].updating">
|
|
||||||
</ion-toggle>
|
|
||||||
<span class="text-gray"
|
|
||||||
*ngIf="preferences!.enableall && notification.processorsByName[currentProcessor!.name].locked">
|
|
||||||
{{'core.settings.locked' | translate }}
|
|
||||||
</span>
|
|
||||||
<!-- If notifications are disabled, show "Disabled" instead of toggle. -->
|
|
||||||
<span *ngIf="!preferences!.enableall">{{ 'core.settings.disabled' | translate }}</span>
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
</ion-grid>
|
|
||||||
|
|
||||||
<!-- Phone view -->
|
<ng-container *ngIf="!loggedInOffLegacyMode">
|
||||||
<ion-list-header class="ion-text-wrap ion-no-margin ion-hide-md-up">
|
<ng-container *ngTemplateOutlet="settings; context: {preferences: preferences}"></ng-container>
|
||||||
{{ notification.displayname }}
|
</ng-container>
|
||||||
</ion-list-header>
|
|
||||||
<!-- If notifications enabled, show toggles. If disabled, show "Disabled" instead of toggle. -->
|
|
||||||
<ion-item *ngFor="let state of ['loggedin', 'loggedoff']" class="ion-text-wrap ion-hide-md-up" lines="none">
|
|
||||||
<ion-label>{{ 'core.settings.' + state | translate }}</ion-label>
|
|
||||||
<ion-spinner slot="end" *ngIf="preferences!.enableall && (notification.processorsByName[currentProcessor!.name][state] &&
|
|
||||||
notification.processorsByName[currentProcessor!.name][state].updating)">
|
|
||||||
</ion-spinner>
|
|
||||||
<ion-toggle slot="end" *ngIf="preferences!.enableall && !notification.processorsByName[currentProcessor!.name].locked"
|
|
||||||
[(ngModel)]="notification.processorsByName[currentProcessor!.name][state].checked"
|
|
||||||
(ngModelChange)="changePreference(notification, state)"
|
|
||||||
[disabled]="notification.processorsByName[currentProcessor!.name][state].updating">
|
|
||||||
</ion-toggle>
|
|
||||||
<span slot="end" *ngIf="preferences!.enableall && notification.processorsByName[currentProcessor!.name].locked"
|
|
||||||
class="text-gray">
|
|
||||||
{{'core.settings.locked' | translate }}
|
|
||||||
</span>
|
|
||||||
<ion-note slot="end" *ngIf="!preferences!.enableall">{{ 'core.settings.disabled' | translate }}</ion-note>
|
|
||||||
</ion-item>
|
|
||||||
</ng-container>
|
|
||||||
</ion-card>
|
|
||||||
</core-loading>
|
</core-loading>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 3.11 or downwards version -->
|
||||||
|
<ng-template #legacySettings let-preferences="preferences">
|
||||||
|
<ion-card *ngFor="let component of components" class="ion-margin-top">
|
||||||
|
<ion-card-header class="ion-no-padding">
|
||||||
|
<ion-item class="ion-text-wrap divider">
|
||||||
|
<ion-label class="ion-text-wrap">
|
||||||
|
<ion-row class="ion-no-padding">
|
||||||
|
<ion-col class="ion-no-padding">
|
||||||
|
<p class="item-heading">{{ component.displayname }}</p>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col size="2" class="ion-text-center ion-no-padding ion-hide-md-down">
|
||||||
|
<p>{{ 'core.settings.loggedin' | translate }}</p>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col size="2" class="ion-text-center ion-no-padding ion-hide-md-down">
|
||||||
|
<p>{{ 'core.settings.loggedoff' | translate }}</p>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-card-header>
|
||||||
|
<ng-container *ngFor="let notification of component.notifications">
|
||||||
|
<!-- Tablet view -->
|
||||||
|
<ion-item class="ion-text-wrap ion-hide-md-down addon-notifications-table-content only-links">
|
||||||
|
<ion-label>
|
||||||
|
<ion-row class="ion-no-padding ion-align-items-center">
|
||||||
|
<ion-col class="ion-margin-horizontal ion-no-padding">
|
||||||
|
<p class="item-heading">{{ notification.displayname }}</p>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col size="2" class="ion-text-center ion-no-padding" *ngFor="let state of ['loggedin', 'loggedoff']">
|
||||||
|
<ng-container *ngIf="preferences!.enableall && notification.processorsByName[currentProcessorName][state]">
|
||||||
|
<!-- If notifications enabled, show toggle. -->
|
||||||
|
<core-button-with-spinner *ngIf="!notification.processorsByName[currentProcessorName].locked"
|
||||||
|
[loading]="notification.processorsByName[currentProcessorName][state].updating">
|
||||||
|
<ion-toggle [(ngModel)]="notification.processorsByName[currentProcessorName][state].checked"
|
||||||
|
(ngModelChange)="changePreferenceLegacy(notification, state)">
|
||||||
|
</ion-toggle>
|
||||||
|
</core-button-with-spinner>
|
||||||
|
<span class="text-gray" *ngIf="notification.processorsByName[currentProcessorName].locked &&
|
||||||
|
notification.processorsByName[currentProcessorName][state].checked">
|
||||||
|
{{'core.settings.forced' | translate }}
|
||||||
|
</span>
|
||||||
|
<span class="text-gray" *ngIf="notification.processorsByName[currentProcessorName].locked &&
|
||||||
|
!notification.processorsByName[currentProcessorName][state].checked">
|
||||||
|
{{'core.settings.disallowed' | translate }}
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
<!-- If notifications are disabled, show "Disabled" instead of toggle. -->
|
||||||
|
<span *ngIf="!preferences!.enableall" class="text-gray">{{ 'core.settings.disabled' | translate }}</span>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<!-- Phone view -->
|
||||||
|
<ion-item class="ion-text-wrap ion-no-margin ion-hide-md-up" lines="none">
|
||||||
|
<p class="item-heading">{{ notification.displayname }}</p>
|
||||||
|
</ion-item>
|
||||||
|
<!-- If notifications enabled, show toggles. If disabled, show "Disabled" instead of toggle. -->
|
||||||
|
<ion-item *ngFor="let state of ['loggedin', 'loggedoff']" class="ion-text-wrap ion-hide-md-up" lines="none">
|
||||||
|
<ion-label class="ion-margin-horizontal">
|
||||||
|
<p>{{ 'core.settings.' + state | translate }}</p>
|
||||||
|
</ion-label>
|
||||||
|
<div slot="end" *ngIf="preferences!.enableall && notification.processorsByName[currentProcessorName][state]">
|
||||||
|
<core-button-with-spinner *ngIf="!notification.processorsByName[currentProcessorName].locked"
|
||||||
|
[loading]="notification.processorsByName[currentProcessorName][state].updating">
|
||||||
|
<ion-toggle *ngIf="!notification.processorsByName[currentProcessorName].locked"
|
||||||
|
[(ngModel)]="notification.processorsByName[currentProcessorName][state].checked"
|
||||||
|
(ngModelChange)="changePreferenceLegacy(notification, state)">
|
||||||
|
</ion-toggle>
|
||||||
|
</core-button-with-spinner>
|
||||||
|
<span class="text-gray" *ngIf="notification.processorsByName[currentProcessorName].locked &&
|
||||||
|
notification.processorsByName[currentProcessorName][state].checked">
|
||||||
|
{{'core.settings.forced' | translate }}
|
||||||
|
</span>
|
||||||
|
<span class="text-gray" *ngIf="notification.processorsByName[currentProcessorName].locked &&
|
||||||
|
!notification.processorsByName[currentProcessorName][state].checked">
|
||||||
|
{{'core.settings.disallowed' | translate }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span class="text-gray" slot="end" *ngIf="!preferences!.enableall">{{ 'core.settings.disabled' | translate }}</span>
|
||||||
|
</ion-item>
|
||||||
|
</ng-container>
|
||||||
|
</ion-card>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<!-- 4.0 or downwards version -->
|
||||||
|
<ng-template #settings let-preferences="preferences">
|
||||||
|
<ion-card *ngFor="let component of components" class="ion-margin-top">
|
||||||
|
<ion-item-divider class="ion-text-wrap">
|
||||||
|
<ion-label>
|
||||||
|
<p class="item-heading">{{ component.displayname }}</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item-divider>
|
||||||
|
<ng-container *ngFor="let notification of component.notifications">
|
||||||
|
<!-- If notifications enabled, show toggles. If disabled, show "Disabled" instead of toggle. -->
|
||||||
|
<ion-item class="ion-text-wrap" lines="none">
|
||||||
|
<ion-label>
|
||||||
|
<p>{{ notification.displayname }}</p>
|
||||||
|
</ion-label>
|
||||||
|
|
||||||
|
<div slot="end" *ngIf="preferences!.enableall">
|
||||||
|
<core-button-with-spinner *ngIf="!notification.processorsByName[currentProcessorName].locked"
|
||||||
|
[loading]="notification.processorsByName[currentProcessorName].updating">
|
||||||
|
<ion-toggle *ngIf="!notification.processorsByName[currentProcessorName].locked"
|
||||||
|
[(ngModel)]="notification.processorsByName[currentProcessorName].enabled"
|
||||||
|
(ngModelChange)="changePreference(notification)">
|
||||||
|
</ion-toggle>
|
||||||
|
</core-button-with-spinner>
|
||||||
|
<span class="text-gray" *ngIf=" notification.processorsByName[currentProcessorName].locked &&
|
||||||
|
notification.processorsByName[currentProcessorName].enabled">
|
||||||
|
{{'core.settings.forced' | translate }}
|
||||||
|
</span>
|
||||||
|
<span class="text-gray" *ngIf=" notification.processorsByName[currentProcessorName].locked &&
|
||||||
|
!notification.processorsByName[currentProcessorName].enabled">
|
||||||
|
{{'core.settings.disallowed' | translate }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span class="text-gray" slot="end" *ngIf="!preferences!.enableall">{{ 'core.settings.disabled' | translate }}</span>
|
||||||
|
</ion-item>
|
||||||
|
</ng-container>
|
||||||
|
</ion-card>
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
:host {
|
.addon-notifications-table-content ion-row {
|
||||||
.addon-notifications-table-content ion-row {
|
min-height: 35px;
|
||||||
min-height: 35px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import {
|
import {
|
||||||
AddonNotifications,
|
AddonNotifications,
|
||||||
AddonNotificationsPreferencesProcessor,
|
|
||||||
AddonNotificationsPreferencesNotificationProcessorState,
|
AddonNotificationsPreferencesNotificationProcessorState,
|
||||||
} from '../../services/notifications';
|
} from '../../services/notifications';
|
||||||
import {
|
import {
|
||||||
|
@ -51,16 +50,20 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
preferences?: AddonNotificationsPreferencesFormatted;
|
preferences?: AddonNotificationsPreferencesFormatted;
|
||||||
components?: AddonNotificationsPreferencesComponentFormatted[];
|
components?: AddonNotificationsPreferencesComponentFormatted[];
|
||||||
currentProcessor?: AddonNotificationsPreferencesProcessor;
|
currentProcessorName = 'airnotifier';
|
||||||
preferencesLoaded = false;
|
preferencesLoaded = false;
|
||||||
notificationSound = false;
|
notificationSound = false;
|
||||||
canChangeSound: boolean;
|
canChangeSound: boolean;
|
||||||
processorHandlers: AddonMessageOutputHandlerData[] = [];
|
processorHandlers: AddonMessageOutputHandlerData[] = [];
|
||||||
|
loggedInOffLegacyMode = false;
|
||||||
|
|
||||||
protected updateTimeout?: number;
|
protected updateTimeout?: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.canChangeSound = CoreLocalNotifications.canDisableSound();
|
this.canChangeSound = CoreLocalNotifications.canDisableSound();
|
||||||
|
|
||||||
|
const currentSite = CoreSites.getRequiredCurrentSite();
|
||||||
|
this.loggedInOffLegacyMode = !currentSite.isVersionGreaterEqualThan('4.0');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,20 +86,20 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
|
||||||
try {
|
try {
|
||||||
const preferences = await AddonNotifications.getNotificationPreferences();
|
const preferences = await AddonNotifications.getNotificationPreferences();
|
||||||
|
|
||||||
if (!this.currentProcessor) {
|
// Initialize current processor. Load "Mobile" (airnotifier) if available.
|
||||||
// Initialize current processor. Load "Mobile" (airnotifier) if available.
|
let currentProcessor = preferences.processors.find((processor) => processor.name == this.currentProcessorName);
|
||||||
this.currentProcessor = AddonNotificationsHelper.getProcessor(preferences.processors, 'airnotifier');
|
if (!currentProcessor) {
|
||||||
|
currentProcessor = preferences.processors[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.currentProcessor) {
|
if (!currentProcessor) {
|
||||||
// Shouldn't happen.
|
// Shouldn't happen.
|
||||||
throw new CoreError('No processor found');
|
throw new CoreError('No processor found');
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.enableall = !preferences.disableall;
|
preferences.enableall = !preferences.disableall;
|
||||||
this.preferences = AddonNotificationsHelper.formatPreferences(preferences);
|
this.preferences = AddonNotificationsHelper.formatPreferences(preferences);
|
||||||
this.loadProcessor(this.currentProcessor);
|
this.loadProcessor(currentProcessor);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
CoreDomUtils.showErrorModal(error);
|
CoreDomUtils.showErrorModal(error);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -114,7 +117,7 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentProcessor = processor;
|
this.currentProcessorName = processor.name;
|
||||||
this.processorHandlers = [];
|
this.processorHandlers = [];
|
||||||
this.components = AddonNotificationsHelper.getProcessorComponents(
|
this.components = AddonNotificationsHelper.getProcessorComponents(
|
||||||
processor.name,
|
processor.name,
|
||||||
|
@ -199,27 +202,21 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
|
||||||
* @param state State name, ['loggedin', 'loggedoff'].
|
* @param state State name, ['loggedin', 'loggedoff'].
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
async changePreference(notification: AddonNotificationsPreferencesNotificationFormatted, state: string): Promise<void> {
|
async changePreferenceLegacy(notification: AddonNotificationsPreferencesNotificationFormatted, state: string): Promise<void> {
|
||||||
const processor = notification.processorsByName?.[this.currentProcessor?.name || ''];
|
const processor = notification.processorsByName?.[this.currentProcessorName];
|
||||||
if (!processor) {
|
if (!processor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const processorState: ProcessorStateFormatted = processor[state];
|
const processorState: ProcessorStateFormatted = processor[state];
|
||||||
const preferenceName = notification.preferencekey + '_' + processorState.name;
|
const preferenceName = notification.preferencekey + '_' + processorState.name;
|
||||||
let value: string | undefined;
|
|
||||||
|
|
||||||
notification.processors.forEach((processor) => {
|
let value = notification.processors
|
||||||
if (processor[state].checked) {
|
.filter((processor) => processor[state].checked)
|
||||||
if (!value) {
|
.map((processor) => processor.name)
|
||||||
value = processor.name;
|
.join(',');
|
||||||
} else {
|
|
||||||
value += ',' + processor.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!value) {
|
if (value == '') {
|
||||||
value = 'none';
|
value = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +236,45 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the value of a certain preference.
|
||||||
|
*
|
||||||
|
* @param notification Notification object.
|
||||||
|
* @return Promise resolved when done.
|
||||||
|
*/
|
||||||
|
async changePreference(notification: AddonNotificationsPreferencesNotificationFormatted): Promise<void> {
|
||||||
|
const processor = notification.processorsByName?.[this.currentProcessorName];
|
||||||
|
if (!processor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const preferenceName = notification.preferencekey + '_enabled';
|
||||||
|
|
||||||
|
let value = notification.processors
|
||||||
|
.filter((processor) => processor.enabled)
|
||||||
|
.map((processor) => processor.name)
|
||||||
|
.join(',');
|
||||||
|
|
||||||
|
if (value == '') {
|
||||||
|
value = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
processor.updating = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await CoreUser.updateUserPreference(preferenceName, value);
|
||||||
|
|
||||||
|
// Update the preferences since they were modified.
|
||||||
|
this.updatePreferencesAfterDelay();
|
||||||
|
} catch (error) {
|
||||||
|
// Show error and revert change.
|
||||||
|
CoreDomUtils.showErrorModal(error);
|
||||||
|
processor.enabled = !processor.enabled;
|
||||||
|
} finally {
|
||||||
|
processor.updating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable all notifications changed.
|
* Enable all notifications changed.
|
||||||
*
|
*
|
||||||
|
@ -294,6 +330,8 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State in notification processor in notification preferences component with some calculated data.
|
* State in notification processor in notification preferences component with some calculated data.
|
||||||
|
*
|
||||||
|
* @deprecated 4.0
|
||||||
*/
|
*/
|
||||||
type ProcessorStateFormatted = AddonNotificationsPreferencesNotificationProcessorState & {
|
type ProcessorStateFormatted = AddonNotificationsPreferencesNotificationProcessorState & {
|
||||||
updating?: boolean; // Calculated in the app. Whether the state is being updated.
|
updating?: boolean; // Calculated in the app. Whether the state is being updated.
|
||||||
|
|
|
@ -77,34 +77,6 @@ export class AddonNotificationsHelperProvider {
|
||||||
return formattedPreferences;
|
return formattedPreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a certain processor from a list of processors.
|
|
||||||
*
|
|
||||||
* @param processors List of processors.
|
|
||||||
* @param name Name of the processor to get.
|
|
||||||
* @param fallback True to return first processor if not found, false to not return any. Defaults to true.
|
|
||||||
* @return Processor.
|
|
||||||
*/
|
|
||||||
getProcessor(
|
|
||||||
processors: AddonNotificationsPreferencesProcessor[],
|
|
||||||
name: string,
|
|
||||||
fallback: boolean = true,
|
|
||||||
): AddonNotificationsPreferencesProcessor | undefined {
|
|
||||||
if (!processors || !processors.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const processor = processors.find((processor) => processor.name == name);
|
|
||||||
if (processor) {
|
|
||||||
return processor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processor not found, return first if requested.
|
|
||||||
if (fallback) {
|
|
||||||
return processors[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the components and notifications that have a certain processor.
|
* Return the components and notifications that have a certain processor.
|
||||||
*
|
*
|
||||||
|
@ -166,7 +138,11 @@ export type AddonNotificationsPreferencesComponentFormatted = Omit<AddonNotifica
|
||||||
* Preferences notification with some calculated data.
|
* Preferences notification with some calculated data.
|
||||||
*/
|
*/
|
||||||
export type AddonNotificationsPreferencesNotificationFormatted = AddonNotificationsPreferencesNotification & {
|
export type AddonNotificationsPreferencesNotificationFormatted = AddonNotificationsPreferencesNotification & {
|
||||||
processorsByName?: Record<string, AddonNotificationsPreferencesNotificationProcessor>; // Calculated in the app.
|
processorsByName?: Record<string, AddonNotificationsPreferencesNotificationProcessorFormatted>; // Calculated in the app.
|
||||||
|
};
|
||||||
|
|
||||||
|
type AddonNotificationsPreferencesNotificationProcessorFormatted = AddonNotificationsPreferencesNotificationProcessor & {
|
||||||
|
updating?: boolean; // Calculated in the app. Whether the state is being updated.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -435,19 +435,24 @@ export type AddonNotificationsPreferencesNotificationProcessor = {
|
||||||
locked: boolean; // Is locked by admin?.
|
locked: boolean; // Is locked by admin?.
|
||||||
lockedmessage?: string; // @since 3.6. Text to display if locked.
|
lockedmessage?: string; // @since 3.6. Text to display if locked.
|
||||||
userconfigured: number; // Is configured?.
|
userconfigured: number; // Is configured?.
|
||||||
loggedin: AddonNotificationsPreferencesNotificationProcessorState;
|
enabled?: boolean; // @since 4.0. Processor enabled.
|
||||||
loggedoff: AddonNotificationsPreferencesNotificationProcessorState;
|
loggedin: AddonNotificationsPreferencesNotificationProcessorState; // @deprecated removed on 4.0.
|
||||||
|
loggedoff: AddonNotificationsPreferencesNotificationProcessorState; // @deprecated removed on 4.0.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State in notification processor in notification preferences component.
|
* State in notification processor in notification preferences component.
|
||||||
|
*
|
||||||
|
* @deprecated removed on 4.0.
|
||||||
*/
|
*/
|
||||||
export type AddonNotificationsPreferencesNotificationProcessorState = {
|
export type AddonNotificationsPreferencesNotificationProcessorState = {
|
||||||
name: string; // Name.
|
name: 'loggedoff' | 'loggedin'; // Name.
|
||||||
displayname: string; // Display name.
|
displayname: string; // Display name.
|
||||||
checked: boolean; // Is checked?.
|
checked: boolean; // Is checked?.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AddonNotificationsPreferencesNotificationProcessorStateSetting = 'loggedoff' | 'loggedin' | 'enabled';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params of core_message_get_messages WS.
|
* Params of core_message_get_messages WS.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
<!-- Reviewing the question. -->
|
<!-- Reviewing the question. -->
|
||||||
<ng-container *ngIf="review">
|
<ng-container *ngIf="review">
|
||||||
<!-- Answer to the question and attachments (reviewing). -->
|
<!-- Answer to the question and attachments (reviewing). -->
|
||||||
<ion-item class="ion-text-wrap" *ngIf="essayQuestion.answer || essayQuestion.answer == ''">
|
<ion-item class="ion-text-wrap" *ngIf="essayQuestion.answer || essayQuestion.answer == ''">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<core-format-text [ngClass]='{"core-monospaced": essayQuestion.isMonospaced}' [component]="component"
|
<core-format-text [ngClass]='{"core-monospaced": essayQuestion.isMonospaced}' [component]="component"
|
||||||
[componentId]="componentId" [text]="essayQuestion.answer" [contextLevel]="contextLevel"
|
[componentId]="componentId" [text]="essayQuestion.answer" [contextLevel]="contextLevel"
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<ion-label position="stacked">
|
<ion-label position="stacked">
|
||||||
<span [core-mark-required]="required">{{ field.name }}</span>
|
<span [core-mark-required]="required">{{ field.name }}</span>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-datetime [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="format" [max]="max"
|
<ion-datetime [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="format" [max]="max"
|
||||||
[min]="min" [monthNames]="monthNames">
|
[min]="min" [monthNames]="monthNames">
|
||||||
</ion-datetime>
|
</ion-datetime>
|
||||||
<core-input-errors [control]="form.controls[modelName]"></core-input-errors>
|
<core-input-errors [control]="form.controls[modelName]"></core-input-errors>
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
<ion-label position="stacked">
|
<ion-label position="stacked">
|
||||||
<span [core-mark-required]="required">{{ field.name }}</span>
|
<span [core-mark-required]="required">{{ field.name }}</span>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-select [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" interface="action-sheet"
|
<ion-select [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" interface="action-sheet"
|
||||||
[interfaceOptions]="{header: field.name}">
|
[interfaceOptions]="{header: field.name}">
|
||||||
<ion-select-option value="">{{ 'core.choosedots' | translate }}</ion-select-option>
|
<ion-select-option value="">{{ 'core.choosedots' | translate }}</ion-select-option>
|
||||||
<ion-select-option *ngFor="let option of options" [value]="option">{{option}}</ion-select-option>
|
<ion-select-option *ngFor="let option of options" [value]="option">{{option}}</ion-select-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
<core-input-errors [control]="form.controls[modelName]"></core-input-errors>
|
<core-input-errors [control]="form.controls[modelName]"></core-input-errors>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<ion-item class="ion-text-wrap">
|
<ion-item class="ion-text-wrap">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<span *ngIf="maxSubmissionsReadable">
|
<span *ngIf="maxSubmissionsReadable">
|
||||||
{{ 'core.maxsizeandattachments' | translate:{$a: {size: maxSizeReadable, attachments: maxSubmissionsReadable} } }}
|
{{ 'core.maxsizeandattachments' | translate:{$a: {size: maxSizeReadable, attachments: maxSubmissionsReadable} } }}
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="!maxSubmissionsReadable">{{ 'core.maxfilesize' | translate:{$a: maxSizeReadable} }}</span>
|
<span *ngIf="!maxSubmissionsReadable">{{ 'core.maxfilesize' | translate:{$a: maxSizeReadable} }}</span>
|
||||||
<span [core-mark-required]="required" class="core-mark-required"></span>
|
<span [core-mark-required]="required" class="core-mark-required"></span>
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
--padding-top: 8px;
|
--padding-top: 8px;
|
||||||
--padding-end: 8px;
|
--padding-end: 8px;
|
||||||
--padding-bottom: 8px;
|
--padding-bottom: 8px;
|
||||||
--padding-start: 8px;
|
|
||||||
|
|
||||||
&.md {
|
&.md {
|
||||||
--background-activated-opacity: 0;
|
--background-activated-opacity: 0;
|
||||||
|
@ -40,6 +39,14 @@
|
||||||
--background-focused-opacity: .15;
|
--background-focused-opacity: .15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ion-button {
|
||||||
|
--padding-start: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-select {
|
||||||
|
--padding-start: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-select,
|
ion-select,
|
||||||
|
@ -48,7 +55,7 @@ ion-button {
|
||||||
color: var(--color);
|
color: var(--color);
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
min-height: 25px;
|
min-height: 26px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 8px;
|
margin: 8px;
|
||||||
box-shadow: var(--box-shadow);
|
box-shadow: var(--box-shadow);
|
||||||
|
@ -109,7 +116,7 @@ ion-button {
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-text {
|
.select-text {
|
||||||
margin-inline-end: auto;
|
@include margin-horizontal(null, auto);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="ion-padding">
|
<div class="ion-padding">
|
||||||
<h2 *ngIf="!isDisabledInSite && isSupportedByTheApp">{{ 'core.whoops' | translate }}</h2>
|
<h2 *ngIf="!isDisabledInSite && isSupportedByTheApp">{{ 'core.whoops' | translate }}</h2>
|
||||||
<h2 *ngIf="isDisabledInSite || !isSupportedByTheApp">{{ 'core.uhoh' | translate }}</h2>
|
<h2 *ngIf="isDisabledInSite || !isSupportedByTheApp">{{ 'core.uhoh' | translate }}</h2>
|
||||||
|
|
||||||
<p class="core-big" *ngIf="isDisabledInSite">{{ 'core.course.activitydisabled' | translate }}</p>
|
<p class="core-big" *ngIf="isDisabledInSite">{{ 'core.course.activitydisabled' | translate }}</p>
|
||||||
<p class="core-big" *ngIf="!isDisabledInSite && isSupportedByTheApp">
|
<p class="core-big" *ngIf="!isDisabledInSite && isSupportedByTheApp">
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
<p class="core-big" *ngIf="!isDisabledInSite && !isSupportedByTheApp">
|
<p class="core-big" *ngIf="!isDisabledInSite && !isSupportedByTheApp">
|
||||||
{{ 'core.course.activitynotyetviewableremoteaddon' | translate }}
|
{{ 'core.course.activitynotyetviewableremoteaddon' | translate }}
|
||||||
</p>
|
</p>
|
||||||
<p *ngIf="isDisabledInSite || !isSupportedByTheApp"><strong>{{ 'core.course.askadmintosupport' | translate }}</strong></p>
|
<p *ngIf="isDisabledInSite || !isSupportedByTheApp"><strong>{{ 'core.course.askadmintosupport' | translate }}</strong></p>
|
||||||
|
|
||||||
<div *ngIf="module && module.url">
|
<div *ngIf="module && module.url">
|
||||||
<p><strong>{{ 'core.course.useactivityonbrowser' | translate }}</strong></p>
|
<p><strong>{{ 'core.course.useactivityonbrowser' | translate }}</strong></p>
|
||||||
|
|
|
@ -100,7 +100,7 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="paypalEnabled">
|
<ion-item class="ion-text-wrap" *ngIf="paypalEnabled">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p class="item-heading">{{ 'core.courses.paypalaccepted' | translate }}</p>
|
<p class="item-heading">{{ 'core.courses.paypalaccepted' | translate }}</p>
|
||||||
<p *ngIf="isMobile">{{ 'core.paymentinstant' | translate }}</p>
|
<p *ngIf="isMobile">{{ 'core.paymentinstant' | translate }}</p>
|
||||||
<ion-button *ngIf="isMobile" expand="block" class="ion-margin-top" (click)="paypalEnrol()">
|
<ion-button *ngIf="isMobile" expand="block" class="ion-margin-top" (click)="paypalEnrol()">
|
||||||
{{ 'core.courses.sendpaymentbutton' | translate }}
|
{{ 'core.courses.sendpaymentbutton' | translate }}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
"disableall": "Disable notifications",
|
"disableall": "Disable notifications",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"disabledfeatures": "Disabled features",
|
"disabledfeatures": "Disabled features",
|
||||||
|
"disallowed": "Disallowed",
|
||||||
"displayformat": "Display format",
|
"displayformat": "Display format",
|
||||||
"enabledownloadsection": "Enable download sections",
|
"enabledownloadsection": "Enable download sections",
|
||||||
"enablefirebaseanalytics": "Enable Firebase analytics",
|
"enablefirebaseanalytics": "Enable Firebase analytics",
|
||||||
|
@ -43,6 +44,7 @@
|
||||||
"filesystemroot": "File system root",
|
"filesystemroot": "File system root",
|
||||||
"fontsize": "Text size",
|
"fontsize": "Text size",
|
||||||
"fontsizecharacter": "A",
|
"fontsizecharacter": "A",
|
||||||
|
"forced": "Locked",
|
||||||
"forcedsetting": "This setting has been forced by your site configuration.",
|
"forcedsetting": "This setting has been forced by your site configuration.",
|
||||||
"forcesafeareamargins": "Force safe area margins",
|
"forcesafeareamargins": "Force safe area margins",
|
||||||
"general": "General",
|
"general": "General",
|
||||||
|
@ -53,7 +55,6 @@
|
||||||
"license": "Licence",
|
"license": "Licence",
|
||||||
"localnotifavailable": "Local notifications available",
|
"localnotifavailable": "Local notifications available",
|
||||||
"locationhref": "Web view URL",
|
"locationhref": "Web view URL",
|
||||||
"locked": "Locked",
|
|
||||||
"loggedin": "Online",
|
"loggedin": "Online",
|
||||||
"loggedoff": "Offline",
|
"loggedoff": "Offline",
|
||||||
"navigatorlanguage": "Navigator language",
|
"navigatorlanguage": "Navigator language",
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<ion-item (longPress)="copyItemInfo($event)" (click)="enableDevOptions()">
|
<ion-item (longPress)="copyItemInfo($event)" (click)="enableDevOptions()">
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<h2>{{ 'core.settings.compilationinfo' | translate }}</h2>
|
<h2>{{ 'core.settings.compilationinfo' | translate }}</h2>
|
||||||
<p *ngIf="deviceInfo.compilationTime">{{ deviceInfo.compilationTime | coreFormatDate: "LLL Z": false }}</p>
|
<p *ngIf="deviceInfo.compilationTime">{{ deviceInfo.compilationTime | coreFormatDate: "LLL Z": false }}</p>
|
||||||
<p *ngIf="deviceInfo.lastCommit">{{ deviceInfo.lastCommit }}</p>
|
<p *ngIf="deviceInfo.lastCommit">{{ deviceInfo.lastCommit }}</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<core-loading [hideUntil]="handlers.loaded">
|
<core-loading [hideUntil]="handlers.loaded">
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-item *ngFor="let handler of handlers.items" [ngClass]="['core-settings-handler', handler.class]"
|
<ion-item *ngFor="let handler of handlers.items" [ngClass]="['core-settings-handler', handler.class]"
|
||||||
[attr.aria-label]="handler.title | translate" detail="true" (click)="handlers.select(handler)" button
|
[attr.aria-label]="handler.title | translate" detail="true" (click)="handlers.select(handler)" button
|
||||||
[attr.aria-current]="handlers.getItemAriaCurrent(handler)">
|
[attr.aria-current]="handlers.getItemAriaCurrent(handler)">
|
||||||
<ion-icon [name]="handler.icon" slot="start" *ngIf="handler.icon" aria-hidden="true">
|
<ion-icon [name]="handler.icon" slot="start" *ngIf="handler.icon" aria-hidden="true">
|
||||||
</ion-icon>
|
</ion-icon>
|
||||||
|
|
Loading…
Reference in New Issue