Skip to content

Commit 716ad34

Browse files
author
g.gorbovskoy
committedJan 15, 2023
feat: notes app
1 parent 3d6a8fc commit 716ad34

22 files changed

+868
-36
lines changed
 

‎.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
.DS_Store
22
.vscode
33
node_modules
4-
yarn.lock
4+
yarn.lock
5+
build
6+
dist

‎app.json

+11-15
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"app": {
33
"appId": 1973010481,
44
"appIdType": 0,
5-
"appName": "notes",
5+
"appName": "BandNotes",
66
"appType": "app",
77
"description": "",
88
"icon": "icon.png",
9-
"vender": "root",
9+
"vender": "gbowsky",
1010
"version": {
1111
"code": 1,
1212
"name": "1.0.0"
@@ -18,25 +18,21 @@
1818
"module": {
1919
"page": {
2020
"pages": [
21-
"page/IndexPage"
22-
],
23-
"window": {
24-
"backgroundColor": "#eeeeee",
25-
"backgroundTextStyle": "light",
26-
"navigationBarBackgroundColor": "#ffffff",
27-
"navigationBarTextStyle": "black",
28-
"navigationBarTitleText": ""
29-
}
21+
"page/IndexPage",
22+
"page/ImagePage",
23+
"page/SettingsPage"
24+
]
3025
}
3126
},
32-
"permissions": [
33-
"gps"
34-
],
27+
"permissions": [],
3528
"runtime": {
3629
"apiVersion": {
3730
"compatible": "1.0.0",
3831
"minVersion": "1.0.0",
3932
"target": "1.0.1"
4033
}
41-
}
34+
},
35+
"externalFilesList": [
36+
"/storage/bn_settings.json"
37+
]
4238
}

‎assets/icon.png

8.48 KB
Loading

‎assets/icons/Slider/contrast.png

664 Bytes
Loading

‎assets/icons/Slider/size.png

483 Bytes
Loading

‎assets/icons/accept.png

913 Bytes
Loading

‎assets/icons/cancel.png

966 Bytes
Loading

‎assets/icons/chevron_back.png

238 Bytes
Loading

‎assets/icons/settings.png

1.01 KB
Loading

‎assets/notes.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[{
2+
"name": "Glasses",
3+
"content": "She needed glasses. It wasn't that she couldn't see without them, but what she could see with them. When she wore glasses, her eyes focused so deeply that she could see not only the physical but also beyond. It was like a superpower. But she needed glasses."
4+
}]

