Skip to content

Commit ebee5c9

Browse files
author
thyttan
committed
Merge branch 'messagegui' into app-loader
2 parents d47d0b0 + 76ddfc5 commit ebee5c9

File tree

3 files changed

+161
-23
lines changed

3 files changed

+161
-23
lines changed

apps/messagegui/ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,4 @@
113113
0.82: Stop buzzing when a message is removed (e.g. call answered)
114114
0.83: Add option to not open the first unread message
115115
0.84: Fix: Assign show message entry to the settings menu and not the message itself.
116+
0.85: (WIP) refactor to display a scroller with three messages loaded. When scrolling to the top or end new/older messages are loaded in.

apps/messagegui/app.js

Lines changed: 159 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ var onMessagesModified = function(type,msg) {
9090
}
9191
if (msg && msg.id=="nav" && msg.t=="modify" && active!="map")
9292
return; // don't show an updated nav message if we're just in the menu
93-
showMessage(msg&&msg.id, false);
93+
showMessagesScroller(msg, false)
9494
};
9595
Bangle.on("message", onMessagesModified);
9696

@@ -246,32 +246,169 @@ function showMusicMessage(msg) {
246246
}, 400);
247247
}
248248

249-
function showMessageScroller(msg) {
250-
cancelReloadTimeout();
249+
function showMessagesScroller(msg, persist, alreadyProcessed) {
250+
if (persist===undefined) {persist = true;}
251+
const MSG_IDX = msg ? MESSAGES.findIndex((m)=>m.id==msg.id) : 0;
252+
const INITIATED_FROM = (
253+
alreadyProcessed===undefined ? "other function" :
254+
(MSG_IDX<=alreadyProcessed.idxSpan.start ? "scrolling up" :
255+
(MSG_IDX >= alreadyProcessed.idxSpan.stop-1 ? "scrolling down" :
256+
undefined))
257+
);
258+
if (!alreadyProcessed) {alreadyProcessed = {idxSpan:{}};} // So `alreadyProcessed.idxSpan.start/stop` can be looked for on first run.
259+
260+
const WU = require("widget_utils");
261+
WU.hide();
262+
263+
if (replying) { return; }
264+
if (persist) {cancelReloadTimeout();} else {resetReloadTimeout();}
265+
266+
let idxSpan = (
267+
INITIATED_FROM==="other function" ?
268+
{start : Math.max(MSG_IDX-1, 0), stop : Math.min(MSG_IDX+2, MESSAGES.length)} :
269+
(INITIATED_FROM==="scrolling up" ?
270+
{start : MSG_IDX, stop : alreadyProcessed.idxSpan.start } :
271+
(INITIATED_FROM==="scrolling down" ?
272+
{ start : alreadyProcessed.idxSpan.stop, stop : Math.min(MSG_IDX+1, MESSAGES.length) } :
273+
undefined))
274+
);
275+
251276
active = "scroller";
252277
var bodyFont = fontBig;
253278
g.setFont(bodyFont);
254-
var lines = [];
255-
if (msg.title) lines = g.wrapString(msg.title, g.getWidth()-10);
256-
var titleCnt = lines.length;
257-
if (titleCnt) lines.push(""); // add blank line after title
258-
lines = lines.concat(g.wrapString(msg.body, g.getWidth()-10),["",/*LANG*/"< Back"]);
279+
var titleLines = [];
280+
var messagesWrapped = [];
281+
for (let i=idxSpan.start ; i<idxSpan.stop ; i++) {
282+
let msgLocal = MESSAGES[i];
283+
msgLocal.new = false;
284+
285+
if (msgLocal.id=="music" || msgLocal.source=="maps" || msgLocal.id =="call") {
286+
idxSpan.stop++
287+
if (idxSpan.stop>=MESSAGES.length) {break;}
288+
continue;
289+
}
290+
291+
var lines = [];
292+
const TITLE_STRING = msgLocal.title||msgLocal.sender||msgLocal.subject||msgLocal.src||"No Title";
293+
//const TITLE_STRING = "".concat(msgLocal.title, msgLocal.title&&"\n",
294+
// msgLocal.sender, msgLocal.sender&&"\n",
295+
// msgLocal.subject, msgLocal.subject&&"\n", msgLocal.src) || "No Title";
296+
lines = g.wrapString(TITLE_STRING, g.getWidth()-10);
297+
for (let i=0; i<lines.length; i++) {
298+
titleLines.push(i + (messagesWrapped[0]?messagesWrapped[0].length:0) +
299+
(messagesWrapped[1]?messagesWrapped[1].length:0));
300+
}
301+
lines = lines.concat(g.wrapString(msgLocal.body, g.getWidth()-10),
302+
["-".repeat(12)]);
303+
messagesWrapped.push(lines);
304+
}
305+
306+
let allLines = [];
307+
for (let i=0 ; i<messagesWrapped.length ; i++) {
308+
allLines = allLines.concat(messagesWrapped[i]);
309+
}
310+
311+
var initScroll = messagesWrapped[0].length;
312+
if (INITIATED_FROM === "other function") {
313+
if (MSG_IDX==0) {initScroll = 0;}
314+
} else if (INITIATED_FROM === "scrolling up") {
315+
titleLines = titleLines.concat(alreadyProcessed.titleLines.
316+
map((x) => x + allLines.length));
317+
allLines = allLines.concat(alreadyProcessed.lines);
318+
} else if (INITIATED_FROM === "scrolling down") {
319+
initScroll = alreadyProcessed.lines.length-(g.getHeight()/g.getFontHeight());
320+
titleLines = alreadyProcessed.titleLines.concat(titleLines.
321+
map((x) => x + alreadyProcessed.lines.length));
322+
allLines = alreadyProcessed.lines.concat(allLines);
323+
}
324+
325+
if (allLines.length == 0 && alreadyProcessed.lines.length == 0) {
326+
cancelReloadTimeout();
327+
returnToClockIfEmpty();
328+
}
329+
330+
alreadyProcessed = { // Update with the newly processed messages.
331+
lines : allLines,
332+
titleLines : titleLines,
333+
idxSpan: {
334+
start : Math.min(idxSpan.start,
335+
(alreadyProcessed.idxSpan.start===undefined) ?
336+
MESSAGES.length : alreadyProcessed.idxSpan.start),
337+
stop : Math.max(idxSpan.stop, alreadyProcessed.idxSpan.stop||0)}
338+
};
339+
340+
function identifyDisplayedMsg(scrollIdx) {
341+
let firstTitleLinePerMsg = [titleLines[0]];
342+
for (let i=1; i<titleLines.length; i++) {
343+
if (titleLines[i]-titleLines[i-1] === 1) {continue;}
344+
firstTitleLinePerMsg.push(titleLines[i]);
345+
}
346+
for (let i=titleLines.length-1; i>=0 ; i--) {
347+
if (scrollIdx>=firstTitleLinePerMsg[i]) {
348+
return MESSAGES[i + alreadyProcessed.idxSpan.start];
349+
}
350+
}
351+
}
352+
353+
let prevScrollIdx; // Used for stopping repeated triggering of next message by the scroller.
354+
let prevPrevScrollIdx; // Used to choose how to identify displayed message when selecting with button.
355+
259356
E.showScroller({
357+
scroll : initScroll*g.getFontHeight(),
260358
h : g.getFontHeight(), // height of each menu item in pixels
261-
c : lines.length, // number of menu items
359+
c : allLines.length, // number of menu items
262360
// a function to draw a menu item
263-
draw : function(idx, r) {
264-
// FIXME: in 2v13 onwards, clearRect(r) will work fine. There's a bug in 2v12
265-
g.setBgColor(idx<titleCnt ? g.theme.bg2 : g.theme.bg).
266-
setColor(idx<titleCnt ? g.theme.fg2 : g.theme.fg).
267-
clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
268-
g.setFont(bodyFont).setFontAlign(0,-1).drawString(lines[idx], r.x+r.w/2, r.y);
269-
}, select : function(idx) {
270-
if (idx>=lines.length-2)
271-
showMessage(msg.id, true);
361+
draw : function(scrollIdx, r) {
362+
"ram";
363+
g.setBgColor(titleLines.find(e=>e==scrollIdx)!==undefined ? g.theme.bg2 : g.theme.bg).
364+
setColor(titleLines.find(e=>e==scrollIdx)!==undefined ? g.theme.fg2 : g.theme.fg).
365+
clearRect(r);
366+
g.setFont(bodyFont).setFontAlign(0,-1).drawString(allLines[scrollIdx], r.x+r.w/2, r.y);
367+
// Load in next/previous message on demand by reinitializing showMessagesScroller while passing on the processed messages.
368+
if (scrollIdx>=allLines.length-1 && scrollIdx!=prevScrollIdx &&
369+
alreadyProcessed.idxSpan.stop<MESSAGES.length) {
370+
setTimeout(() => {
371+
E.showScroller();
372+
if (BTN_WATCH) {clearWatch(BTN_WATCH);}
373+
showMessagesScroller(MESSAGES[alreadyProcessed.idxSpan.stop],
374+
true, alreadyProcessed);
375+
}, 40);
376+
}
377+
if (scrollIdx==0 && scrollIdx!=prevScrollIdx && alreadyProcessed.idxSpan.start>0) {
378+
setTimeout(() => {
379+
E.showScroller();
380+
if (BTN_WATCH) {clearWatch(BTN_WATCH);}
381+
showMessagesScroller(MESSAGES[alreadyProcessed.idxSpan.start-1],
382+
true, alreadyProcessed);
383+
}, 40);
384+
}
385+
if (prevPrevScrollIdx!==prevScrollIdx) {prevPrevScrollIdx = prevScrollIdx;}
386+
prevScrollIdx = scrollIdx;
272387
},
273-
back : () => showMessage(msg.id, true)
388+
select : function(scrollIdx, touch) {
389+
const MSG_SELECT = identifyDisplayedMsg(scrollIdx);
390+
if (touch.type == 0) {
391+
WU.show();
392+
if (BTN_WATCH) {clearWatch(BTN_WATCH);}
393+
showMessage(MSG_SELECT.id, true);
394+
}
395+
if (touch.type == 2) {
396+
WU.show();
397+
if (BTN_WATCH) {clearWatch(BTN_WATCH);}
398+
showMessageSettings(MSG_SELECT);
399+
}
400+
}
274401
});
402+
403+
const BTN_WATCH = setWatch(()=>{
404+
Bangle.emit("drag", {dy:0}); // Compatibility with `kineticscroll`, stopping the scroller so it doesn't continue scrolling when the `showMessage` screen is loaded.
405+
// Zero ms timeout as to not move on before the scroller has registered the emitted drag event.
406+
setTimeout(()=>{const SCROLL_IDX_CENTER_SCREEN = prevScrollIdx>prevPrevScrollIdx ?
407+
prevScrollIdx-5 : prevScrollIdx+5; // FIXME: `±5` should depend on screen height and font height.
408+
WU.show();
409+
showMessage(identifyDisplayedMsg(SCROLL_IDX_CENTER_SCREEN).id, true);
410+
},0)
411+
}, BTN, {edge:'rising'});
275412
}
276413

277414
function showMessageSettings(msg) {
@@ -283,7 +420,7 @@ function showMessageSettings(msg) {
283420
};
284421

285422
if (msg.id!="music")
286-
menu[/*LANG*/"View Message"] = () => showMessageScroller(msg);
423+
menu[/*LANG*/"View Message"] = () => showMessagesScroller(msg);
287424

288425
if (msg.reply && reply) {
289426
menu[/*LANG*/"Reply"] = () => {
@@ -456,7 +593,7 @@ function showMessage(msgid, persist) {
456593
]},
457594
{type:"txt", font:bodyFont, label:body, fillx:1, filly:1, pad:2, cb:()=>{
458595
// allow tapping to show a larger version
459-
showMessageScroller(msg);
596+
showMessagesScroller(msg);
460597
} },
461598
{type:"h",fillx:1, c: footer}
462599
]},{back:goBack});
@@ -502,7 +639,7 @@ function checkMessages(options) {
502639
// If we have a new message, show it
503640
if (!options.ignoreUnread && newMessages.length) {
504641
delete newMessages[0].show; // stop us getting stuck here if we're called a second time
505-
showMessage(newMessages[0].id, false);
642+
showMessagesScroller(newMessages[0], false);
506643
// buzz after showMessage, so being busy during layout doesn't affect the buzz pattern
507644
if (global.BUZZ_ON_NEW_MESSAGE) {
508645
// this is set if we entered the messages app by loading `messagegui.new.js`

apps/messagegui/metadata.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"id": "messagegui",
33
"name": "Message UI",
44
"shortName": "Messages",
5-
"version": "0.84",
5+
"version": "0.85",
66
"description": "Default app to display notifications from iOS and Gadgetbridge/Android",
77
"icon": "app.png",
88
"type": "app",

0 commit comments

Comments
 (0)