MOBILE-3565 settings: Add general settings page

main
Pau Ferrer Ocaña 2020-11-04 17:37:02 +01:00
parent 3be2f204f4
commit a71aa53dae
13 changed files with 781 additions and 13 deletions

View File

@ -84,9 +84,9 @@
}
},
"font_sizes": [
62.5,
75.89,
93.75
100,
110,
120
],
"customurlscheme": "moodlemobile",
"siteurl": "",

View File

@ -0,0 +1,65 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
</ion-buttons>
<ion-title>{{ 'core.settings.general' | translate }}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-item class="ion-text-wrap">
<ion-label>
<h2>{{ 'core.settings.language' | translate }}</h2>
</ion-label>
<ion-select [(ngModel)]="selectedLanguage" (ionChange)="languageChanged()" interface="action-sheet"
[interfaceOptions]="{header: 'core.settings.language' | translate}">
<ion-select-option *ngFor="let entry of languages" [value]="entry.code">{{ entry.name }}</ion-select-option>
</ion-select>
</ion-item>
<ion-item class="ion-text-wrap core-settings-general-font-size item-interactive">
<ion-label>
<h2>{{ 'core.settings.fontsize' | translate }}</h2>
</ion-label>
<ion-segment [(ngModel)]="selectedFontSize" (ionChange)="fontSizeChanged()" color="primary" item-content>
<ion-segment-button *ngFor="let fontSize of fontSizes" [value]="fontSize.size"
[ngStyle]="{'font-size.px': fontSize.style}">
{{ 'core.settings.fontsizecharacter' | translate }}
<!-- Empty element styled with the largest font size, so all buttons share a common baseline. -->
<span [ngStyle]="{'font-size.px': fontSizes[fontSizes.length - 1].style}"></span>
</ion-segment-button>
</ion-segment>
</ion-item>
<ion-item class="ion-text-wrap core-settings-general-color-scheme" *ngIf="colorSchemes.length > 0">
<ion-label>
<h2>{{ 'core.settings.colorscheme' | translate }}</h2>
<p *ngIf="colorSchemeDisabled" class="text-danger">{{ 'core.settings.forcedsetting' | translate }}</p>
</ion-label>
<ion-select [(ngModel)]="selectedScheme" (ionChange)="colorSchemeChanged()" interface="action-sheet"
[disabled]="colorSchemeDisabled" [interfaceOptions]="{header: 'core.settings.colorscheme' | translate}">
<ion-select-option *ngFor="let scheme of colorSchemes" [value]="scheme">
{{ 'core.settings.colorscheme-' + scheme | translate }}</ion-select-option>
</ion-select>
</ion-item>
<ion-item class="ion-text-wrap">
<ion-label>
<h2>{{ 'core.settings.enablerichtexteditor' | translate }}</h2>
<p>{{ 'core.settings.enablerichtexteditordescription' | translate }}</p>
</ion-label>
<ion-toggle [(ngModel)]="richTextEditor" (ionChange)="richTextEditorChanged()"></ion-toggle>
</ion-item>
<ion-item class="ion-text-wrap">
<ion-label>
<h2>{{ 'core.settings.debugdisplay' | translate }}</h2>
<p>{{ 'core.settings.debugdisplaydescription' | translate }}</p>
</ion-label>
<ion-toggle [(ngModel)]="debugDisplay" (ionChange)="debugDisplayChanged()"></ion-toggle>
</ion-item>
<ion-item class="ion-text-wrap" *ngIf="analyticsSupported">
<ion-label>
<h2>{{ 'core.settings.enablefirebaseanalytics' | translate }}</h2>
<p>{{ 'core.settings.enablefirebaseanalyticsdescription' | translate }}</p>
</ion-label>
<ion-toggle [(ngModel)]="analyticsEnabled" (ionChange)="analyticsEnabledChanged()"></ion-toggle>
</ion-item>
</ion-content>

View File

@ -0,0 +1,48 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { FormsModule } from '@angular/forms';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreSettingsGeneralPage } from './general.page';
const routes: Routes = [
{
path: '',
component: CoreSettingsGeneralPage,
},
];
@NgModule({
declarations: [
CoreSettingsGeneralPage,
],
imports: [
RouterModule.forChild(routes),
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule,
FormsModule,
],
})
export class CoreSettingsGeneralPageModule {}

View File

