Merge pull request #2612 from crazyserver/MOBILE-3565

Mobile 3565
main
Dani Palou 2020-11-23 13:05:04 +01:00 committed by GitHub
commit 6f4d8a8440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 241 additions and 51 deletions

View File

@ -31,6 +31,7 @@
<preference name="BackupWebStorage" value="none" /> <preference name="BackupWebStorage" value="none" />
<preference name="ScrollEnabled" value="false" /> <preference name="ScrollEnabled" value="false" />
<preference name="KeyboardDisplayRequiresUserAction" value="false" /> <preference name="KeyboardDisplayRequiresUserAction" value="false" />
<preference name="HideKeyboardFormAccessoryBar" value="false" />
<preference name="AllowInlineMediaPlayback" value="true" /> <preference name="AllowInlineMediaPlayback" value="true" />
<preference name="LoadUrlTimeoutValue" value="60000" /> <preference name="LoadUrlTimeoutValue" value="60000" />
<preference name="load-url-timeout" value="60000" /> <preference name="load-url-timeout" value="60000" />

View File

@ -86,14 +86,6 @@
"forcedefaultlanguage": false, "forcedefaultlanguage": false,
"privacypolicy": "https:\/\/moodle.net\/moodle-app-privacy\/", "privacypolicy": "https:\/\/moodle.net\/moodle-app-privacy\/",
"notificoncolor": "#f98012", "notificoncolor": "#f98012",
"statusbarbg": false,
"statusbarlighttext": false,
"statusbarbgios": "#f98012",
"statusbarlighttextios": true,
"statusbarbgandroid": "#df7310",
"statusbarlighttextandroid": true,
"statusbarbgremotetheme": "#000000",
"statusbarlighttextremotetheme": true,
"enableanalytics": false, "enableanalytics": false,
"enableonboarding": true, "enableonboarding": true,
"forceColorScheme": "", "forceColorScheme": "",

2
package-lock.json generated
View File