‎entrypoint.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
// Export module
2+
let currentScreen = null;
13
let __$$app$$__ = __$$hmAppManager$$__.currentApp;
2-
__$$module$$__ = __$$app$$__.current;
4+
let __$$module$$__ = __$$app$$__.current;
35
__$$module$$__.module = DeviceRuntimeCore.Page({
4-
onInit() {
6+
onInit(p) {
57
new IndexPage().start();
68
},
7-
onDestroy() {
8-
}
9+
onDestroy: () => {}
910
});

‎lib/defaults.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export const DEFAULT_SETTINGS = {
2+
contrast: 0,
3+
fontSize: 20,
4+
caffeinate: false,
5+
};
6+
7+
export const PLACEHOLDER = "Lorem Ipsum Dolor Sit Amet";
8+
9+
export const CONTRAST = [
10+
0x404040,
11+
0x636363,
12+
0xa6a6a6,
13+
0xd7d7d7,
14+
0xffffff,
15+
]

‎lib/fs.js

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
export class FsUtils {
2+
static writeText(fn, data) {
3+
if(!fn.startsWith("/storage")) fn = FsUtils.fullPath(fn);
4+
5+
try {
6+
hmFS.remove(fn);
7+
} catch(e) {}
8+
9+
const buffer = FsUtils.strToUtf8(data);
10+
const f = FsUtils.open(fn, hmFS.O_WRONLY | hmFS.O_CREAT);
11+
hmFS.write(f, buffer, 0, buffer.byteLength);
12+
hmFS.close(f);
13+
}
14+
15+
static read(fn, limit=false) {
16+
if(!fn.startsWith("/storage")) fn = FsUtils.fullPath(fn);
17+
const [st, e] = FsUtils.stat(fn);
18+
const f = FsUtils.open(fn, hmFS.O_RDONLY);
19+
20+
const size = limit ? limit : st.size;
21+
const data = new ArrayBuffer(size);
22+
hmFS.read(f, data, 0, size);
23+
hmFS.close(f);
24+
25+
return data;
26+
}
27+
28+
static fetchTextFile(fn, limit=false) {
29+
const data = FsUtils.read(fn, limit);
30+
31+
const view = new Uint8Array(data);
32+
let str = "";
33+
34+
return FsUtils.Utf8ArrayToStr(view);
35+
}
36+
37+
static stat(path) {
38+
path = FsUtils.fixPath(path);
39+
return hmFS.stat_asset(path);
40+
}
41+
42+
static fixPath(path) {
43+
if(path.startsWith("/storage")) {
44+
const statPath = "../../../" + path.substring(9);
45+
return statPath;
46+
}
47+
return path;
48+
}
49+
50+
static open(path, m) {
51+
if(path.startsWith("/storage")) {
52+
const statPath = "../../../" + path.substring(9);
53+
return hmFS.open_asset(statPath, m);
54+
}
55+
56+
return hmFS.open(path, m);
57+
}
58+
59+
static fetchJSON(fn) {
60+
const text = FsUtils.fetchTextFile(fn);
61+
return JSON.parse(text);
62+
}
63+
64+
static copy(source, dest) {
65+
try {
66+
hmFS.remove(dest);
67+
} catch(e) {}
68+
69+
const buffer = FsUtils.read(source);
70+
const f = FsUtils.open(dest, hmFS.O_WRONLY | hmFS.O_CREAT);
71+
hmFS.write(f, buffer, 0, buffer.byteLength);
72+
hmFS.close(f);
73+
}
74+
75+
static isFolder(path) {
76+
const [st, e] = FsUtils.stat(path);
77+
return (st.mode & 32768) == 0;
78+
}
79+
80+
static getSelfPath() {
81+
if(!FsUtils.selfPath) {
82+
const pkg = hmApp.packageInfo();
83+
const idn = pkg.appId.toString(16).padStart(8, "0").toUpperCase();
84+
return "/storage/js_" + pkg.type + "s/" + idn;
85+
}
86+
87+
return FsUtils.selfPath;
88+
}
89+
90+
static fullPath(path) {
91+
return FsUtils.getSelfPath() + "/assets/" + path;
92+
}
93+
94+
static rmTree(path) {
95+
if(!path.startsWith("/storage")) path = FsUtils.fullPath(path);
96+
97+
const [files, e] = hmFS.readdir(path);
98+
for(let i in files) {
99+
FsUtils.rmTree(path + "/" + files[i]);
100+
}
101+
102+
hmFS.remove(path);
103+
}
104+
105+
static copyTree(source, dest, removeSource) {
106+
if(!source.startsWith("/storage")) source = FsUtils.fullPath(source);
107+
if(!dest.startsWith("/storage")) dest = FsUtils.fullPath(dest);
108+
109+
if(!FsUtils.isFolder(source)) {
110+
console.log("copy", source, "->", dest);
111+
FsUtils.copy(source, dest);
112+
} else {
113+
const [files, e] = hmFS.readdir(source);
114+
hmFS.mkdir(dest);
115+
for(let i in files) {
116+
FsUtils.copyTree(source + "/" + files[i], dest + "/" + files[i], removeSource);
117+
}
118+
}
119+
120+
if(removeSource) {
121+
console.log("Delete", source);
122+
hmFS.remove(source);
123+
}
124+
}
125+
126+
static sizeTree(path) {
127+
if(!path.startsWith("/storage")) path = FsUtils.fullPath(path);
128+
129+
const [files, e] = hmFS.readdir(path);
130+
let value = 0;
131+
132+
for(let fn in files) {
133+
const file = path + "/" + files[fn];
134+
const statPath = "../../../" + file.substring(9);
135+
const [st, e] = hmFS.stat_asset(statPath);
136+
value += st.size ? st.size : FsUtils.sizeTree(file);
137+
}
138+
139+
return value;
140+
}
141+
142+
// https://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
143+
static strToUtf8(str) {
144+
var utf8 = [];
145+
for (var i=0; i < str.length; i++) {
146+
var charcode = str.charCodeAt(i);
147+
if (charcode < 0x80) utf8.push(charcode);
148+
else if (charcode < 0x800) {
149+
utf8.push(0xc0 | (charcode >> 6),
150+
0x80 | (charcode & 0x3f));
151+
} else if (charcode < 0xd800 || charcode >= 0xe000) {
152+
utf8.push(0xe0 | (charcode >> 12),
153+
0x80 | ((charcode>>6) & 0x3f),
154+
0x80 | (charcode & 0x3f));
155+
} else {
156+
i++;
157+
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
158+
| (str.charCodeAt(i) & 0x3ff));
159+
utf8.push(0xf0 | (charcode >>18),
160+
0x80 | ((charcode>>12) & 0x3f),
161+
0x80 | ((charcode>>6) & 0x3f),
162+
0x80 | (charcode & 0x3f));
163+
}
164+
}
165+
166+
return new Uint8Array(utf8).buffer;
167+
}
168+
169+
// source: https://stackoverflow.com/questions/13356493/decode-utf-8-with-javascript
170+
static Utf8ArrayToStr(array) {
171+
var out, i, len, c;
172+
var char2, char3;
173+
174+
out = "";
175+
len = array.length;
176+
i = 0;
177+
while (i < len) {
178+
c = array[i++];
179+
switch (c >> 4) {
180+
case 0:
181+
case 1:
182+
case 2:
183+
case 3:
184+
case 4:
185+
case 5:
186+
case 6:
187+
case 7:
188+
// 0xxxxxxx
189+
out += String.fromCharCode(c);
190+
break;
191+
case 12:
192+
case 13:
193+
// 110x xxxx 10xx xxxx
194+
char2 = array[i++];
195+
out += String.fromCharCode(
196+
((c & 0x1f) << 6) | (char2 & 0x3f)
197+
);
198+
break;
199+
case 14:
200+
// 1110 xxxx 10xx xxxx 10xx xxxx
201+
char2 = array[i++];
202+
char3 = array[i++];
203+
out += String.fromCharCode(
204+
((c & 0x0f) << 12) |
205+
((char2 & 0x3f) << 6) |
206+
((char3 & 0x3f) << 0)
207+
);
208+
break;
209+
}
210+
}
211+
212+
return out;
213+
}
214+
215+
static printBytes(val) {
216+
if(this.fsUnitCfg === undefined)
217+
this.fsUnitCfg = hmFS.SysProGetBool("mmk_tb_fs_unit");
218+
219+
const options = this.fsUnitCfg ? ["B", "KiB", "MiB"] : ["B", "KB", "MB"];
220+
const base = this.fsUnitCfg ? 1024 : 1000;
221+
222+
let curr = 0;
223+
while (val > 800 && curr < options.length) {
224+
val = val / base;
225+
curr++;
226+
}
227+
228+
return Math.round(val * 100) / 100 + " " + options[curr];
229+
}
230+
}