@ -0,0 +1,168 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component } from '@angular/core';
import { CoreConstants } from '@core/constants';
import { CoreConfig } from '@services/config';
import { CoreEvents } from '@singletons/events';
import { CoreLang } from '@services/lang';
import { CoreDomUtils } from '@services/utils/dom';
// import { CorePushNotifications } from '@core/pushnotifications/services/pushnotifications';
import { CoreSettingsHelper, CoreColorScheme } from '../../services/settings.helper';
/**
* Page that displays the general settings.
*/
@Component({
selector: 'page-core-settings-general',
templateUrl: 'general.html',
styleUrls: ['general.scss'],
})
export class CoreSettingsGeneralPage {
languages: { code: string; name: string }[] = [];
selectedLanguage = '';
fontSizes: { size: number; style: number; selected: boolean }[] = [];
selectedFontSize = 0;
richTextEditor = true;
debugDisplay = false;
analyticsSupported = false;
analyticsEnabled = false;
colorSchemes: CoreColorScheme[] = [];
selectedScheme: CoreColorScheme = CoreColorScheme.LIGHT;
colorSchemeDisabled = false;
constructor() {
this.asyncInit();
}
/**
* Async part of the constructor.
*/
protected async asyncInit(): Promise<void> {
// Get the supported languages.
const languages = CoreConstants.CONFIG.languages;
for (const code in languages) {
this.languages.push({
code: code,
name: languages[code],
});
}
// Sort them by name.
this.languages.sort((a, b) => a.name.localeCompare(b.name));
this.selectedLanguage = await CoreLang.instance.getCurrentLanguage();
// Configure color schemes.
if (!CoreConstants.CONFIG.forceColorScheme) {
this.colorSchemeDisabled = CoreSettingsHelper.instance.isColorSchemeDisabledInSite();
if (this.colorSchemeDisabled) {
this.colorSchemes.push(CoreColorScheme.LIGHT);
this.selectedScheme = this.colorSchemes[0];
} else {
this.colorSchemes.push(CoreColorScheme.LIGHT);
this.colorSchemes.push(CoreColorScheme.DARK);
if (window.matchMedia('(prefers-color-scheme: dark)').matches ||
window.matchMedia('(prefers-color-scheme: light)').matches) {
this.colorSchemes.push(CoreColorScheme.AUTO);
}
this.selectedScheme = await CoreConfig.instance.get(CoreConstants.SETTINGS_COLOR_SCHEME, CoreColorScheme.LIGHT);
}
}
this.selectedFontSize = await CoreConfig.instance.get(
CoreConstants.SETTINGS_FONT_SIZE,
CoreConstants.CONFIG.font_sizes[0],
);
this.fontSizes = CoreConstants.CONFIG.font_sizes.map((size) =>
({
size,
// Absolute pixel size based on 1.4rem body text when this size is selected.
style: Math.round(size * 16 / 100),
selected: size === this.selectedFontSize,
}));
this.richTextEditor = await CoreConfig.instance.get(CoreConstants.SETTINGS_RICH_TEXT_EDITOR, true);
this.debugDisplay = await CoreConfig.instance.get(CoreConstants.SETTINGS_DEBUG_DISPLAY, false);
this.analyticsSupported = CoreConstants.CONFIG.enableanalytics;
if (this.analyticsSupported) {
this.analyticsEnabled = await CoreConfig.instance.get(CoreConstants.SETTINGS_ANALYTICS_ENABLED, true);
}
}
/**
* Called when a new language is selected.
*/
languageChanged(): void {
CoreLang.instance.changeCurrentLanguage(this.selectedLanguage).finally(() => {
CoreEvents.trigger(CoreEvents.LANGUAGE_CHANGED, this.selectedLanguage);
});
}
/**
* Called when a new font size is selected.
*/
fontSizeChanged(): void {
this.fontSizes = this.fontSizes.map((fontSize) => {
fontSize.selected = fontSize.size === this.selectedFontSize;
return fontSize;
});
CoreSettingsHelper.instance.setFontSize(this.selectedFontSize);
CoreConfig.instance.set(CoreConstants.SETTINGS_FONT_SIZE, this.selectedFontSize);
}
/**
* Called when a new color scheme is selected.
*/
colorSchemeChanged(): void {
CoreSettingsHelper.instance.setColorScheme(this.selectedScheme);
CoreConfig.instance.set(CoreConstants.SETTINGS_COLOR_SCHEME, this.selectedScheme);
}
/**
* Called when the rich text editor is enabled or disabled.
*/
richTextEditorChanged(): void {
CoreConfig.instance.set(CoreConstants.SETTINGS_RICH_TEXT_EDITOR, this.richTextEditor ? 1 : 0);
}
/**
* Called when the debug display setting is enabled or disabled.
*/
debugDisplayChanged(): void {
CoreConfig.instance.set(CoreConstants.SETTINGS_DEBUG_DISPLAY, this.debugDisplay ? 1 : 0);
CoreDomUtils.instance.setDebugDisplay(this.debugDisplay);
}
/**
* Called when the analytics setting is enabled or disabled.
*
* @todo
*/
async analyticsEnabledChanged(): Promise<void> {
// await this.pushNotificationsProvider.enableAnalytics(this.analyticsEnabled);
CoreConfig.instance.set(CoreConstants.SETTINGS_ANALYTICS_ENABLED, this.analyticsEnabled ? 1 : 0);
}
}

