diff --git a/config/config.json b/config/config.json index 601928dfa..ee5a78a74 100644 --- a/config/config.json +++ b/config/config.json @@ -86,14 +86,6 @@ "forcedefaultlanguage": false, "privacypolicy": "https:\/\/moodle.net\/moodle-app-privacy\/", "notificoncolor": "#f98012", - "statusbarbg": false, - "statusbarlighttext": false, - "statusbarbgios": "#f98012", - "statusbarlighttextios": true, - "statusbarbgandroid": "#df7310", - "statusbarlighttextandroid": true, - "statusbarbgremotetheme": "#000000", - "statusbarlighttextremotetheme": true, "enableanalytics": false, "enableonboarding": true, "forceColorScheme": "", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 0135f049a..91c79bbaf 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -146,6 +146,9 @@ export class AppComponent implements OnInit { } }); }); + + // Set StatusBar properties. + CoreApp.instance.setStatusBarColor(); } /** diff --git a/src/core/services/app.ts b/src/core/services/app.ts index a09eea202..6d91795c4 100644 --- a/src/core/services/app.ts +++ b/src/core/services/app.ts @@ -26,6 +26,7 @@ import { CoreConstants } from '@/core/constants'; import { makeSingleton, Keyboard, Network, StatusBar, Platform, Device } from '@singletons/core.singletons'; import { CoreLogger } from '@singletons/logger'; 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. @@ -611,43 +612,35 @@ export class CoreAppProvider { /** * 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 { - if (typeof CoreConstants.CONFIG.statusbarbgios == 'string' && this.isIOS()) { - // IOS Status bar properties. - StatusBar.instance.overlaysWebView(false); - 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(); + setStatusBarColor(color?: string): void { + if (!color) { + // Get the default color to reset it. + color = getComputedStyle(document.documentElement).getPropertyValue('--ion-statusbar-background').trim(); } + + // 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. + * + * @deprecated Use setStatusBarColor passing the color of the new statusbar color loaded on remote theme or no color to reset. */ resetStatusBarColor(): void { - if (typeof CoreConstants.CONFIG.statusbarbgremotetheme == 'string' && - ((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(); - } + this.setStatusBarColor(); } /** diff --git a/src/core/singletons/colors.ts b/src/core/singletons/colors.ts new file mode 100644 index 000000000..c8cc5cce9 --- /dev/null +++ b/src/core/singletons/colors.ts @@ -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; + } + +} diff --git a/src/theme/variables.scss b/src/theme/variables.scss index e35b04f3c..aeb85e89e 100644 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -100,9 +100,10 @@ --color: var(--custom-bottom-tabs-color, var(--white)); } + --ion-statusbar-background: var(--custom-toolbar-background, var(--ion-color-primary)); ion-toolbar { --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 { --color: var(--custom-toolbar-color, var(--ion-color-primary-contrast)); diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 9d4eedb56..21f818810 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -50,14 +50,6 @@ declare global { forcedefaultlanguage: boolean; privacypolicy: string; notificoncolor: string; - statusbarbg: boolean; - statusbarlighttext: boolean; - statusbarbgios: string; - statusbarlighttextios: boolean; - statusbarbgandroid: string; - statusbarlighttextandroid: boolean; - statusbarbgremotetheme: string; - statusbarlighttextremotetheme: boolean; enableanalytics: boolean; enableonboarding: boolean; forceColorScheme: CoreColorScheme;