‎lib/settings.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { DEFAULT_SETTINGS } from "./defaults";
2+
import { FsUtils } from "./fs";
3+
4+
const SETTINGS_PATH = "/storage/bn_settings.json";
5+
6+
export function loadSettings() {
7+
let result;
8+
9+
try {
10+
result = FsUtils.fetchJSON(SETTINGS_PATH);
11+
} catch {
12+
result = DEFAULT_SETTINGS;
13+
FsUtils.writeText(SETTINGS_PATH, JSON.stringify(DEFAULT_SETTINGS));
14+
}
15+
16+
return result;
17+
}
18+
19+
export function saveSettings({
20+
fontSize,
21+
caffeinate,
22+
contrast,
23+
}) {
24+
const newSettings = {
25+
contrast,
26+
fontSize,
27+
caffeinate,
28+
};
29+
30+
FsUtils.writeText(SETTINGS_PATH, JSON.stringify(newSettings));
31+
}

‎lib/touch.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
export class TouchEventManager {
2+
ontouch = null;
3+
onlongtouch = null;
4+
onlongtouchrepeatly = null;
5+
ontouchdown = null;
6+
ontouchup = null;
7+
ontouchmove = null;
8+
9+
constructor(widget) {
10+
this._init(widget);
11+
}
12+
13+
_init(widget) {
14+
let handleClick = true;
15+
let timerLongTap = -1;
16+
17+
widget.addEventListener(hmUI.event.CLICK_UP, (e) => {
18+
if(this.ontouchup) this.ontouchup(e);
19+
if(handleClick && this.ontouch) this.ontouch(e);
20+
21+
handleClick = false;
22+
timer.stopTimer(timerLongTap);
23+
});
24+
25+
widget.addEventListener(hmUI.event.CLICK_DOWN, (e) => {
26+
if(this.ontouchdown) this.ontouchdown(e);
27+
28+
handleClick = true;
29+
timerLongTap = timer.createTimer(750, 150, () => {
30+
if(handleClick && this.onlongtouch) {
31+
this.onlongtouch(e);
32+
handleClick = false;
33+
}
34+
35+
if(this.onlongtouchrepeatly)
36+
this.onlongtouchrepeatly(e);
37+
})
38+
});
39+
40+
widget.addEventListener(hmUI.event.MOVE, (e) => {
41+
if(this.ontouchmove) this.ontouchmove(e);
42+
43+
handleClick = false;
44+
timer.stopTimer(timerLongTap);
45+
})
46+
}
47+
}