View File

@ -0,0 +1,5 @@
:host {
.core-settings-general-font-size ion-segment {
max-width: 250px;
}
}

View File

@ -0,0 +1,431 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreApp } from '@services/app';
import { CoreCron } from '@services/cron';
import { CoreEvents } from '@singletons/events';
import { CoreFilepool } from '@services/filepool';
import { CoreSite } from '@classes/site';
import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreConstants } from '@core/constants';
import { CoreConfig } from '@services/config';
// import { CoreFilterProvider } from '@core/filter/providers/filter';
import { CoreDomUtils } from '@services/utils/dom';
// import { CoreCourseProvider } from '@core/course/providers/course';
import { makeSingleton, Translate } from '@singletons/core.singletons';
/**
* Object with space usage and cache entries that can be erased.
*/
export interface CoreSiteSpaceUsage {
cacheEntries?: number; // Number of cached entries that can be cleared.
spaceUsage?: number; // Space used in this site (total files + estimate of cache).
}
/**
* Constants to define color schemes.
*/
export const enum CoreColorScheme {
AUTO = 'auto',
LIGHT = 'light',
DARK = 'dark',
}
/**
* Settings helper service.
*/
@Injectable({
providedIn: 'root',
})
export class CoreSettingsHelperProvider {
protected syncPromises: { [s: string]: Promise<void> } = {};
protected prefersDark?: MediaQueryList;
constructor() {
// protected filterProvider: CoreFilterProvider,
// protected courseProvider: CoreCourseProvider,
if (!CoreConstants.CONFIG.forceColorScheme) {
// Update color scheme when a user enters or leaves a site, or when the site info is updated.
const applySiteScheme = (): void => {
if (this.isColorSchemeDisabledInSite()) {
// Dark mode is disabled, force light mode.
this.setColorScheme(CoreColorScheme.LIGHT);
} else {
this.prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
// Reset color scheme settings.
this.initColorScheme();
}
};
CoreEvents.on(CoreEvents.LOGIN, applySiteScheme.bind(this));
CoreEvents.on(CoreEvents.SITE_UPDATED, applySiteScheme.bind(this));
CoreEvents.on(CoreEvents.LOGOUT, () => {
// Reset color scheme settings.
this.initColorScheme();
});
}
}
/**
* Deletes files of a site and the tables that can be cleared.
*
* @param siteName Site Name.
* @param siteId: Site ID.
* @return Resolved with detailed new info when done.
* @todo filterProvider and courseProviderpart.
*/
async deleteSiteStorage(siteName: string, siteId: string): Promise<CoreSiteSpaceUsage> {
const siteInfo: CoreSiteSpaceUsage = {
cacheEntries: 0,
spaceUsage: 0,
};
// siteName = await this.filterProvider.formatText(siteName, { clean: true, singleLine: true, filter: false }, [], siteId);
const title = Translate.instance.instant('core.settings.deletesitefilestitle');
const message = Translate.instance.instant('core.settings.deletesitefiles', { sitename: siteName });
await CoreDomUtils.instance.showConfirm(message, title);
const site = await CoreSites.instance.getSite(siteId);
// Clear cache tables.
const cleanSchemas = CoreSites.instance.getSiteTableSchemasToClear(site);
const promises: Promise<number | void>[] = cleanSchemas.map((name) => site.getDb().deleteRecords(name));
const filepoolService = CoreFilepool.instance;
promises.push(site.deleteFolder().then(() => {
filepoolService.clearAllPackagesStatus(siteId);
filepoolService.clearFilepool(siteId);
// this.courseProvider.clearAllCoursesStatus(siteId);
siteInfo.spaceUsage = 0;
return;
}).catch(async (error) => {
if (error && error.code === FileError.NOT_FOUND_ERR) {
// Not found, set size 0.
filepoolService.clearAllPackagesStatus(siteId);
siteInfo.spaceUsage = 0;
} else {
// Error, recalculate the site usage.
CoreDomUtils.instance.showErrorModal('core.settings.errordeletesitefiles', true);
siteInfo.spaceUsage = await site.getSpaceUsage();
}
}).then(async () => {
CoreEvents.trigger(CoreEvents.SITE_STORAGE_DELETED, {}, siteId);
siteInfo.cacheEntries = await this.calcSiteClearRows(site);
return;
}));
await Promise.all(promises);
return siteInfo;
}
/**
* Calculates each site's usage, and the total usage.
*
* @param siteId ID of the site. Current site if undefined.
* @return Resolved with detailed info when done.
*/
async getSiteSpaceUsage(siteId?: string): Promise<CoreSiteSpaceUsage> {
const site = await CoreSites.instance.getSite(siteId);
// Get space usage.
const siteInfo: CoreSiteSpaceUsage = {
cacheEntries: 0,
spaceUsage: 0,
};
siteInfo.cacheEntries = await this.calcSiteClearRows(site);
siteInfo.spaceUsage = await site.getTotalUsage();
return siteInfo;
}
/**
* Calculate the number of rows to be deleted on a site.
*
* @param site Site object.
* @return If there are rows to delete or not.
*/
protected async calcSiteClearRows(site: CoreSite): Promise<number> {
const clearTables = CoreSites.instance.getSiteTableSchemasToClear(site);
let totalEntries = 0;
await Promise.all(clearTables.map(async (name) =>
totalEntries = await site.getDb().countRecords(name) + totalEntries));
return totalEntries;
}
/**
* 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.
* @todo
*/
getProcessor(processors: any[], name: string, fallback: boolean = true): any {
if (!processors || !processors.length) {
return;
}
for (let i = 0; i < processors.length; i++) {
if (processors[i].name == name) {
return processors[i];
}
}
// Processor not found, return first if requested.
if (fallback) {
return processors[0];
}
}
/**
* Return the components and notifications that have a certain processor.
*
* @param processor Name of the processor to filter.
* @param components Array of components.
* @return Filtered components.
* @todo
*/
getProcessorComponents(processor: string, components: any[]): any[] {
return processor? components : [];
/*
const result = [];
components.forEach((component) => {
// Create a copy of the component with an empty list of notifications.
const componentCopy = CoreUtils.instance.clone(component);
componentCopy.notifications = [];
component.notifications.forEach((notification) => {
let hasProcessor = false;
for (let i = 0; i < notification.processors.length; i++) {
const proc = notification.processors[i];
if (proc.name == processor) {
hasProcessor = true;
notification.currentProcessor = proc;
break;
}
}
if (hasProcessor) {
// Add the notification.
componentCopy.notifications.push(notification);
}
});
if (componentCopy.notifications.length) {
// At least 1 notification added, add the component to the result.
result.push(componentCopy);
}
});
return result;*/
}
/**
* Get the synchronization promise of a site.
*
* @param siteId ID of the site.
* @return Sync promise or null if site is not being syncrhonized.
*/
async getSiteSyncPromise(siteId: string): Promise<void> {
if (this.syncPromises[siteId]) {
return this.syncPromises[siteId];
}
}
/**
* Synchronize a site.
*
* @param syncOnlyOnWifi True to sync only on wifi, false otherwise.
* @param siteId ID of the site to synchronize.
* @return Promise resolved when synchronized, rejected if failure.
*/
async synchronizeSite(syncOnlyOnWifi: boolean, siteId: string): Promise<void> {
if (this.syncPromises[siteId]) {
// There's already a sync ongoing for this site, return the promise.
return this.syncPromises[siteId];
}
const site = await CoreSites.instance.getSite(siteId);
const hasSyncHandlers = CoreCron.instance.hasManualSyncHandlers();
if (site.isLoggedOut()) {
// Cannot sync logged out sites.
throw Translate.instance.instant('core.settings.cannotsyncloggedout');
} else if (hasSyncHandlers && !CoreApp.instance.isOnline()) {
// We need connection to execute sync.
throw Translate.instance.instant('core.settings.cannotsyncoffline');
} else if (hasSyncHandlers && syncOnlyOnWifi && CoreApp.instance.isNetworkAccessLimited()) {
throw Translate.instance.instant('core.settings.cannotsyncwithoutwifi');
}
const syncPromise = Promise.all([
// Invalidate all the site files so they are re-downloaded.
CoreUtils.instance.ignoreErrors(CoreFilepool.instance.invalidateAllFiles(siteId)),
// Invalidate and synchronize site data.
site.invalidateWsCache(),
this.checkSiteLocalMobile(site),
CoreSites.instance.updateSiteInfo(site.getId()),
CoreCron.instance.forceSyncExecution(site.getId()),
// eslint-disable-next-line arrow-body-style
]).then(() => {
return;
});
this.syncPromises[siteId] = syncPromise;
try {
await syncPromise;
} finally {
delete this.syncPromises[siteId];
}
}
/**
* Check if local_mobile was added to the site.
*
* @param site Site to check.
* @return Promise resolved if no action needed.
*/
protected async checkSiteLocalMobile(site: CoreSite): Promise<void> {
try {
// Check if local_mobile was installed in Moodle.
await site.checkIfLocalMobileInstalledAndNotUsed();
} catch {
// Not added, nothing to do.
return;
}
// Local mobile was added. Throw invalid session to force reconnect and create a new token.
CoreEvents.trigger(CoreEvents.SESSION_EXPIRED, {}, site.getId());
throw Translate.instance.instant('core.lostconnection');
}
/**
* Init Settings related to DOM.
*/
async initDomSettings(): Promise<void> {
// Set the font size based on user preference.
const fontSize = await CoreConfig.instance.get(CoreConstants.SETTINGS_FONT_SIZE, CoreConstants.CONFIG.font_sizes[0]);
this.setFontSize(fontSize);
this.initColorScheme();
}
/**
* Init the color scheme.
*/
async initColorScheme(): Promise<void> {
if (CoreConstants.CONFIG.forceColorScheme) {
this.setColorScheme(CoreConstants.CONFIG.forceColorScheme);
} else {
const scheme = await CoreConfig.instance.get(CoreConstants.SETTINGS_COLOR_SCHEME, CoreColorScheme.LIGHT);
this.setColorScheme(scheme);
}
}
/**
* Check if color scheme is disabled in a site.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with whether color scheme is disabled.
*/
async isColorSchemeDisabled(siteId?: string): Promise<boolean> {
const site = await CoreSites.instance.getSite(siteId);
return this.isColorSchemeDisabledInSite(site);
}
/**
* Check if color scheme is disabled in a site.
*
* @param site Site instance. If not defined, current site.
* @return Whether color scheme is disabled.
*/
isColorSchemeDisabledInSite(site?: CoreSite): boolean {
site = site || CoreSites.instance.getCurrentSite();
return site ? site.isFeatureDisabled('NoDelegate_DarkMode') : false;
}
/**
* Set document default font size.
*
* @param fontSize Font size in percentage.
*/
setFontSize(fontSize: number): void {
// @todo Since zoom is deprecated and fontSize is not working, we should do some research here.
document.documentElement.style.zoom = fontSize + '%';
}
/**
* Set body color scheme.
*
* @param colorScheme Name of the color scheme.
*/
setColorScheme(colorScheme: CoreColorScheme): void {
if (colorScheme == CoreColorScheme.AUTO && this.prefersDark) {
// Listen for changes to the prefers-color-scheme media query.
this.prefersDark.addEventListener('change', this.toggleDarkModeListener);
this.toggleDarkMode(this.prefersDark.matches);
} else {
// Stop listening to changes.
this.prefersDark?.removeEventListener('change', this.toggleDarkModeListener);
this.toggleDarkMode(colorScheme == CoreColorScheme.DARK);
}
}
/**
* Listener function to toggle dark mode.
*
* @param e Event object.
*/
protected toggleDarkModeListener = (e: MediaQueryListEvent): void => {
document.body.classList.toggle('dark', e.matches);
};
/**
* Toggles dark mode based on enabled boolean.
*
* @param enable True to enable dark mode, false to disable.
*/
protected toggleDarkMode(enable: boolean = false): void {
document.body.classList.toggle('dark', enable);
}
}
export class CoreSettingsHelper extends makeSingleton(CoreSettingsHelperProvider) {}

