Merge pull request #2178 from awkirk71/master

[Sliding Text Clock] Added Styling and new watch faces
pull/2182/head
Gordon Williams 2022-10-17 10:54:01 +01:00 committed by GitHub
commit fed3a44d42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1178 additions and 537 deletions

View File

@ -8,3 +8,4 @@
0.08: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
0.09: Added button control toggle and other live controls to new settings screen.
0.10: Tell clock widgets to hide.
0.11: Added new styling and watch faces

View File

@ -1,54 +1,81 @@
# Sliding Text Clock - See the time in different languages
Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Please use the upload page to choose which languages you want loaded.
Inspired by the Pebble sliding clock, previous times are scrolled off the screen and new times scrolled on. There are a variety of colours schemes, clock faces and languages available through the settings menu
![](app.png)
## Usage
## Settings
### Bangle 2
Please go to the sliding text clock menu under the settings menu to customise clock. Settings -> Apps -> Sliding Clock
The Bangle 2 has Live Controls switched **off** by default so the colour and language have to be changed from the setting Menu.
Please locate the Sliding Text clock under the setting->apps menu.
With the Live Controls switched on:
#### Bottom right hand corner press
press the bottom right hand corner of the screen to change the colour
| White | Black | Gray | Red |
|----------------------|----------------------|----------------------|----------------------|
| ![](b2_color-01.jpg) | ![](b2_color-02.jpg) | ![](b2_color-03.jpg) | ![](b2_color-04.jpg) |
## Colour
#### Top right hand corner press
press the top right hand corner of the screen to change the language
The colour selection allows to select between different colour schemes. Colour schemes that are currently available are:
### Bangle 1
- White background with black lettering
- Black background with red and white lettering
- Red background with yellow and white lettering.
- Grey background with black and white lettering
- Purple with yellow and white lettering
- Blue with yellow and white lettering
By Default the Live Controls (The side buttons) are switched on, which means the clock face can be controlled dynamically using the 2 side buttons on the right hand side
## Live Control
#### Button 1
Live control allows you to change the colour scheme of the clock by pressing
Use Button 1 (the top right button) to change the language
- The bottom right hand corner of the screen for a bangle 2
- Button 3 on on a bangle 1
| English | English (Traditional) | French | Japanese (Romanji) |
| ---- | ---- | ---- | ---- |
| ![](format-01.jpg) | ![](format-02.jpg) | ![](format-03.jpg) |![](format-04.jpg) |
| **German** | **Spanish** | | |
| ![](format-05.jpg) | ![](format-06.jpg) | | |
When select the watch will move to the next colour in the scheme. The selected colour will not be saved so it will will revert to the last colour select in the menu when the clock is restarted. This option is included to help select the preferred colour with having to continuously go back to the settings menu.
#### Button 3
Button 3 (bottom right button) is used to change the colour
The Live Control is turned off by default on a bangle 2, but is on by default for a bangle 1
| Black | Red | Gray | Purple |
| ---- | ---- | ---- | ---- |
| ![](b1_color-01.jpg) | ![](b1_color-02.jpg) | ![](b1_color-03.jpg) | ![](b1_color-04.jpg) |
## Style
#### Settings
Style controls the clock face.
### English
| Style | English 1 | English 1 Alternative | English 2 | English 2 Alternative | English Hybrid |
| ------ | ----------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------- |
| Screen | ![](slidingtext-screenshot.english.png) | ![](slidingtext-screenshot.english_alt.png) | ![](slidingtext-screenshot.english2.png) | ![](slidingtext-screenshot.english2_alt.png) | ![](slidingtext-screenshot.hybrid.png) |
| Notes | Straight 12 hour English time and Date in words | Straight 12 hour English time and Date in words in alternative style | Traditional English Time | Traditional English Time and Date in alternative style | 24 Hour clock in numbers with minutes and date in words |
### French
| Style | French |
| ------ | -------------- |
| Screen | ![](slidingtext-screenshot.french.png) |
### Spanish
| Style | Spanish |
| ------ | -------------- |
| Screen | ![](slidingtext-screenshot.spanish.png) |
### German
| Style | German 12 Hour | German 24 Hour |
| ------ | -------------- | -------------- |
| Screen | ![](slidingtext-screenshot.german.png) |![](slidingtext-screenshot.german24.png) |
| Notes | 12 Hour German clock in words | 24 Hour German clock in words |
### Japanese
| Style | Japanese |
| ------ | ---------------------------------------- |
| Screen | ![](slidingtext-screenshot.japanese.png) |
| Notes | Simplified Romanji Japanese Clock. |
### Digital
| Style | Digits |
| ------ | --------------------------------------- |
| Screen | ![](slidingtext-screenshot.digital.png) |
| Notes | Sliding version of a digital clock |
To turn off the Live Controls and change the settings statically please visit the settings menu. The settings menu will allow you to:
- Colour Scheme
- Language
- Live Controls (On or Off)
## Further Details
@ -56,7 +83,7 @@ For further details of design and working please visit [The Project Page](https:
## Requests
Reach out to adrian@adriankirk.com if you have feature requests or notice bugs.
Thank you so much for the feedback so far. Please reach out to adrian@adriankirk.com if you have feature requests or notice bugs.
## Creator

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1,71 +0,0 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<p>Please select watch languages (Max 3, only the first 3 selected will be loaded)</p>
<table id="language_selection">
<tr>
<th>Enabled</th>
<th>Name</th>
</tr>
</table>
<p>Click <button id="upload" class="btn btn-primary">Upload</button></p>
<script src="../../core/lib/customize.js"></script>
<script>
var slidingtext_languages=[
{name:"English", shortname:"en"},
{name:"English(Traditional)",shortname:"en2"},
{name:"French",shortname:"fr"},
{name:"Japanese",shortname:"jp"},
{name:"Spanish",shortname:"es"},
{name:"German",shortname:"de"}
];
var selected_languages = ["en","es","jp"];
try{
var stored = localStorage.getItem('slidingtext_stored')
if(stored) selected_languages = JSON.parse(stored);
} catch(e){
console.log("failed to load languages:" + e);
}
console.log("selected languages:" + selected_languages);
var tbl=document.getElementById("language_selection");
for (var i=0; i<slidingtext_languages.length; i++) {
var curr_language = slidingtext_languages[i];
var language_selected = selected_languages.includes(curr_language["shortname"])
var $offset = document.createElement('tr')
$offset.innerHTML = `
<td><input type="checkbox" id="enabled_${i}" ${language_selected? "checked" : ""}></td>
<td>${curr_language['name']}</td>`
tbl.append($offset);
}
// When the 'upload' button is clicked...
document.getElementById("upload").addEventListener("click", function() {
var new_selected_languages=[];
for (var i=0; i<slidingtext_languages.length; i++) {
var curr_language = slidingtext_languages[i];
var checked=document.getElementById("enabled_"+i).checked;
if (checked && new_selected_languages.length < 3 ) {
new_selected_languages.push(curr_language.shortname);
}
}
console.log("new selected languages:" + new_selected_languages);
localStorage.setItem('slidingtext_stored',JSON.stringify(new_selected_languages));
// send finished app (in addition to contents of app.json)
sendCustomizedApp({
storage:[
{name:"slidingtext.languages.json", content:JSON.stringify(new_selected_languages)},
]
});
});
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1,15 +1,15 @@
{
"id": "slidingtext",
"name": "Sliding Clock",
"version": "0.10",
"version": "0.11",
"description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently English, French, Japanese, Spanish and German are supported",
"icon": "slidingtext.png",
"screenshots": [{"url":"slidingtext-screenshot.english.png"},{"url":"slidingtext-screenshot.english2.png"},{"url":"slidingtext-screenshot.hybrid.png"}],
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS","BANGLEJS2"],
"readme": "README.md",
"custom": "custom.html",
"allow_emulator": false,
"allow_emulator": true,
"storage": [
{"name":"slidingtext.app.js","url":"slidingtext.js"},
{"name":"slidingtext.settings.js","url":"slidingtext.settings.js"},
@ -20,7 +20,11 @@
{"name":"slidingtext.locale.es.js","url":"slidingtext.locale.es.js"},
{"name":"slidingtext.locale.fr.js","url":"slidingtext.locale.fr.js"},
{"name":"slidingtext.locale.jp.js","url":"slidingtext.locale.jp.js"},
{"name":"slidingtext.utils.de.js","url":"slidingtext.utils.de.js"},
{"name":"slidingtext.locale.de.js","url":"slidingtext.locale.de.js"},
{"name":"slidingtext.locale.de2.js","url":"slidingtext.locale.de2.js"},
{"name":"slidingtext.locale.dgt.js","url":"slidingtext.locale.dgt.js"},
{"name":"slidingtext.locale.hyb.js","url":"slidingtext.locale.hyb.js"},
{"name":"slidingtext.dtfmt.js","url":"slidingtext.dtfmt.js"}
],
"data": [{"name": "slidingtext.settings.json"}]

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -3,14 +3,20 @@ class DateFormatter {
* A pure virtual class which all the other date formatters will
* inherit from.
* The name will be used to declare the date format when selected
* and the date formatDate methid will return the time formated
* and the date formatDate method will return the time formated
* to the lines of text on the screen
*/
name(){return "no name";}
shortName(){return "no short name"}
formatDate(date){
return ["no","date","defined"];
}
formatDate(date){ return ["no","date","defined"]; }
/**
* returns a map of the different row types
*/
defaultRowTypes(){}
/**
* returns a list of row definitions (1 definition can cover m
*/
defaultRowDefs(){ return [];}
}
module.exports = DateFormatter;

View File

@ -5,18 +5,18 @@
*/
const color_schemes = [
{
name: "black",
background : [0.0,0.0,0.0],
main_bar: [1.0,0.0,0.0],
other_bars: [0.9,0.9,0.9],
},
{
name: "white",
background : [1.0,1.0,1.0],
main_bar: [0.0,0.0,0.0],
other_bars: [0.1,0.1,0.1],
},
{
name: "black",
background : [0.0,0.0,0.0],
main_bar: [1.0,1.0,1.0],
other_bars: [0.9,0.9,0.9],
},
{
name: "red",
background : [1.0,0.0,0.0],
@ -31,14 +31,14 @@ const color_schemes = [
},
{
name: "purple",
background : [1.0,0.0,1.0],
background : [0.3,0.0,0.6],
main_bar: [1.0,1.0,0.0],
other_bars: [0.85,0.85,0.85]
},
{
name: "blue",
background : [0.4,0.7,1.0],
main_bar: [1.0,1.0,1.0],
background : [0.1,0.2,1.0],
main_bar: [1.0,1.0,0.0],
other_bars: [0.9,0.9,0.9]
}
];
@ -66,17 +66,12 @@ let command_stack_high_priority = [];
let command_stack_low_priority = [];
function next_command(){
command = command_stack_high_priority.pop();
var command = command_stack_high_priority.pop();
if(command == null){
//console.log("Low priority command");
command = command_stack_low_priority.pop();
} else {
//console.log("High priority command");
}
if(command != null){
command.call();
} else {
//console.log("no command");
}
}
@ -102,7 +97,9 @@ class ShiftText {
constructor(x,y,txt,font_name,
font_size,speed_x,speed_y,freq_millis,
color,
bg_color){
bg_color,
row_context,
rotation){
this.x = x;
this.tgt_x = x;
this.init_x = x;
@ -118,17 +115,15 @@ class ShiftText {
this.freq_millis = freq_millis;
this.color = color;
this.bg_color = bg_color;
this.row_context = row_context;
this.rotation = rotation;
this.finished_callback=null;
this.timeoutId = null;
}
setColor(color){
this.color = color;
}
setBgColor(bg_color){
this.bg_color = bg_color;
}
getRowContext(){ return this.row_context;}
setColor(color){ this.color = color; }
setBgColor(bg_color){ this.bg_color = bg_color; }
reset(hard_reset) {
//console.log("reset");
this.hide();
this.x = this.init_x;
this.y = this.init_y;
@ -141,13 +136,13 @@ class ShiftText {
}
}
show() {
g.setFontAlign(-1,-1,0);
g.setFontAlign(-1,-1,this.rotation);
g.setFont(this.font_name,this.font_size);
g.setColor(this.color[0],this.color[1],this.color[2]);
g.drawString(this.txt, this.x, this.y);
}
hide(){
g.setFontAlign(-1,-1,0);
g.setFontAlign(-1,-1,this.rotation);
g.setFont(this.font_name,this.font_size);
//console.log("bgcolor:" + this.bg_color);
g.setColor(this.bg_color[0],this.bg_color[1],this.bg_color[2]);
@ -188,6 +183,36 @@ class ShiftText {
this.tgt_y = new_y;
this._doMove();
}
scrollInFromBottom(txt,to_y){
if(to_y == null)
to_y = this.init_y;
this.setTextPosition(txt, this.init_x, g.getHeight()*2);
this.moveTo(this.init_x,to_y);
}
scrollInFromLeft(txt,to_x){
if(to_x == null)
to_x = this.init_x;
this.setTextPosition(txt, -txt.length * this.font_size - this.font_size, this.init_y);
this.moveTo(to_x,this.init_y);
}
scrollInFromRight(txt,to_x){
if(to_x == null)
to_x = this.init_x;
this.setTextPosition(txt, g.getWidth() + this.font_size, this.init_y);
this.moveTo(to_x,this.init_y);
}
scrollOffToLeft(){
this.moveTo(-this.txt.length * this.font_size, this.init_y);
}
scrollOffToRight(){
this.moveTo(g.getWidth() + this.font_size, this.init_y);
}
scrollOffToBottom(){
this.moveTo(this.init_x,g.getHeight()*2);
}
onFinished(finished_callback){
this.finished_callback = finished_callback;
}
@ -230,135 +255,234 @@ class ShiftText {
if(!finished){
this.timeoutId = setTimeout(this._doMove.bind(this), this.freq_millis);
} else if(this.finished_callback != null){
//console.log("finished - calling:" + this.finished_callback);
this.finished_callback.call();
this.finished_callback = null;
}
}
}
const CLOCK_TEXT_SPEED_X = 10;
// a list of display rows
let row_displays;
function setRowDisplays(y, heights) {
var cols = [
main_color(), other_color(), other_color(), other_color(), main_color()
];
row_displays = [];
for (var i=0;i<heights.length;i++) {
row_displays.push(new ShiftText(g.getWidth(),y,'',"Vector",heights[i],CLOCK_TEXT_SPEED_X,1,10,cols[i],bg_color()));
y += heights[i];
}
}
function bangleVersion(){
return (g.getHeight()>200)? 1 : 2;
}
if (bangleVersion()<2)
setRowDisplays(50, [40,30,30,30,40]);
else
setRowDisplays(34, [35,25,25,25,35]);
let row_displays;
function initDisplay(settings) {
if(row_displays != null){
return;
}
if(settings == null){
settings = {};
}
var row_types = {
large: {
color: 'major',
speed: 'medium',
angle_to_horizontal: 0,
scroll_off: ['left'],
scroll_in: ['right'],
size: 'large'
},
medium: {
color: 'minor',
speed: 'slow',
angle_to_horizontal: 0,
scroll_off: ['left'],
scroll_in: ['right'],
size: 'medium'
},
small: {
color: 'minor',
speed: 'superslow',
angle_to_horizontal: 0,
scroll_off: ['left'],
scroll_in: ['right'],
size: 'small'
}
};
function mergeMaps(map1,map2){
if(map2 == null){
return;
}
Object.keys(map2).forEach(key => {
if(map1.hasOwnProperty(key)){
map1[key] = mergeObjects(map1[key], map2[key]);
} else {
map1[key] = map2[key];
}
});
}
function mergeObjects(obj1, obj2){
const result = {};
Object.keys(obj1).forEach(key => result[key] = (obj2.hasOwnProperty(key))? obj2[key] : obj1[key]);
return result;
}
const row_type_overide = date_formatter.defaultRowTypes();
mergeMaps(row_types,row_type_overide);
mergeMaps(row_types,settings.row_types);
var row_defs = (settings.row_defs != null && settings.row_defs.length > 0)?
settings.row_defs : date_formatter.defaultRowDefs();
var heights = {
vvsmall: [15,13],
vsmall: [20,15],
ssmall: [22,17],
small: [25,20],
msmall: [29,22],
medium: [40,25],
mlarge: [45,35],
large: [50,40],
vlarge: [60,50],
slarge: [110,90]
};
var rotations = {
0: 0,
90: 3,
180: 2,
270: 1,
};
var speeds = {
fast: 20,
medium: 10,
slow: 5,
vslow: 2,
superslow: 1
};
function create_row_type(row_type, row_def){
const speed = speeds[row_type.speed];
const rotation = rotations[row_type.angle_to_horizontal];
const height = heights[row_type.size];
const scroll_ins = [];
if(row_type.scroll_in.includes('left')){
scroll_ins.push((row_display,txt)=> row_display.scrollInFromLeft(txt));
}
if(row_type.scroll_in.includes('right')){
scroll_ins.push((row_display,txt)=> row_display.scrollInFromRight(txt));
}
if(row_type.scroll_in.includes('up')){
scroll_ins.push((row_display,txt)=> row_display.scrollInFromBottom(txt));
}
var scroll_in;
if(scroll_ins.length === 0){
scroll_in = (row_display,txt)=> row_display.scrollInFromLeft(txt);
} else if(scroll_ins.length === 1){
scroll_in = scroll_ins[0];
} else {
scroll_in = (row_display,txt) =>{
const idx = (Math.random() * scroll_ins.length) | 0;
return scroll_ins[idx](row_display,txt);
};
}
const scroll_offs = [];
if(row_type.scroll_off.includes('left')){
scroll_offs.push((row_display)=> row_display.scrollOffToLeft());
}
if(row_type.scroll_off.includes('right')){
scroll_offs.push((row_display)=> row_display.scrollOffToRight());
}
if(row_type.scroll_off.includes('down')){
scroll_offs.push((row_display)=> row_display.scrollOffToBottom());
}
var scroll_off;
if(scroll_offs.length === 0){
scroll_off = (row_display)=> row_display.scrollOffToLeft();
} else if(scroll_offs.length === 1){
scroll_off = scroll_offs[0];
} else {
scroll_off = (row_display) =>{
var idx = (Math.random() * scroll_off.length) | 0;
return scroll_offs[idx](row_display);
};
}
var text_formatter = (txt)=>txt;
const SPACES = ' ';
if(row_def.hasOwnProperty("alignment")){
const alignment = row_def.alignment;
if(alignment.startsWith("centre")){
const padding = parseInt(alignment.split("-")[1]);
if(padding > 0){
text_formatter = (txt) => {
const front_spaces = (padding - txt.length)/2 | 0;
return front_spaces > 0? SPACES.substring(0,front_spaces + 1) + txt : txt;
};
}
}
}
const version = bangleVersion() - 1;
const Y_RESERVED = 20;
return {
row_speed: speed,
row_height: height[version],
row_rotation: rotation,
x: (row_no) => row_def.init_coords[0] * g.getWidth() + row_def.row_direction[0] * height[version] * row_no,
y: (row_no) => Y_RESERVED + row_def.init_coords[1] * (g.getHeight() - Y_RESERVED) + row_def.row_direction[1] * height[version] * row_no,
scroll_in: scroll_in,
scroll_off: scroll_off,
fg_color: () => (row_type.color === 'major')? main_color(): other_color(),
row_text_formatter : text_formatter
};
}
row_displays = [];
row_defs.forEach(row_def =>{
const row_type = create_row_type(row_types[row_def.type],row_def);
// we now create the number of rows specified of that type
for(var row_no=0; row_no<row_def.rows; row_no++){
row_displays.push(new ShiftText(row_type.x(row_no),
row_type.y(row_no),
'',
"Vector",
row_type.row_height,
row_type.row_speed,
row_type.row_speed,
10,
row_type.fg_color(),
bg_color(),
row_type,
row_type.row_rotation
)
);
}
});
// dereference the setup variables to release the memory
row_defs = null;
row_types = null;
heights = null;
rotations = null;
speeds = null;
}
function nextColorTheme(){
color_scheme_index += 1;
if(color_scheme_index > row_displays.length){
if(color_scheme_index >= color_schemes.length){
color_scheme_index = 0;
}
setColorScheme(color_schemes[color_scheme_index]);
reset_clock(true);
draw_clock();
updateColorScheme();
resetClock(true);
drawClock();
}
function setColorScheme(color_scheme){
setColor(color_scheme.main_bar,
color_scheme.other_bars,
color_scheme.background);
}
function setColor(main_color,other_color,bg_color){
row_displays[0].setColor(main_color);
row_displays[0].setBgColor(bg_color);
for(var i=1; i<row_displays.length - 1; i++){
row_displays[i].setColor(other_color);
row_displays[i].setBgColor(bg_color);
function updateColorScheme(){
const bgcolor = bg_color();
for(var i=0; i<row_displays.length; i++){
row_displays[i].setColor(row_displays[i].getRowContext().fg_color());
row_displays[i].setBgColor(bgcolor);
}
row_displays[row_displays.length - 1].setColor(main_color);
row_displays[row_displays.length - 1].setBgColor(bg_color);
g.setColor(bg_color[0],bg_color[1],bg_color[2]);
g.fillRect(0,24, g.getWidth(), g.getHeight());
g.setColor(bgcolor[0],bgcolor[1],bgcolor[2]);
g.fillRect(0, 24, g.getWidth(), g.getHeight());
}
// load the date formats and laguages required
LANGUAGES_FILE = "slidingtext.languages.json";
var LANGUAGES_DEFAULT = ["en","en2"];
var locales = null;
try{
locales = require("Storage").readJSON(LANGUAGES_FILE);
if(locales != null){
console.log("loaded languages:" + JSON.stringify(locales));
} else {
console.log("no languages loaded");
locales = LANGUAGES_DEFAULT;
}
} catch(e){
console.log("failed to load languages:" + e);
}
if(locales == null || locales.length == 0){
locales = LANGUAGES_DEFAULT;
console.log("defaulting languages to locale:" + locales);
}
let date_formatters = [];
for(var i=0; i< locales.length; i++){
console.log("loading locale:" + locales[i]);
var Formatter = require("slidingtext.locale." + locales[i] + ".js");
date_formatters.push(new Formatter());
}
// current index of the date formatter to display
let date_formatter_idx = 0;
let date_formatter = date_formatters[date_formatter_idx];
function changeFormatter(){
date_formatter_idx += 1;
if(date_formatter_idx >= date_formatters.length){
date_formatter_idx = 0;
}
console.log("changing to formatter " + date_formatter_idx);
date_formatter = date_formatters[date_formatter_idx];
reset_clock(true);
draw_clock();
command_stack_high_priority.unshift(
function() {
//console.log("move in new:" + txt);
// first select the top or bottom to display the formatter name
// We choose the first spare row without text
var format_name_display = row_displays[row_displays.length - 1];
if (format_name_display.txt != '') {
format_name_display = row_displays[0];
}
if (format_name_display.txt != ''){
return;
}
format_name_display.speed_x = 3;
format_name_display.onFinished(function(){
format_name_display.speed_x = CLOCK_TEXT_SPEED_X;
console.log("return speed to:" + format_name_display.speed_x)
next_command();
});
format_name_display.setTextXPosition(date_formatter.name(),220);
format_name_display.moveToX(-date_formatter.name().length * format_name_display.font_size);
}
);
}
var DISPLAY_TEXT_X = 20;
function reset_clock(hard_reset){
function resetClock(hard_reset){
console.log("reset_clock hard_reset:" + hard_reset);
setColorScheme(color_schemes[color_scheme_index]);
updateColorScheme();
if(!hard_reset && last_draw_time != null){
// If its not a hard reset then we want to reset the
// rows set to the last time. If the last time is too long
@ -366,15 +490,14 @@ function reset_clock(hard_reset){
// In this way the watch wakes by scrolling
// off the last time and scroll on the new time
var reset_time = last_draw_time;
var last_minute_millis = Date.now() - 60000;
const last_minute_millis = Date.now() - 60000;
if(reset_time.getTime() < last_minute_millis){
reset_time = display_time(new Date(last_minute_millis));
}
var rows = date_formatter.formatDate(reset_time);
const rows = date_formatter.formatDate(reset_time);
for (var i = 0; i < rows.length; i++) {
row_displays[i].hide();
row_displays[i].speed_x = CLOCK_TEXT_SPEED_X;
row_displays[i].x = DISPLAY_TEXT_X;
row_displays[i].x = row_displays[i].init_x;
row_displays[i].y = row_displays[i].init_y;
if(row_displays[i].timeoutId != null){
clearTimeout(row_displays[i].timeoutId);
@ -384,12 +507,8 @@ function reset_clock(hard_reset){
}
} else {
// do a hard reset and clear everything out
for (var i = 0; i < row_displays.length; i++) {
row_displays[i].speed_x = CLOCK_TEXT_SPEED_X;
row_displays[i].reset(hard_reset);
}
row_displays.forEach(row_display => row_display.reset(hard_reset));
}
reset_commands();
}
@ -405,13 +524,13 @@ function display_time(date){
}
}
function draw_clock(){
function drawClock(){
var date = new Date();
// we don't want the time to be displayed
// and then immediately be trigger another time
if(last_draw_time != null &&
Date.now() - last_draw_time.getTime() < next_minute_boundary_secs * 1000 &&
date.getTime() - last_draw_time.getTime() < next_minute_boundary_secs * 1000 &&
has_commands() ){
console.log("skipping draw clock");
return;
@ -420,65 +539,54 @@ function draw_clock(){
}
reset_commands();
date = display_time(date);
console.log("draw_clock:" + last_draw_time.toISOString() + " display:" + date.toISOString());
const mem = process.memory(false);
console.log("draw_clock:" + last_draw_time.toISOString() + " display:" + date.toISOString() +
" memory:" + mem.usage / mem.total);
var rows = date_formatter.formatDate(date);
var display;
const rows = date_formatter.formatDate(date);
for (var i = 0; i < rows.length; i++) {
display = row_displays[i];
var txt = rows[i];
//console.log(i + "->" + txt);
display_row(display,txt);
const display = row_displays[i];
if(display != null){
const txt = display.getRowContext().row_text_formatter(rows[i]);
display_row(display,txt);
}
}
// If the dateformatter has not returned enough
// rows then treat the reamining rows as empty
// rows then treat the remaining rows as empty
for (var j = i; j < row_displays.length; j++) {
display = row_displays[j];
//console.log(i + "->''(empty)");
const display = row_displays[j];
display_row(display,'');
}
next_command();
//console.log(date);
}
function display_row(display,txt){
if(display == null) {
console.log("no display for text:" + txt)
return;
}
if(display.txt == null || display.txt == ''){
if(txt != '') {
command_stack_high_priority.unshift(
function () {
//console.log("move in new:" + txt);
if(display.txt == null || display.txt === ''){
if(txt !== '') {
command_stack_high_priority.unshift(()=>{
display.onFinished(next_command);
display.setTextXPosition(txt, 240);
display.moveToX(DISPLAY_TEXT_X);
display.getRowContext().scroll_in(display,txt);
}
);
}
} else if(txt != display.txt && display.txt != null){
command_stack_high_priority.push(
function(){
//console.log("move out:" + txt);
} else if(txt !== display.txt && display.txt != null){
command_stack_high_priority.push(()=>{
display.onFinished(next_command);
display.moveToX(-display.txt.length * display.font_size);
display.getRowContext().scroll_off(display);
}
);
command_stack_low_priority.push(
function(){
//console.log("move in:" + txt);
command_stack_low_priority.push(() => {
display.onFinished(next_command);
display.setTextXPosition(txt,240);
display.moveToX(DISPLAY_TEXT_X);
display.getRowContext().scroll_in(display,txt);
}
);
} else {
command_stack_high_priority.push(
function(){
//console.log("move in2:" + txt);
display.setTextXPosition(txt,DISPLAY_TEXT_X);
command_stack_high_priority.push(() => {
display.setTextPosition(txt,display.init_x, display.init_y);
next_command();
}
);
@ -489,26 +597,92 @@ function display_row(display,txt){
* called from load_settings on startup to
* set the color scheme to named value
*/
function set_colorscheme(colorscheme_name){
function setColorScheme(colorscheme_name){
console.log("setting color scheme:" + colorscheme_name);
for (var i=0; i < color_schemes.length; i++) {
if(color_schemes[i].name == colorscheme_name){
if(color_schemes[i].name === colorscheme_name){
color_scheme_index = i;
console.log("match");
setColorScheme(color_schemes[color_scheme_index]);
updateColorScheme();
break;
}
}
}
function set_dateformat(dateformat_name){
console.log("setting date format:" + dateformat_name);
for (var i=0; i < date_formatters.length; i++) {
if(date_formatters[i].shortName() == dateformat_name){
date_formatter_idx = i;
date_formatter = date_formatters[date_formatter_idx];
console.log("match");
var date_formatter;
function setDateformat(shortname){
/**
* Demonstration Date formatter so that we can see the
* clock working in the emulator
*/
class DigitDateTimeFormatter {
constructor() {}
format00(num){
const value = (num | 0);
if(value > 99 || value < 0)
throw "must be between in range 0-99";
if(value < 10)
return "0" + value.toString();
else
return value.toString();
}
formatDate(now){
const hours = now.getHours() ;
const time_txt = this.format00(hours) + ":" + this.format00(now.getMinutes());
const date_txt = require('locale').dow(now,1) + " " + this.format00(now.getDate());
const month_txt = require('locale').month(now);
return [time_txt, date_txt, month_txt];
}
defaultRowTypes(){
return {
large: {
scroll_off: ['left', 'right', 'down'],
scroll_in: ['left', 'right', 'up'],
size: 'vlarge'
},
small: {
angle_to_horizontal: 90,
scroll_off: ['down'],
scroll_in: ['up'],
size: 'vvsmall'
}
};
}
defaultRowDefs() {
return [
{
type: 'large',
row_direction: [0.0,1.0],
init_coords: [0.1,0.35],
rows: 1
},
{
type: 'small',
row_direction: [1.0,0],
init_coords: [0.85,0.99],
rows: 2
}
];
}
}
console.log("setting date format:" + shortname);
try {
if (date_formatter == null) {
if(shortname === "default"){
date_formatter = new DigitDateTimeFormatter();
} else {
const date_formatter_class = require("slidingtext.locale." + shortname + ".js");
date_formatter = new date_formatter_class();
}
}
} catch(e){
console.log("not loaded:" + shortname);
}
if(date_formatter == null){
date_formatter = new DigitDateTimeFormatter();
}
}
@ -517,64 +691,44 @@ const PREFERENCE_FILE = "slidingtext.settings.json";
/**
* Called on startup to set the watch to the last preference settings
*/
function load_settings(){
var setScheme = false;
try{
var settings = require("Storage").readJSON(PREFERENCE_FILE);
if(settings != null){
console.log("loaded:" + JSON.stringify(settings));
if(settings.color_scheme != null){
set_colorscheme(settings.color_scheme);
setScheme = true;
}
if(settings.date_format != null){
set_dateformat(settings.date_format);
}
if(settings.enable_live_controls == null){
settings.enable_live_controls = (bangleVersion() <= 1);
}
enable_live_controls = settings.enable_live_controls;
} else {
console.log("no settings to load");
enable_live_controls = (bangleVersion() <= 1);
function loadSettings() {
try {
const settings = Object.assign({},
require('Storage').readJSON(PREFERENCE_FILE, true) || {});
if (settings.date_formatter == null) {
settings.date_formatter = "en";
}
console.log("loaded settings:" + JSON.stringify(settings));
setDateformat(settings.date_formatter);
initDisplay(settings);
if (settings.color_scheme != null) {
setColorScheme(settings.color_scheme);
} else {
setColorScheme("black");
}
if (settings.enable_live_controls == null) {
settings.enable_live_controls = (bangleVersion() <= 1);
}
enable_live_controls = settings.enable_live_controls;
console.log("enable_live_controls=" + enable_live_controls);
} catch(e){
} catch (e) {
console.log("failed to load settings:" + e);
}
// just set up as default
if (!setScheme)
setColorScheme(color_schemes[color_scheme_index]);
}
/**
* Called on button press to save down the last preference settings
*/
function save_settings(){
var settings = {
date_format : date_formatter.shortName(),
color_scheme : color_schemes[color_scheme_index].name,
enable_live_controls: enable_live_controls
};
console.log("saving:" + JSON.stringify(settings));
require("Storage").writeJSON(PREFERENCE_FILE,settings);
}
function button1pressed() {
console.log("button1pressed");
if (enable_live_controls) {
changeFormatter();
save_settings();
if (row_displays === undefined) {
setDateformat("default");
initDisplay();
updateColorScheme();
}
const mem = process.memory(true);
console.log("init complete memory:" + mem.usage / mem.total);
}
function button3pressed() {
console.log("button3pressed");
if (enable_live_controls) {
nextColorTheme();
reset_clock(true);
draw_clock();
save_settings();
resetClock(true);
drawClock();
}
}
@ -589,12 +743,11 @@ function clearTimers(){
}
function startTimers(){
var date = new Date();
var secs = date.getSeconds();
var nextMinuteStart = 60 - secs;
//console.log("scheduling clock draw in " + nextMinuteStart + " seconds");
const date = new Date();
const secs = date.getSeconds();
const nextMinuteStart = 60 - secs;
setTimeout(scheduleDrawClock,nextMinuteStart * 1000);
draw_clock();
drawClock();
}
/**
@ -613,17 +766,17 @@ function scheduleDrawClock(){
if (Bangle.isLCDOn()) {
console.log("schedule draw of clock");
intervalRef = setInterval(() => {
if (!shouldRedraw()) {
console.log("draw clock callback - skipped redraw");
} else {
console.log("draw clock callback");
draw_clock()
}
}, 60 * 1000
if (!shouldRedraw()) {
console.log("draw clock callback - skipped redraw");
} else {
console.log("draw clock callback");
drawClock();
}
}, 60 * 1000
);
if (shouldRedraw()) {
draw_clock();
drawClock();
} else {
console.log("scheduleDrawClock - skipped redraw");
}
@ -636,20 +789,19 @@ Bangle.on('lcdPower', (on) => {
if (on) {
console.log("lcdPower: on");
Bangle.drawWidgets();
reset_clock(false);
resetClock(false);
startTimers();
} else {
console.log("lcdPower: off");
reset_clock(false);
resetClock(false);
clearTimers();
}
});
g.clear();
load_settings();
loadSettings();
// Show launcher when button pressed
Bangle.setUI("clockupdown", d=>{
if (d<0) button1pressed();
if (d>0) button3pressed();
});
Bangle.loadWidgets();

View File

@ -1,95 +1,43 @@
var DateFormatter = require("slidingtext.dtfmt.js");
const germanNumberStr = [ ["NULL",""], // 0
["EINS",""], // 1
["ZWEI",""], //2
["DREI",''], //3
["VIER",''], //4
["FÜNF",''], //5
["SECHS",''], //6
["SIEBEN",''], //7
["ACHT",''], //8
["NEUN",''], // 9,
["ZEHN",''], // 10
["ELF",''], // 11,
["ZWÖLF",''], // 12
["DREI",'ZEHN'], // 13
["VIER",'ZEHN'], // 14
["FÜNF",'ZEHN'], // 15
["SECH",'ZEHN'], // 16
["SIEB",'ZEHN'], // 17
["ACHT",'ZEHN'], // 18
["NEUN",'ZEHN'], // 19
];
const germanTensStr = ["NULL",//0
"ZEHN",//10
"ZWANZIG",//20
"DREIßIG",//30
"VIERZIG",//40
"FÜNFZIG",//50
"SECHZIG"//60
]
const germanUnit = ["",//0
"EINUND",//1
"ZWEIUND",//2
"DREIUND",//3
"VIERUND", //4
"FÜNFUND", //5
"SECHSUND", //6
"SIEBENUND", //7
"ACHTUND", //8
"NEUNUND" //9
]
function germanHoursToText(hours){
hours = hours % 12;
if(hours == 0){
hours = 12;
}
return germanNumberStr[hours][0];
}
function germanMinsToText(mins) {
if (mins < 20) {
return germanNumberStr[mins];
} else {
var tens = (mins / 10 | 0);
var word1 = germanTensStr[tens];
var remainder = mins - tens * 10;
var word2 = germanUnit[remainder];
return [word2, word1];
}
}
const DateFormatter = require("slidingtext.dtfmt.js");
const germanHoursToText = require("slidingtext.utils.de.js").germanHoursToText;
const germanMinsToText = require("slidingtext.utils.de.js").germanMinsToText;
/**
* German 12 hour clock
*/
class GermanDateFormatter extends DateFormatter {
constructor() { super();}
name(){return "German";}
shortName(){return "de"}
constructor() {
super();
}
formatDate(date){
var mins = date.getMinutes();
var hourOfDay = date.getHours();
var hours = germanHoursToText(hourOfDay);
//console.log('hourOfDay->' + hourOfDay + ' hours text->' + hours)
// Deal with the special times first
if(mins == 0){
var hours = germanHoursToText(hourOfDay);
const mins = date.getMinutes();
const hourOfDay = date.getHours();
const hours = germanHoursToText(hourOfDay);
if(mins === 0){
return [hours,"UHR", "","",""];
} /*else if(mins == 30){
var hours = germanHoursToText(hourOfDay+1);
return ["", "", "HALB","", hours];
} else if(mins == 15){
var hours = germanHoursToText(hourOfDay);
return ["", "", "VIERTEL", "NACH",hours];
} else if(mins == 45) {
var hours = germanHoursToText(hourOfDay+1);
return ["", "", "VIERTEL", "VOR",hours];
} */ else {
var mins_txt = germanMinsToText(mins);
} else {
const mins_txt = germanMinsToText(mins);
return [hours, "UHR", mins_txt[0],mins_txt[1]];
}
}
defaultRowTypes(){ return {};}
defaultRowDefs(){
return [
{
type: 'large',
init_coords: [0.05,0.1],
row_direction: [0.0,1.0],
rows: 1
},
{
type: 'medium',
init_coords: [0.05,0.4],
row_direction: [0.0,1.0],
rows: 3
}
];
}
}
module.exports = GermanDateFormatter;

View File

@ -0,0 +1,49 @@
const DateFormatter = require("slidingtext.dtfmt.js");
const german24HoursToText = require("slidingtext.utils.de.js").german24HoursToText;
const germanMinsToText = require("slidingtext.utils.de.js").germanMinsToText;
/**
* German 24 hour clock
*/
class German24HourDateFormatter extends DateFormatter {
constructor() {
super();
}
formatDate(date){
const mins = date.getMinutes();
const hourOfDay = date.getHours();
const hours = german24HoursToText(hourOfDay);
const display_hours = (hours[1] === '')? ["", hours[0]] : hours;
if(mins === 0){
return [display_hours[0],display_hours[1],"UHR", "","",""];
} else {
const mins_txt = germanMinsToText(mins);
return [display_hours[0],display_hours[1], "UHR", mins_txt[0],mins_txt[1]];
}
}
defaultRowTypes(){ return {
large:{
size: 'mlarge'
}
};}
defaultRowDefs(){
return [
{
type: 'large',
init_coords: [0.05,0.06],
row_direction: [0.0,1.0],
rows: 2
},
{
type: 'medium',
init_coords: [0.05,0.5],
row_direction: [0.0,1.0],
rows: 3
}
];
}
}
module.exports = German24HourDateFormatter;

View File

@ -0,0 +1,63 @@
const Locale = require('locale');
class DigitDateTimeFormatter {
constructor() {}
format00(num){
const value = (num | 0);
if(value > 99 || value < 0)
throw "must be between in range 0-99";
if(value < 10)
return "0" + value.toString();
else
return value.toString();
}
formatDate(now){
const hours = now.getHours() ;
const time_txt = this.format00(hours) + ":" + this.format00(now.getMinutes());
const date_txt = Locale.dow(now,1) + " " + this.format00(now.getDate());
return [time_txt[0], time_txt[1],time_txt[2], time_txt[3],time_txt[4],date_txt];
}
defaultRowTypes(){
return {
large: {
scroll_off: ['down'],
scroll_in: ['up'],
size: 'vlarge',
speed: 'medium'
},
small: {
angle_to_horizontal: 0,
scroll_off: ['left'],
scroll_in: ['right'],
}
};
}
defaultRowDefs() {
return [
{
type: 'large',
row_direction: [0.7,0.0],
init_coords: [0.1,0.35],
rows: 3
},
{
type: 'large',
row_direction: [0.7,0.0],
init_coords: [0.6,0.35],
rows: 2
},
{
type: 'small',
row_direction: [0.0,1.0],
init_coords: [0.1,0.05],
rows: 1
}
];
}
}
module.exports = DigitDateTimeFormatter;

View File

@ -1,15 +1,55 @@
var DateFormatter = require("slidingtext.dtfmt.js");
const DateFormatter = require("slidingtext.dtfmt.js");
const hoursToText = require("slidingtext.utils.en.js").hoursToText;
const numberToText = require("slidingtext.utils.en.js").numberToText;
const dayOfWeek = require("slidingtext.utils.en.js").dayOfWeek;
const numberToDayNumberText = require("slidingtext.utils.en.js").numberToDayNumberText;
const monthToText = require("slidingtext.utils.en.js").monthToText;
class EnglishDateFormatter extends DateFormatter {
constructor() { super();}
name(){return "English";}
shortName(){return "en"}
constructor() {
super();
}
formatDate(date){
var hours_txt = hoursToText(date.getHours());
var mins_txt = numberToText(date.getMinutes());
return [hours_txt,mins_txt[0],mins_txt[1]];
const hours_txt = hoursToText(date.getHours());
const mins_txt = numberToText(date.getMinutes());
const day_of_week = dayOfWeek(date);
const date_txt = numberToDayNumberText(date.getDate()).join(' ');
const month = monthToText(date);
return [hours_txt,mins_txt[0],mins_txt[1],day_of_week,date_txt,month];
}
defaultRowTypes() {
return {
small: {size: 'ssmall'}
};
}
defaultRowDefs(){
const row_defs = [
{
type: 'large',
init_coords: [0.05,0.07],
row_direction: [0.0,1.0],
rows: 1
},
{
type: 'medium',
init_coords: [0.05,0.31],
row_direction: [0.0,1.0],
rows: 2
}
];
const bangleVersion = (g.getHeight()>200)? 1 : 2;
if(bangleVersion > 1){
row_defs.push(
{
type: 'small',
init_coords: [0.05,0.75],
row_direction: [0.0,1.0],
rows: 2
}
)
}
return row_defs;
}
}

View File

@ -1,4 +1,6 @@
var DateFormatter = require("slidingtext.dtfmt.js");
const DateFormatter = require("slidingtext.dtfmt.js");
const dayOfWeekShort = require("slidingtext.utils.en.js").dayOfWeekShort;
const numberToDayNumberText = require("slidingtext.utils.en.js").numberToDayNumberText;
const hoursToText = require("slidingtext.utils.en.js").hoursToText;
const numberToText = require("slidingtext.utils.en.js").numberToText;
@ -6,24 +8,24 @@ class EnglishTraditionalDateFormatter extends DateFormatter {
constructor() {
super();
}
name(){return "English (Traditional)";}
shortName(){return "en2"}
formatDate(date){
var mins = date.getMinutes();
const day_of_week = dayOfWeekShort(date);
const date_txt = numberToDayNumberText(date.getDate()).join(' ');
const mins = date.getMinutes();
var hourOfDay = date.getHours();
if(mins > 30){
hourOfDay += 1;
}
var hours = hoursToText(hourOfDay);
const hours = hoursToText(hourOfDay);
// Deal with the special times first
if(mins == 0){
return [hours,"", "O'","CLOCK"];
} else if(mins == 30){
return ["","HALF", "PAST", "", hours];
} else if(mins == 15){
return ["","QUARTER", "PAST", "", hours];
} else if(mins == 45) {
return ["", "QUARTER", "TO", "", hours];
if(mins === 0){
return [hours,"", "O'","CLOCK","", day_of_week, date_txt];
} else if(mins === 30){
return ["","HALF", "PAST", "", hours, day_of_week, date_txt];
} else if(mins === 15){
return ["","QUARTER", "PAST", "", hours, day_of_week, date_txt];
} else if(mins === 45) {
return ["", "QUARTER", "TO", "", hours, day_of_week, date_txt];
}
var mins_txt;
var from_to;
@ -37,18 +39,57 @@ class EnglishTraditionalDateFormatter extends DateFormatter {
from_to = "PAST";
mins_txt = numberToText(mins_value);
}
if(mins_txt[1] != '') {
return ['', mins_txt[0], mins_txt[1], from_to, hours];
if(mins_txt[1] !== '') {
return ['', mins_txt[0], mins_txt[1], from_to, hours, day_of_week, date_txt];
} else {
if(mins_value % 5 == 0) {
return ['', mins_txt[0], from_to, '', hours];
} else if(mins_value == 1){
return ['', mins_txt[0], 'MINUTE', from_to, hours];
if(mins_value % 5 === 0) {
return ['', mins_txt[0], from_to, '', hours, day_of_week, date_txt];
} else if(mins_value === 1){
return ['', mins_txt[0], 'MINUTE', from_to, hours, day_of_week, date_txt];
} else {
return ['', mins_txt[0], 'MINUTES', from_to, hours];
return ['', mins_txt[0], 'MINUTES', from_to, hours, day_of_week, date_txt];
}
}
}
defaultRowTypes(){
return {
small: {
speed: 'medium',
scroll_off: ['left','right'],
scroll_in: ['left','right'],
},
large: {
speed: 'medium',
color: 'major',
scroll_off: ['left','right'],
scroll_in: ['left','right']
}
};
}
defaultRowDefs(){
return [
{
type: 'large',
init_coords: [0.05,0.1],
row_direction: [0.0,1.0],
rows: 1
},
{
type: 'small',
init_coords: [0.05,0.35],
row_direction: [0.0,1.0],
rows: 3
},
{
type: 'large',
init_coords: [0.05,0.75],
row_direction: [0.0,1.0],
rows: 1
}
];
}
}
module.exports = EnglishTraditionalDateFormatter;

View File

@ -34,7 +34,7 @@ const spanishNumberStr = [ ["ZERO"], // 0
function spanishHoursToText(hours){
hours = hours % 12;
if(hours == 0){
if(hours === 0){
hours = 12;
}
return spanishNumberStr[hours][0];
@ -45,34 +45,52 @@ function spanishMinsToText(mins){
}
class SpanishDateFormatter extends DateFormatter {
constructor() { super();}
name(){return "Spanish";}
shortName(){return "es"}
constructor() {
super();
}
formatDate(date){
var mins = date.getMinutes();
const mins = date.getMinutes();
var hourOfDay = date.getHours();
if(mins > 30){
hourOfDay += 1;
}
var hours = spanishHoursToText(hourOfDay);
const hours = spanishHoursToText(hourOfDay);
//console.log('hourOfDay->' + hourOfDay + ' hours text->' + hours)
// Deal with the special times first
if(mins == 0){
if(mins === 0){
return [hours,"", "","",""];
} else if(mins == 30){
} else if(mins === 30){
return [hours, "Y", "MEDIA",""];
} else if(mins == 15){
} else if(mins === 15){
return [hours, "Y", "CUARTO",""];
} else if(mins == 45) {
} else if(mins === 45) {
return [hours, "MENOS", "CUARTO",""];
} else if(mins > 30){
var mins_txt = spanishMinsToText(60-mins);
const mins_txt = spanishMinsToText(60-mins);
return [hours, "MENOS", mins_txt[0],mins_txt[1]];
} else {
var mins_txt = spanishMinsToText(mins);
const mins_txt = spanishMinsToText(mins);
return [hours, "Y", mins_txt[0],mins_txt[1]];
}
}
defaultRowTypes(){ return {};}
defaultRowDefs(){
return [
{
type: 'large',
init_coords: [0.05,0.1],
row_direction: [0.0,1.0],
rows: 1
},
{
type: 'medium',
init_coords: [0.05,0.4],
row_direction: [0.0,1.0],
rows: 3
}
];
}
}
module.exports = SpanishDateFormatter;

View File

@ -14,14 +14,14 @@ const frenchNumberStr = [ "ZERO", "UNE", "DEUX", "TROIS", "QUATRE",
function frenchHoursToText(hours){
hours = hours % 12;
if(hours == 0){
if(hours === 0){
hours = 12;
}
return frenchNumberStr[hours];
}
function frenchHeures(hours){
if(hours % 12 == 1){
if(hours % 12 === 1){
return 'HEURE';
} else {
return 'HEURES';
@ -29,33 +29,33 @@ function frenchHeures(hours){
}
class FrenchDateFormatter extends DateFormatter {
constructor() { super(); }
name(){return "French";}
shortName(){return "fr"}
constructor() {
super();
}
formatDate(date){
var hours = frenchHoursToText(date.getHours());
var heures = frenchHeures(date.getHours());
var mins = date.getMinutes();
if(mins == 0){
if(hours == 0){
const mins = date.getMinutes();
if(mins === 0){
if(hours === 0){
return ["MINUIT", "",""];
} else if(hours == 12){
} else if(hours === 12){
return ["MIDI", "",""];
} else {
return [hours, heures,""];
}
} else if(mins == 30){
} else if(mins === 30){
return [hours, heures,'ET DEMIE'];
} else if(mins == 15){
} else if(mins === 15){
return [hours, heures,'ET QUART'];
} else if(mins == 45){
} else if(mins === 45){
var next_hour = date.getHours() + 1;
hours = frenchHoursToText(next_hour);
heures = frenchHeures(next_hour);
return [hours, heures,"MOINS",'LET QUART'];
}
if(mins > 30){
var to_mins = 60-mins;
const to_mins = 60-mins;
var mins_txt = frenchNumberStr[to_mins];
next_hour = date.getHours() + 1;
hours = frenchHoursToText(next_hour);
@ -66,6 +66,30 @@ class FrenchDateFormatter extends DateFormatter {
return [ hours, heures , mins_txt ];
}
}
defaultRowTypes(){
return {
small: {
speed: 'vslow'
}
};
}
defaultRowDefs(){
return [
{
type: 'large',
init_coords: [0.05,0.1],
row_direction: [0.0,1.0],
rows: 1
},
{
type: 'small',
init_coords: [0.05,0.4],
row_direction: [0.0,1.0],
rows: 3
}
];
}
}
module.exports = FrenchDateFormatter;

View File

@ -0,0 +1,80 @@
const DateFormatter = require("slidingtext.dtfmt.js");
const numberToText = require("slidingtext.utils.en.js").numberToText;
const dayOfWeek = require("slidingtext.utils.en.js").dayOfWeekShort;
class EnglishDateFormatter extends DateFormatter {
constructor() {
super();
}
format00(num){
const value = (num | 0);
if(value > 99 || value < 0)
throw "must be between in range 0-99";
if(value < 10)
return "0" + value.toString();
else
return value.toString();
}
formatDate(date){
const hours_txt = this.format00(date.getHours());
const mins_txt = numberToText(date.getMinutes());
const day_of_week = dayOfWeek(date);
const date_txt = day_of_week + " " + this.format00(date.getDate());
return [hours_txt,mins_txt[0],mins_txt[1],date_txt];
}
defaultRowTypes() {
return {
large: {
size: 'slarge',
scroll_off: ['left','down'],
scroll_in: ['up','left'],
},
medium: {
size: 'msmall',
scroll_off: ['down'],
scroll_in: ['up'],
angle_to_horizontal: 90
},
small: {
size: 'ssmall',
scroll_off: ['left'],
scroll_in: ['left'],
}
};
}
defaultRowDefs(){
const row_defs = [
{
type: 'large',
init_coords: [0.05,0.35],
row_direction: [0.0,1.0],
rows: 1
},
{
type: 'medium',
init_coords: [0.68,0.95],
row_direction: [1.0,0.0],
angle_to_horizontal: 90,
rows: 2
}];
const bangleVersion = (g.getHeight()>200)? 1 : 2;
if(bangleVersion > 1){
row_defs.push(
{
type: 'small',
init_coords: [0.05, 0.1],
row_direction: [0.0, 1.0],
rows: 1
}
)
}
return row_defs;
}
}
module.exports = EnglishDateFormatter;

View File

@ -1,4 +1,4 @@
var DateFormatter = require("slidingtext.dtfmt.js");
const DateFormatter = require("slidingtext.dtfmt.js");
/**
* Japanese date formatting
@ -28,21 +28,21 @@ const japaneseMinuteStr = [ ["", "PUN"],
function japaneseHoursToText(hours){
hours = hours % 12;
if(hours == 0){
if(hours === 0){
hours = 12;
}
return japaneseHourStr[hours];
}
function japaneseMinsToText(mins){
if(mins == 0){
if(mins === 0){
return ["",""];
} else if(mins == 30)
} else if(mins === 30)
return ["HAN",""];
else {
var units = mins % 10;
var mins_txt = japaneseMinuteStr[units];
var tens = mins /10 | 0;
const units = mins % 10;
const mins_txt = japaneseMinuteStr[units];
const tens = mins /10 | 0;
if(tens > 0){
var tens_txt = tensPrefixStr[tens];
var minutes_txt;
@ -59,14 +59,32 @@ function japaneseMinsToText(mins){
}
class JapaneseDateFormatter extends DateFormatter {
constructor() { super(); }
name(){return "Japanese (Romanji)";}
shortName(){return "jp"}
constructor() {
super();
}
formatDate(date){
var hours_txt = japaneseHoursToText(date.getHours());
var mins_txt = japaneseMinsToText(date.getMinutes());
const hours_txt = japaneseHoursToText(date.getHours());
const mins_txt = japaneseMinsToText(date.getMinutes());
return [hours_txt,"JI", mins_txt[0], mins_txt[1] ];
}
defaultRowTypes(){ return {}; }
defaultRowDefs(){
return [
{
type: 'large',
init_coords: [0.05,0.1],
row_direction: [0.0,1.0],
rows: 1
},
{
type: 'medium',
init_coords: [0.05,0.4],
row_direction: [0.0,1.0],
rows: 3
}
];
}
}
module.exports = JapaneseDateFormatter;

View File

@ -1,33 +1,151 @@
(function(back) {
const PREFERENCE_FILE = "slidingtext.settings.json";
var settings = Object.assign({},
const settings = Object.assign({},
require('Storage').readJSON(PREFERENCE_FILE, true) || {});
const bangleVersion = (g.getHeight()>200)? 1 : 2;
// the screen controls are defaulted on for a bangle 1 and off for a bangle 2
if(settings.enable_live_controls == null){
settings.enable_live_controls = (g.getHeight()> 200);
settings.enable_live_controls = bangleVersion < 2;
}
console.log("loaded:" + JSON.stringify(settings));
const locale_mappings = (bangleVersion > 1)? {
'english' : { date_formatter: 'en' },
'english alt': {
date_formatter: 'en',
row_types: {
large:{
size: 'mlarge',
angle_to_horizontal: 90,
scroll_off: ['down'],
scroll_in: ['up'],
speed: 'vslow'
},
medium: {
size: 'msmall',
scroll_off: ['right'],
scroll_in: ['right'],
},
small: {
scroll_off: ['right'],
scroll_in: ['right'],
}
},
row_defs: [
{
type: 'large',
init_coords: [0.05,0.99],
row_direction: [1.0,0.0],
alignment: 'centre-6',
rows: 1
},
{
type: 'medium',
init_coords: [0.26,0.1],
row_direction: [0.0,1.0],
rows: 2
},
{
type: 'small',
init_coords: [0.26,0.65],
row_direction: [0.0,1.0],
rows: 3
}
]
},
'english2': { date_formatter: 'en2' },
'english2 alt': { date_formatter: 'en2',
row_types: {
vsmall: {
color: 'minor',
speed: 'superslow',
angle_to_horizontal: 0,
scroll_off: ['left'],
scroll_in: ['left'],
size: 'ssmall'
},
small: {
scroll_off: ['left'],
scroll_in: ['left']
},
large: {
size: 'mlarge',
angle_to_horizontal: 90,
color: 'major',
scroll_off: ['down'],
scroll_in: ['up']
}
},
row_defs: [
{
type: 'large',
init_coords: [0.8,0.99],
row_direction: [0.0,1.0],
alignment: 'centre-6',
rows: 1
},
{
type: 'small',
init_coords: [0.05,0.45],
row_direction: [0.0,1.0],
rows: 3
},
{
type: 'large',
init_coords: [0.8,0.99],
row_direction: [0.0,1.0],
alignment: 'centre-6',
rows: 1
},
{
type: 'vsmall',
init_coords: [0.05,0.1],
row_direction: [0.0,1.0],
rows: 2
},
]
},
'french': { date_formatter:'fr'},
'german': { date_formatter: 'de'},
'german 24h': { date_formatter: 'de2'},
'spanish': { date_formatter: 'es'},
'japanese': { date_formatter: 'jp'},
'hybrid': { date_formatter: 'hyb'},
'digits': { date_formatter: 'dgt'},
} : {
'english' : { date_formatter: 'en' },
'french': { date_formatter:'fr'},
'german': { date_formatter: 'de'},
'spanish': { date_formatter: 'es'},
'japanese': { date_formatter: 'jp'},
'hybrid': { date_formatter: 'hyb'},
'digits': { date_formatter: 'dgt'},
}
const LANGUAGES_FILE = "slidingtext.languages.json";
const LANGUAGES_DEFAULT = ["en","en2"];
var locales = null;
try {
locales = require("Storage").readJSON(LANGUAGES_FILE);
} catch(e) {
console.log("failed to load languages:" + e);
}
if(locales == null || locales.length == 0){
locales = LANGUAGES_DEFAULT;
console.log("defaulting languages to locale:" + locales);
}
const locales = Object.keys(locale_mappings);
function writeSettings() {
if(settings.date_format == null){
settings.date_format = 'en';
}
const styling = locale_mappings[settings.date_format];
if(styling.date_formatter != null)
settings.date_formatter = styling.date_formatter;
settings.row_types = {};
if(styling.row_types != null)
settings.row_types = styling.row_types;
settings.row_defs = [];
if(styling.row_defs != null)
settings.row_defs = styling.row_defs;
console.log("saving:" + JSON.stringify(settings));
require('Storage').writeJSON(PREFERENCE_FILE, settings);
}
// Helper method which uses int-based menu item for set of string values
function stringItems(startvalue, writer, values) {
function stringItems(startvalue, writer, values, value_mapping) {
return {
value: (startvalue === undefined ? 0 : values.indexOf(startvalue)),
format: v => values[v],
@ -36,7 +154,8 @@
wrap: true,
step: 1,
onchange: v => {
writer(values[v]);
const write_value = (value_mapping == null)? values[v] : value_mapping(values[v]);
writer(write_value);
writeSettings();
}
};
@ -51,8 +170,8 @@
E.showMenu({
"" : { "title" : "Sliding Text" },
"< Back" : () => back(),
"Colour": stringInSettings("color_scheme", ["white", "black", "red","grey","purple","blue"]),
"Languages": stringInSettings("date_format", locales),
"Colour": stringInSettings("color_scheme", ["black","white", "red","grey","purple","blue"]),
"Style": stringInSettings("date_format", locales, (l)=>locale_mappings[l] ),
"Live Control": {
value: (settings.enable_live_controls !== undefined ? settings.enable_live_controls : true),
format: v => v ? "On" : "Off",

View File

@ -0,0 +1,86 @@
const germanNumberStr = [ ["NULL",""], // 0
["EINS",""], // 1
["ZWEI",""], //2
["DREI",""], //3
["VIER",""], //4
["FÜNF",""], //5
["SECHS",""], //6
["SIEBEN",""], //7
["ACHT",""], //8
["NEUN",""], // 9,
["ZEHN",""], // 10
["ELF",""], // 11,
["ZWÖLF",""], // 12
["DREI","ZEHN"], // 13
["VIER","ZEHN"], // 14
["FÜNF","ZEHN"], // 15
["SECH","ZEHN"], // 16
["SIEB","ZEHN"], // 17
["ACHT","ZEHN"], // 18
["NEUN","ZEHN"], // 19
["ZWANZIG",""], // 20
["EIN","UNDZWANZIG"], // 21
["ZWEI","UNDZWANZIG"], //22
["DREI","UNDZWANZIG"], // 23
["VIER","UNDZWANZIG"] // 24
];
const germanTensStr = ["NULL",//0
"ZEHN",//10
"ZWANZIG",//20
"DREIßIG",//30
"VIERZIG",//40
"FÜNFZIG",//50
"SECHZIG"//60
]
const germanUnit = ["",//0
"EINUND",//1
"ZWEIUND",//2
"DREIUND",//3
"VIERUND", //4
"FÜNFUND", //5
"SECHSUND", //6
"SIEBENUND", //7
"ACHTUND", //8
"NEUNUND" //9
]
function germanHoursToText(hours){
hours = hours % 12;
if(hours === 0){
hours = 12;
}
if(hours === 1){
return "EIN"
} else {
return germanNumberStr[hours][0];
}
}
function german24HoursToText(hours){
hours = hours % 24;
if(hours === 0){
return hours[24] ;
} else if(hours === 1){
return ["EIN",""];
} else {
return germanNumberStr[hours];
}
}
function germanMinsToText(mins) {
if (mins < 20) {
return germanNumberStr[mins];
} else {
const tens = (mins / 10 | 0);
const word1 = germanTensStr[tens];
const remainder = mins - tens * 10;
const word2 = germanUnit[remainder];
return [word2, word1];
}
}
exports.germanMinsToText = germanMinsToText;
exports.germanHoursToText = germanHoursToText;
exports.german24HoursToText = german24HoursToText;

View File

@ -3,12 +3,26 @@ const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE",
"ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN",
"FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN",
"NINETEEN", "TWENTY"];
const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY",
"FIFTY"];
const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FORTY", "FIFTY"];
const dayNames = ["SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"];
const monthStr = [
"JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JULY",
"AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"
]
const dateNumberStr = ["ZEROTH", "FIRST", "SECOND", "THIRD", "FORTH", "FIFTH",
"SIXTH","SEVENTH","EIGHTH","NINTH","TENTH","ELEVENTH","TWELFTH","THIRTEENTH",
"FOURTEENTH", "FIFTEENTH", "SIXTEENTH", "SEVENTEENTH", "EIGHTEENTH", "NINETEENTH",
"TWENTIETH"
]
const dayOfWeek = (date) => dayNames[date.getDay()];
const dayOfWeekShort = (date) => dayNames[date.getDay()].substring(0,3);
const monthToText = (date)=>monthStr[date.getMonth()-1];
const hoursToText = (hours)=>{
hours = hours % 12;
if(hours == 0){
if(hours === 0){
hours = 12;
}
return numberStr[hours];
@ -18,9 +32,9 @@ const numberToText = (value)=> {
var word1 = '';
var word2 = '';
if(value > 20){
var tens = (value / 10 | 0);
const tens = (value / 10 | 0);
word1 = tensStr[tens];
var remainder = value - tens * 10;
const remainder = value - tens * 10;
if(remainder > 0){
word2 = numberStr[remainder];
}
@ -30,5 +44,27 @@ const numberToText = (value)=> {
return [word1,word2];
}
const numberToDayNumberText = (value) => {
var word1 = '';
var word2 = '';
if(value === 30) {
word1 = "THIRTIETH";
} else if(value > 20){
const tens = (value / 10 | 0);
word1 = tensStr[tens];
const remainder = value - tens * 10;
if(remainder > 0){
word2 = dateNumberStr[remainder];
}
} else if(value > 0) {
word1 = dateNumberStr[value];
}
return [word1,word2];
}
exports.monthToText = monthToText;
exports.hoursToText = hoursToText;
exports.numberToText = numberToText;
exports.numberToText = numberToText;
exports.numberToDayNumberText = numberToDayNumberText;
exports.dayOfWeek = dayOfWeek;
exports.dayOfWeekShort = dayOfWeekShort;