FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat(dark-mode): add system appearance property, event and CSS classes by vchimev · Pull Request #7887 · NativeScript/NativeScript · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension .ts  (16) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
37 changes: 28 additions & 9 deletions tns-core-modules/application/application-common.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
} from "./application";

import { CLASS_PREFIX, pushToRootViewCssClasses, removeFromRootViewCssClasses } from "../css/system-classes";
import { DeviceOrientation } from "../ui/enums/enums";
import { DeviceOrientation, SystemAppearance } from "../ui/enums/enums";

export { UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData };

Expand All @@ -55,13 +55,19 @@ export const lowMemoryEvent = "lowMemory";
export const uncaughtErrorEvent = "uncaughtError";
export const discardedErrorEvent = "discardedError";
export const orientationChangedEvent = "orientationChanged";
export const systemAppearanceChangedEvent = "systemAppearanceChanged";

const ORIENTATION_CSS_CLASSES = [
`${CLASS_PREFIX}${DeviceOrientation.portrait}`,
`${CLASS_PREFIX}${DeviceOrientation.landscape}`,
`${CLASS_PREFIX}${DeviceOrientation.unknown}`
];

const SYSTEM_APPEARANCE_CSS_CLASSES = [
`${CLASS_PREFIX}${SystemAppearance.light}`,
`${CLASS_PREFIX}${SystemAppearance.dark}`
];

let cssFile: string = "./app.css";

let resources: any = {};
Expand Down Expand Up @@ -126,17 +132,30 @@ export function loadAppCss(): void {
}
}

function applyCssClass(rootView: View, cssClass: string) {
pushToRootViewCssClasses(cssClass);
rootView.cssClasses.add(cssClass);
}

function removeCssClass(rootView: View, cssClass: string) {
removeFromRootViewCssClasses(cssClass);
rootView.cssClasses.delete(cssClass);
}

export function orientationChanged(rootView: View, newOrientation: "portrait" | "landscape" | "unknown"): void {
const newOrientationCssClass = `${CLASS_PREFIX}${newOrientation}`;
if (!rootView.cssClasses.has(newOrientationCssClass)) {
const removeCssClass = (c: string) => {
removeFromRootViewCssClasses(c);
rootView.cssClasses.delete(c);
};

ORIENTATION_CSS_CLASSES.forEach(c => removeCssClass(c));
pushToRootViewCssClasses(newOrientationCssClass);
rootView.cssClasses.add(newOrientationCssClass);
ORIENTATION_CSS_CLASSES.forEach(cssClass => removeCssClass(rootView, cssClass));
applyCssClass(rootView, newOrientationCssClass);
rootView._onCssStateChange();
}
}

export function systemAppearanceChanged(rootView: View, newSystemAppearance: "dark" | "light"): void {
const newSystemAppearanceCssClass = `${CLASS_PREFIX}${newSystemAppearance}`;
if (!rootView.cssClasses.has(newSystemAppearanceCssClass)) {
SYSTEM_APPEARANCE_CSS_CLASSES.forEach(cssClass => removeCssClass(rootView, cssClass));
applyCssClass(rootView, newSystemAppearanceCssClass);
rootView._onCssStateChange();
}
}
Expand Down
74 changes: 60 additions & 14 deletions tns-core-modules/application/application.android.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import {
AndroidApplication as AndroidApplicationDefinition,
ApplicationEventData,
CssChangedEventData,
OrientationChangedEventData
OrientationChangedEventData,
SystemAppearanceChangedEventData
} from ".";

import {
displayedEvent, hasListeners, livesync, lowMemoryEvent, notify, Observable, on,
orientationChanged, orientationChangedEvent, setApplication, suspendEvent
orientationChanged, orientationChangedEvent, setApplication, suspendEvent,
systemAppearanceChanged, systemAppearanceChangedEvent
} from "./application-common";

