Application orientation changed event

This commit is contained in:
vakrilov
2015-07-29 11:43:12 +03:00
parent 5b2679717e
commit 6ebd488735
19 changed files with 274 additions and 66 deletions

View File

@ -79,6 +79,7 @@
<TypeScriptCompile Include="apps\action-bar-demo\pages\data-binding.ts">
<DependentUpon>data-binding.xml</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="apps\orientation-demo\app.ts" />
<TypeScriptCompile Include="apps\notifications-demo\app.ts" />
<TypeScriptCompile Include="apps\notifications-demo\main-page.ts">
<DependentUpon>main-page.xml</DependentUpon>
@ -107,6 +108,9 @@
<Content Include="apps\action-bar-demo\pages\center-view.xml" />
<Content Include="apps\action-bar-demo\pages\data-binding.xml" />
<Content Include="apps\gallery-app\content\html-view.xml" />
<Content Include="apps\orientation-demo\main-page.port.xml">
<SubType>Designer</SubType>
</Content>
<Content Include="apps\notifications-demo\main-page.xml">
<SubType>Designer</SubType>
</Content>
@ -135,6 +139,7 @@
<DependentUpon>page-title-icon.xml</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="apps\animations\model.ts" />
<TypeScriptCompile Include="apps\orientation-demo\main-page.ts" />
<TypeScriptCompile Include="apps\tests\ui\animation\animation-tests.ts" />
<TypeScriptCompile Include="ui\animation\animation.d.ts" />
<TypeScriptCompile Include="ui\animation\animation-common.ts">
@ -1777,6 +1782,9 @@
<Content Include="apps\notifications-demo\package.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="apps\orientation-demo\package.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="js-libs\esprima\LICENSE.BSD" />
<Content Include="source-control.md" />
<Content Include="ui\segmented-bar\package.json">

View File

@ -14,6 +14,7 @@ export var resumeEvent = "resume";
export var exitEvent = "exit";
export var lowMemoryEvent = "lowMemory";
export var uncaughtErrorEvent = "uncaughtError";
export var orientationChangedEvent = "orientationChanged";
export var cssFile: string = "app.css"

View File

