Skip to content

Commit

Permalink
MOBILE-4331 app: Change navigation bar color according to the theme.
Browse files Browse the repository at this point in the history
  • Loading branch information
crazyserver committed Jul 12, 2023
1 parent 7e2f70e commit 331e206
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 25 deletions.
39 changes: 29 additions & 10 deletions cordova-plugin-moodleapp/src/android/SystemUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;

import android.view.View;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsControllerCompat;

import org.json.JSONArray;

public class SystemUI extends CordovaPlugin {
Expand All @@ -33,7 +37,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
try {
switch (action) {
case "setNavigationBarColor":
this.setNavigationBarColor(args.getString(0));
this.setNavigationBarColor(args.getString(0), args.getBoolean(1));
callbackContext.success();

return true;
Expand All @@ -45,7 +49,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
return false;
}

private void setNavigationBarColor(String color) {
private void setNavigationBarColor(String color, Boolean lightNavigationBar) {
if (Build.VERSION.SDK_INT < 21) {
return;
}
Expand All @@ -54,20 +58,35 @@ private void setNavigationBarColor(String color) {
return;
}

final boolean useLightNavigationBar = lightNavigationBar != null && lightNavigationBar;

Log.d(TAG, "Setting navigation bar color to " + color);

this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010;
final Window window = cordova.getActivity().getWindow();
int uiOptions = window.getDecorView().getSystemUiVisibility();

uiOptions = uiOptions | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
uiOptions = uiOptions & ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;

window.getDecorView().setSystemUiVisibility(uiOptions);
final View decorView = window.getDecorView();
WindowInsetsControllerCompat windowInsetController = WindowCompat.getInsetsController(window, decorView);

if (windowInsetController != null) {
windowInsetController.setAppearanceLightNavigationBars(useLightNavigationBar);
} else {
// Deprectated in SDK 30.
final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010;
int uiOptions = decorView.getSystemUiVisibility();

uiOptions = uiOptions | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
uiOptions = uiOptions & ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
if (Build.VERSION.SDK_INT >= 26 && useLightNavigationBar) {
uiOptions = uiOptions | SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
} else {
uiOptions = uiOptions & ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
}

decorView.setSystemUiVisibility(uiOptions);
}

try {
// Using reflection makes sure any 5.0+ device will work without having to compile with SDK level 21
Expand Down
5 changes: 3 additions & 2 deletions cordova-plugin-moodleapp/src/ts/plugins/SystemUI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ export class SystemUI {
* Set navigation bar color.
*
* @param color Color.
* @param lightNavigationBar Wether to use light colors on buttors to contrast or not.
*/
async setNavigationBarColor(color: string): Promise<void> {
async setNavigationBarColor(color: string, lightNavigationBar: boolean): Promise<void> {
await new Promise((resolve, reject) => {
cordova.exec(resolve, reject, 'SystemUI', 'setNavigationBarColor', [color]);
cordova.exec(resolve, reject, 'SystemUI', 'setNavigationBarColor', [color, !!lightNavigationBar]);
});
}

Expand Down
3 changes: 1 addition & 2 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@ export class AppComponent implements OnInit, AfterViewInit {
const isOnline = CoreNetwork.isOnline();
CoreDomUtils.toggleModeClass('core-offline', !isOnline, { includeLegacy: true });

// Set StatusBar properties.
CoreApp.setStatusBarColor();
CoreApp.setSystemUIColors();
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/core/features/settings/services/settings-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ export class CoreSettingsHelperProvider {
CoreDomUtils.toggleModeClass('dark', enable, { includeLegacy: true });
this.darkModeObservable.next(enable);

CoreApp.setStatusBarColor();
CoreApp.setSystemUIColors();
}
}

Expand Down
12 changes: 5 additions & 7 deletions src/core/features/styles/services/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,7 @@ export class CoreStylesService {
this.disableStyleElement(style, true);
});

// Set StatusBar properties.
CoreApp.setStatusBarColor();
CoreApp.setSystemUIColors();
}

/**
Expand Down Expand Up @@ -341,7 +340,7 @@ export class CoreStylesService {
this.disableStyleElementByName(siteId, sourceName, false);
}

CoreApp.setStatusBarColor();
CoreApp.setSystemUIColors();
}
}

Expand Down Expand Up @@ -371,8 +370,7 @@ export class CoreStylesService {
}));

if (!disabled) {
// Set StatusBar properties.
CoreApp.setStatusBarColor();
CoreApp.setSystemUIColors();
}
}

Expand All @@ -390,7 +388,7 @@ export class CoreStylesService {
await this.setStyle(CoreStylesService.TMP_SITE_ID, handler, false, config);
}));

CoreApp.setStatusBarColor();
CoreApp.setSystemUIColors();
}

/**
Expand Down Expand Up @@ -438,7 +436,7 @@ export class CoreStylesService {
}
delete this.stylesEls[siteId];

CoreApp.setStatusBarColor();
CoreApp.setSystemUIColors();
}
}

Expand Down
42 changes: 39 additions & 3 deletions src/core/services/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import { Injectable } from '@angular/core';

import { CoreDB } from '@services/db';
import { CoreEvents } from '@singletons/events';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';

import { makeSingleton, Keyboard, StatusBar } from '@singletons';
Expand All @@ -31,6 +31,8 @@ import { CorePromisedValue } from '@classes/promised-value';
import { Subscription } from 'rxjs';
import { CorePlatform } from '@services/platform';
import { CoreNetwork, CoreNetworkConnection } from '@services/network';
import { CoreNative } from '@features/native/services/native';
import { CoreMainMenuProvider } from '@features/mainmenu/services/mainmenu';

/**
* Factory to provide some global functionalities, like access to the global app database.
Expand All @@ -56,9 +58,14 @@ export class CoreAppProvider {
protected keyboardClosing = false;
protected redirect?: CoreRedirectData;
protected schemaVersionsTable = asyncInstance<CoreDatabaseTable<SchemaVersionsDBEntry, 'name'>>();
protected mainMenuListener?: CoreEventObserver;

constructor() {
this.logger = CoreLogger.getInstance('CoreAppProvider');
if (CorePlatform.isAndroid()) {
this.mainMenuListener =
CoreEvents.on(CoreMainMenuProvider.MAIN_MENU_VISIBILITY_UPDATED, () => this.setAndroidNavigationBarColor());
}
}

/**
Expand Down Expand Up @@ -200,7 +207,7 @@ export class CoreAppProvider {
* @returns Store URL.
*/
getAppStoreUrl(storesConfig: CoreStoreConfig): string | undefined {
if (this.isIOS() && storesConfig.ios) {
if (CorePlatform.isIOS() && storesConfig.ios) {
return 'itms-apps://itunes.apple.com/app/' + storesConfig.ios;
}

Expand Down Expand Up @@ -618,6 +625,14 @@ export class CoreAppProvider {
return () => false;
}

/**
* Set System UI Colors.
*/
setSystemUIColors(): void {
this.setStatusBarColor();
this.setAndroidNavigationBarColor();
}

/**
* Set StatusBar color depending on platform.
*
Expand All @@ -638,7 +653,7 @@ export class CoreAppProvider {
const useLightText = CoreColors.isWhiteContrastingBetter(color);

// styleDefault will use white text on iOS when darkmode is on. Force the background to black.
if (this.isIOS() && !useLightText && window.matchMedia('(prefers-color-scheme: dark)').matches) {
if (CorePlatform.isIOS() && !useLightText && window.matchMedia('(prefers-color-scheme: dark)').matches) {
StatusBar.backgroundColorByHexString('#000000');
StatusBar.styleLightContent();
} else {
Expand Down Expand Up @@ -684,6 +699,27 @@ export class CoreAppProvider {
}
}

/**
* Set NavigationBar color for Android
*
* @param color RGB color to use as background. If not set the css variable will be read.
*/
protected setAndroidNavigationBarColor(color?: string): void {
if (!CorePlatform.isAndroid()) {
return;
}

if (!color) {
// Get the default color to change it.
color = CoreColors.getBottomPageBackgroundColor();
}

const useLightText = CoreColors.isWhiteContrastingBetter(color);

console.error(color, useLightText);
CoreNative.plugin('systemUI')?.setNavigationBarColor(color, !useLightText);
}

}

export const CoreApp = makeSingleton(CoreAppProvider);
Expand Down
19 changes: 19 additions & 0 deletions src/core/singletons/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,23 @@ export class CoreColors {
return CoreColors.getColorHex(color);
}

/**
* Get the bottom page current background color. Bottom bar if shown or page background otherwise.
*
* @returns Color in hex format.
*/
static getBottomPageBackgroundColor(): string {
const element = document.querySelector('ion-tabs.placement-bottom:not(.tabshidden) ion-tab-bar.mainmenu-tabs');
let color: string;

if (element) {
color = getComputedStyle(element).getPropertyValue('--background').trim();
} else {
// Fallback, it won't always work.
color = getComputedStyle(document.body).getPropertyValue('--ion-background-color').trim();
}

return CoreColors.getColorHex(color);
}

}

0 comments on commit 331e206

Please sign in to comment.