import { profile } from "../profiling";
Expand Down Expand Up @@ -51,6 +53,7 @@ export class AndroidApplication extends Observable implements AndroidApplication
public static activityRequestPermissionsEvent = ActivityRequestPermissions;

private _orientation: "portrait" | "landscape" | "unknown";
private _systemAppearance: "light" | "dark";
public paused: boolean;
public nativeApp: android.app.Application;
public context: android.content.Context;
Expand Down Expand Up @@ -93,9 +96,8 @@ export class AndroidApplication extends Observable implements AndroidApplication
if (!this._orientation) {
const resources = this.context.getResources();
const configuration = <android.content.res.Configuration>resources.getConfiguration();
const orientation = configuration.orientation;

this._orientation = getOrientationValue(orientation);
this._orientation = getOrientationValue(configuration);
}

return this._orientation;
Expand All @@ -105,6 +107,21 @@ export class AndroidApplication extends Observable implements AndroidApplication
this._orientation = value;
}

get systemAppearance(): "light" | "dark" {
if (!this._systemAppearance) {
const resources = this.context.getResources();
const configuration = <android.content.res.Configuration>resources.getConfiguration();

this._systemAppearance = getSystemAppearanceValue(configuration);
}

return this._systemAppearance;
}

set systemAppearance(value: "light" | "dark") {
this._systemAppearance = value;
}

public registerBroadcastReceiver(intentFilter: string, onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) {
ensureBroadCastReceiverClass();
const that = this;
Expand All @@ -131,6 +148,7 @@ export class AndroidApplication extends Observable implements AndroidApplication
}
}
}