@ -3,6 +3,7 @@ import dts = require("application");
import frame = require("ui/frame");
import types = require("utils/types");
import observable = require("data/observable");
import enums = require("ui/enums");
global.moduleMerge(appModule, exports);
@ -206,6 +207,8 @@ export class AndroidApplication extends observable.Observable implements dts.And
exports.notify({ eventName: dts.launchEvent, object: this, android: intent });
setupOrientationListener(this);
/* In the onLaunch event we expect the following setup, which ensures a root frame:
* var frame = require("ui/frame");
* var rootFrame = new frame.Frame();
@ -315,3 +318,36 @@ exports.start = function () {
}
exports.android = new AndroidApplication();
var currentOrientation: number;
function setupOrientationListener(androidApp: AndroidApplication) {
androidApp.registerBroadcastReceiver(android.content.Intent.ACTION_CONFIGURATION_CHANGED, onConfigurationChanged);
currentOrientation = androidApp.context.getResources().getConfiguration().orientation
}
function onConfigurationChanged(context: android.content.Context, intent: android.content.Intent) {
var orientation = context.getResources().getConfiguration().orientation;
if (currentOrientation !== orientation) {
currentOrientation = orientation;
var newValue;
switch (orientation) {
case android.content.res.Configuration.ORIENTATION_LANDSCAPE:
newValue = enums.DeviceOrientation.landscape;
break;
case android.content.res.Configuration.ORIENTATION_PORTRAIT:
newValue = enums.DeviceOrientation.portrait;
break;
default:
newValue = enums.DeviceOrientation.unknown;
break;
}
exports.notify(<dts.OrientationChangedEventData> {
eventName: dts.orientationChangedEvent,
android: context,
newValue: newValue,
object: exports.android,
});
}
}

View File

@ -45,6 +45,11 @@ declare module "application" {
*/
export var lowMemoryEvent: string;
/**
* String value used when hooking to orientationChanged event.
*/
export var orientationChangedEvent: string;
/**
* Event data containing information for the application events.
*/
@ -70,6 +75,16 @@ declare module "application" {
object: any;
}
/**
* Event data containing information for orientation changed event.
*/
export interface OrientationChangedEventData extends ApplicationEventData {
/**
* New orientation value.
*/
newValue: string;
}
/**
* The main page path (without the file extension) for the application starting from the application root.
* For example if you have page called "main.js" in a folder called "subFolder" and your root folder is "app" you can specify mainModule like this:
@ -146,6 +161,14 @@ declare module "application" {
*/
export function on(eventNames: string, callback: (data: any) => void, thisArg?: any);
/**
* Shortcut alias to the removeEventListener method.
* @param eventNames - String corresponding to events (e.g. "onLaunch").
* @param callback - Callback function which will be removed.
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/
export function off(eventNames: string, callback ?: any, thisArg ?: any);
/**
* Notifies all the registered listeners for the event provided in the data.eventName.
* @param data The data associated with the event.
@ -188,6 +211,11 @@ declare module "application" {
*/
export function on(event: "uncaughtError", callback: (args: ApplicationEventData) => void, thisArg?: any);
/**
* This event is raised the orientation of the current device has changed.
*/
export function on(event: "orientationChanged", callback: (args: OrientationChangedEventData) => void, thisArg?: any);
/**
* This is the Android-specific application object instance.
* Encapsulates methods and properties specific to the Android platform.

View File

@ -4,7 +4,7 @@ import utils = require("utils/utils");
import types = require("utils/types");
import view = require("ui/core/view");
import definition = require("application");
import enums = require("ui/enums");
global.moduleMerge(appModule, exports);
export var mainModule: string;
@ -61,10 +61,11 @@ class TNSAppDelegate extends UIResponder implements UIApplicationDelegate {
return;
}
}
var app: IOSApplication = exports.ios;
setupOrientationListener(app);
this.window.content = topFrame;
this.window.rootViewController = topFrame.ios.controller;
var app: IOSApplication = exports.ios;
app.rootController = this.window.rootViewController;
this.window.makeKeyAndVisible();
return true;
@ -193,4 +194,40 @@ exports.start = function () {
definition.notify({ eventName: definition.uncaughtErrorEvent, object: <any>definition.ios, ios: error });
}
}
}
var currentOrientation: number;
function setupOrientationListener(iosApp: IOSApplication) {
iosApp.addNotificationObserver(UIDeviceOrientationDidChangeNotification, onOreintationDidChange)
currentOrientation = UIDevice.currentDevice().orientation;
}
function onOreintationDidChange(notification: NSNotification) {
var orientation = UIDevice.currentDevice().orientation;
if (currentOrientation !== orientation) {
currentOrientation = orientation;
var newValue;
switch (orientation) {
case UIDeviceOrientation.UIDeviceOrientationLandscapeRight:
case UIDeviceOrientation.UIDeviceOrientationLandscapeLeft:
newValue = enums.DeviceOrientation.landscape;
break;
case UIDeviceOrientation.UIDeviceOrientationPortrait:
case UIDeviceOrientation.UIDeviceOrientationPortraitUpsideDown:
newValue = enums.DeviceOrientation.portrait;
break;
default:
newValue = enums.DeviceOrientation.unknown;
break;
}
exports.notify(<definition.OrientationChangedEventData>{
eventName: definition.orientationChangedEvent,
ios: exports.ios,
newValue: newValue,
object: exports.ios,
});
}
}

View File

@ -5,6 +5,7 @@ import labelModule = require("ui/label");
var batteryLabel: labelModule.Label;
var registered = false;
export function onPageLoaded(args: observable.EventData) {
var page = <pages.Page>args.object;
batteryLabel = page.getViewById<labelModule.Label>("batteryLabel");
@ -36,4 +37,4 @@ export function onPageLoaded(args: observable.EventData) {
application.ios.addNotificationObserver(UIDeviceBatteryLevelDidChangeNotification, onReceiveCallback);
}
registered = true;
}
}

View File

@ -1,4 +1,4 @@
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="onPageLoaded">
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="onPageLoaded" unloaded="onPageUnloaded">
<StackLayout>
<Label id="batteryLabel" text="Battery" style.fontSize="30" horizontalAlignment="stretch" textAlignment="center"/>
</StackLayout>

View File

@ -0,0 +1,14 @@
import application = require("application");
application.mainModule = "main-page";
application.on(application.exitEvent, () => {
if (application.android) {
application.android.unregisterBroadcastReceiver(android.content.Intent.ACTION_BATTERY_CHANGED);
}
else {
application.ios.removeNotificationObserver(UIDeviceBatteryLevelDidChangeNotification);
}
});
application.start();

View File

@ -0,0 +1,5 @@
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="onPageLoaded" unloaded="onPageUnloaded" navigatedTo="pageNavigatedTo">
<GridLayout>
<TextView text="{{ oreintation }}" />
</GridLayout>
</Page>

View File

@ -0,0 +1,21 @@
import application = require("application");
import observable = require("data/observable");
import pageModule = require("ui/page");
var vm = new observable.Observable();
function orientationChanged(data) {
console.log("Orientation changed: " + data.newValue);
vm.set("oreintation", data.newValue);
}
export function onPageLoaded(args: observable.EventData) {
var page = <pageModule.Page>args.object;
application.on(application.orientationChangedEvent, orientationChanged, page);
page.bindingContext = vm;
vm.set("oreintation", "not changed");
}
export function onPageUnloaded(args: observable.EventData) {
var page = <pageModule.Page>args.object;
<any>application.off(application.orientationChangedEvent, orientationChanged, page);
}

View File

@ -0,0 +1,2 @@
{ "name" : "page-reload-demo",
"main" : "app.js" }

View File

@ -14,7 +14,10 @@ declare module "file-system/file-name-resolver" {
resolveFileName(path: string, ext: string): string;
}
export function resolveFileName(path: string, ext: string): string;
//@private
export function findFileMatch(path: string, ext: string, candidates: Array<string>, context: PlatformContext): string
//@endprivate
}

View File

@ -2,6 +2,8 @@
import fs = require("file-system");
import types = require("utils/types");
import trace = require("trace");
import platform = require("platform");
import application = require("application");
var MIN_WH: string = "minWH";
var MIN_W: string = "minW";
@ -79,7 +81,7 @@ var paltformQualifier: QualifierSpec = {
value === "ios";
},
getMatchValue(value: string, context: definition.PlatformContext): number{
getMatchValue(value: string, context: definition.PlatformContext): number {
return value === context.os.toLowerCase() ? 1 : -1;
}
}
@ -90,7 +92,7 @@ var orientationQualifier: QualifierSpec = {
value === "port";
},
getMatchValue(value: string, context: definition.PlatformContext): number{
getMatchValue(value: string, context: definition.PlatformContext): number {
var isLandscape: number = (context.width > context.height) ? 1 : -1;
return (value === "land") ? isLandscape : -isLandscape;
}
@ -213,3 +215,27 @@ function checkQualifier(value: string, context: definition.PlatformContext) {
return -1;
}
var appEventAttached: boolean = false;
var resolverInstance: FileNameResolver;
export function resolveFileName(path: string, ext: string): string {
if (!appEventAttached) {
application.on(application.orientationChangedEvent, (data) => {
resolverInstance = undefined;
});
appEventAttached = true;
}
if (!resolverInstance) {
resolverInstance = new FileNameResolver({
width: platform.screen.mainScreen.widthDIPs,
height: platform.screen.mainScreen.heightDIPs,
os: platform.device.os,
deviceType: platform.device.deviceType
});
}
return resolverInstance.resolveFileName(path, ext);
}

View File

@ -92,22 +92,39 @@ export class device implements definition.device {
}
}
var mainScreenInfo: definition.ScreenMetrics;
var mainScreen: MainScreen;
// This is a "static" class and it is used like a name-space.
// This is a "static" class and it is used like a namespace.
// It is not meant to be initialized - thus it is not capitalized
export class screen implements definition.screen {
static get mainScreen(): definition.ScreenMetrics {
if (!mainScreenInfo) {
if (!mainScreen) {
var metrics = utils.ad.getApplicationContext().getResources().getDisplayMetrics();
mainScreenInfo = {
widthPixels: metrics.widthPixels,
heightPixels: metrics.heightPixels,
scale: metrics.density,
widthDIPs: metrics.widthPixels / metrics.density,
heightDIPs: metrics.heightPixels / metrics.density
}
mainScreen = new MainScreen(metrics);
}
return mainScreenInfo;
return mainScreen;
}
}
class MainScreen implements definition.ScreenMetrics {
private _metrics: android.util.DisplayMetrics;
constructor(metrics: android.util.DisplayMetrics) {
this._metrics = metrics;
}
get widthPixels(): number {
return this._metrics.widthPixels;
}
get heightPixels(): number {
return this._metrics.heightPixels;
}
get scale(): number {
return this._metrics.density;
}
get widthDIPs(): number {
return this._metrics.widthPixels / this._metrics.density;
}
get heightDIPs(): number {
return this._metrics.heightPixels / this._metrics.density;
}
}

View File

@ -86,26 +86,38 @@ export class device implements definition.device {
}
}
var mainScreenInfo: definition.ScreenMetrics = null;
var mainScreen: MainScreen;
// This is a "static" class and it is used like a name-space.
// It is not meant to be initialized - thus it is not capitalized
export class screen implements definition.screen {
static get mainScreen(): definition.ScreenMetrics {
if (!mainScreenInfo) {
var mainScreen = UIScreen.mainScreen();
if (mainScreen) {
var size = mainScreen.bounds.size;
var scale = mainScreen.scale;
mainScreenInfo = {
widthPixels: size.width * scale,
heightPixels: size.height * scale,
scale: scale,
widthDIPs: size.width,
heightDIPs: size.height
}
}
if (!mainScreen) {
mainScreen = new MainScreen(UIScreen.mainScreen());
}
return mainScreenInfo;
return mainScreen;
}
}
class MainScreen implements definition.ScreenMetrics {
private _screen: UIScreen;
constructor(metrics: UIScreen) {
this._screen = metrics;
}
get widthPixels(): number {
return this.widthDIPs * this.scale;
}
get heightPixels(): number {
return this.heightDIPs * this.scale;
}
get scale(): number {
return this._screen.scale;
}
get widthDIPs(): number {
return this._screen.bounds.size.width;
}
get heightDIPs(): number {
return this._screen.bounds.size.height;
}
}

View File

@ -193,11 +193,11 @@ function loadCustomComponent(componentPath: string, componentName?: string, attr
fullComponentPathFilePathWithoutExt = fs.path.join(fs.knownFolders.currentApp().path, componentPath, componentName);
}
var xmlFilePath = resolveFilePath(fullComponentPathFilePathWithoutExt, "xml");
var xmlFilePath = fileResolverModule.resolveFileName(fullComponentPathFilePathWithoutExt, "xml");
if (xmlFilePath) {
// Custom components with XML
var jsFilePath = resolveFilePath(fullComponentPathFilePathWithoutExt, "js");
var jsFilePath = fileResolverModule.resolveFileName(fullComponentPathFilePathWithoutExt, "js");
var subExports;
if (jsFilePath) {
@ -220,7 +220,7 @@ function loadCustomComponent(componentPath: string, componentName?: string, attr
}
// Add component CSS file if exists.
var cssFilePath = resolveFilePath(fullComponentPathFilePathWithoutExt, "css");
var cssFilePath = fileResolverModule.resolveFileName(fullComponentPathFilePathWithoutExt, "css");
if (cssFilePath) {
if (parentPage) {
parentPage.addCssFile(cssFilePath);
@ -232,19 +232,6 @@ function loadCustomComponent(componentPath: string, componentName?: string, attr
return result;
}
var fileNameResolver: fileResolverModule.FileNameResolver;
function resolveFilePath(path, ext): string {
if (!fileNameResolver) {
fileNameResolver = new fileResolverModule.FileNameResolver({
width: platform.screen.mainScreen.widthDIPs,
height: platform.screen.mainScreen.heightDIPs,
os: platform.device.os,
deviceType: platform.device.deviceType
});
}
return fileNameResolver.resolveFileName(path, ext);
}
export function load(pathOrOptions: string | definition.LoadOptions, context?: any): view.View {
var viewToReturn: view.View;
var componentModule: componentBuilder.ComponentModule;

18
ui/enums/enums.d.ts vendored
View File

@ -104,6 +104,24 @@
export var vertical: string;
}
/**
* Orientation of a device.
*/
module DeviceOrientation {
/**
* Portrait orientation.
*/
export var portrait: string;
/**
* Landscape orientation.
*/
export var landscape: string;
/**
* Orientation cannot be determined.
*/
export var unknown: string;
}
/**
* HorizontalAlignment indicates where an element should be displayed on the horizontal axis relative to the allocated layout slot of the parent element.
*/

