MOBILE-3565 login: Initial implementation of init page
parent
cf9a261e21
commit
81ce1a7d01
|
@ -9525,6 +9525,11 @@
|
|||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
|
||||
"integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
"@angular/platform-browser-dynamic": "~10.0.0",
|
||||
"@angular/router": "~10.0.0",
|
||||
"@ionic-native/core": "^5.0.0",
|
||||
"@ionic-native/splash-screen": "^5.0.0",
|
||||
"@ionic-native/splash-screen": "^5.28.0",
|
||||
"@ionic-native/status-bar": "^5.0.0",
|
||||
"@ionic/angular": "^5.0.0",
|
||||
"com-darryncampbell-cordova-plugin-intent": "^2.0.0",
|
||||
|
@ -73,6 +73,7 @@
|
|||
"cordova-support-google-services": "^1.2.1",
|
||||
"cordova.plugins.diagnostic": "^6.0.2",
|
||||
"es6-promise-plugin": "^4.2.2",
|
||||
"moment": "^2.29.0",
|
||||
"nl.kingsquare.cordova.background-audio": "^1.0.1",
|
||||
"phonegap-plugin-multidex": "^1.0.0",
|
||||
"phonegap-plugin-push": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v3",
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgModule, Injector } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { RouteReuseStrategy } from '@angular/router';
|
||||
|
||||
|
@ -21,13 +21,42 @@ import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
|||
import { AppComponent } from './app.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
|
||||
import { CoreAppProvider } from '@services/app';
|
||||
import { CoreInitDelegate } from '@services/init';
|
||||
import { CoreUtilsProvider } from '@services/utils/utils';
|
||||
|
||||
import { CoreEmulatorModule } from '@core/emulator/emulator.module';
|
||||
import { CoreLoginModule } from '@core/login/login.module';
|
||||
|
||||
import { setSingletonsInjector } from '@singletons/core.singletons';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
entryComponents: [],
|
||||
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(),
|
||||
AppRoutingModule,
|
||||
CoreEmulatorModule,
|
||||
CoreLoginModule,
|
||||
],
|
||||
providers: [
|
||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
|
||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||
CoreAppProvider,
|
||||
CoreInitDelegate,
|
||||
CoreUtilsProvider,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
export class AppModule {
|
||||
constructor(injector: Injector,
|
||||
initDelegate: CoreInitDelegate,
|
||||
) {
|
||||
|
||||
// Set the injector.
|
||||
setSingletonsInjector(injector);
|
||||
|
||||
// Execute the init processes.
|
||||
initDelegate.executeInitProcesses();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
// (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 { Injector, Type } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Stub class used to type anonymous classes created in CoreSingletonsFactory#makeSingleton method.
|
||||
*/
|
||||
class CoreSingleton {}
|
||||
|
||||
/**
|
||||
* Token that can be used to resolve instances from the injector.
|
||||
*/
|
||||
export type CoreInjectionToken<Service> = Type<Service> | Type<any> | string;
|
||||
|
||||
/**
|
||||
* Singleton class created using the factory.
|
||||
*/
|
||||
export type CoreSingletonClass<Service> = typeof CoreSingleton & { instance: Service };
|
||||
|
||||
/**
|
||||
* Factory used to create CoreSingleton classes that get instances from an injector.
|
||||
*/
|
||||
export class CoreSingletonsFactory {
|
||||
|
||||
/**
|
||||
* Angular injector used to resolve singleton instances.
|
||||
*/
|
||||
private injector: Injector;
|
||||
|
||||
/**
|
||||
* Set the injector that will be used to resolve instances in the singletons created with this factory.
|
||||
*
|
||||
* @param injector Injector.
|
||||
*/
|
||||
setInjector(injector: Injector): void {
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a singleton that will hold an instance resolved from the factory injector.
|
||||
*
|
||||
* @param injectionToken Injection token used to resolve the singleton instance. This is usually the service class if the
|
||||
* provider was defined using a class or the string used in the `provide` key if it was defined using an object.
|
||||
*/
|
||||
makeSingleton<Service>(injectionToken: CoreInjectionToken<Service>): CoreSingletonClass<Service> {
|
||||
// tslint:disable: no-this-assignment
|
||||
const factory = this;
|
||||
|
||||
return class {
|
||||
|
||||
private static _instance: Service;
|
||||
|
||||
static get instance(): Service {
|
||||
// Initialize instances lazily.
|
||||
if (!this._instance) {
|
||||
this._instance = factory.injector.get(injectionToken);
|
||||
}
|
||||
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// (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.
|
||||
|
||||
/**
|
||||
* Context levels enumeration.
|
||||
*/
|
||||
export const enum ContextLevel {
|
||||
SYSTEM = 'system',
|
||||
USER = 'user',
|
||||
COURSECAT = 'coursecat',
|
||||
COURSE = 'course',
|
||||
MODULE = 'module',
|
||||
BLOCK = 'block',
|
||||
}
|
||||
|
||||
/**
|
||||
* Static class to contain all the core constants.
|
||||
*/
|
||||
export class CoreConstants {
|
||||
static SECONDS_YEAR = 31536000;
|
||||
static SECONDS_WEEK = 604800;
|
||||
static SECONDS_DAY = 86400;
|
||||
static SECONDS_HOUR = 3600;
|
||||
static SECONDS_MINUTE = 60;
|
||||
static WIFI_DOWNLOAD_THRESHOLD = 104857600; // 100MB.
|
||||
static DOWNLOAD_THRESHOLD = 10485760; // 10MB.
|
||||
static MINIMUM_FREE_SPACE = 10485760; // 10MB.
|
||||
static IOS_FREE_SPACE_THRESHOLD = 524288000; // 500MB.
|
||||
static DONT_SHOW_ERROR = 'CoreDontShowError';
|
||||
static NO_SITE_ID = 'NoSite';
|
||||
|
||||
// Settings constants.
|
||||
static SETTINGS_RICH_TEXT_EDITOR = 'CoreSettingsRichTextEditor';
|
||||
static SETTINGS_NOTIFICATION_SOUND = 'CoreSettingsNotificationSound';
|
||||
static SETTINGS_SYNC_ONLY_ON_WIFI = 'CoreSettingsSyncOnlyOnWifi';
|
||||
static SETTINGS_DEBUG_DISPLAY = 'CoreSettingsDebugDisplay';
|
||||
static SETTINGS_REPORT_IN_BACKGROUND = 'CoreSettingsReportInBackground'; // @deprecated since 3.5.0
|
||||
static SETTINGS_SEND_ON_ENTER = 'CoreSettingsSendOnEnter';
|
||||
static SETTINGS_FONT_SIZE = 'CoreSettingsFontSize';
|
||||
static SETTINGS_COLOR_SCHEME = 'CoreSettingsColorScheme';
|
||||
static SETTINGS_ANALYTICS_ENABLED = 'CoreSettingsAnalyticsEnabled';
|
||||
|
||||
// WS constants.
|
||||
static WS_TIMEOUT = 30000; // Timeout when not in WiFi.
|
||||
static WS_TIMEOUT_WIFI = 30000; // Timeout when in WiFi.
|
||||
static WS_PREFIX = 'local_mobile_';
|
||||
|
||||
// Login constants.
|
||||
static LOGIN_SSO_CODE = 2; // SSO in browser window is required.
|
||||
static LOGIN_SSO_INAPP_CODE = 3; // SSO in embedded browser is required.
|
||||
static LOGIN_LAUNCH_DATA = 'CoreLoginLaunchData';
|
||||
|
||||
// Download status constants.
|
||||
static DOWNLOADED = 'downloaded';
|
||||
static DOWNLOADING = 'downloading';
|
||||
static NOT_DOWNLOADED = 'notdownloaded';
|
||||
static OUTDATED = 'outdated';
|
||||
static NOT_DOWNLOADABLE = 'notdownloadable';
|
||||
|
||||
// Constants from Moodle's resourcelib.
|
||||
static RESOURCELIB_DISPLAY_AUTO = 0; // Try the best way.
|
||||
static RESOURCELIB_DISPLAY_EMBED = 1; // Display using object tag.
|
||||
static RESOURCELIB_DISPLAY_FRAME = 2; // Display inside frame.
|
||||
static RESOURCELIB_DISPLAY_NEW = 3; // Display normal link in new window.
|
||||
static RESOURCELIB_DISPLAY_DOWNLOAD = 4; // Force download of file instead of display.
|
||||
static RESOURCELIB_DISPLAY_OPEN = 5; // Open directly.
|
||||
static RESOURCELIB_DISPLAY_POPUP = 6; // Open in "emulated" pop-up without navigation.
|
||||
|
||||
// Feature constants. Used to report features that are, or are not, supported by a module.
|
||||
static FEATURE_GRADE_HAS_GRADE = 'grade_has_grade'; // True if module can provide a grade.
|
||||
static FEATURE_GRADE_OUTCOMES = 'outcomes'; // True if module supports outcomes.
|
||||
static FEATURE_ADVANCED_GRADING = 'grade_advanced_grading'; // True if module supports advanced grading methods.
|
||||
static FEATURE_CONTROLS_GRADE_VISIBILITY = 'controlsgradevisbility'; // True if module controls grade visibility over gradebook.
|
||||
static FEATURE_PLAGIARISM = 'plagiarism'; // True if module supports plagiarism plugins.
|
||||
static FEATURE_COMPLETION_TRACKS_VIEWS = 'completion_tracks_views'; // True if module tracks whether somebody viewed it.
|
||||
static FEATURE_COMPLETION_HAS_RULES = 'completion_has_rules'; // True if module has custom completion rules.
|
||||
static FEATURE_NO_VIEW_LINK = 'viewlink'; // True if module has no 'view' page (like label).
|
||||
static FEATURE_IDNUMBER = 'idnumber'; // True if module wants support for setting the ID number for grade calculation purposes.
|
||||
static FEATURE_GROUPS = 'groups'; // True if module supports groups.
|
||||
static FEATURE_GROUPINGS = 'groupings'; // True if module supports groupings.
|
||||
static FEATURE_MOD_ARCHETYPE = 'mod_archetype'; // Type of module.
|
||||
static FEATURE_MOD_INTRO = 'mod_intro'; // True if module supports intro editor.
|
||||
static FEATURE_MODEDIT_DEFAULT_COMPLETION = 'modedit_default_completion'; // True if module has default completion.
|
||||
static FEATURE_COMMENT = 'comment';
|
||||
static FEATURE_RATE = 'rate';
|
||||
static FEATURE_BACKUP_MOODLE2 = 'backup_moodle2'; // True if module supports backup/restore of moodle2 format.
|
||||
static FEATURE_SHOW_DESCRIPTION = 'showdescription'; // True if module can show description on course main page.
|
||||
static FEATURE_USES_QUESTIONS = 'usesquestions'; // True if module uses the question bank.
|
||||
|
||||
// Pssobile archetypes for modules.
|
||||
static MOD_ARCHETYPE_OTHER = 0; // Unspecified module archetype.
|
||||
static MOD_ARCHETYPE_RESOURCE = 1; // Resource-like type module.
|
||||
static MOD_ARCHETYPE_ASSIGNMENT = 2; // Assignment module archetype.
|
||||
static MOD_ARCHETYPE_SYSTEM = 3; // System (not user-addable) module archetype.
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// (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';
|
||||
|
||||
// Ionic Native services.
|
||||
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
|
||||
|
||||
/**
|
||||
* This module handles the emulation of Cordova plugins in browser and desktop.
|
||||
*
|
||||
* It includes the "mock" of all the Ionic Native services that should be supported in browser and desktop,
|
||||
* otherwise those features would only work in a Cordova environment.
|
||||
*
|
||||
* This module also determines if the app should use the original service or the mock. In each of the "useFactory"
|
||||
* functions we check if the app is running in mobile or not, and then provide the right service to use.
|
||||
*/
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
],
|
||||
providers: [
|
||||
SplashScreen,
|
||||
]
|
||||
})
|
||||
export class CoreEmulatorModule { }
|
|
@ -14,13 +14,19 @@
|
|||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { CoreLoginInitPage } from './pages/init/init.page';
|
||||
import { CoreLoginSitePage } from './pages/site/site.page';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: CoreLoginInitPage,
|
||||
},
|
||||
{
|
||||
path: 'site',
|
||||
component: CoreLoginSitePage,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -19,6 +19,7 @@ import { IonicModule } from '@ionic/angular';
|
|||
|
||||
import { CoreLoginRoutingModule } from './login-routing.module';
|
||||
import { CoreLoginInitPage } from './pages/init/init.page';
|
||||
import { CoreLoginSitePage } from './pages/site/site.page';
|
||||
|
||||
|
||||
@NgModule({
|
||||
|
@ -29,6 +30,7 @@ import { CoreLoginInitPage } from './pages/init/init.page';
|
|||
],
|
||||
declarations: [
|
||||
CoreLoginInitPage,
|
||||
CoreLoginSitePage,
|
||||
],
|
||||
})
|
||||
export class CoreLoginModule {}
|
||||
|
|
|
@ -12,7 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreInit } from '@services/init';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
import { SplashScreen } from '@singletons/core.singletons';
|
||||
|
||||
/**
|
||||
* Page that displays a "splash screen" while the app is being initialized.
|
||||
|
@ -22,4 +28,69 @@ import { Component } from '@angular/core';
|
|||
templateUrl: 'init.html',
|
||||
styleUrls: ['init.scss'],
|
||||
})
|
||||
export class CoreLoginInitPage { }
|
||||
export class CoreLoginInitPage implements OnInit {
|
||||
|
||||
constructor(protected router: Router) {}
|
||||
|
||||
/**
|
||||
* Initialize the component.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
// Wait for the app to be ready.
|
||||
CoreInit.instance.ready().then(() => {
|
||||
// Check if there was a pending redirect.
|
||||
const redirectData = CoreApp.instance.getRedirect();
|
||||
if (redirectData.siteId) {
|
||||
// Unset redirect data.
|
||||
CoreApp.instance.storeRedirect('', '', '');
|
||||
|
||||
// Only accept the redirect if it was stored less than 20 seconds ago.
|
||||
if (Date.now() - redirectData.timemodified < 20000) {
|
||||
// if (redirectData.siteId != CoreConstants.NO_SITE_ID) {
|
||||
// // The redirect is pointing to a site, load it.
|
||||
// return this.sitesProvider.loadSite(redirectData.siteId, redirectData.page, redirectData.params)
|
||||
// .then((loggedIn) => {
|
||||
|
||||
// if (loggedIn) {
|
||||
// return this.loginHelper.goToSiteInitialPage(this.navCtrl, redirectData.page, redirectData.params,
|
||||
// { animate: false });
|
||||
// }
|
||||
// }).catch(() => {
|
||||
// // Site doesn't exist.
|
||||
// return this.loadPage();
|
||||
// });
|
||||
// } else {
|
||||
// // No site to load, open the page.
|
||||
// return this.loginHelper.goToNoSitePage(this.navCtrl, redirectData.page, redirectData.params);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
return this.loadPage();
|
||||
}).then(() => {
|
||||
// If we hide the splash screen now, the init view is still seen for an instant. Wait a bit to make sure it isn't seen.
|
||||
setTimeout(() => {
|
||||
SplashScreen.instance.hide();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the right page.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async loadPage(): Promise<void> {
|
||||
// if (this.sitesProvider.isLoggedIn()) {
|
||||
// if (this.loginHelper.isSiteLoggedOut()) {
|
||||
// return this.sitesProvider.logout().then(() => {
|
||||
// return this.loadPage();
|
||||
// });
|
||||
// }
|
||||
|
||||
// return this.loginHelper.goToSiteInitialPage();
|
||||
// }
|
||||
|
||||
await this.router.navigate(['/login/site']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<ion-content>
|
||||
Site page.
|
||||
</ion-content>
|
|
@ -0,0 +1,33 @@
|
|||
// (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, OnInit } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Page that displays a "splash screen" while the app is being initialized.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'page-core-login-site',
|
||||
templateUrl: 'site.html',
|
||||
styleUrls: ['site.scss'],
|
||||
})
|
||||
export class CoreLoginSitePage implements OnInit {
|
||||
|
||||
/**
|
||||
* Initialize the component.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
app-root page-core-login-init {
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
// (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 { makeSingleton } from '@singletons/core.singletons';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
|
||||
/**
|
||||
* Data stored for a redirect to another page/site.
|
||||
*/
|
||||
export type CoreRedirectData = {
|
||||
/**
|
||||
* ID of the site to load.
|
||||
*/
|
||||
siteId?: string;
|
||||
|
||||
/**
|
||||
* Name of the page to redirect to.
|
||||
*/
|
||||
page?: string;
|
||||
|
||||
/**
|
||||
* Params to pass to the page.
|
||||
*/
|
||||
params?: any;
|
||||
|
||||
/**
|
||||
* Timestamp when this redirect was last modified.
|
||||
*/
|
||||
timemodified?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Factory to provide some global functionalities, like access to the global app database.
|
||||
* @description
|
||||
* Each service or component should be responsible of creating their own database tables. Example:
|
||||
*
|
||||
* constructor(appProvider: CoreAppProvider) {
|
||||
* this.appDB = appProvider.getDB();
|
||||
* this.appDB.createTableFromSchema(this.tableSchema);
|
||||
* }
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreAppProvider {
|
||||
protected logger: CoreLogger;
|
||||
|
||||
constructor() {
|
||||
this.logger = CoreLogger.getInstance('CoreAppProvider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve redirect data.
|
||||
*
|
||||
* @return Object with siteid, state, params and timemodified.
|
||||
*/
|
||||
getRedirect(): CoreRedirectData {
|
||||
if (localStorage && localStorage.getItem) {
|
||||
try {
|
||||
const data: CoreRedirectData = {
|
||||
siteId: localStorage.getItem('CoreRedirectSiteId'),
|
||||
page: localStorage.getItem('CoreRedirectState'),
|
||||
params: localStorage.getItem('CoreRedirectParams'),
|
||||
timemodified: parseInt(localStorage.getItem('CoreRedirectTime'), 10)
|
||||
};
|
||||
|
||||
if (data.params) {
|
||||
data.params = JSON.parse(data.params);
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (ex) {
|
||||
this.logger.error('Error loading redirect data:', ex);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store redirect params.
|
||||
*
|
||||
* @param siteId Site ID.
|
||||
* @param page Page to go.
|
||||
* @param params Page params.
|
||||
*/
|
||||
storeRedirect(siteId: string, page: string, params: any): void {
|
||||
if (localStorage && localStorage.setItem) {
|
||||
try {
|
||||
localStorage.setItem('CoreRedirectSiteId', siteId);
|
||||
localStorage.setItem('CoreRedirectState', page);
|
||||
localStorage.setItem('CoreRedirectParams', JSON.stringify(params));
|
||||
localStorage.setItem('CoreRedirectTime', String(Date.now()));
|
||||
} catch (ex) {
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class CoreApp extends makeSingleton(CoreAppProvider) {}
|
|
@ -0,0 +1,178 @@
|
|||
// (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 { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { makeSingleton } from '@singletons/core.singletons';
|
||||
|
||||
/**
|
||||
* Interface that all init handlers must implement.
|
||||
*/
|
||||
export type CoreInitHandler = {
|
||||
/**
|
||||
* A name to identify the handler.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The highest priority is executed first. You should use values lower than MAX_RECOMMENDED_PRIORITY.
|
||||
*/
|
||||
priority?: number;
|
||||
|
||||
/**
|
||||
* Set this to true when this process should be resolved before any following one.
|
||||
*/
|
||||
blocking?: boolean;
|
||||
|
||||
/**
|
||||
* Function to execute during the init process.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
load(): Promise<void>;
|
||||
};
|
||||
|
||||
/*
|
||||
* Provider for initialisation mechanisms.
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreInitDelegate {
|
||||
static DEFAULT_PRIORITY = 100; // Default priority for init processes.
|
||||
static MAX_RECOMMENDED_PRIORITY = 600;
|
||||
|
||||
protected initProcesses = {};
|
||||
protected logger: CoreLogger;
|
||||
protected readiness;
|
||||
|
||||
constructor() {
|
||||
this.logger = CoreLogger.getInstance('CoreInitDelegate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the registered init processes.
|
||||
*
|
||||
* Reserved for core use, do not call directly.
|
||||
*/
|
||||
executeInitProcesses(): void {
|
||||
let ordered = [];
|
||||
|
||||
if (typeof this.readiness == 'undefined') {
|
||||
this.initReadiness();
|
||||
}
|
||||
|
||||
// Re-ordering by priority.
|
||||
for (const name in this.initProcesses) {
|
||||
ordered.push(this.initProcesses[name]);
|
||||
}
|
||||
ordered.sort((a, b) => {
|
||||
return b.priority - a.priority;
|
||||
});
|
||||
|
||||
ordered = ordered.map((data: CoreInitHandler) => {
|
||||
return {
|
||||
func: this.prepareProcess.bind(this, data),
|
||||
blocking: !!data.blocking,
|
||||
};
|
||||
});
|
||||
|
||||
// Execute all the processes in order to solve dependencies.
|
||||
CoreUtils.instance.executeOrderedPromises(ordered).finally(this.readiness.resolve);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the readiness promise.
|
||||
*/
|
||||
protected initReadiness(): void {
|
||||
this.readiness = CoreUtils.instance.promiseDefer();
|
||||
this.readiness.promise.then(() => this.readiness.resolved = true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantly returns if the app is ready.
|
||||
*
|
||||
* @return Whether it's ready.
|
||||
*/
|
||||
isReady(): boolean {
|
||||
return this.readiness.resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to return a function that executes the process.
|
||||
*
|
||||
* @param data The data of the process.
|
||||
* @return Promise of the process.
|
||||
*/
|
||||
protected prepareProcess(data: CoreInitHandler): Promise<any> {
|
||||
let promise;
|
||||
|
||||
this.logger.debug(`Executing init process '${data.name}'`);
|
||||
|
||||
try {
|
||||
promise = data.load();
|
||||
} catch (e) {
|
||||
this.logger.error('Error while calling the init process \'' + data.name + '\'. ' + e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies when the app is ready. This returns a promise that is resolved when the app is initialised.
|
||||
*
|
||||
* @return Resolved when the app is initialised. Never rejected.
|
||||
*/
|
||||
ready(): Promise<any> {
|
||||
if (typeof this.readiness == 'undefined') {
|
||||
// Prevent race conditions if this is called before executeInitProcesses.
|
||||
this.initReadiness();
|
||||
}
|
||||
|
||||
return this.readiness.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an initialisation process.
|
||||
*
|
||||
* @description
|
||||
* Init processes can be used to add initialisation logic to the app. Anything that should block the user interface while
|
||||
* some processes are done should be an init process. It is recommended to use a priority lower than MAX_RECOMMENDED_PRIORITY
|
||||
* to make sure that your process does not happen before some essential other core processes.
|
||||
*
|
||||
* An init process should never change state or prompt user interaction.
|
||||
*
|
||||
* This delegate cannot be used by site plugins.
|
||||
*
|
||||
* @param instance The instance of the handler.
|
||||
*/
|
||||
registerProcess(handler: CoreInitHandler): void {
|
||||
if (typeof handler.priority == 'undefined') {
|
||||
handler.priority = CoreInitDelegate.DEFAULT_PRIORITY;
|
||||
}
|
||||
|
||||
if (typeof this.initProcesses[handler.name] != 'undefined') {
|
||||
this.logger.log(`Process '${handler.name}' already registered.`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(`Registering process '${handler.name}'.`);
|
||||
this.initProcesses[handler.name] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
export class CoreInit extends makeSingleton(CoreInitDelegate) {}
|
|
@ -0,0 +1,159 @@
|
|||
// (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 { CoreLogger } from '@singletons/logger';
|
||||
import { makeSingleton } from '@singletons/core.singletons';
|
||||
|
||||
/*
|
||||
* "Utils" service with helper functions.
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreUtilsProvider {
|
||||
protected logger: CoreLogger;
|
||||
|
||||
constructor() {
|
||||
this.logger = CoreLogger.getInstance('CoreUtilsProvider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to Promise.all, but if a promise fails this function's promise won't be rejected until ALL promises have finished.
|
||||
*
|
||||
* @param promises Promises.
|
||||
* @return Promise resolved if all promises are resolved and rejected if at least 1 promise fails.
|
||||
*/
|
||||
allPromises(promises: Promise<any>[]): Promise<any> {
|
||||
if (!promises || !promises.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject): void => {
|
||||
const total = promises.length;
|
||||
let count = 0;
|
||||
let hasFailed = false;
|
||||
let error;
|
||||
|
||||
promises.forEach((promise) => {
|
||||
promise.catch((err) => {
|
||||
hasFailed = true;
|
||||
error = err;
|
||||
}).finally(() => {
|
||||
count++;
|
||||
|
||||
if (count === total) {
|
||||
// All promises have finished, reject/resolve.
|
||||
if (hasFailed) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute promises one depending on the previous.
|
||||
*
|
||||
* @param orderedPromisesData Functions to be executed.
|
||||
* @return Promise resolved when all promises are resolved.
|
||||
*/
|
||||
executeOrderedPromises(orderedPromisesData: OrderedPromiseData[]): Promise<any> {
|
||||
const promises = [];
|
||||
let dependency = Promise.resolve();
|
||||
|
||||
// Execute all the processes in order.
|
||||
for (const i in orderedPromisesData) {
|
||||
const data = orderedPromisesData[i];
|
||||
|
||||
// Add the process to the dependency stack.
|
||||
const promise = dependency.finally(() => {
|
||||
try {
|
||||
return data.function();
|
||||
} catch (e) {
|
||||
this.logger.error(e.message);
|
||||
|
||||
return;
|
||||
}
|
||||
});
|
||||
promises.push(promise);
|
||||
|
||||
// If the new process is blocking, we set it as the dependency.
|
||||
if (data.blocking) {
|
||||
dependency = promise;
|
||||
}
|
||||
}
|
||||
|
||||
// Return when all promises are done.
|
||||
return this.allPromises(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to AngularJS $q.defer().
|
||||
*
|
||||
* @return The deferred promise.
|
||||
*/
|
||||
promiseDefer<T>(): PromiseDefer<T> {
|
||||
const deferred: PromiseDefer<T> = {};
|
||||
|
||||
deferred.promise = new Promise((resolve, reject): void => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
|
||||
return deferred;
|
||||
}
|
||||
}
|
||||
|
||||
export class CoreUtils extends makeSingleton(CoreUtilsProvider) {}
|
||||
|
||||
/**
|
||||
* Data for each entry of executeOrderedPromises.
|
||||
*/
|
||||
export type OrderedPromiseData = {
|
||||
/**
|
||||
* Function to execute.
|
||||
*/
|
||||
function: () => Promise<any>;
|
||||
|
||||
/**
|
||||
* Whether the promise should block the following one.
|
||||
*/
|
||||
blocking?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Deferred promise. It's similar to the result of $q.defer() in AngularJS.
|
||||
*/
|
||||
export type PromiseDefer<T> = {
|
||||
/**
|
||||
* The promise.
|
||||
*/
|
||||
promise?: Promise<T>;
|
||||
|
||||
/**
|
||||
* Function to resolve the promise.
|
||||
*
|
||||
* @param value The resolve value.
|
||||
*/
|
||||
resolve?: (value?: T) => void;
|
||||
|
||||
/**
|
||||
* Function to reject the promise.
|
||||
*
|
||||
* @param reason The reject param.
|
||||
*/
|
||||
reject?: (reason?: any) => void;
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { Injector } from '@angular/core';
|
||||
|
||||
import { SplashScreen as SplashScreenPlugin } from '@ionic-native/splash-screen/ngx';
|
||||
|
||||
import { CoreSingletonsFactory, CoreInjectionToken, CoreSingletonClass } from '@classes/singletons-factory';
|
||||
|
||||
const factory = new CoreSingletonsFactory();
|
||||
|
||||
/**
|
||||
* Set the injector that will be used to resolve instances in the singletons of this module.
|
||||
*
|
||||
* @param injector Module injector.
|
||||
*/
|
||||
export function setSingletonsInjector(injector: Injector): void {
|
||||
factory.setInjector(injector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a singleton for this module.
|
||||
*
|
||||
* @param injectionToken Injection token used to resolve the singleton instance. This is usually the service class if the
|
||||
* provider was defined using a class or the string used in the `provide` key if it was defined using an object.
|
||||
*/
|
||||
export function makeSingleton<Service>(injectionToken: CoreInjectionToken<Service>): CoreSingletonClass<Service> {
|
||||
return factory.makeSingleton(injectionToken);
|
||||
}
|
||||
|
||||
export class SplashScreen extends makeSingleton(SplashScreenPlugin) {}
|
|
@ -0,0 +1,90 @@
|
|||
// (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 * as moment from 'moment';
|
||||
import { environment } from '@/environments/environment';
|
||||
|
||||
/**
|
||||
* Helper service to display messages in the console.
|
||||
*
|
||||
* @description
|
||||
* This service is meant to improve log messages, adding a timestamp and a name to all log messages.
|
||||
*
|
||||
* In your class constructor, call getInstance to configure your class name:
|
||||
* CoreLogger.getInstance('InitPage');
|
||||
*
|
||||
* Then you can call the log function you want to use in this logger instance.
|
||||
*/
|
||||
export class CoreLogger {
|
||||
log: LogFunction;
|
||||
info: LogFunction;
|
||||
warn: LogFunction;
|
||||
debug: LogFunction;
|
||||
error: LogFunction;
|
||||
|
||||
/**
|
||||
* Get a logger instance for a certain class, service or component.
|
||||
*
|
||||
* @param className Name to use in the messages.
|
||||
* @return Instance.
|
||||
*/
|
||||
static getInstance(className: string): CoreLogger {
|
||||
// Disable log on production.
|
||||
if (environment.production) {
|
||||
/* tslint:next-line no-console */
|
||||
console.warn('Log is disabled in production app');
|
||||
|
||||
return {
|
||||
log: () => {},
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
debug: () => {},
|
||||
error: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
className = className || '';
|
||||
|
||||
/* tslint:disable no-console */
|
||||
|
||||
return {
|
||||
log: CoreLogger.prepareLogFn(console.log.bind(console), className),
|
||||
info: CoreLogger.prepareLogFn(console.info.bind(console), className),
|
||||
warn: CoreLogger.prepareLogFn(console.warn.bind(console), className),
|
||||
debug: CoreLogger.prepareLogFn(console.debug.bind(console), className),
|
||||
error: CoreLogger.prepareLogFn(console.error.bind(console), className),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a logging function, concatenating the timestamp and class name to all messages.
|
||||
*
|
||||
* @param logFn Log function to use.
|
||||
* @param className Name to use in the messages.
|
||||
* @return Prepared function.
|
||||
*/
|
||||
private static prepareLogFn(logFn: LogFunction, className: string): LogFunction {
|
||||
// Return our own function that will call the logging function with the treated message.
|
||||
return (...args): void => {
|
||||
const now = moment().format('l LTS');
|
||||
args[0] = now + ' ' + className + ': ' + args[0]; // Prepend timestamp and className to the original message.
|
||||
logFn.apply(null, args);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log function type.
|
||||
*/
|
||||
type LogFunction = (...data: any[]) => void;
|
16
tslint.json
16
tslint.json
|
@ -1,12 +1,6 @@
|
|||
{
|
||||
"extends": "tslint:recommended",
|
||||
"rules": {
|
||||
"align": {
|
||||
"options": [
|
||||
"parameters",
|
||||
"statements"
|
||||
]
|
||||
},
|
||||
"array-type": false,
|
||||
"arrow-return-shorthand": true,
|
||||
"curly": true,
|
||||
|
@ -22,12 +16,6 @@
|
|||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
],
|
||||
"eofline": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
|
@ -141,7 +129,9 @@
|
|||
"template-no-negated-async": true,
|
||||
"use-lifecycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"object-literal-sort-keys": false
|
||||
"object-literal-sort-keys": false,
|
||||
"forin": false,
|
||||
"triple-equals": false
|
||||
},
|
||||
"rulesDirectory": [
|
||||
"codelyzer"
|
||||
|
|
Loading…
Reference in New Issue