‎lib/ui.js

+224
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
import { TouchEventManager } from './touch';
2+
import {
3+
UI_HEADER_GROUP_WIDGET_STYLE,
4+
UI_HEADER_TITLE_FULL_WIDGET_STYLE,
5+
UI_HEADER_SUBTITLE_WIDGET_STYLE,
6+
UI_HEADER_TITLE_ONLY_WIDGET_STYLE,
7+
UI_SIMPLELIST_DIMENS_STYLE,
8+
UI_SIMPLELIST_CONTROL_SETTINGS,
9+
UI_ASSET_SETTINGS_56,
10+
UI_ASSET_ACCEPT_56,
11+
UI_ASSET_CANCEL_56,
12+
UI_ICON_56_BOTTOM_DIMENS,
13+
UI_BUTTON_WIDGET_STYLE
14+
} from './ui.styles';
15+
16+
export function Header({
17+
title = 'Title',
18+
subtitle,
19+
onBack,
20+
}) {
21+
const group = hmUI.createWidget(hmUI.widget.GROUP, UI_HEADER_GROUP_WIDGET_STYLE);
22+
23+
if (subtitle) {
24+
group.createWidget(hmUI.widget.TEXT, {
25+
...UI_HEADER_TITLE_FULL_WIDGET_STYLE,
26+
text: title,
27+
});
28+
29+
group.createWidget(hmUI.widget.TEXT, {
30+
...UI_HEADER_SUBTITLE_WIDGET_STYLE,
31+
text: subtitle,
32+
});
33+
34+
return group;
35+
}
36+
37+
if (onBack) {
38+
group.createWidget(hmUI.widget.IMG, {
39+
x: 6,
40+
y: 70,
41+
w: 10,
42+
h: 18,
43+
src: 'icons/chevron_back.png'
44+
});
45+
46+
group.createWidget(hmUI.widget.TEXT, {
47+
...UI_HEADER_TITLE_ONLY_WIDGET_STYLE,
48+
x: 16,
49+
w: 192 - 16,
50+
text: title,
51+
});
52+
53+
const tappable = group.createWidget(hmUI.widget.IMG, {
54+
x: 0,
55+
y: 0,
56+
w: 192,
57+
h: 96,
58+
src: '',
59+
});
60+
61+
const touchManager = new TouchEventManager(tappable);
62+
touchManager.ontouch = onBack;
63+
64+
return group;
65+
}
66+
67+
group.createWidget(hmUI.widget.TEXT, {
68+
...UI_HEADER_TITLE_ONLY_WIDGET_STYLE,
69+
text: title,
70+
});
71+
72+
return group;
73+
}
74+
75+
export function Bottom({ icon, onClick }) {
76+
let style = {
77+
text: '',
78+
click_func: onClick,
79+
...UI_ICON_56_BOTTOM_DIMENS,
80+
}
81+
82+
hmUI.createWidget(hmUI.widget.FILL_RECT, {
83+
...UI_ICON_56_BOTTOM_DIMENS,
84+
})
85+
86+
switch (icon) {
87+
case 'settings':
88+
style.normal_src = UI_ASSET_SETTINGS_56;
89+
style.press_src = UI_ASSET_SETTINGS_56;
90+
break;
91+
case 'cancel':
92+
style.normal_src = UI_ASSET_CANCEL_56;
93+
style.press_src = UI_ASSET_CANCEL_56;
94+
break;
95+
default:
96+
style.normal_src = UI_ASSET_ACCEPT_56;
97+
style.press_src = UI_ASSET_ACCEPT_56;
98+
}
99+
100+
return hmUI.createWidget(hmUI.widget.BUTTON, style);
101+
}
102+
103+
export function SimpleList(
104+
list = [],
105+
onClick = (list, index) => { console.log(index) },
106+
paddingTop = 0,
107+
paddingBottom = 0,
108+
) {
109+
return hmUI.createWidget(hmUI.widget.SCROLL_LIST, {
110+
...UI_SIMPLELIST_DIMENS_STYLE({ paddingTop, paddingBottom }),
111+
...UI_SIMPLELIST_CONTROL_SETTINGS,
112+
data_array: list,
113+
data_count: list.length,
114+
item_click_func: onClick,
115+
data_type_config: [{
116+
start: 0,
117+
end: list.length - 1,
118+
type_id: 1
119+
}],
120+
data_type_config_count: 1
121+
});
122+
}
123+
124+
export function Slider({
125+
x,
126+
y,
127+
mode,
128+
onIncrement,
129+
onDecrement,
130+
}) {
131+
const group = hmUI.createWidget(hmUI.widget.GROUP, {
132+
x,
133+
y,
134+
w: 192,
135+
h: 64,
136+
});
137+
138+
group.createWidget(hmUI.widget.FILL_RECT, {
139+
color: 0x1c1c1c,
140+
radius: 16,
141+
x: 0,
142+
y: 0,
143+
w: 192,
144+
h: 64,
145+
})
146+
147+
group.createWidget(hmUI.widget.BUTTON, {
148+
x: 0,
149+
y: 0,
150+
w: 192 / 3,
151+
h: 64,
152+
text: '-',
153+
text_size: 24,
154+
...UI_BUTTON_WIDGET_STYLE,
155+
click_func: onDecrement,
156+
});
157+
158+
group.createWidget(hmUI.widget.FILL_RECT, {
159+
color: 0x3c3c3c,
160+
radius: 0,
161+
x: 192 / 3 - 2,
162+
y: (64 - 36) / 2,
163+
w: 1,
164+
h: 36,
165+
})
166+
167+
switch (mode) {
168+
case 'size':
169+
group.createWidget(hmUI.widget.IMG, {
170+
x: 192 / 3,
171+
y: 0,
172+
w: 192 / 3,
173+
h: 64,
174+
pos_y: (64 - 19) / 2,
175+
pos_x: (64 - 30) / 2,
176+
src: 'icons/Slider/size.png'
177+
});
178+
break
179+
default:
180+
case 'contrast':
181+
group.createWidget(hmUI.widget.IMG, {
182+
x: 192 / 3,
183+
y: 0,
184+
w: 192 / 3,
185+
h: 64,
186+
pos_y: (64 - 18) / 2,
187+
pos_x: (64 - 34) / 2,
188+
src: 'icons/Slider/contrast.png'
189+
});
190+
}
191+
192+
group.createWidget(hmUI.widget.FILL_RECT, {
193+
color: 0x3c3c3c,
194+
radius: 0,
195+
x: 192 / 3 * 2 - 1,
196+
y: (64 - 36) / 2,
197+
w: 1,
198+
h: 36,
199+
})
200+
201+
202+
group.createWidget(hmUI.widget.BUTTON, {
203+
x: 192 / 3 * 2,
204+
y: 0,
205+
w: 192 / 3,
206+
h: 64,
207+
text: '+',
208+
text_size: 24,
209+
...UI_BUTTON_WIDGET_STYLE,
210+
click_func: onIncrement,
211+
});
212+
}
213+
214+
export function Button(x, y, w, h, text, onClick) {
215+
return hmUI.createWidget(hmUI.widget.BUTTON, {
216+
click_func: onClick,
217+
text: text,
218+
x: x,
219+
y: y,
220+
w: w,
221+
h: h,
222+
...UI_BUTTON_WIDGET_STYLE,
223+
});
224+
}