@ -6522,7 +6522,7 @@
"integrity": "sha512-EYC5eQFVkoYXq39l7tYKE6lEjHJ04mvTmKXxGL7quHLdFPfJMNzru/UYpn92AOfpl3PQaZmou78C7EgmFOwFQQ==" "integrity": "sha512-EYC5eQFVkoYXq39l7tYKE6lEjHJ04mvTmKXxGL7quHLdFPfJMNzru/UYpn92AOfpl3PQaZmou78C7EgmFOwFQQ=="
}, },
"cordova-plugin-wkuserscript": { "cordova-plugin-wkuserscript": {
"version": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git#6413f4bb3c2565f353e690b5c1450b69ad9e860e", "version": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git#aa77d0f98a3fb106f2e798e5adf5882f01a2c947",
"from": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git" "from": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git"
}, },
"cordova-plugin-wkwebview-cookies": { "cordova-plugin-wkwebview-cookies": {

View File

@ -17,9 +17,16 @@ import { NavController } from '@ionic/angular';
import { CoreLangProvider } from '@services/lang'; import { CoreLangProvider } from '@services/lang';
import { CoreLoginHelperProvider } from '@features/login/services/login.helper'; import { CoreLoginHelperProvider } from '@features/login/services/login.helper';
import { CoreEvents, CoreEventSessionExpiredData } from '@singletons/events'; import {
CoreEvents,
CoreEventSessionExpiredData,
CoreEventSiteAddedData,
CoreEventSiteData,
CoreEventSiteUpdatedData,
} from '@singletons/events';
import { Network, NgZone, Platform } from '@singletons/core.singletons'; import { Network, NgZone, Platform } from '@singletons/core.singletons';
import { CoreApp } from '@services/app'; import { CoreApp } from '@services/app';
import { CoreSites } from '@services/sites';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -37,6 +44,14 @@ export class AppComponent implements OnInit {
/** /**
* Component being initialized. * Component being initialized.
*
* @todo Review all old code to see if something is missing:
* - IAB events listening.
* - Platform pause/resume subscriptions.
* - handleOpenURL and openWindowSafely.
* - Screen orientation events (probably it can be removed).
* - Back button registering to close modal first.
* - Note: HideKeyboardFormAccessoryBar has been moved to config.xml.
*/ */
ngOnInit(): void { ngOnInit(): void {
CoreEvents.on(CoreEvents.LOGOUT, () => { CoreEvents.on(CoreEvents.LOGOUT, () => {
@ -55,9 +70,59 @@ export class AppComponent implements OnInit {
this.loginHelper.sessionExpired(data); this.loginHelper.sessionExpired(data);
}); });
// Listen for passwordchange and usernotfullysetup events to open InAppBrowser.
CoreEvents.on(CoreEvents.PASSWORD_CHANGE_FORCED, (data: CoreEventSiteData) => {
this.loginHelper.passwordChangeForced(data.siteId!);
});
CoreEvents.on(CoreEvents.USER_NOT_FULLY_SETUP, (data: CoreEventSiteData) => {
this.loginHelper.openInAppForEdit(data.siteId!, '/user/edit.php', 'core.usernotfullysetup');
});
// Listen for sitepolicynotagreed event to accept the site policy.
CoreEvents.on(CoreEvents.SITE_POLICY_NOT_AGREED, (data: CoreEventSiteData) => {
this.loginHelper.sitePolicyNotAgreed(data.siteId);
});
CoreEvents.on(CoreEvents.LOGIN, async (data: CoreEventSiteData) => {
if (data.siteId) {
const site = await CoreSites.instance.getSite(data.siteId);
const info = site.getInfo();
if (info) {
// Add version classes to body.
this.removeVersionClass();
this.addVersionClass(CoreSites.instance.getReleaseNumber(info.release || ''));
}
}
this.loadCustomStrings();
});
CoreEvents.on(CoreEvents.SITE_UPDATED, (data: CoreEventSiteUpdatedData) => {
if (data.siteId == CoreSites.instance.getCurrentSiteId()) {
this.loadCustomStrings();
// Add version classes to body.
this.removeVersionClass();
this.addVersionClass(CoreSites.instance.getReleaseNumber(data.release || ''));
}
});
CoreEvents.on(CoreEvents.SITE_ADDED, (data: CoreEventSiteAddedData) => {
if (data.siteId == CoreSites.instance.getCurrentSiteId()) {
this.loadCustomStrings();
// Add version classes to body.
this.removeVersionClass();
this.addVersionClass(CoreSites.instance.getReleaseNumber(data.release || ''));
}
});
this.onPlatformReady(); this.onPlatformReady();
} }
/**
* Async init function on platform ready.
*/
protected async onPlatformReady(): Promise<void> { protected async onPlatformReady(): Promise<void> {
await Platform.instance.ready(); await Platform.instance.ready();
@ -81,6 +146,19 @@ export class AppComponent implements OnInit {
} }
}); });
}); });
// Set StatusBar properties.
CoreApp.instance.setStatusBarColor();
}
/**
* Load custom lang strings. This cannot be done inside the lang provider because it causes circular dependencies.
*/
protected loadCustomStrings(): void {
const currentSite = CoreSites.instance.getCurrentSite();
if (currentSite) {
this.langProvider.loadCustomStringsFromSite(currentSite);
}
} }
/** /**

View File

@ -20,13 +20,10 @@ import { CoreSearchComponentsModule } from './components/components.module';
import { SITE_SCHEMA } from './services/search-history-db'; import { SITE_SCHEMA } from './services/search-history-db';
@NgModule({ @NgModule({
declarations: [
],
imports: [ imports: [
CoreSearchComponentsModule, CoreSearchComponentsModule,
], ],
providers: [ providers: [
CoreSearchComponentsModule,
{ provide: CORE_SITE_SCHEMAS, useValue: [SITE_SCHEMA], multi: true }, { provide: CORE_SITE_SCHEMAS, useValue: [SITE_SCHEMA], multi: true },
], ],
}) })

View File

@ -26,6 +26,7 @@ import { CoreConstants } from '@/core/constants';
import { makeSingleton, Keyboard, Network, StatusBar, Platform, Device } from '@singletons/core.singletons'; import { makeSingleton, Keyboard, Network, StatusBar, Platform, Device } from '@singletons/core.singletons';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { DBNAME, SCHEMA_VERSIONS_TABLE_NAME, SCHEMA_VERSIONS_TABLE_SCHEMA, SchemaVersionsDBEntry } from '@services/app.db'; import { DBNAME, SCHEMA_VERSIONS_TABLE_NAME, SCHEMA_VERSIONS_TABLE_SCHEMA, SchemaVersionsDBEntry } from '@services/app.db';
import { CoreColors } from '../singletons/colors';
/** /**
* Factory to provide some global functionalities, like access to the global app database. * Factory to provide some global functionalities, like access to the global app database.
@ -611,43 +612,35 @@ export class CoreAppProvider {
/** /**
* Set StatusBar color depending on platform. * Set StatusBar color depending on platform.
*
* @param color RGB color to use as status bar background. If not set the css variable will be read.
*/ */
setStatusBarColor(): void { setStatusBarColor(color?: string): void {
if (typeof CoreConstants.CONFIG.statusbarbgios == 'string' && this.isIOS()) { if (!color) {
// IOS Status bar properties. // Get the default color to reset it.
StatusBar.instance.overlaysWebView(false); color = getComputedStyle(document.documentElement).getPropertyValue('--ion-statusbar-background').trim();
StatusBar.instance.backgroundColorByHexString(CoreConstants.CONFIG.statusbarbgios);
CoreConstants.CONFIG.statusbarlighttextios ? StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
} else if (typeof CoreConstants.CONFIG.statusbarbgandroid == 'string' && this.isAndroid()) {
// Android Status bar properties.
StatusBar.instance.backgroundColorByHexString(CoreConstants.CONFIG.statusbarbgandroid);
CoreConstants.CONFIG.statusbarlighttextandroid ?
StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
} else if (typeof CoreConstants.CONFIG.statusbarbg == 'string') {
// Generic Status bar properties.
this.isIOS() && StatusBar.instance.overlaysWebView(false);
StatusBar.instance.backgroundColorByHexString(CoreConstants.CONFIG.statusbarbg);
CoreConstants.CONFIG.statusbarlighttext ? StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
} else {
// Default Status bar properties.
this.isAndroid() ? StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
} }
// Make darker on Android.
if (this.isAndroid()) {
color = CoreColors.darker(color);
}
const useLightText = CoreColors.isWhiteContrastingBetter(color);
const statusBar = StatusBar.instance;
statusBar.backgroundColorByHexString(color);
useLightText ? statusBar.styleLightContent() : statusBar.styleDefault();
this.isIOS() && statusBar.overlaysWebView(false);
} }
/** /**
* Reset StatusBar color if any was set. * Reset StatusBar color if any was set.
*
* @deprecated Use setStatusBarColor passing the color of the new statusbar color loaded on remote theme or no color to reset.
*/ */
resetStatusBarColor(): void { resetStatusBarColor(): void {
if (typeof CoreConstants.CONFIG.statusbarbgremotetheme == 'string' && this.setStatusBarColor();
((typeof CoreConstants.CONFIG.statusbarbgios == 'string' && this.isIOS()) ||
(typeof CoreConstants.CONFIG.statusbarbgandroid == 'string' && this.isAndroid()) ||
typeof CoreConstants.CONFIG.statusbarbg == 'string')) {
// If the status bar has been overriden and there's a fallback color for remote themes, use it now.
this.isIOS() && StatusBar.instance.overlaysWebView(false);
StatusBar.instance.backgroundColorByHexString(CoreConstants.CONFIG.statusbarbgremotetheme);
CoreConstants.CONFIG.statusbarlighttextremotetheme ?
StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
}
} }
/** /**

View File

@ -21,6 +21,7 @@ import { CoreConfig } from '@services/config';
import { makeSingleton, Translate, Platform } from '@singletons/core.singletons'; import { makeSingleton, Translate, Platform } from '@singletons/core.singletons';
import * as moment from 'moment'; import * as moment from 'moment';
import { CoreSite } from '../classes/site';
/* /*
* Service to handle language features, like changing the current language. * Service to handle language features, like changing the current language.
@ -311,6 +312,19 @@ export class CoreLangProvider {
}); });
} }
/**
* Loads custom strings obtained from site.
*
* @param currentSite Current site object.
*/
loadCustomStringsFromSite(currentSite: CoreSite): void {
const customStrings = currentSite.getStoredConfig('tool_mobile_customlangstrings');
if (typeof customStrings != 'undefined') {
this.loadCustomStrings(customStrings);
}
}
/** /**
* Load certain custom strings. * Load certain custom strings.
* *

View File

@ -0,0 +1,117 @@
// (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.
/**
* Color components contained within a rgb color.
*/
interface ColorComponents {
red: number; // Red component of an RGB color [0-255].
green: number; // Green component of an RGB color [0-255].
blue: number; // Blue component of an RGB color [0-255].
}
/**
* Singleton with helper functions for colors.
*/
export class CoreColors {
/**
* Returns better contrast color.
*
* @param color Black or white texts.
* @return True if white contrasts better than black. False otherwise.
*/
static isWhiteContrastingBetter(color: string): boolean {
return CoreColors.luma(color) < 165;
}
/**
* Returns the same color 10% darker to be used as status bar on Android.
*
* @param color Color to get darker.
* @return Darker Hex RGB color.
*/
static darker(color: string, percent: number = 10): string {
percent = 1 - (percent / 100);
const components = CoreColors.hexToRGB(color);
components.red = Math.floor(components.red * percent) ;
components.green = Math.floor(components.green * percent) ;
components.blue = Math.floor(components.blue * percent) ;
return CoreColors.RGBToHex(components);
}
/**
* Gets the luma of a color.
*
* @param color Hex RGB color.
* @return Luma number based on SMPTE C, Rec. 709 weightings.
*/
protected static luma(color: string): number {
const rgb = CoreColors.hexToRGB(color);
return (rgb.red * 0.2126) + (rgb.green * 0.7152) + (rgb.blue * 0.0722);
}
/**
* Converts Hex RGB to Color components.
*
* @param color Hexadec RGB Color.
* @return RGB color components.
*/
protected static hexToRGB(color: string): ColorComponents {
if (color.charAt(0) == '#') {
color = color.substr(1);
}
if (color.length === 3) {
color = color.charAt(0) + color.charAt(0) + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2);
} else if (color.length !== 6) {
throw('Invalid hex color: ' + color);
}
return {
red: parseInt(color.substr(0, 2), 16),
green: parseInt(color.substr(2, 2), 16),
blue: parseInt(color.substr(4, 2), 16),
};
}
/**
* Converts RGB components to Hex string.
*
* @param color Color components.
* @return RGB color in string.
*/
protected static RGBToHex(color: ColorComponents): string {
return '#' + CoreColors.componentToHex(color.red) +
CoreColors.componentToHex(color.green) +
CoreColors.componentToHex(color.blue);
}
/**
* Converts a color component from decimal to hexadec.
*
* @param c color component in decimal.
* @return Hexadec of the color component.
*/
protected static componentToHex(c: number): string {
const hex = c.toString(16);
return hex.length == 1 ? '0' + hex : hex;
}
}

