diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index 7b6e29e65..343b95001 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -79,6 +79,7 @@
data-binding.xml
+
main-page.xml
@@ -107,6 +108,9 @@
+
+ Designer
+
Designer
@@ -135,6 +139,7 @@
page-title-icon.xml
+
@@ -1777,6 +1782,9 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/application/application-common.ts b/application/application-common.ts
index 89357cfdf..44aa07c6d 100644
--- a/application/application-common.ts
+++ b/application/application-common.ts
@@ -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"
diff --git a/application/application.android.ts b/application/application.android.ts
index fcbcbd2bb..213a44bd7 100644
--- a/application/application.android.ts
+++ b/application/application.android.ts
@@ -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( {
+ eventName: dts.orientationChangedEvent,
+ android: context,
+ newValue: newValue,
+ object: exports.android,
+ });
+ }
+}
diff --git a/application/application.d.ts b/application/application.d.ts
index b9b502cad..0f247614c 100644
--- a/application/application.d.ts
+++ b/application/application.d.ts
@@ -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.
diff --git a/application/application.ios.ts b/application/application.ios.ts
index 00d8ca8e9..ac3226e23 100644
--- a/application/application.ios.ts
+++ b/application/application.ios.ts
@@ -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: definition.ios, ios: error });
}
-}
\ No newline at end of file
+}
+
+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({
+ eventName: definition.orientationChangedEvent,
+ ios: exports.ios,
+ newValue: newValue,
+ object: exports.ios,
+ });
+ }
+}
diff --git a/apps/notifications-demo/main-page.ts b/apps/notifications-demo/main-page.ts
index b931bfe47..ac1a15874 100644
--- a/apps/notifications-demo/main-page.ts
+++ b/apps/notifications-demo/main-page.ts
@@ -5,6 +5,7 @@ import labelModule = require("ui/label");
var batteryLabel: labelModule.Label;
var registered = false;
+
export function onPageLoaded(args: observable.EventData) {
var page = args.object;
batteryLabel = page.getViewById("batteryLabel");
@@ -36,4 +37,4 @@ export function onPageLoaded(args: observable.EventData) {
application.ios.addNotificationObserver(UIDeviceBatteryLevelDidChangeNotification, onReceiveCallback);
}
registered = true;
-}
\ No newline at end of file
+}
diff --git a/apps/notifications-demo/main-page.xml b/apps/notifications-demo/main-page.xml
index fd325a4c8..03b37f36a 100644
--- a/apps/notifications-demo/main-page.xml
+++ b/apps/notifications-demo/main-page.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/apps/orientation-demo/app.ts b/apps/orientation-demo/app.ts
new file mode 100644
index 000000000..0708869a4
--- /dev/null
+++ b/apps/orientation-demo/app.ts
@@ -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();
diff --git a/apps/orientation-demo/main-page.port.xml b/apps/orientation-demo/main-page.port.xml
new file mode 100644
index 000000000..5ac9e933c
--- /dev/null
+++ b/apps/orientation-demo/main-page.port.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/apps/orientation-demo/main-page.ts b/apps/orientation-demo/main-page.ts
new file mode 100644
index 000000000..bd6b6529e
--- /dev/null
+++ b/apps/orientation-demo/main-page.ts
@@ -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 = args.object;
+ application.on(application.orientationChangedEvent, orientationChanged, page);
+
+ page.bindingContext = vm;
+ vm.set("oreintation", "not changed");
+}
+
+export function onPageUnloaded(args: observable.EventData) {
+ var page = args.object;
+ application.off(application.orientationChangedEvent, orientationChanged, page);
+}
diff --git a/apps/orientation-demo/package.json b/apps/orientation-demo/package.json
new file mode 100644
index 000000000..8f939eb01
--- /dev/null
+++ b/apps/orientation-demo/package.json
@@ -0,0 +1,2 @@
+{ "name" : "page-reload-demo",
+ "main" : "app.js" }
\ No newline at end of file
diff --git a/file-system/file-name-resolver.d.ts b/file-system/file-name-resolver.d.ts
index 257263414..2d9e5d370 100644
--- a/file-system/file-name-resolver.d.ts
+++ b/file-system/file-name-resolver.d.ts
@@ -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, context: PlatformContext): string
//@endprivate
+
}
\ No newline at end of file
diff --git a/file-system/file-name-resolver.ts b/file-system/file-name-resolver.ts
index 481206a11..fdf023498 100644
--- a/file-system/file-name-resolver.ts
+++ b/file-system/file-name-resolver.ts
@@ -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);
+}
+
diff --git a/platform/platform.android.ts b/platform/platform.android.ts
index 82f17988f..69f008092 100644
--- a/platform/platform.android.ts
+++ b/platform/platform.android.ts
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/platform/platform.ios.ts b/platform/platform.ios.ts
index 44e1ff22e..1f76a58c5 100644
--- a/platform/platform.ios.ts
+++ b/platform/platform.ios.ts
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/ui/builder/builder.ts b/ui/builder/builder.ts
index 060c4a325..343f143f4 100644
--- a/ui/builder/builder.ts
+++ b/ui/builder/builder.ts
@@ -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;
diff --git a/ui/enums/enums.d.ts b/ui/enums/enums.d.ts
index eed1541b0..00f5466ba 100644
--- a/ui/enums/enums.d.ts
+++ b/ui/enums/enums.d.ts
@@ -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.
*/
diff --git a/ui/enums/enums.ts b/ui/enums/enums.ts
index ebaa1a3d8..fc0ba9749 100644
--- a/ui/enums/enums.ts
+++ b/ui/enums/enums.ts
@@ -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";
diff --git a/ui/frame/frame-common.ts b/ui/frame/frame-common.ts
index ba3769f30..eef4bfff3 100644
--- a/ui/frame/frame-common.ts
+++ b/ui/frame/frame-common.ts
@@ -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 = [];
@@ -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 = element;
// Possible CSS file path.
- var cssFileName = resolveFilePath(moduleNamePath, "css");
+ var cssFileName = fileResolverModule.resolveFileName(moduleNamePath, "css");
if (cssFileName) {
page.addCssFile(cssFileName);
}