‎lib/ui.styles.js

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
const UI_WIDTH = 192;
2+
const UI_HEIGHT = 490;
3+
const UI_ROUND_ZONE_HEIGHT = 96;
4+
5+
const UI_CHEVRON_WIDTH = 10;
6+
const UI_CORNER_RADIUS = 16;
7+
const UI_VERTICAL_SPACING = 12;
8+
const UI_CONTROL_HEIGHT = 64;
9+
10+
const UI_TITLE_FONT_SIZE = 24;
11+
const UI_SUBTITLE_FONT_SIZE = 20;
12+
const UI_PRIMARY_FOREGROUND = 0xFFFFFF;
13+
const UI_SECONDARY_FOREGROUND = 0xC1C1C1;
14+
15+
const UI_SECONDARY_BACKGROUND = 0x1C1C1C;
16+
const UI_ACTIVE_BACKGROUND = 0x2C2C2C;
17+
18+
const UI_TITLE_TEXT_STYLE = {
19+
text_size: UI_TITLE_FONT_SIZE,
20+
align_h: hmUI.align.CENTER_H,
21+
align_v: hmUI.align.BOTTOM,
22+
color: UI_PRIMARY_FOREGROUND,
23+
};
24+
25+
const UI_SUBTITLE_TEXT_STYLE = {
26+
text_size: UI_SUBTITLE_FONT_SIZE,
27+
align_h: hmUI.align.CENTER_H,
28+
align_v: hmUI.align.CENTER_V,
29+
color: UI_SECONDARY_FOREGROUND,
30+
};
31+
32+
export const UI_HEADER_GROUP_WIDGET_STYLE = {
33+
h: UI_ROUND_ZONE_HEIGHT,
34+
w: UI_WIDTH,
35+
x: 0,
36+
y: 0,
37+
};
38+
39+
const UI_HEADER_TITLE_W_SUB_DIMENS_STYLE = {
40+
w: UI_WIDTH,
41+
h: UI_ROUND_ZONE_HEIGHT - UI_SUBTITLE_FONT_SIZE,
42+
x: 0,
43+
y: 0,
44+
};
45+
46+
const UI_HEADER_SUBTITLE_DIMENS_STYLE = {
47+
w: UI_WIDTH,
48+
h: UI_SUBTITLE_FONT_SIZE,
49+
x: 0,
50+
y: UI_HEADER_TITLE_W_SUB_DIMENS_STYLE.h,
51+
};
52+
53+
/* Header({}) */
54+
55+
export const UI_HEADER_TITLE_FULL_WIDGET_STYLE = {
56+
...UI_TITLE_TEXT_STYLE,
57+
...UI_HEADER_TITLE_W_SUB_DIMENS_STYLE,
58+
};
59+
60+
export const UI_HEADER_SUBTITLE_WIDGET_STYLE = {
61+
...UI_SUBTITLE_TEXT_STYLE,
62+
...UI_HEADER_SUBTITLE_DIMENS_STYLE,
63+
};
64+
65+
export const UI_HEADER_TITLE_ONLY_WIDGET_STYLE = {
66+
...UI_TITLE_TEXT_STYLE,
67+
...UI_HEADER_GROUP_WIDGET_STYLE,
68+
};
69+
70+
/* SimpleList({}) */
71+
72+
const UI_SIMPLELIST_TEXT_VIEW_STYLE = {
73+
x: 0,
74+
y: 0,
75+
w: UI_WIDTH,
76+
h: UI_CONTROL_HEIGHT,
77+
key: 'name',
78+
color: UI_PRIMARY_FOREGROUND,
79+
text_size: UI_TITLE_FONT_SIZE,
80+
}
81+
82+
const UI_SIMPLELIST_CONTROL_STYLE = {
83+
type_id: 1,
84+
item_bg_color: UI_SECONDARY_BACKGROUND,
85+
item_bg_radius: UI_CORNER_RADIUS,
86+
text_view: [UI_SIMPLELIST_TEXT_VIEW_STYLE],
87+
text_view_count: 1,
88+
item_height: UI_CONTROL_HEIGHT,
89+
}
90+
91+
export const UI_SIMPLELIST_CONTROL_SETTINGS = {
92+
item_space: UI_VERTICAL_SPACING,
93+
item_config: [UI_SIMPLELIST_CONTROL_STYLE],
94+
item_config_count: 1,
95+
}
96+
97+
export const UI_SIMPLELIST_DIMENS_STYLE = ({paddingTop, paddingBottom}) => ({
98+
x: paddingTop,
99+
y: 96 + paddingTop,
100+
h: UI_HEIGHT - UI_ROUND_ZONE_HEIGHT - paddingTop - paddingBottom,
101+
w: 192,
102+
})
103+
104+
/* Button({}) */
105+
106+
export const UI_BUTTON_WIDGET_STYLE = {
107+
normal_color: UI_SECONDARY_BACKGROUND,
108+
press_color: UI_ACTIVE_BACKGROUND,
109+
radius: UI_CORNER_RADIUS,
110+
}
111+
112+
/* Top and bottom buttons */
113+
114+
export const UI_ICON_56_SIZES = {
115+
w: 56,
116+
h: 56,
117+
};
118+
119+
export const UI_ICON_56_TOP_DIMENS = {
120+
x: 68,
121+
y: 26,
122+
...UI_ICON_56_SIZES,
123+
};
124+
125+
export const UI_ICON_56_BOTTOM_DIMENS = {
126+
x: 0,
127+
y: UI_HEIGHT - UI_ROUND_ZONE_HEIGHT,
128+
w: UI_WIDTH,
129+
h: UI_ROUND_ZONE_HEIGHT,
130+
color: UI_SECONDARY_BACKGROUND,
131+
};
132+
133+
export const UI_ASSET_CANCEL_56 = 'icons/cancel.png';
134+
export const UI_ASSET_ACCEPT_56 = 'icons/accept.png';
135+
export const UI_ASSET_SETTINGS_56 = 'icons/settings.png';

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"dependencies": {},
33
"devDependencies": {
4+
"esbuild": "^0.17.0",
45
"zeppos-device-types-v1": "^1.0.9"
56
}
67
}