View File

@ -205,6 +205,11 @@ export type CoreEventSiteData = {
*/ */
export type CoreEventSiteUpdatedData = CoreEventSiteData & CoreSiteInfoResponse; export type CoreEventSiteUpdatedData = CoreEventSiteData & CoreSiteInfoResponse;
/**
* Data passed to SITE_ADDED event.
*/
export type CoreEventSiteAddedData = CoreEventSiteData & CoreSiteInfoResponse;
/** /**
* Data passed to SESSION_EXPIRED event. * Data passed to SESSION_EXPIRED event.
*/ */

View File

@ -100,9 +100,10 @@
--color: var(--custom-bottom-tabs-color, var(--white)); --color: var(--custom-bottom-tabs-color, var(--white));
} }
--ion-statusbar-background: var(--custom-toolbar-background, var(--ion-color-primary));
ion-toolbar { ion-toolbar {
--color: var(--custom-toolbar-color, var(--ion-color-primary-contrast)); --color: var(--custom-toolbar-color, var(--ion-color-primary-contrast));
--background: var(--custom-toolbar-background, var(--ion-color-primary)); --background: var(--ion-statusbar-background);
ion-spinner { ion-spinner {
--color: var(--custom-toolbar-color, var(--ion-color-primary-contrast)); --color: var(--custom-toolbar-color, var(--ion-color-primary-contrast));

View File

@ -50,14 +50,6 @@ declare global {
forcedefaultlanguage: boolean; forcedefaultlanguage: boolean;
privacypolicy: string; privacypolicy: string;
notificoncolor: string; notificoncolor: string;
statusbarbg: boolean;
statusbarlighttext: boolean;
statusbarbgios: string;
statusbarlighttextios: boolean;
statusbarbgandroid: string;
statusbarlighttextandroid: boolean;
statusbarbgremotetheme: string;
statusbarlighttextremotetheme: boolean;
enableanalytics: boolean; enableanalytics: boolean;
enableonboarding: boolean; enableonboarding: boolean;
forceColorScheme: CoreColorScheme; forceColorScheme: CoreColorScheme;