View File

@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { Routes } from '@angular/router';
import { CoreMainMenuRoutingModule } from '@core/mainmenu/mainmenu-routing.module';
import { CoreSettingsHelperProvider } from './services/settings.helper';
const routes: Routes = [
{
@ -25,7 +26,21 @@ const routes: Routes = [
];
@NgModule({
imports: [CoreMainMenuRoutingModule.forChild(routes)],
exports: [CoreMainMenuRoutingModule],
imports: [
CoreMainMenuRoutingModule.forChild(routes),
],
exports: [
CoreMainMenuRoutingModule,
],
providers: [
CoreSettingsHelperProvider,
],
})
export class CoreSettingsInitModule {}
export class CoreSettingsInitModule {
constructor(settingsHelper: CoreSettingsHelperProvider) {
// @todo
// settingsHelper.initDomSettings();
}
}

View File

@ -20,6 +20,10 @@ const routes: Routes = [
path: 'about',
loadChildren: () => import('./pages/about/about.page.module').then( m => m.CoreSettingsAboutPageModule),
},
{
path: 'general',
loadChildren: () => import('./pages/general/general.page.module').then( m => m.CoreSettingsGeneralPageModule),
},
{
path: '',
loadChildren: () => import('./pages/app/app.page.module').then( m => m.CoreSettingsAppPageModule),

View File

@ -101,6 +101,7 @@ export class CoreAppProvider {
});
});
// @todo
// this.platform.registerBackButtonAction(() => {
// this.backButtonAction();
// }, 100);
@ -157,7 +158,7 @@ export class CoreAppProvider {
async createTablesFromSchema(schema: CoreAppSchema): Promise<void> {
this.logger.debug(`Apply schema to app DB: ${schema.name}`);
let oldVersion;
let oldVersion: number;
try {
// Wait for the schema versions table to be created.

View File

@ -834,17 +834,14 @@ export class CoreDomUtilsProvider {
* @return Promise resolved with boolean: true if enabled, false otherwise.
*/
isRichTextEditorEnabled(): Promise<boolean> {
if (this.isRichTextEditorSupported()) {
return CoreConfig.instance.get(CoreConstants.SETTINGS_RICH_TEXT_EDITOR, true).then((enabled) => !!enabled);
}
return Promise.resolve(false);
return CoreConfig.instance.get(CoreConstants.SETTINGS_RICH_TEXT_EDITOR, true).then((enabled) => !!enabled);
}
/**
* Check if rich text editor is supported in the platform.
*
* @return Whether it's supported.
* @deprecated since 3.9.5
*/
isRichTextEditorSupported(): boolean {
return true;

View File

@ -127,3 +127,21 @@ ion-avatar ion-img, ion-avatar img {
background-color: --var(--gray-light);
}
// Action sheet.
.md ion-action-sheet {
.action-sheet-group-cancel {
-webkit-filter: drop-shadow(0px 3px 3px rgba(var(--action-sheet-shadow-color)));
filter: drop-shadow(0px 3px 3px rgba(var(--action-sheet-shadow-color)));
}
.action-sheet-title {
border-bottom: 1px solid var(--title-border-color);
}
}
.ios ion-action-sheet {
.action-sheet-title {
font-size: 16px;
}
}

View File

@ -105,6 +105,21 @@
--background: var(--custom-toolbar-background, var(--ion-color-primary));
}
ion-action-sheet {
--action-sheet-shadow-color: var(--custom--action-sheet-shadow-color, 0, 0, 0, 1);
--button-color-selected: var(--custom--action-sheet-selected-color, var(--core-color));
--title-border-color: var(--custom-title-border-color, var(--gray));
@media (min-height: 500px) {
--max-height: 50%;
--height: 100%;
}
.action-sheet-cancel {
--button-color: var(--ion-color-danger);
}
}
core-tabs {
--background: var(--custom-tabs-background, var(--white));
ion-slide {

View File

@ -14,6 +14,7 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { CoreColorScheme } from '@core/settings/services/settings.helper';
import { CoreSitesDemoSiteData } from '@services/sites';
declare global {
@ -59,7 +60,7 @@ declare global {
statusbarlighttextremotetheme: boolean;
enableanalytics: boolean;
enableonboarding: boolean;
forceColorScheme: string;
forceColorScheme: CoreColorScheme;
forceLoginLogo: boolean;
ioswebviewscheme: string;
appstores: Record<string, string>;