‎page/IndexPage.js

+29-14
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,38 @@
1+
import { FsUtils } from "../lib/fs";
2+
import { Bottom, Header, SimpleList } from "../lib/ui";
3+
14
class IndexPage {
2-
start() {
3-
hmUI.createWidget(hmUI.widget.TEXT, {
4-
x: 0,
5-
y: 0,
6-
w: 196,
7-
h: 96,
8-
text: 'hello world',
9-
fontSize: 16,
10-
align_h: hmUI.align.CENTER_H,
11-
align_v: hmUI.align.CENTER_V,
12-
color: 0xffffff,
13-
});
14-
}
5+
openSettings() {
6+
hmApp.gotoPage({
7+
url: 'page/SettingsPage',
8+
});
9+
}
10+
openNote(index) {
11+
hmApp.gotoPage({
12+
url: 'page/NotePage',
13+
param: index,
14+
});
15+
}
16+
start() {
17+
this.data = FsUtils.fetchJSON("notes.json");
18+
19+
Header({
20+
title: 'BandNotes',
21+
})
22+
SimpleList(this.data, (_, index) => {
23+
this.openNote(index);
24+
}, 0, 96);
25+
26+
Bottom({ icon: 'settings', onClick: () => {
27+
this.openSettings();
28+
}});
29+
}
1530
}
1631

