let DetailsScreen = SCREEN.EmptyScreen.template($ => ({ contents: [ SCREEN.EmptyBody($, { skin: whiteSkin, anchor: 'BODY', contents: [ Layout($, { left: 0, right: 0, top: 0, bottom: 0, behavior: new RearrangingBehavior }), Container($, { width: application.width - 8, top: 4, height: application.height/2 - 8, anchor: 'PICTURE', contents: [ Picture($, { left: 0, right: 0, top: 0, bottom: 0, aspect: 'fit', url: $.image, }) ] }), Content($, { left: 4, right: 4, top: application.height/2 - 4, height: 2, skin: separatorSkin, anchor: 'BORDER', }), Container($, { left: 0, right: 0, top: application.height/2, bottom: 0, anchor: 'DESCRIPTION', clip: true, contents: [ SCROLLER.VerticalScroller($, { contents: [ Text($, { left: 0, right: 0, top: 0, style: productDescriptionStyle, string: $.description, }), SCROLLER.VerticalScrollbar($, { }), SCROLLER.BottomScrollerShadow($, { }), ] }), ], }), ], }), Header($, { anchor: 'HEADER' }), ], }));
var ServicesScreen = Container.template(function($) { return { left: 0, right: 0, top: 0, bottom: 0, skin: whiteSkin, contents: [ CREATIONS.DynamicHeader($), Container($, { left: 0, right: 0, top: 32, bottom: 0, behavior: BLEServiceDiscoveryBehavior, contents: [ SCROLLER.VerticalScroller($, { clip: true, contents: [ Column($, { left:0, right:0, top:0, behavior: SCREEN.ListBehavior({ addBusyLine: function(list) { list.add(new ListEmptyItem("Discovering services...")); }, addItemLine: function(list, item, index) { list.add(new ServiceItem(item)); }, addLines: function(list, items, more) { for (var i = 0, c = items.length; i < c; ++i) { this.addItemLine(list, items[i], i); } if (0 == list.length) this.addBusyLine(list); else list.insert(new CategoryHeader("Services"), list.first); }, onCreate: function(list, data) { this.data = data; this.reload(list); }, onServiceAdded: function(list, peripheral, service) { this.reload(list); }, reload: function(list) { list.cancel(); list.empty(); var entries = []; var services = this.data.peripheral.services; for (var uuid in services) entries.push(services[uuid]); entries.sort(function(a, b) {return a.name.toLowerCase().compare(b.name.toLowerCase())}); var length = entries.length; this.data.items = new Array(length); for (var i = 0; i < length; ++i) this.data.items[i] = {service: entries[i]}; this.addLines(list, this.data.items, false); } }), }), SCROLLER.VerticalScrollbar($), SCROLLER.BottomScrollerShadow($) ] }), ], }) ] }});
var DevicesScreen = Container.template(function($) { return { left: 0, right: 0, top: 0, bottom: 0, skin: whiteSkin, behavior: Behavior({ onBackButton: function(container) { application.invoke(new Message("xkpr://shell/close?id=" + application.id)); }, }), contents: [ CREATIONS.DynamicHeader($), Container($, { left: 0, right: 0, top: 32, bottom: 0, behavior: BLEDeviceDiscoveryBehavior, contents: [ SCROLLER.VerticalScroller($, { clip: true, contents: [ Column($, { left:0, right:0, top:0, behavior: SCREEN.ListBehavior({ addBusyLine: function(list) { list.add(new ListEmptyItem("Scanning...")); }, addItemLine: function(list, item, index) { list.add(new DeviceListItem(item)); }, addLines: function(list, items, more) { for (var i = 0, c = items.length; i < c; ++i) { this.addItemLine(list, items[i], i); } if (0 == list.length) this.addBusyLine(list); }, onCreate: function(list, data) { this.data = data; this.reload(list); }, onPeripheralAdded: function(list, peripheral) { this.reload(list); }, onPeripheralRemoved: function(list, peripheral) { this.reload(list); return true; }, reload: function(list) { list.cancel(); list.empty(); this.data.items.length = []; for (var address in model.data.peripherals) { var peripheral = model.data.peripherals[address]; var item = { peripheral: peripheral, action: "/services?" + serializeQuery({address: peripheral.address}) } this.data.items.push(item); } this.addLines(list, this.data.items, false); } }), }), SCROLLER.VerticalScrollbar($), SCROLLER.BottomScrollerShadow($) ] }), ], }) ] }});
var CharacteristicsScreen = Container.template(function($) { return { left: 0, right: 0, top: 0, bottom: 0, skin: whiteSkin, contents: [ CREATIONS.DynamicHeader($), Container($, { left: 0, right: 0, top: 32, bottom: 0, behavior: BLEServiceCharacteristicsBrowserBehavior, contents: [ SCROLLER.VerticalScroller($, { clip: true, contents: [ Column($, { left:0, right:0, top:0, behavior: SCREEN.ListBehavior({ addBusyLine: function(list) { list.add(new ListEmptyItem("Discovering characteristics...")); }, addItemLine: function(list, item, index) { list.add(new CharacteristicItem(item)); }, addLines: function(list, items, more) { if (items.length) { list.add(new CategoryHeader("Service")); list.add(new ListGenericItem(this.service.name)); list.add(new CategoryHeader("Characteristics"), list.first); } for (var i = 0, c = items.length; i < c; ++i) { this.addItemLine(list, items[i], i); } if (0 == list.length) this.addBusyLine(list); }, onCreate: function(list, data) { this.data = data; this.peripheral = this.data.peripheral; this.service = this.data.service; this.gatt_service = (this.service.uuid in model.data.gatt_services ? model.data.gatt_services[this.service.uuid] : undefined); this.reload(list); }, onServiceCharacteristicsAdded: function(list, service) { this.reload(list); }, reload: function(list) { list.cancel(); list.empty(); var items = this.data.items = []; var characteristics = this.service.characteristics; var gatt_service = this.gatt_service; for (var i = 0, c = characteristics.length; i < c; ++i) { var characteristic = characteristics[i]; var item = { name: "Unknown Characteristic", handle: characteristic.handle, uuid: characteristic.uuid, properties: this.getPropertyStrings(characteristic.properties), } if (gatt_service && (characteristic.uuid in gatt_service.characteristics)) item.name = gatt_service.characteristics[characteristic.uuid].name; if (-1 != item.properties.indexOf("Read")) { item.action = "/value?" + serializeQuery({ peripheral_address: this.peripheral.address, service_uuid: this.service.uuid, handle: characteristic.handle, characteristic_uuid: item.uuid, name: item.name }); } items.push(item); } this.addLines(list, items, false); }, getPropertyStrings: function(properties) { var propertyStrings = []; for (var i = 0, c = properties.length; i < c; ++i) { var property = properties[i]; if ("broadcast" == property) propertyStrings.push("Broadcast"); else if ("read" == property) propertyStrings.push("Read"); else if ("writeWithoutResponse" == property) propertyStrings.push("Write without response"); else if ("write" == property) propertyStrings.push("Write"); else if ("notify" == property) propertyStrings.push("Notify"); else if ("indicate" == property) propertyStrings.push("Indicate"); } return propertyStrings.join(","); }, }), }), SCROLLER.VerticalScrollbar($), SCROLLER.BottomScrollerShadow($) ] }), ], }) ] }});
var CharacteristicValueScreen = Container.template(function($) { return { left: 0, right: 0, top: 0, bottom: 0, skin: whiteSkin, contents: [ CREATIONS.DynamicHeader($), Container($, { left: 0, right: 0, top: 32, bottom: 0, behavior: BLEServiceCharacteristicValueBrowserBehavior, contents: [ SCROLLER.VerticalScroller($, { clip: true, contents: [ Column($, { left:0, right:0, top:0, behavior: SCREEN.ListBehavior({ addBusyLine: function(list) { list.add(new ListEmptyItem("Reading characteristic value...")); }, addItemLine: function(list, item, index) { list.add(new CharacteristicValueItem(item)); }, addLines: function(list, items, more) { if (items.length) { list.add(new CategoryHeader("Service")); list.add(new ListGenericItem(this.service.name)); list.add(new CategoryHeader("Characteristic")); list.add(new ListCharacteristicItem({name: this.data.name, uuid: this.data.uuid})); list.add(new CategoryHeader("Value")); } for (var i = 0, c = items.length; i < c; ++i) { this.addItemLine(list, items[i], i); } if (0 == list.length) this.addBusyLine(list); }, onCreate: function(list, data) { this.data = data; this.peripheral = this.data.peripheral; this.service = this.data.service; this.addBusyLine(list); }, onCharacteristicValueRead: function(list) { this.reload(list); }, reload: function(list) { list.cancel(); list.empty(); var items = this.data.items = []; var item = { uuid: this.data.uuid, ascii: this.data.ascii, hex: this.data.hex } items.push(item); this.addLines(list, items, false); }, }), }), SCROLLER.VerticalScrollbar($), SCROLLER.BottomScrollerShadow($) ] }), ], }) ] }});
var Screen = Container.template(function($) { return { left:0, right:0, top:0, bottom:0, active:true, contents: [ Container($, { left:0, right:0, top:0, bottom:0, skin:new Skin({ fill:"#FFFFFF" }), contents: [ Container($, { width:280, height:210, skin:new Skin({ fill:"#F0F0F0" }), contents: [ Layer($, { anchor:"LAYER", width:280, height:210, alpha: true, contents: [ Label($, { style:titleStyle, string: $.title }), ], }) ], }), ], }), Container($, { left:0, top:0, active:true, behavior: Object.create(CONTROL.ButtonBehavior.prototype, { onTap: { value: function(container) { application.invoke(new Message("xkpr://shell/close?id=" + application.id)); }}, }), contents: [ Content($, { skin:toolsSkin, variant:0 }), ] }), Container($, { width:32, right:4, height:32, top:0, active:true, behavior: Object.create(CONTROL.ButtonBehavior.prototype, { onDisplayed: { value: function(container) { this.menuVisible = false; this.onTap(container); }}, onTap: { value: function(container) { if (this.menuVisible) container.container.run(new MenuTransition, container, container.last.width - 4); else container.container.run(new MenuTransition, container, 4 - container.last.width); this.menuVisible = !this.menuVisible; }}, }), contents: [ Content($, { skin:toolsSkin, variant:1 }), Layout($, { left:32, top:0, skin:menuSkin, behavior: Object.create(Behavior.prototype, { onMeasureHorizontally: { value: function(layout) { var size = layout.first.first.measure(); return size.width + 4; }}, onMeasureVertically: { value: function(layout) { var size = layout.first.first.measure(); return Math.min(size.height + 4, application.height); }}, }), contents: [ SCROLLER.VerticalScroller($, { left:4, clip:true, contents:[ Menu($), SCROLLER.TopScrollerShadow($), SCROLLER.BottomScrollerShadow($), ]}), ] }), ] }), ], }});
var Screen = Container.template(function($) { return { left:0, right:0, top:0, bottom:0, active:true, contents: [ Canvas($, { anchor:"CANVAS", left:0, right:0, top:0, bottom:0, active:true, behavior: Object.create(Behavior.prototype, { onDisplaying: { value: function(canvas) { var ctx = canvas.getContext("2d"); ctx.fillStyle = "white" ctx.fillRect(0, 0, canvas.width, canvas.height); }}, onFinished: { value: function(canvas) { if (model.replayIndex >= model.replayStack.length) { var ctx = canvas.getContext("2d"); ctx.fillStyle = "white" ctx.fillRect(0, 0, canvas.width, canvas.height); model.replayIndex = 0; } else { model.replayStack[model.replayIndex].replay(canvas); model.replayIndex++; } canvas.time = 0; canvas.start(); }}, onTouchBegan: { value: function(canvas, id, x, y, ticks) { if (model.replayFlag) return; this.position = canvas.position; x -= this.position.x; y -= this.position.y; var ctx = canvas.getContext("2d"); ctx.lineWidth = model.data.thickness ctx.strokeStyle = model.data.color ctx.beginPath(); ctx.moveTo(x, y); model.replayStack.push(new ReplayMove(x, y)); }}, onTouchMoved: { value: function(canvas, id, x, y, ticks) { if (model.replayFlag) return; x -= this.position.x; y -= this.position.y; var ctx = canvas.getContext("2d"); ctx.lineTo(x, y); ctx.stroke(); model.replayStack.push(new ReplayLine(x, y)); }}, }), }), Container($, { left:0, top:0, active:true, behavior: Object.create(CONTROL.ButtonBehavior.prototype, { onTap: { value: function(container) { application.invoke(new Message("xkpr://shell/close?id=" + application.id)); }}, }), contents: [ Content($, { skin:toolsSkin, variant:0 }), ] }), Container($, { width:32, right:4, height:32, top:0, active:true, behavior: Object.create(CONTROL.ButtonBehavior.prototype, { onDisplayed: { value: function(container) { this.menuVisible = false; this.onTap(container); }}, onTap: { value: function(container) { if (this.menuVisible) container.container.run(new MenuTransition, container, container.last.width - 4); else container.container.run(new MenuTransition, container, 4 - container.last.width); this.menuVisible = !this.menuVisible; }}, }), contents: [ Content($, { skin:toolsSkin, variant:1 }), Layout($, { left:32, top:0, skin:menuSkin, behavior: Object.create(Behavior.prototype, { onMeasureHorizontally: { value: function(layout) { var size = layout.first.first.measure(); return size.width + 4; }}, onMeasureVertically: { value: function(layout) { var size = layout.first.first.measure(); return Math.min(size.height + 4, application.height); }}, }), contents: [ SCROLLER.VerticalScroller($, { left:4, clip:true, contents:[ Menu($), SCROLLER.TopScrollerShadow($), SCROLLER.BottomScrollerShadow($), ]}), ] }), ] }), ], }});
var Screen = Container.template(function($) { return { left:0, right:0, top:0, bottom:0, skin:THEME.whiteSkin, contents: [ Port($, { anchor:"PORT", left:0, right:0, top:0, bottom:0, active:true, behavior: Object.create(Behavior.prototype, { onCreate: { value: function(port, data) { this.data = data; }}, onDraw: { value: function(port) { port.projectImage3D(testTexture, this.data.billboard, this.data.camera); }}, }), }), Container($, { left:0, top:0, active:true, behavior: Object.create(CONTROL.ButtonBehavior.prototype, { onTap: { value: function(container) { application.invoke(new Message("xkpr://shell/close?id=" + application.id)); }}, }), contents: [ Content($, { skin:toolsSkin, variant:0 }), ] }), Container($, { width:32, right:4, height:32, top:0, active:true, behavior: Object.create(CONTROL.ButtonBehavior.prototype, { onDisplayed: { value: function(container) { this.menuVisible = false; this.onTap(container); }}, onTap: { value: function(container) { if (this.menuVisible) container.container.run(new MenuTransition, container, container.last.width - 4); else container.container.run(new MenuTransition, container, 4 - container.last.width); this.menuVisible = !this.menuVisible; }}, }), contents: [ Content($, { skin:toolsSkin, variant:1 }), Layout($, { left:32, top:0, skin:menuSkin, behavior: Object.create(Behavior.prototype, { onMeasureHorizontally: { value: function(layout) { var size = layout.first.first.measure(); return size.width + 4; }}, onMeasureVertically: { value: function(layout) { var size = layout.first.first.measure(); return Math.min(size.height + 4, application.height); }}, }), contents: [ SCROLLER.VerticalScroller($, { left:4, clip:true, contents:[ Menu($), SCROLLER.TopScrollerShadow($), SCROLLER.BottomScrollerShadow($), ]}), ] }), ] }), ], }});