export interface AndroidApplication {
on(eventNames: string, callback: (data: AndroidActivityEventData) => void, thisArg?: any);
on(event: "activityCreated", callback: (args: AndroidActivityBundleEventData) => void, thisArg?: any);
Expand Down Expand Up @@ -252,12 +270,9 @@ export function orientation(): "portrait" | "landscape" | "unknown" {
return androidApp.orientation;
}

on(orientationChangedEvent, (args: OrientationChangedEventData) => {
const rootView = getRootView();
if (rootView) {
orientationChanged(rootView, args.newValue);
}
});
export function systemAppearance(): "dark" | "light" {
return androidApp.systemAppearance;
}

global.__onLiveSync = function __onLiveSync(context?: ModuleContext) {
if (androidApp && androidApp.paused) {
Expand All @@ -268,7 +283,9 @@ global.__onLiveSync = function __onLiveSync(context?: ModuleContext) {
livesync(rootView, context);
};

function getOrientationValue(orientation: number): "portrait" | "landscape" | "unknown" {
function getOrientationValue(configuration: android.content.res.Configuration): "portrait" | "landscape" | "unknown" {
const orientation = configuration.orientation;

switch (orientation) {
case android.content.res.Configuration.ORIENTATION_LANDSCAPE:
return "landscape";
Expand All @@ -279,6 +296,19 @@ function getOrientationValue(orientation: number): "portrait" | "landscape" | "u
}
}

// https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#configuration_changes
function getSystemAppearanceValue(configuration: android.content.res.Configuration): "dark" | "light" {
const systemAppearance = configuration.uiMode & android.content.res.Configuration.UI_MODE_NIGHT_MASK;

switch (systemAppearance) {
case android.content.res.Configuration.UI_MODE_NIGHT_YES:
Comment thread
vchimev marked this conversation as resolved.
return "dark";
case android.content.res.Configuration.UI_MODE_NIGHT_NO:
case android.content.res.Configuration.UI_MODE_NIGHT_UNDEFINED:
return "light";
}
}

function initLifecycleCallbacks() {
const setThemeOnLaunch = profile("setThemeOnLaunch", (activity: androidx.appcompat.app.AppCompatActivity) => {
// Set app theme after launch screen was used during startup
Expand Down Expand Up @@ -380,19 +410,35 @@ function initComponentCallbacks() {
// TODO: This is skipped for now, test carefully for OutOfMemory exceptions
}),

onConfigurationChanged: profile("onConfigurationChanged", function (newConfig: android.content.res.Configuration) {
const newConfigOrientation = newConfig.orientation;
const newOrientation = getOrientationValue(newConfigOrientation);
onConfigurationChanged: profile("onConfigurationChanged", function (newConfiguration: android.content.res.Configuration) {
const newOrientation = getOrientationValue(newConfiguration);

if (androidApp.orientation !== newOrientation) {
androidApp.orientation = newOrientation;
orientationChanged(getRootView(), newOrientation);

notify(<OrientationChangedEventData>{
eventName: orientationChangedEvent,
android: androidApp.nativeApp,
newValue: androidApp.orientation,
object: androidApp
});

return;
}

const newSystemAppearance = getSystemAppearanceValue(newConfiguration);

if (androidApp.systemAppearance !== newSystemAppearance) {
androidApp.systemAppearance = newSystemAppearance;
systemAppearanceChanged(getRootView(), newSystemAppearance);

notify(<SystemAppearanceChangedEventData>{
eventName: systemAppearanceChangedEvent,
android: androidApp.nativeApp,
newValue: androidApp.systemAppearance,
object: androidApp
});
}
})
});
Expand Down
41 changes: 39 additions & 2 deletions tns-core-modules/application/application.d.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ export interface OrientationChangedEventData extends ApplicationEventData {
newValue: "portrait" | "landscape" | "unknown";
}

/**
* Event data containing information for system appearance changed event.
*/
export interface SystemAppearanceChangedEventData extends ApplicationEventData {
/**
* New system appearance value.
*/
newValue: "light" | "dark";
}

/**
* Event data containing information about unhandled application errors.
*/
Expand Down Expand Up @@ -281,16 +291,29 @@ export function on(event: "uncaughtError", callback: (args: UnhandledErrorEventD
export function on(event: "discardedError", callback: (args: DiscardedErrorEventData) => void, thisArg?: any);

/**
* This event is raised the orientation of the current device has changed.
* This event is raised when the orientation of the application changes.
*/
export function on(event: "orientationChanged", callback: (args: OrientationChangedEventData) => void, thisArg?: any);

/**
* This event is raised when the operating system appearance changes
* between light and dark theme (for Android);
* between light and dark mode (for iOS) and vice versa.
*/
export function on(event: "systemAppearanceChanged", callback: (args: SystemAppearanceChangedEventData) => void, thisArg?: any);

/**
* Gets the orientation of the application.
* Available values: "portrait", "landscape", "unknown".
*/
export function orientation(): "portrait" | "landscape" | "unknown";

/**
* Gets the operating system appearance.
* Available values: "dark", "light".
*/
export function systemAppearance(): "dark" | "light";

/**
* This is the Android-specific application object instance.
* Encapsulates methods and properties specific to the Android platform.
Expand Down Expand Up @@ -425,6 +448,12 @@ export class AndroidApplication extends Observable {
*/
orientation: "portrait" | "landscape" | "unknown";

/**
* Gets the system appearance.
* Available values: "dark", "light".
*/
systemAppearance: "dark" | "light";

/**
* The name of the application package.
*/
Expand Down Expand Up @@ -604,6 +633,12 @@ export interface iOSApplication {
*/
orientation: "portrait" | "landscape" | "unknown";

/**
* Gets the system appearance.
* Available values: "dark", "light".
*/
systemAppearance: "dark" | "light";

/**
* The [UIApplication](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html).
*/
Expand All @@ -627,7 +662,9 @@ export interface iOSApplication {
removeNotificationObserver(observer: any, notificationName: string): void;
}

/* tslint:disable */
/**
* @deprecated
*/
export interface RootViewControllerImpl {
contentController: any;
}
Expand Down
Loading

Back | FazBrowse Home | New Git URL