1732
let __$$app$$__ = __$$hmAppManager$$__.currentApp;
1833
__$$module$$__ = __$$app$$__.current;
1934
__$$module$$__.module = DeviceRuntimeCore.Page({
20-
onInit(p) {
35+
onInit() {
2136
new IndexPage().start();
2237
}
2338
});

‎page/NotePage.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { CONTRAST } from "../lib/defaults";
2+
import { FsUtils } from "../lib/fs";
3+
import { loadSettings } from "../lib/settings";
4+
import { Header } from "../lib/ui";
5+
6+
class NotePage {
7+
constructor(index) {
8+
this.start(FsUtils.fetchJSON("notes.json")[index]);
9+
}
10+
11+
start(note) {
12+
const { fontSize, contrast } = loadSettings();
13+
const { name, content } = note;
14+
const { height } = hmUI.getTextLayout(content, {
15+
text_size: fontSize,
16+
text_width: 192,
17+
wrapped: 1,
18+
});
19+
20+
Header({
21+
title: name,
22+
leftIcon: true,
23+
});
24+
25+
hmUI.createWidget(hmUI.widget.TEXT, {
26+
x: 0,
27+
y: 96,
28+
h: height + 96,
29+
w: 192,
30+
text: content,
31+
color: CONTRAST[contrast],
32+
text_size: fontSize,
33+
text_style: hmUI.text_style.WRAP,
34+
});
35+
}
36+
}
37+
38+
let __$$app$$__ = __$$hmAppManager$$__.currentApp;
39+
__$$module$$__ = __$$app$$__.current;
40+
__$$module$$__.module = DeviceRuntimeCore.Page({
41+
onInit(index) {
42+
new NotePage(index);
43+
}
44+
});

‎page/SettingsPage.js

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { CONTRAST, PLACEHOLDER } from "../lib/defaults";
2+
import { loadSettings, saveSettings } from "../lib/settings";
3+
import { Bottom, Header, Slider } from "../lib/ui";
4+
5+
class SettingsPage {
6+
onSizeDecrement() {
7+
if (this.settings.fontSize >= 14) {
8+
this.settings.fontSize -= 2;
9+
this.text.setProperty(hmUI.prop.TEXT_SIZE, this.settings.fontSize);
10+
}
11+
}
12+
13+
onSizeIncrement() {
14+
if (this.settings.fontSize <= 32) {
15+
this.settings.fontSize += 2;
16+
this.text.setProperty(hmUI.prop.TEXT_SIZE, this.settings.fontSize);
17+
}
18+
}
19+
20+
onContrastDecrement() {
21+
if (this.settings.contrast - 1 >= 0) {
22+
this.settings.contrast --;
23+
this.text.setProperty(hmUI.prop.COLOR, CONTRAST[this.settings.contrast]);
24+
}
25+
}
26+
27+
onContrastIncrement() {
28+
if (this.settings.contrast + 1 <= 4) {
29+
this.settings.contrast ++;
30+
this.text.setProperty(hmUI.prop.COLOR, CONTRAST[this.settings.contrast]);
31+
}
32+
}
33+
34+
start() {
35+
this.settings = loadSettings();
36+
37+
Header({
38+
title: 'Settings',
39+
onBack: () => hmApp.goBack(),
40+
})
41+
42+
this.text = hmUI.createWidget(hmUI.widget.TEXT, {
43+
x: 0,
44+
y: 96 + 12,
45+
h: 100,
46+
w: 192,
47+
text: PLACEHOLDER,
48+
text_size: this.settings.fontSize,
49+
color: CONTRAST[this.settings.contrast],
50+
text_style: hmUI.text_style.WRAP,
51+
});
52+
53+
Slider({
54+
x: 0,
55+
y: 96 + 112 + 12,
56+
onIncrement: () => this.onSizeIncrement(),
57+
onDecrement: () => this.onSizeDecrement(),
58+
mode: 'size'
59+
})
60+
61+
Slider({
62+
x: 0,
63+
y: 96 + 112 + 12 + 64 + 12,
64+
onIncrement: () => this.onContrastIncrement(),
65+
onDecrement: () => this.onContrastDecrement(),
66+
mode: 'contrast'
67+
})
68+
69+
Bottom({
70+
onClick: () => {
71+
saveSettings(this.settings);
72+
hmApp.goBack();
73+
}
74+
});
75+
}
76+
}
77+
78+
let __$$app$$__ = __$$hmAppManager$$__.currentApp;
79+
__$$module$$__ = __$$app$$__.current;
80+
__$$module$$__.module = DeviceRuntimeCore.Page({
81+
onInit(p) {
82+
new SettingsPage().start();
83+
}
84+
});

‎zmake.json

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
{
2-
"esbuild": false,
3-
"esbuild_params": "--bundle"
2+
"esbuild": true,
3+
"esbuild_params": "--bundle",
4+
"adb_install": true,
5+
"adb_path": "/storage/emulated/0/Download/",
6+
"add_preview_asset": true
47
}

0 commit comments

Comments
 (0)
Please sign in to comment.