Initial commit
This commit is contained in:
commit
c310cd7943
19 changed files with 3939 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
dist/
|
2
app-side/i18n/en-US.po
Normal file
2
app-side/i18n/en-US.po
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
msgid "example"
|
||||||
|
msgstr "This is an example in app-side"
|
60
app-side/index.js
Normal file
60
app-side/index.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { MessageBuilder } from "../shared/message-side";
|
||||||
|
|
||||||
|
const messageBuilder = new MessageBuilder();
|
||||||
|
|
||||||
|
async function fetchDirectory(ctx) {
|
||||||
|
try {
|
||||||
|
const res = await fetch({
|
||||||
|
url: "https://directory.spaceapi.io",
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
const resBody =
|
||||||
|
typeof res.body === "string" ? JSON.parse(res.body) : res.body;
|
||||||
|
|
||||||
|
ctx.response({
|
||||||
|
data: { success: true, result: resBody },
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
ctx.response({
|
||||||
|
data: { success: false, result: {} },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchStatus(url, ctx) {
|
||||||
|
try {
|
||||||
|
const res = await fetch({
|
||||||
|
url: url,
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
const resBody =
|
||||||
|
typeof res.body === "string" ? JSON.parse(res.body) : res.body;
|
||||||
|
|
||||||
|
ctx.response({
|
||||||
|
data: { success: true, result: resBody },
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
ctx.response({
|
||||||
|
data: { success: false, result: {} },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppSideService({
|
||||||
|
onInit() {
|
||||||
|
messageBuilder.listen(() => {});
|
||||||
|
|
||||||
|
messageBuilder.on("request", (ctx) => {
|
||||||
|
const jsonRpc = messageBuilder.buf2Json(ctx.request.payload);
|
||||||
|
if (jsonRpc.method === "GET_DIRECTORY") {
|
||||||
|
return fetchDirectory(ctx);
|
||||||
|
} else if (jsonRpc.method === "GET_STATUS") {
|
||||||
|
return fetchStatus(jsonRpc.url, ctx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onRun() {},
|
||||||
|
|
||||||
|
onDestroy() {},
|
||||||
|
});
|
28
app.js
Normal file
28
app.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import "./shared/device-polyfill";
|
||||||
|
import { MessageBuilder } from "./shared/message";
|
||||||
|
import { getPackageInfo } from "@zos/app";
|
||||||
|
import * as ble from "@zos/ble";
|
||||||
|
|
||||||
|
App({
|
||||||
|
globalData: {
|
||||||
|
messageBuilder: null,
|
||||||
|
},
|
||||||
|
onCreate(options) {
|
||||||
|
console.log("app on create invoke");
|
||||||
|
const { appId } = getPackageInfo();
|
||||||
|
const messageBuilder = new MessageBuilder({
|
||||||
|
appId,
|
||||||
|
appDevicePort: 20,
|
||||||
|
appSidePort: 0,
|
||||||
|
ble,
|
||||||
|
});
|
||||||
|
this.globalData.messageBuilder = messageBuilder;
|
||||||
|
messageBuilder.connect();
|
||||||
|
},
|
||||||
|
|
||||||
|
onDestroy(options) {
|
||||||
|
console.log("app on destroy invoke");
|
||||||
|
this.globalData.messageBuilder &&
|
||||||
|
this.globalData.messageBuilder.disConnect();
|
||||||
|
},
|
||||||
|
});
|
57
app.json
Normal file
57
app.json
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"configVersion": "v2",
|
||||||
|
"app": {
|
||||||
|
"appId": 28358,
|
||||||
|
"appName": "ZeppSpace",
|
||||||
|
"appType": "app",
|
||||||
|
"version": {
|
||||||
|
"code": 1,
|
||||||
|
"name": "1.0.1"
|
||||||
|
},
|
||||||
|
"icon": "icon.png",
|
||||||
|
"vender": "pauljako",
|
||||||
|
"description": "A ZeppOS App for SpaceAPI"
|
||||||
|
},
|
||||||
|
"permissions": [
|
||||||
|
"data:os.device.info",
|
||||||
|
"device:os.local_storage",
|
||||||
|
"device:os.geolocation"
|
||||||
|
],
|
||||||
|
"runtime": {
|
||||||
|
"apiVersion": {
|
||||||
|
"compatible": "2.0.0",
|
||||||
|
"target": "2.0.0",
|
||||||
|
"minVersion": "2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"debug": false,
|
||||||
|
"targets": {
|
||||||
|
"bip5": {
|
||||||
|
"module": {
|
||||||
|
"page": {
|
||||||
|
"pages": ["pages/home/index", "pages/status/index"]
|
||||||
|
},
|
||||||
|
"app-side": {
|
||||||
|
"path": "app-side/index"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"platforms": [
|
||||||
|
{
|
||||||
|
"name": "bip5",
|
||||||
|
"deviceSource": 8454400
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bip5-w",
|
||||||
|
"deviceSource": 8454401
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"designWidth": 380
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"i18n": {
|
||||||
|
"en-US": {
|
||||||
|
"appName": "ZeppSpace"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultLanguage": "en-US"
|
||||||
|
}
|
BIN
assets/bip5/icon.png
Normal file
BIN
assets/bip5/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
2
pages/home/i18n/en-US.po
Normal file
2
pages/home/i18n/en-US.po
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
msgid "example"
|
||||||
|
msgstr "This is an example in device"
|
78
pages/home/index.js
Normal file
78
pages/home/index.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import {
|
||||||
|
createWidget,
|
||||||
|
widget,
|
||||||
|
align,
|
||||||
|
updateStatusBarTitle,
|
||||||
|
event,
|
||||||
|
} from "@zos/ui";
|
||||||
|
import { log as Logger, px } from "@zos/utils";
|
||||||
|
import { push } from "@zos/router";
|
||||||
|
import {
|
||||||
|
DEFAULT_COLOR,
|
||||||
|
DEFAULT_COLOR_TRANSPARENT,
|
||||||
|
} from "../../utils/config/constants";
|
||||||
|
import { DEVICE_WIDTH } from "../../utils/config/device";
|
||||||
|
import VisLog from "@silver-zepp/vis-log";
|
||||||
|
const vis = new VisLog("index.js");
|
||||||
|
|
||||||
|
const logger = Logger.getLogger("ZeppSpace");
|
||||||
|
const { messageBuilder } = getApp()._options.globalData;
|
||||||
|
|
||||||
|
let spaces = {};
|
||||||
|
|
||||||
|
Page({
|
||||||
|
state: {},
|
||||||
|
build() {
|
||||||
|
updateStatusBarTitle("Spaces (Loading)");
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchData() {
|
||||||
|
messageBuilder
|
||||||
|
.request({
|
||||||
|
method: "GET_DIRECTORY",
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
vis.log("data received");
|
||||||
|
const statusSuccess = data["success"];
|
||||||
|
if (!statusSuccess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let spaceNames = Object.fromEntries(
|
||||||
|
Object.entries(data["result"]).sort(([a], [b]) => a.localeCompare(b)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let yPos = 70;
|
||||||
|
for (let key in spaceNames) {
|
||||||
|
if (spaceNames.hasOwnProperty(key)) {
|
||||||
|
spaces[key] = createWidget(widget.TEXT, {
|
||||||
|
x: 0,
|
||||||
|
y: px(yPos),
|
||||||
|
w: px(DEVICE_WIDTH),
|
||||||
|
h: px(50),
|
||||||
|
align_h: align.CENTER_H,
|
||||||
|
align_v: align.CENTER_V,
|
||||||
|
text_size: px(32),
|
||||||
|
color: 0xffffff,
|
||||||
|
text: key,
|
||||||
|
});
|
||||||
|
|
||||||
|
spaces[key].addEventListener(event.CLICK_UP, (info) => {
|
||||||
|
push({
|
||||||
|
url: "pages/status/index",
|
||||||
|
params: {
|
||||||
|
name: key,
|
||||||
|
url: spaceNames[key],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
yPos += 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStatusBarTitle("Spaces");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
2
pages/status/i18n/en-US.po
Normal file
2
pages/status/i18n/en-US.po
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
msgid "example"
|
||||||
|
msgstr "This is an example in device"
|
110
pages/status/index.js
Normal file
110
pages/status/index.js
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import { createWidget, widget, align, updateStatusBarTitle } from "@zos/ui";
|
||||||
|
import { log as Logger, px } from "@zos/utils";
|
||||||
|
import { back } from "@zos/router";
|
||||||
|
import {
|
||||||
|
DEFAULT_COLOR,
|
||||||
|
DEFAULT_COLOR_TRANSPARENT,
|
||||||
|
} from "../../utils/config/constants";
|
||||||
|
import { DEVICE_WIDTH } from "../../utils/config/device";
|
||||||
|
import VisLog from "@silver-zepp/vis-log";
|
||||||
|
const vis = new VisLog("index.js");
|
||||||
|
|
||||||
|
const logger = Logger.getLogger("ZeppSpace");
|
||||||
|
const { messageBuilder } = getApp()._options.globalData;
|
||||||
|
|
||||||
|
let title = "";
|
||||||
|
let url = "";
|
||||||
|
|
||||||
|
Page({
|
||||||
|
state: {},
|
||||||
|
onInit(params) {
|
||||||
|
const data = JSON.parse(params);
|
||||||
|
if (data["url"] == undefined || data["name"] == undefined) {
|
||||||
|
back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
title = data["name"];
|
||||||
|
url = data["url"];
|
||||||
|
},
|
||||||
|
build() {
|
||||||
|
updateStatusBarTitle(title + " (Loading)");
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchData() {
|
||||||
|
messageBuilder
|
||||||
|
.request({
|
||||||
|
method: "GET_STATUS",
|
||||||
|
url: url,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
const statusSuccess = data["success"];
|
||||||
|
if (!statusSuccess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let open = data["result"]["state"]["open"];
|
||||||
|
|
||||||
|
let openText = open ? "Yes" : "No";
|
||||||
|
|
||||||
|
createWidget(widget.TEXT, {
|
||||||
|
x: 0,
|
||||||
|
y: px(70),
|
||||||
|
w: px(DEVICE_WIDTH),
|
||||||
|
h: px(50),
|
||||||
|
align_h: align.CENTER_H,
|
||||||
|
align_v: align.CENTER_V,
|
||||||
|
text_size: px(32),
|
||||||
|
color: 0xffffff,
|
||||||
|
text: "Open: " + openText,
|
||||||
|
});
|
||||||
|
|
||||||
|
createWidget(widget.TEXT, {
|
||||||
|
x: 0,
|
||||||
|
y: px(120),
|
||||||
|
w: px(DEVICE_WIDTH),
|
||||||
|
h: px(50),
|
||||||
|
align_h: align.CENTER_H,
|
||||||
|
align_v: align.CENTER_V,
|
||||||
|
text_size: px(32),
|
||||||
|
color: 0xffffff,
|
||||||
|
text:
|
||||||
|
"Last Updated: " +
|
||||||
|
this.convertTime(data["result"]["state"]["lastchange"]),
|
||||||
|
});
|
||||||
|
|
||||||
|
updateStatusBarTitle(title);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
convertTime(timestamp) {
|
||||||
|
var a = new Date(timestamp * 1000);
|
||||||
|
var today = new Date();
|
||||||
|
var yesterday = new Date(Date.now() - 86400000);
|
||||||
|
var months = [
|
||||||
|
"Jan",
|
||||||
|
"Feb",
|
||||||
|
"Mar",
|
||||||
|
"Apr",
|
||||||
|
"May",
|
||||||
|
"Jun",
|
||||||
|
"Jul",
|
||||||
|
"Aug",
|
||||||
|
"Sep",
|
||||||
|
"Oct",
|
||||||
|
"Nov",
|
||||||
|
"Dec",
|
||||||
|
];
|
||||||
|
var year = a.getFullYear();
|
||||||
|
var month = months[a.getMonth()];
|
||||||
|
var date = a.getDate();
|
||||||
|
var hour = a.getHours() < 10 ? "0" + a.getHours() : a.getHours();
|
||||||
|
var min = a.getMinutes() < 10 ? "0" + a.getMinutes() : a.getMinutes();
|
||||||
|
if (a.setHours(0, 0, 0, 0) == today.setHours(0, 0, 0, 0))
|
||||||
|
return hour + ":" + min;
|
||||||
|
else if (a.setHours(0, 0, 0, 0) == yesterday.setHours(0, 0, 0, 0))
|
||||||
|
return "Yesterday, " + hour + ":" + min;
|
||||||
|
else if (year == today.getFullYear()) return date + " " + month;
|
||||||
|
else return date + " " + month + " " + year;
|
||||||
|
},
|
||||||
|
});
|
67
shared/data.js
Normal file
67
shared/data.js
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
export function json2buf(json) {
|
||||||
|
return str2buf(json2str(json))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function json2bin(json) {
|
||||||
|
return str2bin(json2str(json))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function len(binOrBuf) {
|
||||||
|
return binOrBuf.byteLength
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buf2json(buf) {
|
||||||
|
return str2json(buf2str(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function str2json(str) {
|
||||||
|
return JSON.parse(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function json2str(json) {
|
||||||
|
return JSON.stringify(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function str2buf(str) {
|
||||||
|
return Buffer.from(str, 'utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buf2str(buf) {
|
||||||
|
return buf.toString('utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bin2buf(bin) {
|
||||||
|
return Buffer.from(bin)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buf2bin(buf) {
|
||||||
|
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buf2hex(buf) {
|
||||||
|
return buf.toString('hex')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bin2hex(bin) {
|
||||||
|
return buf2hex(bin2buf(bin))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bin2json(bin) {
|
||||||
|
return buf2json(bin2buf(bin))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bin2str(bin) {
|
||||||
|
return buf2str(bin2buf(bin))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function str2bin(str) {
|
||||||
|
return buf2bin(str2buf(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function allocOfBin(size = 0) {
|
||||||
|
return Buffer.alloc(size).buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
export function allocOfBuf(size = 0) {
|
||||||
|
return Buffer.alloc(size)
|
||||||
|
}
|
35
shared/defer.js
Normal file
35
shared/defer.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
export function Deferred() {
|
||||||
|
const defer = {}
|
||||||
|
|
||||||
|
defer.promise = new Promise(function (resolve, reject) {
|
||||||
|
defer.resolve = resolve
|
||||||
|
defer.reject = reject
|
||||||
|
})
|
||||||
|
|
||||||
|
return defer
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delay(ms) {
|
||||||
|
const defer = Deferred()
|
||||||
|
|
||||||
|
setTimeout(defer.resolve, ms)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
}
|
||||||
|
|
||||||
|
export function timeout(ms, cb) {
|
||||||
|
const defer = Deferred()
|
||||||
|
ms = ms || 1000
|
||||||
|
|
||||||
|
const wait = setTimeout(() => {
|
||||||
|
clearTimeout(wait)
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
cb && cb(defer.resolve, defer.reject)
|
||||||
|
} else {
|
||||||
|
defer.reject('Timed out in ' + ms + 'ms.')
|
||||||
|
}
|
||||||
|
}, ms)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
}
|
6
shared/device-polyfill.js
Normal file
6
shared/device-polyfill.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import './es6-promise'
|
||||||
|
ES6Promise.polyfill()
|
||||||
|
|
||||||
|
Promise._setScheduler(function (flush) {
|
||||||
|
flush && flush()
|
||||||
|
})
|
1149
shared/es6-promise.js
Normal file
1149
shared/es6-promise.js
Normal file
File diff suppressed because it is too large
Load diff
42
shared/event.js
Normal file
42
shared/event.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
export class EventBus {
|
||||||
|
constructor() {
|
||||||
|
this.map = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
on(type, cb) {
|
||||||
|
if (this.map.has(type)) {
|
||||||
|
this.map.get(type).push(cb)
|
||||||
|
} else {
|
||||||
|
this.map.set(type, [cb])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
off(type, cb) {
|
||||||
|
if (type) {
|
||||||
|
if (cb) {
|
||||||
|
const cbs = this.map.get(type)
|
||||||
|
|
||||||
|
if (!cbs) return
|
||||||
|
const index = cbs.findIndex((i) => i === cb)
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
cbs.splice(index, 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.map.delete(type)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.map.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(type, ...args) {
|
||||||
|
for (let cb of this.map.get(type) ? this.map.get(type) : []) {
|
||||||
|
cb && cb(...args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count(type) {
|
||||||
|
return this.map.get(type) ? this.map.get(type).length : 0
|
||||||
|
}
|
||||||
|
}
|
1145
shared/message-side.js
Normal file
1145
shared/message-side.js
Normal file
File diff suppressed because it is too large
Load diff
1151
shared/message.js
Normal file
1151
shared/message.js
Normal file
File diff suppressed because it is too large
Load diff
2
utils/config/constants.js
Normal file
2
utils/config/constants.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export const DEFAULT_COLOR = 0xfc6950;
|
||||||
|
export const DEFAULT_COLOR_TRANSPARENT = 0xfeb4a8;
|
2
utils/config/device.js
Normal file
2
utils/config/device.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
import { getDeviceInfo } from "@zos/device";
|
||||||
|
export const { width: DEVICE_WIDTH, height: DEVICE_HEIGHT } = getDeviceInfo();
|
Loading…
Add table
Add a link
Reference in a new issue