MOBILE-3976 notifications: Use new enabled setting on 4.0 onward

main
Pau Ferrer Ocaña 2022-01-28 17:41:10 +01:00
parent 0b50611700
commit 93251a5594
5 changed files with 202 additions and 119 deletions

View File

@ -35,75 +35,144 @@
</ion-card>
<!-- Show processor selector. -->
<core-combobox *ngIf="preferences && preferences.processors && preferences.processors.length > 0"
[selection]="currentProcessor!.name" (onChange)="changeProcessor($event)">
<core-combobox *ngIf="preferences && preferences.processors && preferences.processors.length > 0" [selection]="currentProcessorName"
(onChange)="changeProcessor($event)">
<ion-select-option class="ion-text-wrap" *ngFor="let processor of preferences.processors" [value]="processor.name">
{{ processor.displayname }}
</ion-select-option>
</core-combobox>
<ion-card list *ngFor="let component of components" class="ion-margin-top">
<ion-item-divider class="ion-text-wrap">
<ion-grid class="ion-no-padding">
<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>
<ng-container *ngIf="loggedInOffLegacyMode">
<ng-container *ngTemplateOutlet="legacySettings; context: {preferences: preferences}"></ng-container>
</ng-container>
<!-- Phone view -->
<ion-list-header class="ion-text-wrap ion-no-margin ion-hide-md-up">
{{ notification.displayname }}
</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>
<ng-container *ngIf="!loggedInOffLegacyMode">
<ng-container *ngTemplateOutlet="settings; context: {preferences: preferences}"></ng-container>
</ng-container>
</core-loading>
</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>

View File

@ -1,5 +1,3 @@
:host {
.addon-notifications-table-content ion-row {
min-height: 35px;
}
.addon-notifications-table-content ion-row {
min-height: 35px;
}

View File

@ -27,7 +27,6 @@ import { CoreError } from '@classes/errors/error';
import { CoreEvents } from '@singletons/events';
import {
AddonNotifications,
AddonNotificationsPreferencesProcessor,
AddonNotificationsPreferencesNotificationProcessorState,
} from '../../services/notifications';
import {
@ -51,16 +50,20 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
preferences?: AddonNotificationsPreferencesFormatted;
components?: AddonNotificationsPreferencesComponentFormatted[];
currentProcessor?: AddonNotificationsPreferencesProcessor;
currentProcessorName = 'airnotifier';
preferencesLoaded = false;
notificationSound = false;
canChangeSound: boolean;
processorHandlers: AddonMessageOutputHandlerData[] = [];
loggedInOffLegacyMode = false;
protected updateTimeout?: number;
constructor() {
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 {
const preferences = await AddonNotifications.getNotificationPreferences();
if (!this.currentProcessor) {
// Initialize current processor. Load "Mobile" (airnotifier) if available.
this.currentProcessor = AddonNotificationsHelper.getProcessor(preferences.processors, 'airnotifier');
// Initialize current processor. Load "Mobile" (airnotifier) if available.
let currentProcessor = preferences.processors.find((processor) => processor.name == this.currentProcessorName);
if (!currentProcessor) {
currentProcessor = preferences.processors[0];
}
if (!this.currentProcessor) {
if (!currentProcessor) {
// Shouldn't happen.
throw new CoreError('No processor found');
}
preferences.enableall = !preferences.disableall;
this.preferences = AddonNotificationsHelper.formatPreferences(preferences);
this.loadProcessor(this.currentProcessor);
this.loadProcessor(currentProcessor);
} catch (error) {
CoreDomUtils.showErrorModal(error);
} finally {
@ -114,7 +117,7 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
return;
}
this.currentProcessor = processor;
this.currentProcessorName = processor.name;
this.processorHandlers = [];
this.components = AddonNotificationsHelper.getProcessorComponents(
processor.name,
@ -199,27 +202,21 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
* @param state State name, ['loggedin', 'loggedoff'].
* @return Promise resolved when done.
*/
async changePreference(notification: AddonNotificationsPreferencesNotificationFormatted, state: string): Promise<void> {
const processor = notification.processorsByName?.[this.currentProcessor?.name || ''];
async changePreferenceLegacy(notification: AddonNotificationsPreferencesNotificationFormatted, state: string): Promise<void> {
const processor = notification.processorsByName?.[this.currentProcessorName];
if (!processor) {
return;
}
const processorState: ProcessorStateFormatted = processor[state];
const preferenceName = notification.preferencekey + '_' + processorState.name;
let value: string | undefined;
notification.processors.forEach((processor) => {
if (processor[state].checked) {
if (!value) {
value = processor.name;
} else {
value += ',' + processor.name;
}
}
});
let value = notification.processors
.filter((processor) => processor[state].checked)
.map((processor) => processor.name)
.join(',');
if (!value) {
if (value == '') {
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.
*
@ -294,6 +330,8 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
/**
* State in notification processor in notification preferences component with some calculated data.
*
* @deprecated 4.0
*/
type ProcessorStateFormatted = AddonNotificationsPreferencesNotificationProcessorState & {
updating?: boolean; // Calculated in the app. Whether the state is being updated.

View File

@ -77,34 +77,6 @@ export class AddonNotificationsHelperProvider {
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.
*
@ -166,7 +138,11 @@ export type AddonNotificationsPreferencesComponentFormatted = Omit<AddonNotifica
* Preferences notification with some calculated data.
*/
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.
};
/**

View File

@ -451,6 +451,8 @@ export type AddonNotificationsPreferencesNotificationProcessorState = {
checked: boolean; // Is checked?.
};
export type AddonNotificationsPreferencesNotificationProcessorStateSetting = 'loggedoff' | 'loggedin' | 'enabled';
/**
* Params of core_message_get_messages WS.
*/