View File

@ -25,6 +25,12 @@ export module Orientation {
export var vertical = "vertical";
}
export module DeviceOrientation {
export var portrait = "portrait";
export var landscape = "landscape";
export var unknown = "unknown";
}
export module HorizontalAlignment {
export var left = "left";
export var center = "center";

View File

@ -6,7 +6,6 @@ import trace = require("trace");
import builder = require("ui/builder");
import fs = require("file-system");
import utils = require("utils/utils");
import platform = require("platform");
import fileResolverModule = require("file-system/file-name-resolver");
var frameStack: Array<Frame> = [];
@ -47,7 +46,7 @@ export function resolvePageFromEntry(entry: definition.NavigationEntry): pages.P
var moduleNamePath = fs.path.join(currentAppPath, entry.moduleName);
var moduleExports;
var moduleExportsResolvedPath = resolveFilePath(moduleNamePath, "js");
var moduleExportsResolvedPath = fileResolverModule.resolveFileName(moduleNamePath, "js");
if (moduleExportsResolvedPath) {
trace.write("Loading JS file: " + moduleExportsResolvedPath, trace.categories.Navigation);
@ -72,25 +71,12 @@ export function resolvePageFromEntry(entry: definition.NavigationEntry): pages.P
return page;
}
var fileNameResolver: fileResolverModule.FileNameResolver;
function resolveFilePath(path, ext) : string {
if (!fileNameResolver) {
fileNameResolver = new fileResolverModule.FileNameResolver({
width: platform.screen.mainScreen.widthDIPs,
height: platform.screen.mainScreen.heightDIPs,
os: platform.device.os,
deviceType: platform.device.deviceType
});
}
return fileNameResolver.resolveFileName(path, ext);
}
function pageFromBuilder(moduleNamePath: string, moduleExports: any): pages.Page {
var page: pages.Page;
var element: view.View;
// Possible XML file path.
var fileName = resolveFilePath(moduleNamePath, "xml");
var fileName = fileResolverModule.resolveFileName(moduleNamePath, "xml");
if (fileName) {
trace.write("Loading XML file: " + fileName, trace.categories.Navigation);
@ -100,7 +86,7 @@ function pageFromBuilder(moduleNamePath: string, moduleExports: any): pages.Page
page = <pages.Page>element;
// Possible CSS file path.
var cssFileName = resolveFilePath(moduleNamePath, "css");
var cssFileName = fileResolverModule.resolveFileName(moduleNamePath, "css");
if (cssFileName) {
page.addCssFile(cssFileName);
}