MOBILE-2329 settings: Migrate preferences
parent
ee7808643b
commit
99af917816
|
@ -270,7 +270,7 @@ export class SQLiteDB {
|
|||
deleteRecords(table: string, conditions?: object): Promise<any> {
|
||||
if (conditions === null || typeof conditions == 'undefined') {
|
||||
// No conditions, delete the whole table.
|
||||
return this.execute(`DELETE FROM TABLE ${table}`);
|
||||
return this.execute(`DELETE FROM ${table}`);
|
||||
}
|
||||
|
||||
const selectAndParams = this.whereClause(conditions);
|
||||
|
|
|
@ -30,6 +30,7 @@ export class CoreConstants {
|
|||
static SETTINGS_RICH_TEXT_EDITOR = 'CoreSettingsRichTextEditor';
|
||||
static SETTINGS_NOTIFICATION_SOUND = 'CoreSettingsNotificationSound';
|
||||
static SETTINGS_SYNC_ONLY_ON_WIFI = 'CoreSettingsSyncOnlyOnWifi';
|
||||
static SETTINGS_REPORT_IN_BACKGROUND = 'CoreSettingsReportInBackground';
|
||||
|
||||
// WS constants.
|
||||
static WS_TIMEOUT = 30000;
|
||||
|
|
|
@ -279,7 +279,7 @@ export class FileMock extends File {
|
|||
maxIterations = 10;
|
||||
// More accurate. Factor is 1.1.
|
||||
calculateByRequest(size, 1.1).then((size: number) => {
|
||||
return size / 1024; // Return size in KB.
|
||||
resolve(size / 1024); // Return size in KB.
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -45,9 +45,9 @@ export class CoreLoginSitesPage {
|
|||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.sitesProvider.getSites().then((sites) => {
|
||||
this.sitesProvider.getSortedSites().then((sites) => {
|
||||
// Remove protocol from the url to show more url text.
|
||||
sites = sites.map((site) => {
|
||||
this.sites = sites.map((site) => {
|
||||
site.siteUrl = site.siteUrl.replace(/^https?:\/\//, '');
|
||||
site.badge = 0;
|
||||
this.pushNotificationsProvider.getSiteCounter(site.id).then((counter) => {
|
||||
|
@ -57,24 +57,6 @@ export class CoreLoginSitesPage {
|
|||
return site;
|
||||
});
|
||||
|
||||
// Sort sites by url and fullname.
|
||||
this.sites = sites.sort((a, b) => {
|
||||
// First compare by site url without the protocol.
|
||||
let compareA = a.siteUrl.toLowerCase(),
|
||||
compareB = b.siteUrl.toLowerCase();
|
||||
const compare = compareA.localeCompare(compareB);
|
||||
|
||||
if (compare !== 0) {
|
||||
return compare;
|
||||
}
|
||||
|
||||
// If site url is the same, use fullname instead.
|
||||
compareA = a.fullName.toLowerCase().trim();
|
||||
compareB = b.fullName.toLowerCase().trim();
|
||||
|
||||
return compareA.localeCompare(compareB);
|
||||
});
|
||||
|
||||
this.showDelete = false;
|
||||
}).catch(() => {
|
||||
// Shouldn't happen.
|
||||
|
|
|
@ -1,12 +1,49 @@
|
|||
{
|
||||
"about": "About",
|
||||
"appready": "App ready",
|
||||
"cannotsyncoffline": "Cannot synchronise offline.",
|
||||
"cannotsyncwithoutwifi": "Cannot synchronise because the current settings only allow to synchronise when connected to Wi-Fi. Please connect to a Wi-Fi network.",
|
||||
"cordovadevicemodel": "Cordova device model",
|
||||
"cordovadeviceosversion": "Cordova device OS version",
|
||||
"cordovadeviceplatform": "Cordova device platform",
|
||||
"cordovadeviceuuid": "Cordova device UUID",
|
||||
"cordovaversion": "Cordova version",
|
||||
"currentlanguage": "Current language",
|
||||
"deletesitefiles": "Are you sure that you want to delete the downloaded files from the site '{{sitename}}'?",
|
||||
"deletesitefilestitle": "Delete site files",
|
||||
"deviceinfo": "Device info",
|
||||
"deviceos": "Device OS",
|
||||
"devicewebworkers": "Device web workers supported",
|
||||
"disableall": "Disable notifications",
|
||||
"disabled": "Disabled",
|
||||
"displayformat": "Display format",
|
||||
"enablerichtexteditor": "Enable text editor",
|
||||
"enablerichtexteditordescription": "If enabled, a text editor will be available when entering content.",
|
||||
"enablesyncwifi": "Allow sync only when on Wi-Fi",
|
||||
"errordeletesitefiles": "Error deleting site files.",
|
||||
"errorsyncsite": "Error synchronising site data. Please check your Internet connection and try again.",
|
||||
"estimatedfreespace": "Estimated free space",
|
||||
"filesystemroot": "File system root",
|
||||
"general": "General",
|
||||
"language": "Language",
|
||||
"license": "License",
|
||||
"localnotifavailable": "Local notifications available",
|
||||
"locationhref": "Web view URL",
|
||||
"loggedin": "Online",
|
||||
"loggedoff": "Offline",
|
||||
"navigatorlanguage": "Navigator language",
|
||||
"navigatoruseragent": "Navigator userAgent",
|
||||
"networkstatus": "Internet connection status",
|
||||
"privacypolicy": "Privacy policy",
|
||||
"reportinbackground": "Report errors automatically",
|
||||
"settings": "Settings",
|
||||
"sites": "Sites",
|
||||
"spaceusage": "Space usage",
|
||||
"synchronization": "Synchronisation"
|
||||
"synchronization": "Synchronisation",
|
||||
"synchronizenow": "Synchronise now",
|
||||
"syncsettings": "Synchronisation settings",
|
||||
"total": "Total",
|
||||
"versioncode": "Version code",
|
||||
"versionname": "Version name",
|
||||
"wificonnection": "Wi-Fi connection"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ 'core.settings.about' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-item text-wrap>
|
||||
<h2>{{ appName }} {{ versionName }}</h2>
|
||||
</ion-item>
|
||||
<ion-item-group>
|
||||
<ion-item-divider text-wrap color="light">
|
||||
{{ 'core.settings.license' | translate }}
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap>
|
||||
<h2>Apache 2.0</h2>
|
||||
<p><a href="http://www.apache.org/licenses/LICENSE-2.0" core-link auto-login="no">http://www.apache.org/licenses/LICENSE-2.0</a></p>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
<ion-item-group *ngIf="privacyPolicy">
|
||||
<ion-item-divider text-wrap color="light">
|
||||
{{ 'core.settings.privacypolicy' | translate }}
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap>
|
||||
<p><a [href]="privacyPolicy" core-link auto-login="no">{{ privacyPolicy }}</a></p>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
<ion-item-group>
|
||||
<ion-item-divider text-wrap color="light">
|
||||
{{ 'core.settings.deviceinfo' | translate }}
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap *ngIf="versionName">
|
||||
<h2>{{ 'core.settings.versionname' | translate}}</h2>
|
||||
<p>{{ versionName }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="versionCode">
|
||||
<h2>{{ 'core.settings.versioncode' | translate}}</h2>
|
||||
<p>{{ versionCode }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="fileSystemRoot">
|
||||
<h2>{{ 'core.settings.filesystemroot' | translate}}</h2>
|
||||
<p><a *ngIf="fsClickable" [href]="fileSystemRoot" core-link auto-login="no">{{ filesystemroot }}</a></p>
|
||||
<p *ngIf="!fsClickable">{{ fileSystemRoot }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="navigator && navigator.userAgent">
|
||||
<h2>{{ 'core.settings.navigatoruseragent' | translate}}</h2>
|
||||
<p>{{ navigator.userAgent }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="navigator && navigator.language">
|
||||
<h2>{{ 'core.settings.navigatorlanguage' | translate}}</h2>
|
||||
<p>{{ navigator.language }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="locationHref">
|
||||
<h2>{{ 'core.settings.locationhref' | translate}}</h2>
|
||||
<p>{{ locationHref }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="appReady">
|
||||
<h2>{{ 'core.settings.appready' | translate}}</h2>
|
||||
<p>{{ appReady | translate }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="deviceType">
|
||||
<h2>{{ 'core.settings.displayformat' | translate}}</h2>
|
||||
<p>{{ deviceType | translate }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="deviceOs">
|
||||
<h2>{{ 'core.settings.deviceos' | translate}}</h2>
|
||||
<p>{{ deviceOs | translate }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="currentLanguage">
|
||||
<h2>{{ 'core.settings.currentlanguage' | translate}}</h2>
|
||||
<p>{{ currentLanguage }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="networkStatus">
|
||||
<h2>{{ 'core.settings.networkstatus' | translate}}</h2>
|
||||
<p>{{ networkStatus | translate }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="wifiConnection">
|
||||
<h2>{{ 'core.settings.wificonnection' | translate}}</h2>
|
||||
<p>{{ wifiConnection | translate }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="deviceWebWorkers">
|
||||
<h2>{{ 'core.settings.devicewebworkers' | translate}}</h2>
|
||||
<p>{{ deviceWebWorkers | translate }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="device && device.cordova">
|
||||
<h2>{{ 'core.settings.cordovaversion' | translate}}</h2>
|
||||
<p>{{ device.cordova }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="device && device.platform">
|
||||
<h2>{{ 'core.settings.cordovadeviceplatform' | translate}}</h2>
|
||||
<p>{{ device.platform }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="device && device.version">
|
||||
<h2>{{ 'core.settings.cordovadeviceosversion' | translate}}</h2>
|
||||
<p>{{ device.version }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="device && device.model">
|
||||
<h2>{{ 'core.settings.cordovadevicemodel' | translate}}</h2>
|
||||
<p>{{ device.model }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="device && device.uuid">
|
||||
<h2>{{ 'core.settings.cordovadeviceuuid' | translate}}</h2>
|
||||
<p>{{ device.uuid }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="localNotifAvailable">
|
||||
<h2>{{ 'core.settings.localnotifavailable' | translate}}</h2>
|
||||
<p>{{ localNotifAvailable | translate }}</p>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-content>
|
|
@ -0,0 +1,33 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreSettingsAboutPage } from './about';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreSettingsAboutPage
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
IonicPageModule.forChild(CoreSettingsAboutPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class CoreSettingsAboutPageModule {}
|
|
@ -0,0 +1,105 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { IonicPage, Platform } from 'ionic-angular';
|
||||
import { Device } from '@ionic-native/device';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFileProvider } from '@providers/file';
|
||||
import { CoreInitDelegate } from '@providers/init';
|
||||
import { CoreLangProvider } from '@providers/lang';
|
||||
import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
||||
import { CoreConfigConstants } from '../../../../configconstants';
|
||||
|
||||
/**
|
||||
* Page that displays the about settings.
|
||||
*/
|
||||
@IonicPage({segment: 'core-settings-about'})
|
||||
@Component({
|
||||
selector: 'page-core-settings-about',
|
||||
templateUrl: 'about.html',
|
||||
})
|
||||
export class CoreSettingsAboutPage {
|
||||
|
||||
appName: string;
|
||||
versionName: string;
|
||||
versionCode: number;
|
||||
privacyPolicy: string;
|
||||
navigator: Navigator;
|
||||
locationHref: string;
|
||||
appReady: string;
|
||||
deviceType: string;
|
||||
deviceOs: string;
|
||||
currentLanguage: string;
|
||||
networkStatus: string;
|
||||
wifiConnection: string;
|
||||
deviceWebWorkers: string;
|
||||
device: Device;
|
||||
fileSystemRoot: string;
|
||||
fsClickable: boolean;
|
||||
storageType: string;
|
||||
localNotifAvailable: string;
|
||||
|
||||
constructor(platform: Platform, device: Device, appProvider: CoreAppProvider, fileProvider: CoreFileProvider,
|
||||
initDelegate: CoreInitDelegate, langProvider: CoreLangProvider,
|
||||
localNotificationsProvider: CoreLocalNotificationsProvider) {
|
||||
|
||||
this.appName = appProvider.isDesktop() ? CoreConfigConstants.desktopappname : CoreConfigConstants.appname;
|
||||
this.versionName = CoreConfigConstants.versionname;
|
||||
this.versionCode = CoreConfigConstants.versioncode;
|
||||
this.privacyPolicy = CoreConfigConstants.privacypolicy;
|
||||
|
||||
this.navigator = window.navigator;
|
||||
if (window.location && window.location.href) {
|
||||
const url = window.location.href;
|
||||
this.locationHref = url.substr(0, url.indexOf('#'));
|
||||
}
|
||||
|
||||
this.appReady = initDelegate.isReady() ? 'core.yes' : 'core.no';
|
||||
this.deviceType = platform.is('tablet') ? 'core.tablet' : 'core.phone';
|
||||
|
||||
if (platform.is('android')) {
|
||||
this.deviceOs = 'core.android';
|
||||
} else if (platform.is('ios')) {
|
||||
this.deviceOs = 'core.ios';
|
||||
} else if (platform.is('windows')) {
|
||||
this.deviceOs = 'core.windowsphone';
|
||||
} else {
|
||||
const matches = navigator.userAgent.match(/\(([^\)]*)\)/);
|
||||
if (matches && matches.length > 1) {
|
||||
this.deviceOs = matches[1];
|
||||
} else {
|
||||
this.deviceOs = 'core.unknown';
|
||||
}
|
||||
}
|
||||
|
||||
langProvider.getCurrentLanguage().then((lang) => {
|
||||
this.currentLanguage = lang;
|
||||
});
|
||||
|
||||
this.networkStatus = appProvider.isOnline() ? 'core.online' : 'core.offline';
|
||||
this.wifiConnection = appProvider.isNetworkAccessLimited() ? 'core.no' : 'core.yes';
|
||||
this.deviceWebWorkers = !!window['Worker'] && !!window['URL'] ? 'core.yes' : 'core.no';
|
||||
this.device = device;
|
||||
|
||||
if (fileProvider.isAvailable()) {
|
||||
fileProvider.getBasePath().then((basepath) => {
|
||||
this.fileSystemRoot = basepath;
|
||||
this.fsClickable = fileProvider.usesHTMLAPI();
|
||||
});
|
||||
}
|
||||
|
||||
this.localNotifAvailable = localNotificationsProvider.isAvailable() ? 'core.yes' : 'core.no';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ 'core.settings.general' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-item text-wrap>
|
||||
<ion-label><h2>{{ 'core.settings.language' | translate }}</h2></ion-label>
|
||||
<ion-select [(ngModel)]="selectedLanguage" (ngModelChange)="languageChanged()">
|
||||
<ion-option *ngFor="let code of languageCodes" [value]="code">{{ languages[code] }}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="rteSupported">
|
||||
<ion-label>
|
||||
<h2>{{ 'core.settings.enablerichtexteditor' | translate }}</h2>
|
||||
<p>{{ 'core.settings.enablerichtexteditordescription' | translate }}</p>
|
||||
</ion-label>
|
||||
<ion-toggle [(ngModel)]="richTextEditor" (ngModelChange)="richTextEditorChanged()"></ion-toggle>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="showReport">
|
||||
<ion-label><h2>{{ 'core.settings.reportinbackground' | translate }}</h2></ion-label>
|
||||
<ion-toggle [(ngModel)]="reportInBackground" (ngModelChange)="reportInBackgroundChanged()"></ion-toggle>
|
||||
</ion-item>
|
||||
</ion-content>
|
|
@ -0,0 +1,33 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreSettingsGeneralPage } from './general';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreSettingsGeneralPage
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
IonicPageModule.forChild(CoreSettingsGeneralPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class CoreSettingsGeneralPageModule {}
|
|
@ -0,0 +1,93 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { IonicPage } from 'ionic-angular';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
import { CoreConfigProvider } from '@providers/config';
|
||||
import { CoreFileProvider } from '@providers/file';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreLangProvider } from '@providers/lang';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
||||
import { CoreConfigConstants } from '../../../../configconstants';
|
||||
|
||||
/**
|
||||
* Page that displays the general settings.
|
||||
*/
|
||||
@IonicPage({segment: 'core-settings-general'})
|
||||
@Component({
|
||||
selector: 'page-core-settings-general',
|
||||
templateUrl: 'general.html',
|
||||
})
|
||||
export class CoreSettingsGeneralPage {
|
||||
|
||||
languages = {};
|
||||
languageCodes = [];
|
||||
selectedLanguage: string;
|
||||
rteSupported: boolean;
|
||||
richTextEditor: boolean;
|
||||
showReport: boolean;
|
||||
reportInBackground: boolean;
|
||||
|
||||
constructor(appProvider: CoreAppProvider, private configProvider: CoreConfigProvider, fileProvider: CoreFileProvider,
|
||||
private eventsProvider: CoreEventsProvider, private langProvider: CoreLangProvider,
|
||||
private domUtils: CoreDomUtilsProvider,
|
||||
localNotificationsProvider: CoreLocalNotificationsProvider) {
|
||||
|
||||
this.languages = CoreConfigConstants.languages;
|
||||
this.languageCodes = Object.keys(this.languages);
|
||||
langProvider.getCurrentLanguage().then((currentLanguage) => {
|
||||
this.selectedLanguage = currentLanguage;
|
||||
});
|
||||
|
||||
this.rteSupported = this.domUtils.isRichTextEditorSupported();
|
||||
if (this.rteSupported) {
|
||||
this.configProvider.get(CoreConstants.SETTINGS_RICH_TEXT_EDITOR, true).then((richTextEditorEnabled) => {
|
||||
this.richTextEditor = richTextEditorEnabled;
|
||||
});
|
||||
}
|
||||
|
||||
if (localStorage && localStorage.getItem && localStorage.setItem) {
|
||||
this.showReport = true;
|
||||
this.reportInBackground = parseInt(localStorage.getItem(CoreConstants.SETTINGS_REPORT_IN_BACKGROUND), 10) === 1;
|
||||
} else {
|
||||
this.showReport = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new language is selected.
|
||||
*/
|
||||
languageChanged(): void {
|
||||
this.langProvider.changeCurrentLanguage(this.selectedLanguage).finally(() => {
|
||||
this.eventsProvider.trigger(CoreEventsProvider.LANGUAGE_CHANGED);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the rich text editor is enabled or disabled.
|
||||
*/
|
||||
richTextEditorChanged(): void {
|
||||
this.configProvider.set(CoreConstants.SETTINGS_RICH_TEXT_EDITOR, this.richTextEditor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the report in background setting is enabled or disabled.
|
||||
*/
|
||||
reportInBackgroundChanged(): void {
|
||||
localStorage.setItem(CoreConstants.SETTINGS_REPORT_IN_BACKGROUND, this.reportInBackground ? '1' : '0');
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
<ion-icon name="stats" item-start></ion-icon>
|
||||
<p>{{ 'core.settings.spaceusage' | translate }}</p>
|
||||
</ion-item>
|
||||
<ion-item (click)="openHandler('CoreSettingSynchronizationPage')" [title]="'core.settings.synchronization' | translate" [class.core-split-item-selected]="'CoreSettingSynchronizationPage' == selectedPage" detail-push>
|
||||
<ion-item (click)="openHandler('CoreSettingsSynchronizationPage')" [title]="'core.settings.synchronization' | translate" [class.core-split-item-selected]="'CoreSettingsSynchronizationPage' == selectedPage" detail-push>
|
||||
<ion-icon name="sync" item-start></ion-icon>
|
||||
<p>{{ 'core.settings.synchronization' | translate }}</p>
|
||||
</ion-item>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ 'core.settings.spaceusage' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="usageLoaded" (ionRefresh)="refreshData($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="usageLoaded">
|
||||
<ion-item *ngFor="let site of sites" [class.core-primary-item]="site.id == currentSiteId">
|
||||
<h2><core-format-text [text]="site.siteName"></core-format-text></h2>
|
||||
<p>{{ site.fullName }}</p>
|
||||
<p item-end>{{ site.spaceUsage | coreBytesToSize }}</p>
|
||||
<button ion-button icon-only clear color="danger" item-end (click)="deleteSiteFiles(site)" [hidden]="!site.spaceUsage > '0'" [attr.aria-label]="'core.settings.deletesitefilestitle' | translate">
|
||||
<ion-icon name="trash"></ion-icon>
|
||||
</button>
|
||||
</ion-item>
|
||||
<ion-item-divider color="light">
|
||||
<p>{{ 'core.settings.total' | translate }}</p>
|
||||
<p item-end>{{ totalUsage | coreBytesToSize }}</p>
|
||||
</ion-item-divider>
|
||||
<ion-item-divider color="light">
|
||||
<p>{{ 'core.settings.estimatedfreespace' | translate }}</p>
|
||||
<p item-end>{{ freeSpace | coreBytesToSize }}</p>
|
||||
</ion-item-divider>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -0,0 +1,35 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreSettingsSpaceUsagePage } from './space-usage';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CorePipesModule } from '@pipes/pipes.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreSettingsSpaceUsagePage
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
IonicPageModule.forChild(CoreSettingsSpaceUsagePage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class CoreSettingsSpaceUsagePageModule {}
|
|
@ -0,0 +1,180 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { IonicPage } from 'ionic-angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreFileProvider } from '@providers/file';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
|
||||
/**
|
||||
* Page that displays the space usage settings.
|
||||
*/
|
||||
@IonicPage({segment: 'core-settings-space-usage'})
|
||||
@Component({
|
||||
selector: 'page-core-settings-space-usage',
|
||||
templateUrl: 'space-usage.html',
|
||||
})
|
||||
export class CoreSettingsSpaceUsagePage {
|
||||
|
||||
usageLoaded = false;
|
||||
sites = [];
|
||||
currentSiteId = '';
|
||||
totalUsage = 0;
|
||||
freeSpace = 0;
|
||||
|
||||
constructor(private fileProvider: CoreFileProvider, private filePoolProvider: CoreFilepoolProvider,
|
||||
private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider,
|
||||
private translate: TranslateService, private domUtils: CoreDomUtilsProvider) {
|
||||
this.currentSiteId = this.sitesProvider.getCurrentSiteId();
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.fetchData().finally(() => {
|
||||
this.usageLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to calculate each site's usage, and the total usage.
|
||||
*
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
protected calculateSizeUsage(): Promise<any> {
|
||||
return this.sitesProvider.getSortedSites().then((sites) => {
|
||||
this.sites = sites;
|
||||
|
||||
// Get space usage.
|
||||
const promises = this.sites.map((siteEntry) => {
|
||||
return this.sitesProvider.getSite(siteEntry.id).then((site) => {
|
||||
return site.getSpaceUsage().then((size) => {
|
||||
siteEntry.spaceUsage = size;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to calculate total usage.
|
||||
*/
|
||||
protected calculateTotalUsage(): void {
|
||||
let total = 0;
|
||||
this.sites.forEach((site) => {
|
||||
if (site.spaceUsage) {
|
||||
total += parseInt(site.spaceUsage, 10);
|
||||
}
|
||||
});
|
||||
this.totalUsage = total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to calculate free space in the device.
|
||||
*
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
protected calculateFreeSpace(): Promise<any> {
|
||||
if (this.fileProvider.isAvailable()) {
|
||||
return this.fileProvider.calculateFreeSpace().then((freeSpace) => {
|
||||
this.freeSpace = freeSpace;
|
||||
}).catch(() => {
|
||||
this.freeSpace = 0;
|
||||
});
|
||||
} else {
|
||||
this.freeSpace = 0;
|
||||
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to calculate space usage and free space in the device.
|
||||
*
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
protected fetchData(): Promise<any> {
|
||||
return Promise.all([
|
||||
this.calculateSizeUsage().then(() => this.calculateTotalUsage()),
|
||||
this.calculateFreeSpace(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the data.
|
||||
*
|
||||
* @param {any} refresher Refresher.
|
||||
*/
|
||||
refreshData(refresher: any): void {
|
||||
this.fetchData().finally(() => {
|
||||
refresher.complete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to update site size, along with total usage and free space.
|
||||
*
|
||||
* @param {any} site Site object with space usage.
|
||||
* @param {number} newUsage New space usage of the site in bytes.
|
||||
*/
|
||||
protected updateSiteUsage(site: any, newUsage: number): void {
|
||||
const oldUsage = site.spaceUsage;
|
||||
site.spaceUsage = newUsage;
|
||||
this.totalUsage -= oldUsage - newUsage;
|
||||
this.freeSpace += oldUsage - newUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes files of a site.
|
||||
*
|
||||
* @param {any} siteData Site object with space usage.
|
||||
*/
|
||||
deleteSiteFiles(siteData: any): void {
|
||||
this.textUtils.formatText(siteData.siteName).then((siteName) => {
|
||||
const title = this.translate.instant('core.settings.deletesitefilestitle');
|
||||
const message = this.translate.instant('core.settings.deletesitefiles', {sitename: siteName});
|
||||
|
||||
this.domUtils.showConfirm(message, title).then(() => {
|
||||
return this.sitesProvider.getSite(siteData.id);
|
||||
}).then((site) => {
|
||||
site.deleteFolder().then(() => {
|
||||
this.filePoolProvider.clearAllPackagesStatus(site.id);
|
||||
this.filePoolProvider.clearFilepool(site.id);
|
||||
this.updateSiteUsage(siteData, 0);
|
||||
}).catch((error) => {
|
||||
if (error && error.code === FileError.NOT_FOUND_ERR) {
|
||||
// Not found, set size 0.
|
||||
this.filePoolProvider.clearAllPackagesStatus(site.id);
|
||||
this.updateSiteUsage(siteData, 0);
|
||||
} else {
|
||||
// Error, recalculate the site usage.
|
||||
this.domUtils.showErrorModal('core.settings.errordeletesitefiles', true);
|
||||
site.getSpaceUsage().then((size) => {
|
||||
this.updateSiteUsage(siteData, size);
|
||||
});
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
// Ignore cancelled confirmation modal.
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ 'core.settings.synchronization' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<core-loading [hideUntil]="sitesLoaded">
|
||||
<ion-item-divider color="light">
|
||||
<p>{{ 'core.settings.syncsettings' | translate }}</p>
|
||||
</ion-item-divider>
|
||||
<ion-item>
|
||||
<ion-label>{{ 'core.settings.enablesyncwifi' | translate }}</ion-label>
|
||||
<ion-toggle item-end [(ngModel)]="syncOnlyOnWifi" (ngModelChange)="syncOnlyOnWifiChanged()">
|
||||
</ion-toggle>
|
||||
</ion-item>
|
||||
<ion-item-divider color="light">
|
||||
<p>{{ 'core.settings.sites' | translate }}</p>
|
||||
</ion-item-divider>
|
||||
<ion-item *ngFor="let site of sites" [class.core-primary-item]="site.id == currentSiteId">
|
||||
<h2><core-format-text [text]="site.siteName"></core-format-text></h2>
|
||||
<p>{{ site.fullName }}</p>
|
||||
<p>{{ site.siteUrl }}</p>
|
||||
<button ion-button icon-only clear item-end *ngIf="!isSynchronizing(site.id)" (click)="synchronize(site.id)" [title]="site.siteName" [attr.aria-label]="'core.settings.synchronizenow' | translate">
|
||||
<ion-icon name="sync"></ion-icon>
|
||||
</button>
|
||||
<ion-spinner item-end *ngIf="isSynchronizing(site.id)"></ion-spinner>
|
||||
</ion-item>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -0,0 +1,35 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreSettingsSynchronizationPage } from './synchronization';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CorePipesModule } from '@pipes/pipes.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreSettingsSynchronizationPage
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
IonicPageModule.forChild(CoreSettingsSynchronizationPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class CoreSettingsSynchronizationPageModule {}
|
|
@ -0,0 +1,113 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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, OnDestroy } from '@angular/core';
|
||||
import { IonicPage } from 'ionic-angular';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider, CoreSiteBasicInfo } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreConfigProvider } from '@providers/config';
|
||||
import { CoreSettingsHelper } from '@core/settings/providers/helper';
|
||||
|
||||
/**
|
||||
* Page that displays the synchronization settings.
|
||||
*/
|
||||
@IonicPage({segment: 'core-settings-synchronization'})
|
||||
@Component({
|
||||
selector: 'page-core-settings-synchronization',
|
||||
templateUrl: 'synchronization.html',
|
||||
})
|
||||
export class CoreSettingsSynchronizationPage implements OnDestroy {
|
||||
|
||||
sites: CoreSiteBasicInfo[] = [];
|
||||
sitesLoaded = false;
|
||||
sitesObserver: any;
|
||||
currentSiteId = '';
|
||||
syncOnlyOnWifi = false;
|
||||
isDestroyed = false;
|
||||
|
||||
constructor(private configProvider: CoreConfigProvider, private eventsProvider: CoreEventsProvider,
|
||||
private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
|
||||
private settingsHelper: CoreSettingsHelper) {
|
||||
|
||||
this.currentSiteId = this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
this.sitesObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, (data) => {
|
||||
this.sitesProvider.getSite(data.siteId).then((site) => {
|
||||
const siteInfo = site.getInfo();
|
||||
const siteEntry = this.sites.find((siteEntry) => siteEntry.id == site.id);
|
||||
if (siteEntry) {
|
||||
siteEntry.siteUrl = siteInfo.siteurl;
|
||||
siteEntry.siteName = siteInfo.sitename;
|
||||
siteEntry.fullName = siteInfo.fullname;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.sitesProvider.getSortedSites().then((sites) => {
|
||||
this.sites = sites;
|
||||
}).finally(() => {
|
||||
this.sitesLoaded = true;
|
||||
});
|
||||
|
||||
this.configProvider.get(CoreConstants.SETTINGS_SYNC_ONLY_ON_WIFI, true).then((syncOnlyOnWifi) => {
|
||||
this.syncOnlyOnWifi = syncOnlyOnWifi;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when sync only on wifi setting is enabled or disabled.
|
||||
*/
|
||||
syncOnlyOnWifiChanged(): void {
|
||||
this.configProvider.set(CoreConstants.SETTINGS_SYNC_ONLY_ON_WIFI, this.syncOnlyOnWifi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncrhonizes a site.
|
||||
*
|
||||
* @param {string} siteId Site ID.
|
||||
*/
|
||||
synchronize(siteId: string): void {
|
||||
this.settingsHelper.synchronizeSite(this.syncOnlyOnWifi, siteId).catch((error) => {
|
||||
if (this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
this.domUtils.showErrorModalDefault(error, 'core.settings.errorsyncsite', true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if site is beeing synchronized.
|
||||
*
|
||||
* @param {string} siteId Site ID.
|
||||
* @return {boolean} True if site is beeing synchronized, false otherwise.
|
||||
*/
|
||||
isSynchronizing(siteId: string): boolean {
|
||||
return !!this.settingsHelper.getSiteSyncPromise(siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Page destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.isDestroyed = true;
|
||||
this.sitesObserver && this.sitesObserver.off();
|
||||
}
|
||||
}
|
|
@ -13,8 +13,14 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreCronDelegate } from '@providers/cron';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
/**
|
||||
* Settings helper service.
|
||||
|
@ -22,8 +28,11 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
|
|||
@Injectable()
|
||||
export class CoreSettingsHelper {
|
||||
protected logger;
|
||||
protected syncPromises = {};
|
||||
|
||||
constructor(loggerProvider: CoreLoggerProvider, private utils: CoreUtilsProvider) {
|
||||
constructor(loggerProvider: CoreLoggerProvider, private appProvider: CoreAppProvider, private cronDelegate: CoreCronDelegate,
|
||||
private eventsProvider: CoreEventsProvider, private filePoolProvider: CoreFilepoolProvider,
|
||||
private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider, private translate: TranslateService) {
|
||||
this.logger = loggerProvider.getInstance('CoreSettingsHelper');
|
||||
}
|
||||
|
||||
|
@ -91,4 +100,79 @@ export class CoreSettingsHelper {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the synchronization promise of a site.
|
||||
*
|
||||
* @param {string} siteId ID of the site.
|
||||
* @return {Promise<any> | null} Sync promise or null if site is not being syncrhonized.
|
||||
*/
|
||||
getSiteSyncPromise(siteId: string): Promise<any> {
|
||||
if (this.syncPromises[siteId]) {
|
||||
return this.syncPromises[siteId];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize a site.
|
||||
*
|
||||
* @param {boolean} syncOnlyOnWifi True to sync only on wifi, false otherwise.
|
||||
* @param {string} siteId ID of the site to synchronize.
|
||||
* @return {Promise<any>} Promise resolved when synchronized, rejected if failure.
|
||||
*/
|
||||
synchronizeSite(syncOnlyOnWifi: boolean, siteId: string): Promise<any> {
|
||||
if (this.syncPromises[siteId]) {
|
||||
// There's already a sync ongoing for this site, return the promise.
|
||||
return this.syncPromises[siteId];
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
const hasSyncHandlers = this.cronDelegate.hasManualSyncHandlers();
|
||||
|
||||
if (hasSyncHandlers && !this.appProvider.isOnline()) {
|
||||
// We need connection to execute sync.
|
||||
return Promise.reject(this.translate.instant('core.settings.cannotsyncoffline'));
|
||||
} else if (hasSyncHandlers && syncOnlyOnWifi && this.appProvider.isNetworkAccessLimited()) {
|
||||
return Promise.reject(this.translate.instant('core.settings.cannotsyncwithoutwifi'));
|
||||
}
|
||||
|
||||
// Invalidate all the site files so they are re-downloaded.
|
||||
promises.push(this.filePoolProvider.invalidateAllFiles(siteId).catch(() => {
|
||||
// Ignore errors.
|
||||
}));
|
||||
|
||||
// Get the site to invalidate data.
|
||||
promises.push(this.sitesProvider.getSite(siteId).then((site) => {
|
||||
// Invalidate the WS cache.
|
||||
return site.invalidateWsCache().then(() => {
|
||||
const subPromises = [];
|
||||
|
||||
// Check if local_mobile was installed in Moodle.
|
||||
subPromises.push(site.checkIfLocalMobileInstalledAndNotUsed().then(() => {
|
||||
// Local mobile was added. Throw invalid session to force reconnect and create a new token.
|
||||
this.eventsProvider.trigger(CoreEventsProvider.SESSION_EXPIRED, {}, siteId);
|
||||
|
||||
return Promise.reject(this.translate.instant('core.lostconnection'));
|
||||
}, () => {
|
||||
// Update site info.
|
||||
return this.sitesProvider.updateSiteInfo(siteId);
|
||||
}));
|
||||
|
||||
// Execute cron if needed.
|
||||
subPromises.push(this.cronDelegate.forceSyncExecution(siteId));
|
||||
|
||||
return Promise.all(subPromises);
|
||||
});
|
||||
}));
|
||||
|
||||
const syncPromise = Promise.all(promises);
|
||||
this.syncPromises[siteId] = syncPromise;
|
||||
syncPromise.finally(() => {
|
||||
delete this.syncPromises[siteId];
|
||||
});
|
||||
|
||||
return syncPromise;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -870,6 +870,36 @@ export class CoreSitesProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of sites stored, sorted by URL and full name.
|
||||
*
|
||||
* @param {String[]} [ids] IDs of the sites to get. If not defined, return all sites.
|
||||
* @return {Promise<CoreSiteBasicInfo[]>} Promise resolved when the sites are retrieved.
|
||||
*/
|
||||
getSortedSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> {
|
||||
return this.getSites(ids).then((sites) => {
|
||||
// Sort sites by url and ful lname.
|
||||
sites.sort((a, b) => {
|
||||
// First compare by site url without the protocol.
|
||||
let compareA = a.siteUrl.replace(/^https?:\/\//, '').toLowerCase(),
|
||||
compareB = b.siteUrl.replace(/^https?:\/\//, '').toLowerCase();
|
||||
const compare = compareA.localeCompare(compareB);
|
||||
|
||||
if (compare !== 0) {
|
||||
return compare;
|
||||
}
|
||||
|
||||
// If site url is the same, use fullname instead.
|
||||
compareA = a.fullName.toLowerCase().trim();
|
||||
compareB = b.fullName.toLowerCase().trim();
|
||||
|
||||
return compareA.localeCompare(compareB);
|
||||
});
|
||||
|
||||
return sites;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of IDs of sites stored.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue