Merge branch 'master' into master
|
@ -0,0 +1,478 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
id="svg4149"
|
||||
viewBox="0 0 19.191 30.044001"
|
||||
height="30.044001"
|
||||
width="19.191">
|
||||
<defs
|
||||
id="defs4151">
|
||||
<linearGradient
|
||||
id="linearGradient28799-4">
|
||||
<stop
|
||||
id="stop28801-13"
|
||||
offset="0"
|
||||
style="stop-color:#fefefc;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#fefefc;stop-opacity:1"
|
||||
offset="0.75733864"
|
||||
id="stop28807-8" />
|
||||
<stop
|
||||
id="stop28803-8"
|
||||
offset="1"
|
||||
style="stop-color:#d4d4d4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="14.572236"
|
||||
fy="137.66095"
|
||||
fx="223.19559"
|
||||
cy="137.66095"
|
||||
cx="223.19559"
|
||||
gradientTransform="matrix(1.0857794,-0.03431182,0.03943781,1.2479887,-154.54194,-26.542647)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient29032"
|
||||
xlink:href="#linearGradient28799-4" />
|
||||
<radialGradient
|
||||
r="14.572236"
|
||||
fy="137.66095"
|
||||
fx="223.19559"
|
||||
cy="137.66095"
|
||||
cx="223.19559"
|
||||
gradientTransform="matrix(0.81524244,-0.03431182,0.02961133,1.2479887,-129.43743,-26.542647)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient29648"
|
||||
xlink:href="#linearGradient28799-4" />
|
||||
<linearGradient
|
||||
id="linearGradient14392-7">
|
||||
<stop
|
||||
style="stop-color:#3e2a06;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop14394-8" />
|
||||
<stop
|
||||
style="stop-color:#ad780a;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop14396-6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient14392-7"
|
||||
id="linearGradient14477"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.87491199,0,0,0.81148755,60.367186,62.586953)"
|
||||
x1="442.03912"
|
||||
y1="371.54401"
|
||||
x2="490.12241"
|
||||
y2="293.58548" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient14392-7"
|
||||
id="linearGradient14485"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(4e-6,9.6185359e-6)"
|
||||
x1="442.03912"
|
||||
y1="371.54401"
|
||||
x2="490.12241"
|
||||
y2="293.58548" />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14186-9">
|
||||
<path
|
||||
id="path14188-1"
|
||||
d="m 137.57703,281.0191 c 1.59929,-0.66295 3.3982,-0.78361 5.10074,-0.46963 1.70253,0.31398 3.31141,1.04948 4.74342,2.02239 2.86402,1.94583 4.98821,4.77774 7.02263,7.57952 4.67189,6.43406 9.16868,13.00227 13.24488,19.8293 3.30635,5.53766 6.34352,11.25685 10.16415,16.45304 2.49398,3.3919 5.3066,6.53947 7.813,9.92221 2.50639,3.38273 4.72794,7.05586 5.83931,11.11662 1.44411,5.27653 0.88463,11.09291 -1.62666,15.95302 -1.76663,3.41896 -4.47646,6.35228 -7.77242,8.33898 -3.29595,1.9867 -7.17064,3.01444 -11.01635,2.87021 -6.11413,-0.2293 -11.69944,-3.28515 -17.38362,-5.54906 -11.58097,-4.6125 -24.15978,-6.0594 -36.09666,-9.65174 -3.66859,-1.10404 -7.27582,-2.4107 -10.96988,-3.42629 -1.64125,-0.45122 -3.30866,-0.8482 -4.85875,-1.55144 -1.55008,-0.70325 -2.999548,-1.7491 -3.86171,-3.21675 -0.666391,-1.13439 -0.948386,-2.47002 -0.930187,-3.78554 0.0182,-1.31552 0.325889,-2.61453 0.773815,-3.85158 0.895851,-2.47409 2.343262,-4.71374 3.320162,-7.15696 1.59511,-3.98935 1.88169,-8.38839 1.66657,-12.67942 -0.21511,-4.29103 -0.91078,-8.54478 -1.20454,-12.83115 -0.13118,-1.91406 -0.18066,-3.85256 0.18479,-5.73598 0.36545,-1.88343 1.17577,-3.72459 2.55771,-5.05541 1.27406,-1.22693 2.96492,-1.95531 4.69643,-2.31651 1.73151,-0.3612 3.51533,-0.37747 5.28367,-0.33762 1.76833,0.0399 3.54067,0.13425 5.30351,-0.0106 1.76284,-0.14488 3.53347,-0.54055 5.06911,-1.41828 1.45996,-0.83447 2.65433,-2.0745 3.64374,-3.43424 0.9894,-1.35974 1.78909,-2.84573 2.60891,-4.31396 0.81983,-1.46823 1.66834,-2.93151 2.74157,-4.22611 1.07324,-1.2946 2.38923,-2.42304 3.94266,-3.06698"
|
||||
style="fill:#402c07;fill-opacity:1;stroke:none" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath15031-3">
|
||||
<path
|
||||
style="fill:none;stroke:#729fcf;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 248.06066,184.61218 c -2.60091,3.4397 -5.23338,6.85555 -7.89695,10.24696 -2.83301,3.60715 -5.70116,7.1866 -8.58729,10.75139 -3.54135,4.37407 -7.15155,8.79286 -9.44912,13.93045 -1.97407,4.41422 -2.91014,9.20748 -4.26498,13.84932 -1.53862,5.27153 -3.62627,10.37023 -5.97071,15.33612 -2.1648,4.58539 -4.54978,9.06293 -6.93891,13.53553 -1.73823,3.25407 -3.50515,6.58104 -4.10782,10.22071 -0.47627,2.87632 -0.19849,5.84423 0.53376,8.66626 0.73224,2.82202 1.90964,5.5106 3.23775,8.10601 5.66724,11.07504 14.17003,20.62168 24.24176,27.92472 4.57063,3.31418 9.46669,6.18109 14.60245,8.52595 2.78247,1.27041 5.71355,2.40436 8.77186,2.45744 1.52915,0.0265 3.0741,-0.22544 4.47434,-0.84055 1.40024,-0.6151 2.65068,-1.60373 3.48254,-2.88709 1.02278,-1.5779 1.36992,-3.53829 1.16461,-5.40743 -0.2053,-1.86914 -0.93484,-3.65294 -1.91324,-5.25873 -2.38997,-3.92251 -6.1652,-6.76055 -9.79642,-9.57343 -7.84055,-6.07358 -15.42466,-12.48038 -22.68212,-19.23996 -2.04911,-1.90854 -4.0984,-3.87759 -5.53019,-6.28412 -1.3943,-2.34352 -2.14763,-5.01375 -2.65783,-7.69253 -1.39963,-7.34872 -1.0404,-15.0827 1.45958,-22.13343 0.97802,-2.75834 2.27066,-5.39225 3.51815,-8.03965 2.1622,-4.58855 4.21133,-9.26299 7.04933,-13.46723 3.53268,-5.23334 8.24484,-9.67275 11.15147,-15.27803 2.45457,-4.7335 3.49353,-10.05742 4.36185,-15.31831 0.66531,-4.03089 1.24751,-8.07549 1.74613,-12.13037"
|
||||
id="path15033-2" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14822-9">
|
||||
<path
|
||||
d="m 386.1875,285.32775 c -0.40516,-1.10369 -1.11845,-2.08156 -1.9907,-2.86987 -0.87226,-0.78832 -1.90049,-1.39229 -2.98278,-1.85155 -2.16459,-0.91852 -4.52053,-1.26149 -6.83152,-1.69556 -2.17919,-0.40931 -4.34179,-0.90631 -6.52782,-1.27734 -2.27136,-0.38551 -4.6179,-0.63213 -6.8653,-0.1253 -1.96583,0.44333 -3.7845,1.45879 -5.27172,2.81864 -1.48723,1.35984 -2.64911,3.0564 -3.48499,4.89007 -1.47218,3.22952 -1.93451,6.86503 -1.65394,10.40316 0.20882,2.63325 0.87532,5.34594 2.60877,7.33912 1.40065,1.61052 3.38733,2.61526 5.43398,3.22092 3.52502,1.04316 7.36663,0.98822 10.86038,-0.1553 5.76689,-1.93113 10.87568,-5.77387 14.33034,-10.77903 1.13861,-1.64963 2.11217,-3.44809 2.5532,-5.4034 0.33597,-1.48955 0.34831,-3.08112 -0.1779,-4.51456"
|
||||
id="path14824-1"
|
||||
style="fill:none;stroke:#ce5c00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14822-2-4">
|
||||
<path
|
||||
d="m 386.1875,285.32775 c -0.40516,-1.10369 -1.11845,-2.08156 -1.9907,-2.86987 -0.87226,-0.78832 -1.90049,-1.39229 -2.98278,-1.85155 -2.16459,-0.91852 -4.52053,-1.26149 -6.83152,-1.69556 -2.17919,-0.40931 -4.34179,-0.90631 -6.52782,-1.27734 -2.27136,-0.38551 -4.6179,-0.63213 -6.8653,-0.1253 -1.96583,0.44333 -3.7845,1.45879 -5.27172,2.81864 -1.48723,1.35984 -2.64911,3.0564 -3.48499,4.89007 -1.47218,3.22952 -1.93451,6.86503 -1.65394,10.40316 0.20882,2.63325 0.87532,5.34594 2.60877,7.33912 1.40065,1.61052 3.38733,2.61526 5.43398,3.22092 3.52502,1.04316 7.36663,0.98822 10.86038,-0.1553 5.76689,-1.93113 10.87568,-5.77387 14.33034,-10.77903 1.13861,-1.64963 2.11217,-3.44809 2.5532,-5.4034 0.33597,-1.48955 0.34831,-3.08112 -0.1779,-4.51456"
|
||||
id="path14824-6-5"
|
||||
style="fill:none;stroke:#ce5c00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="linearGradient14518-6">
|
||||
<stop
|
||||
id="stop14540-0"
|
||||
offset="0"
|
||||
style="stop-color:#110800;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#a65a00;stop-opacity:0.80000001;"
|
||||
offset="0.59066743"
|
||||
id="stop14542-5" />
|
||||
<stop
|
||||
style="stop-color:#ff921e;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop14522-4" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14489-3">
|
||||
<path
|
||||
style="fill:url(#linearGradient14485);fill-opacity:1;stroke:none"
|
||||
d="m 516.00562,331.8756 c -0.6714,1.71905 -1.62682,3.32679 -2.81579,4.73826 -2.6238,3.11482 -6.268,5.17039 -9.89648,7.01985 -6.1886,3.15437 -12.60169,5.92177 -18.41964,9.71654 -3.89802,2.54249 -7.4959,5.52671 -10.86016,8.74238 -2.87719,2.75012 -5.60582,5.68745 -8.83247,8.01771 -3.25567,2.35122 -7.01915,4.05426 -10.99061,4.6502 -4.83026,0.72481 -9.82134,-0.21289 -14.29898,-2.16416 -3.13754,-1.36728 -6.15569,-3.3229 -7.96301,-6.22931 -1.81425,-2.91754 -2.22807,-6.48813 -2.23266,-9.92375 -0.008,-6.07666 1.11824,-12.09004 2.17848,-18.07349 0.88097,-4.97177 1.71949,-9.95483 2.26013,-14.97502 0.98337,-9.13118 0.9763,-18.35278 0.3199,-27.51327 -0.10993,-1.53416 -0.23754,-3.0832 -0.008,-4.60412 0.22922,-1.52092 0.85475,-3.0367 2.02069,-4.03986 1.07696,-0.9266 2.52093,-1.33598 3.93947,-1.4145 1.41854,-0.0785 2.83404,0.14655 4.23982,0.35197 3.31254,0.48405 6.65159,0.8649 9.88917,1.71656 2.04284,0.53738 4.03315,1.25925 6.0722,1.81081 3.40258,0.92039 6.96639,1.36144 10.46739,0.95192 3.76917,-0.44089 7.42987,-1.85678 11.22363,-1.76474 1.55658,0.0378 3.1015,0.33171 4.58649,0.79985 1.51539,0.47772 3.00914,1.16182 4.12281,2.29512 0.84639,0.8613 1.43579,1.94539 1.87872,3.06879 0.65982,1.67352 1.01492,3.457 1.16703,5.24945 0.13475,1.58788 0.11343,3.19441 0.41433,4.75933 0.49503,2.57458 1.84746,4.92305 3.52848,6.93494 1.68102,2.01189 3.68982,3.72048 5.69641,5.40783 1.99908,1.68103 4.0106,3.35469 6.16708,4.82839 1.0121,0.69165 2.05642,1.33949 3.01736,2.10062 0.96094,0.76113 1.84466,1.6468 2.44543,2.71535 0.81492,1.44944 1.06377,3.2077 0.68307,4.82635 h 2e-5"
|
||||
id="path14491-6" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14481-1">
|
||||
<path
|
||||
style="fill:url(#linearGradient14485);fill-opacity:1;stroke:none"
|
||||
d="m 516.00562,331.8756 c -0.6714,1.71905 -1.62682,3.32679 -2.81579,4.73826 -2.6238,3.11482 -6.268,5.17039 -9.89648,7.01985 -6.1886,3.15437 -12.60169,5.92177 -18.41964,9.71654 -3.89802,2.54249 -7.4959,5.52671 -10.86016,8.74238 -2.87719,2.75012 -5.60582,5.68745 -8.83247,8.01771 -3.25567,2.35122 -7.01915,4.05426 -10.99061,4.6502 -4.83026,0.72481 -9.82134,-0.21289 -14.29898,-2.16416 -3.13754,-1.36728 -6.15569,-3.3229 -7.96301,-6.22931 -1.81425,-2.91754 -2.22807,-6.48813 -2.23266,-9.92375 -0.008,-6.07666 1.11824,-12.09004 2.17848,-18.07349 0.88097,-4.97177 1.71949,-9.95483 2.26013,-14.97502 0.98337,-9.13118 0.9763,-18.35278 0.3199,-27.51327 -0.10993,-1.53416 -0.23754,-3.0832 -0.008,-4.60412 0.22922,-1.52092 0.85475,-3.0367 2.02069,-4.03986 1.07696,-0.9266 2.52093,-1.33598 3.93947,-1.4145 1.41854,-0.0785 2.83404,0.14655 4.23982,0.35197 3.31254,0.48405 6.65159,0.8649 9.88917,1.71656 2.04284,0.53738 4.03315,1.25925 6.0722,1.81081 3.40258,0.92039 6.96639,1.36144 10.46739,0.95192 3.76917,-0.44089 7.42987,-1.85678 11.22363,-1.76474 1.55658,0.0378 3.1015,0.33171 4.58649,0.79985 1.51539,0.47772 3.00914,1.16182 4.12281,2.29512 0.84639,0.8613 1.43579,1.94539 1.87872,3.06879 0.65982,1.67352 1.01492,3.457 1.16703,5.24945 0.13475,1.58788 0.11343,3.19441 0.41433,4.75933 0.49503,2.57458 1.84746,4.92305 3.52848,6.93494 1.68102,2.01189 3.68982,3.72048 5.69641,5.40783 1.99908,1.68103 4.0106,3.35469 6.16708,4.82839 1.0121,0.69165 2.05642,1.33949 3.01736,2.10062 0.96094,0.76113 1.84466,1.6468 2.44543,2.71535 0.81492,1.44944 1.06377,3.2077 0.68307,4.82635 h 2e-5"
|
||||
id="path14483-3" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14473-5">
|
||||
<path
|
||||
style="fill:url(#linearGradient14477);fill-opacity:1;stroke:none"
|
||||
d="m 511.82669,331.89986 c -0.60617,1.40358 -1.44178,2.70776 -2.46357,3.84504 -2.32524,2.58805 -5.50706,4.22246 -8.65855,5.69652 -5.42045,2.53534 -11.00071,4.7788 -16.11556,7.88485 -3.38301,2.05437 -6.53696,4.47221 -9.50169,7.09434 -2.52461,2.23286 -4.92977,4.6271 -7.72763,6.50627 -2.88313,1.93644 -6.17534,3.29888 -9.61582,3.77358 -4.21817,0.58201 -8.55335,-0.18335 -12.51035,-1.75619 -2.7091,-1.07682 -5.36625,-2.6185 -6.96693,-5.05501 -1.53813,-2.3413 -1.9333,-5.25173 -1.95338,-8.053 -0.0354,-4.93859 0.96501,-9.81816 1.90598,-14.66641 0.78215,-4.02995 1.52682,-8.0717 1.97741,-12.15204 0.81784,-7.40607 0.66114,-14.88536 0.27989,-22.32668 -0.064,-1.24906 -0.13361,-2.5105 0.0789,-3.74301 0.21256,-1.23251 0.73646,-2.45247 1.68171,-3.27147 0.93914,-0.8137 2.20952,-1.15942 3.45104,-1.2115 1.24152,-0.0521 2.47642,0.16381 3.70512,0.34927 2.88969,0.43617 5.81087,0.7091 8.65215,1.39297 1.78651,0.43 3.53091,1.02011 5.31265,1.46945 2.98632,0.75312 6.09645,1.10709 9.15804,0.77247 3.2941,-0.36004 6.50688,-1.50957 9.81969,-1.43207 1.35838,0.0318 2.70755,0.27142 4.01277,0.64907 1.31265,0.3798 2.61744,0.9202 3.6071,1.86246 0.72535,0.69061 1.25006,1.56936 1.64371,2.49029 0.57625,1.34814 0.88626,2.79994 1.02105,4.25986 0.11897,1.28855 0.10468,2.59405 0.36251,3.86214 0.4369,2.14878 1.63966,4.08139 3.11506,5.70353 1.4754,1.62214 3.22406,2.96752 4.9559,4.31247 1.75634,1.36398 3.50975,2.7398 5.39565,3.91818 0.88228,0.55128 1.79349,1.05932 2.63473,1.67142 0.84123,0.61209 1.61878,1.33907 2.14473,2.23668 0.68386,1.16711 0.90229,2.59857 0.59763,3.91652 h 2e-5"
|
||||
id="path14475-9" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14656-7">
|
||||
<path
|
||||
d="m 304.84727,225.44951 c 6.01627,4.92338 9.77707,12.317 10.94319,20.00305 1.8254,12.03148 -2.34636,24.07488 -6.44591,35.53273 -0.81749,2.28481 -1.63978,4.59033 -1.96473,6.99513 -0.32495,2.4048 -0.11897,4.94825 1.02948,7.08594 1.30279,2.42497 3.73227,4.12469 6.36677,4.92292 2.58877,0.78438 5.39365,0.76103 8.01466,0.0922 2.62101,-0.66882 5.06097,-1.96774 7.18716,-3.63996 5.48002,-4.30997 8.75799,-10.98552 10.01043,-17.84394 1.25243,-6.85841 0.63908,-13.92879 -0.551,-20.7983 -1.62313,-9.36916 -4.30898,-18.53961 -7.74003,-27.40773 -2.51766,-6.50732 -5.46794,-12.91081 -9.61753,-18.52016 -4.04611,-5.46946 -9.16208,-10.08954 -13.10336,-15.63502 -2.73209,-3.84412 -4.89983,-8.13097 -8.1917,-11.50812 -1.64594,-1.68858 -3.57654,-3.13527 -5.76975,-4.00143 -2.19321,-0.86616 -4.66356,-1.12446 -6.93254,-0.48249 -1.50468,0.42573 -2.89193,1.23739 -4.03791,2.30136 -1.14598,1.06397 -2.05268,2.37637 -2.69275,3.80312 -1.28015,2.85349 -1.47719,6.11241 -0.96512,9.1977 0.66114,3.98343 2.44407,7.69333 4.46569,11.18873 2.27396,3.93169 4.918,7.71926 8.38442,10.65407 3.5985,3.04664 7.96161,5.07413 11.61053,8.0602"
|
||||
id="path14658-9"
|
||||
style="fill:none;stroke:#c17d11;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clipPath29644-8"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path29646-8"
|
||||
d="m 54.232441,122.36218 c -1.780966,0.097 -3.484616,0.91899 -4.787851,2.1367 -1.303235,1.21771 -2.221372,2.81176 -2.786181,4.50357 -1.129618,3.38363 -0.875481,7.05177 -0.618698,10.60973 0.23251,3.22162 0.470404,6.50533 1.676785,9.50158 0.60319,1.49813 1.450247,2.91021 2.580338,4.06395 1.130092,1.15374 2.551736,2.04189 4.118297,2.43447 1.468838,0.36809 3.038161,0.29183 4.482784,-0.16209 1.444623,-0.45391 2.763917,-1.27887 3.846236,-2.33791 1.57904,-1.54507 2.643262,-3.5662 3.253449,-5.68947 0.610186,-2.12328 0.784157,-4.35155 0.752401,-6.56053 -0.03974,-2.76435 -0.400909,-5.53851 -1.265755,-8.16439 -0.864846,-2.62588 -2.245742,-5.10327 -4.172795,-7.08561 -0.933308,-0.96009 -1.997766,-1.80513 -3.198586,-2.39747 -1.200819,-0.59233 -2.54344,-0.92535 -3.880424,-0.85253"
|
||||
style="fill:url(#radialGradient29648);fill-opacity:1;stroke:none" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="linearGradient28469-0">
|
||||
<stop
|
||||
style="stop-color:#d2940a;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop28479-4" />
|
||||
<stop
|
||||
style="stop-color:#d89c08;stop-opacity:1"
|
||||
offset="0.75143719"
|
||||
id="stop28477-2" />
|
||||
<stop
|
||||
id="stop28485-7"
|
||||
offset="0.86579126"
|
||||
style="stop-color:#b67e07;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop28473-1"
|
||||
offset="1"
|
||||
style="stop-color:#946106;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient28275-8">
|
||||
<stop
|
||||
id="stop28277-1"
|
||||
offset="0"
|
||||
style="stop-color:#ad780a;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#d89e08;stop-opacity:1"
|
||||
offset="0.11972899"
|
||||
id="stop28291-9" />
|
||||
<stop
|
||||
style="stop-color:#edb80b;stop-opacity:1"
|
||||
offset="0.25514477"
|
||||
id="stop28289-6" />
|
||||
<stop
|
||||
style="stop-color:#ebc80d;stop-opacity:1"
|
||||
offset="0.39194193"
|
||||
id="stop28287-6" />
|
||||
<stop
|
||||
style="stop-color:#f5d838;stop-opacity:1"
|
||||
offset="0.52741116"
|
||||
id="stop28285-7" />
|
||||
<stop
|
||||
style="stop-color:#f6d811;stop-opacity:1"
|
||||
offset="0.76906693"
|
||||
id="stop28283-7" />
|
||||
<stop
|
||||
id="stop28279-5"
|
||||
offset="1"
|
||||
style="stop-color:#f5cd31;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient29529-6">
|
||||
<stop
|
||||
id="stop29531-0"
|
||||
offset="0"
|
||||
style="stop-color:#3a2903;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#735208;stop-opacity:1"
|
||||
offset="0.55472803"
|
||||
id="stop29539-7" />
|
||||
<stop
|
||||
id="stop29533-8"
|
||||
offset="1"
|
||||
style="stop-color:#ac8c04;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient29477-3">
|
||||
<stop
|
||||
id="stop29479-5"
|
||||
offset="0"
|
||||
style="stop-color:#757574;stop-opacity:0" />
|
||||
<stop
|
||||
style="stop-color:#757574;stop-opacity:1;"
|
||||
offset="0.26291031"
|
||||
id="stop29487-5" />
|
||||
<stop
|
||||
style="stop-color:#757574;stop-opacity:1;"
|
||||
offset="0.5"
|
||||
id="stop29485-0" />
|
||||
<stop
|
||||
id="stop29481-3"
|
||||
offset="1"
|
||||
style="stop-color:#757574;stop-opacity:0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient29336-6">
|
||||
<stop
|
||||
id="stop29338-1"
|
||||
offset="0"
|
||||
style="stop-color:#646464;stop-opacity:0" />
|
||||
<stop
|
||||
style="stop-color:#646464;stop-opacity:0.5825243"
|
||||
offset="0.30628255"
|
||||
id="stop29344-7" />
|
||||
<stop
|
||||
id="stop29354-5"
|
||||
offset="0.47000006"
|
||||
style="stop-color:#646464;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#646464;stop-opacity:0.25728154"
|
||||
offset="0.72834015"
|
||||
id="stop29356-3" />
|
||||
<stop
|
||||
id="stop29340-6"
|
||||
offset="1"
|
||||
style="stop-color:#646464;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient28976-3">
|
||||
<stop
|
||||
id="stop28978-7"
|
||||
offset="0"
|
||||
style="stop-color:#747474;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#8c8c8c;stop-opacity:1;"
|
||||
offset="0.125"
|
||||
id="stop29259-5" />
|
||||
<stop
|
||||
style="stop-color:#a4a4a4;stop-opacity:1;"
|
||||
offset="0.25"
|
||||
id="stop29257-0" />
|
||||
<stop
|
||||
style="stop-color:#d4d4d4;stop-opacity:1"
|
||||
offset="0.5"
|
||||
id="stop28984-4" />
|
||||
<stop
|
||||
id="stop28986-0"
|
||||
offset="0.61919296"
|
||||
style="stop-color:#d4d4d4;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop28980-2"
|
||||
offset="1"
|
||||
style="stop-color:#7c7c7c;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="clipPath29028-5"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path29030-7"
|
||||
d="m 85.75,122.36218 c -2.780425,1.91023 -5.110569,4.57487 -6.25,7.75 -1.436029,4.00163 -0.885838,8.48071 0.5,12.5 1.419488,4.11688 3.793788,8.04098 7.37932,10.51234 1.792766,1.23567 3.868091,2.08301 6.030402,2.33859 2.162311,0.25558 4.409274,-0.0949 6.340278,-1.10093 2.35312,-1.22596 4.14782,-3.37278 5.26217,-5.78076 1.11436,-2.40798 1.5888,-5.0701 1.73783,-7.71924 0.18989,-3.37546 -0.14047,-6.80646 -1.25,-10 -1.20527,-3.46909 -3.39005,-6.67055 -6.472754,-8.6666 -1.541351,-0.99803 -3.291947,-1.68356 -5.110883,-1.93515 -1.818936,-0.25158 -3.704766,-0.0633 -5.416363,0.60175 -0.975471,0.37901 -1.887438,0.9074 -2.75,1.5"
|
||||
style="fill:url(#radialGradient29032);fill-opacity:1;stroke:none" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="linearGradient28935-8">
|
||||
<stop
|
||||
id="stop28937-7"
|
||||
offset="0"
|
||||
style="stop-color:#949494;stop-opacity:0.39215687;" />
|
||||
<stop
|
||||
style="stop-color:#949494;stop-opacity:1;"
|
||||
offset="0.5"
|
||||
id="stop28943-3" />
|
||||
<stop
|
||||
id="stop28939-8"
|
||||
offset="1"
|
||||
style="stop-color:#949494;stop-opacity:0.39215687;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient28853-5">
|
||||
<stop
|
||||
id="stop28855-3"
|
||||
offset="0"
|
||||
style="stop-color:#020204;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#020204;stop-opacity:1"
|
||||
offset="0.73448181"
|
||||
id="stop28865-0" />
|
||||
<stop
|
||||
id="stop28857-9"
|
||||
offset="1"
|
||||
style="stop-color:#5c5c5c;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="clipPath20"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path18"
|
||||
d="M 0,0 H 1920 V 1080 H 0 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clipPath70"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path68"
|
||||
d="M 0,0 H 1920 V 1080 H 0 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clipPath84"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path82"
|
||||
d="M 0,0 H 1920 V 1080 H 0 Z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
transform="translate(0,-1022.3182)"
|
||||
id="layer1">
|
||||
<path
|
||||
id="path5206"
|
||||
d=""
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path5204"
|
||||
d=""
|
||||
style="fill:#000000" />
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g1740"
|
||||
transform="matrix(0.1420516,0,0,-0.1420516,103.61175,1146.9897)">
|
||||
<g
|
||||
transform="translate(-1082.1477,-40.602139)"
|
||||
style="stroke-width:9.38626099"
|
||||
id="g14">
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g16"
|
||||
clip-path="url(#clipPath20)">
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g22"
|
||||
transform="translate(485.7208,801.7501)">
|
||||
<path
|
||||
d="M 0,0 H -6.408 V 21.503 H 0 c 1.176,0 2.129,-0.953 2.129,-2.129 V 2.129 C 2.129,0.953 1.176,0 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path24" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g26"
|
||||
transform="translate(467.9097,852.7021)">
|
||||
<path
|
||||
d="m 0,0 -1.811,-1.811 -10.287,10.287 1.811,1.811 c 1.424,1.425 3.734,1.425 5.159,0 L 0,5.159 C 1.425,3.734 1.425,1.425 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path28" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g30"
|
||||
transform="translate(457.6224,762.014)">
|
||||
<path
|
||||
d="m 0,0 -1.811,1.811 10.287,10.287 1.811,-1.811 c 1.425,-1.425 1.425,-3.734 0,-5.159 L 5.159,0 C 3.734,-1.425 1.425,-1.425 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path32" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g34"
|
||||
transform="translate(449.515,753.7302)">
|
||||
<path
|
||||
d="m 0,0 v 4.934 c 0,0 -24.07,-8.855 -32.093,-8.855 -8.023,0 -32.093,8.855 -32.093,8.855 V 0 c 0,-2.713 0.889,-5.101 2.238,-6.509 1.433,-7.677 3.125,-26.35 3.681,-32.625 0,-4.333 2.261,-7.845 5.052,-7.845 h 42.245 c 2.79,0 5.051,3.512 5.051,7.845 v 10e-4 c 0.556,6.275 2.248,24.947 3.682,32.624 C -0.889,-5.101 0,-2.714 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path36" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g38"
|
||||
transform="translate(385.3291,871.2729)">
|
||||
<path
|
||||
d="m 0,0 v -4.934 c 0,0 24.07,8.855 32.093,8.855 8.023,0 32.093,-8.855 32.093,-8.855 V 0 c 0,2.713 -0.889,5.101 -2.238,6.509 -1.433,7.677 -3.125,26.35 -3.681,32.624 0,4.333 -2.261,7.846 -5.051,7.846 H 10.97 c -2.79,0 -5.051,-3.513 -5.051,-7.846 v 0 C 5.363,32.858 3.671,14.186 2.237,6.509 0.889,5.101 0,2.714 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path40" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g42"
|
||||
transform="translate(371.6938,858.2298)">
|
||||
<path
|
||||
d="m 0,0 c -25.255,-25.255 -25.255,-66.201 0,-91.456 25.255,-25.255 66.201,-25.255 91.456,0 25.256,25.255 25.255,66.201 0,91.456 C 66.201,25.255 25.255,25.255 0,0 m 85.935,-85.935 c -22.206,-22.205 -58.208,-22.205 -80.413,0 -22.206,22.206 -22.206,58.208 -0.001,80.414 22.206,22.205 58.208,22.205 80.414,0 22.206,-22.206 22.206,-58.208 0,-80.414"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path44" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
d="m -665.93071,765.84586 h 2.41 v -34.464 h -2.41 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path76" />
|
||||
<g
|
||||
transform="translate(-1082.1477,-40.602139)"
|
||||
style="stroke-width:9.38626099"
|
||||
id="g78">
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g80"
|
||||
clip-path="url(#clipPath84)">
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g86"
|
||||
transform="translate(438.6725,783.7013)">
|
||||
<path
|
||||
d="m 0,0 c -1.568,-1.333 -3.448,-1.998 -5.643,-1.998 -3.761,0 -6.583,1.704 -8.464,5.113 l 2.058,1.235 c 0.666,-1.215 1.469,-2.156 2.409,-2.822 0.98,-0.744 2.312,-1.117 3.997,-1.117 3.683,0 5.525,1.567 5.525,4.703 0,1.371 -0.646,2.566 -1.939,3.585 -0.393,0.235 -0.951,0.5 -1.675,0.793 -0.726,0.294 -1.617,0.637 -2.675,1.029 -1.96,0.705 -3.37,1.411 -4.231,2.116 -1.255,1.019 -1.881,2.488 -1.881,4.408 0,1.646 0.626,3.057 1.881,4.232 1.214,1.214 2.8,1.822 4.76,1.822 2.704,0 4.996,-0.94 6.877,-2.821 L -0.764,18.75 c -1.332,1.332 -3.037,1.998 -5.114,1.998 -2.821,0 -4.232,-1.234 -4.232,-3.703 0,-1.097 0.431,-1.998 1.294,-2.703 0.705,-0.55 1.821,-1.079 3.35,-1.587 1.331,-0.471 2.429,-0.911 3.291,-1.323 0.862,-0.411 1.508,-0.774 1.94,-1.087 C 1.449,9.052 2.292,7.308 2.292,5.114 2.292,2.998 1.528,1.293 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path88" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path264"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
d="m -662.67221,771.89946 c 0,-1.134 -0.919,-2.053 -2.053,-2.053 -1.134,0 -2.054,0.919 -2.054,2.053 0,1.134 0.92,2.053 2.054,2.053 1.134,0 2.053,-0.919 2.053,-2.053" />
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g266"
|
||||
transform="translate(-662.03281,778.14876)">
|
||||
<path
|
||||
d="m 0,0 2.015,-1.321 21.656,33.028 -2.015,1.322 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path268" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 28 KiB |
47
README.md
|
@ -6,6 +6,10 @@ Bangle.js App Loader (and Apps)
|
|||
* Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps)
|
||||
* Try the **development version** at [github.io](https://espruino.github.io/BangleApps/)
|
||||
|
||||
**All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By
|
||||
submitting code to this repository you confirm that you are happy with it being MIT licensed,
|
||||
and that it is not licensed in another way that would make this impossible.
|
||||
|
||||
## How does it work?
|
||||
|
||||
* A list of apps is in `apps.json`
|
||||
|
@ -32,6 +36,7 @@ easily distinguish between file types, we use the following:
|
|||
* `stuff.img` is an image
|
||||
* `stuff.app.js` is JS code for applications
|
||||
* `stuff.wid.js` is JS code for widgets
|
||||
* `stuff.settings.js` is JS code for the settings menu
|
||||
* `stuff.boot.js` is JS code that automatically gets run at boot time
|
||||
* `stuff.json` is used for JSON settings for an app
|
||||
|
||||
|
@ -314,6 +319,48 @@ the data you require from Bangle.js.
|
|||
|
||||
See [apps/gpsrec/interface.html](the GPS Recorder) for a full example.
|
||||
|
||||
### Adding configuration to the "Settings" menu
|
||||
|
||||
Apps (or widgets) can add their own settings to the "Settings" menu under "App/widget settings".
|
||||
To do so, the app needs to include a `settings.js` file, containing a single function
|
||||
that handles configuring the app.
|
||||
When the app settings are opened, this function is called with one
|
||||
argument, `back`: a callback to return to the settings menu.
|
||||
|
||||
Example `settings.js`
|
||||
```js
|
||||
// make sure to enclose the function in parentheses
|
||||
(function(back) {
|
||||
let settings = require('Storage').readJSON('app.settings.json',1)||{};
|
||||
function save(key, value) {
|
||||
settings[key] = value;
|
||||
require('Storage').write('app.settings.json',settings);
|
||||
}
|
||||
const appMenu = {
|
||||
'': {'title': 'App Settings'},
|
||||
'< Back': back,
|
||||
'Monkeys': {
|
||||
value: settings.monkeys||12,
|
||||
onchange: (m) => {save('monkeys', m)}
|
||||
}
|
||||
};
|
||||
E.showMenu(appMenu)
|
||||
})
|
||||
```
|
||||
In this example the app needs to add both `app.settings.js` and
|
||||
`app.settings.json` to `apps.json`:
|
||||
```json
|
||||
{ "id": "app",
|
||||
...
|
||||
"storage": [
|
||||
...
|
||||
{"name":"app.settings.js","url":"settings.js"},
|
||||
{"name":"app.settings.json","content":"{}"}
|
||||
]
|
||||
},
|
||||
```
|
||||
That way removing the app also cleans up `app.settings.json`.
|
||||
|
||||
## Coding hints
|
||||
|
||||
- use `g.setFont(.., size)` to multiply the font size, eg ("6x8",3) : "18x24"
|
||||
|
|
50
apps.json
|
@ -27,7 +27,7 @@
|
|||
{ "id": "daysl",
|
||||
"name": "Days left",
|
||||
"icon": "app.png",
|
||||
"version":"0.02",
|
||||
"version":"0.03",
|
||||
"description": "Shows you the days left until a certain date. Date can be set with a settings app and is written to a file.",
|
||||
"tags": "",
|
||||
"allow_emulator":false,
|
||||
|
@ -78,24 +78,26 @@
|
|||
{ "id": "welcome",
|
||||
"name": "Welcome",
|
||||
"icon": "app.png",
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"description": "Appears at first boot and explains how to use Bangle.js",
|
||||
"tags": "start,welcome",
|
||||
"allow_emulator":true,
|
||||
"storage": [
|
||||
{"name":"welcome.js","url":"welcome.js"},
|
||||
{"name":"welcome.app.js","url":"app.js"},
|
||||
{"name":"welcome.settings.js","url":"settings.js"},
|
||||
{"name":"welcome.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "gbridge",
|
||||
"name": "Gadgetbridge",
|
||||
"icon": "app.png",
|
||||
"version":"0.06",
|
||||
"version":"0.07",
|
||||
"description": "The default notification handler for Gadgetbridge notifications from Android",
|
||||
"tags": "tool,system,android,widget",
|
||||
"type":"widget",
|
||||
"storage": [
|
||||
{"name":"gbridge.app.js","url":"app.js"},
|
||||
{"name":"gbridge.settings.js","url":"settings.js"},
|
||||
{"name":"gbridge.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"gbridge.wid.js","url":"widget.js"}
|
||||
]
|
||||
|
@ -117,11 +119,12 @@
|
|||
{ "id": "setting",
|
||||
"name": "Settings",
|
||||
"icon": "settings.png",
|
||||
"version":"0.08",
|
||||
"version":"0.10",
|
||||
"description": "A menu for setting up Bangle.js",
|
||||
"tags": "tool,system",
|
||||
"storage": [
|
||||
{"name":"setting.app.js","url":"settings.js"},
|
||||
{"name":"setting.boot.js","url":"boot.js"},
|
||||
{"name":"setting.json","url":"settings-default.json","evaluate":true},
|
||||
{"name":"setting.img","url":"settings-icon.js","evaluate":true}
|
||||
],
|
||||
|
@ -159,7 +162,7 @@
|
|||
{ "id": "aclock",
|
||||
"name": "Analog Clock",
|
||||
"icon": "clock-analog.png",
|
||||
"version":"0.10",
|
||||
"version": "0.11",
|
||||
"description": "An Analog Clock",
|
||||
"tags": "clock",
|
||||
"type":"clock",
|
||||
|
@ -336,13 +339,16 @@
|
|||
},
|
||||
{ "id": "widbatpc",
|
||||
"name": "Battery Level Widget (with percentage)",
|
||||
"shortName": "Battery Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.06",
|
||||
"version":"0.08",
|
||||
"description": "Show the current battery level and charging status in the top right of the clock, with charge percentage",
|
||||
"tags": "widget,battery",
|
||||
"type":"widget",
|
||||
"storage": [
|
||||
{"name":"widbatpc.wid.js","url":"widget.js"}
|
||||
{"name":"widbatpc.wid.js","url":"widget.js"},
|
||||
{"name":"widbatpc.settings.js","url":"settings.js"},
|
||||
{"name":"widbatpc.settings.json","content": "{}"}
|
||||
]
|
||||
},
|
||||
{ "id": "widbt",
|
||||
|
@ -864,6 +870,19 @@
|
|||
{"name":"torch.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "wohrm",
|
||||
"name": "Workout HRM",
|
||||
"icon": "app.png",
|
||||
"version":"0.06",
|
||||
"description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.",
|
||||
"tags": "hrm,workout",
|
||||
"type": "app",
|
||||
"allow_emulator":true,
|
||||
"storage": [
|
||||
{"name":"wohrm.app.js","url":"app.js"},
|
||||
{"name":"wohrm.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "widid",
|
||||
"name": "Bluetooth ID Widget",
|
||||
"icon": "widget.png",
|
||||
|
@ -1014,7 +1033,7 @@
|
|||
"name": "Touch Launcher",
|
||||
"shortName":"Menu",
|
||||
"icon": "app.png",
|
||||
"version":"0.02",
|
||||
"version":"0.04",
|
||||
"description": "Touch enable left to right launcher.",
|
||||
"tags": "tool,system,launcher",
|
||||
"type":"launch",
|
||||
|
@ -1060,5 +1079,18 @@
|
|||
"storage": [
|
||||
{"name":"widmp.wid.js","url":"widget.js"}
|
||||
]
|
||||
},
|
||||
{ "id": "minionclk",
|
||||
"name": "Minion clock",
|
||||
"icon": "minionclk.png",
|
||||
"version": "0.01",
|
||||
"description": "Minion themed clock.",
|
||||
"tags": "clock,minion",
|
||||
"type": "clock",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"minionclk.app.js","url":"app.js"},
|
||||
{"name":"minionclk.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
0.08: make dots bigger and date more readable
|
||||
0.09: center date, remove box around it, internal refactor to remove redundant code.
|
||||
0.10: remove debug, refactor seconds to show elapsed secs each time app is displayed
|
||||
0.11: shift face down for widget area, maximize face size, 0 pad single digit date, use locale for date
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// eliminate ide undefined errors
|
||||
let g;
|
||||
let Bangle;
|
||||
|
||||
|
@ -5,15 +6,18 @@ let Bangle;
|
|||
const locale = require('locale');
|
||||
const p = Math.PI / 2;
|
||||
const pRad = Math.PI / 180;
|
||||
const faceWidth = 100; // watch face radius
|
||||
const faceWidth = 100; // watch face radius (240/2 - 24px for widget area)
|
||||
const widgetHeight=24+1;
|
||||
let timer = null;
|
||||
let currentDate = new Date();
|
||||
const centerPx = g.getWidth() / 2;
|
||||
const centerX = g.getWidth() / 2;
|
||||
const centerY = (g.getWidth() / 2) + widgetHeight/2;
|
||||
|
||||
|
||||
const seconds = (angle) => {
|
||||
const a = angle * pRad;
|
||||
const x = centerPx + Math.sin(a) * faceWidth;
|
||||
const y = centerPx - Math.cos(a) * faceWidth;
|
||||
const x = centerX + Math.sin(a) * faceWidth;
|
||||
const y = centerY - Math.cos(a) * faceWidth;
|
||||
|
||||
// if 15 degrees, make hour marker larger
|
||||
const radius = (angle % 15) ? 2 : 4;
|
||||
|
@ -25,14 +29,14 @@ const hand = (angle, r1, r2) => {
|
|||
const r3 = 3;
|
||||
|
||||
g.fillPoly([
|
||||
Math.round(centerPx + Math.sin(a) * r1),
|
||||
Math.round(centerPx - Math.cos(a) * r1),
|
||||
Math.round(centerPx + Math.sin(a + p) * r3),
|
||||
Math.round(centerPx - Math.cos(a + p) * r3),
|
||||
Math.round(centerPx + Math.sin(a) * r2),
|
||||
Math.round(centerPx - Math.cos(a) * r2),
|
||||
Math.round(centerPx + Math.sin(a - p) * r3),
|
||||
Math.round(centerPx - Math.cos(a - p) * r3)
|
||||
Math.round(centerX + Math.sin(a) * r1),
|
||||
Math.round(centerY - Math.cos(a) * r1),
|
||||
Math.round(centerX + Math.sin(a + p) * r3),
|
||||
Math.round(centerY - Math.cos(a + p) * r3),
|
||||
Math.round(centerX + Math.sin(a) * r2),
|
||||
Math.round(centerY - Math.cos(a) * r2),
|
||||
Math.round(centerX + Math.sin(a - p) * r3),
|
||||
Math.round(centerY - Math.cos(a - p) * r3)
|
||||
]);
|
||||
};
|
||||
|
||||
|
@ -54,6 +58,7 @@ const drawAll = () => {
|
|||
seconds((360 * i) / 60);
|
||||
}
|
||||
onSecond();
|
||||
|
||||
};
|
||||
|
||||
const resetSeconds = () => {
|
||||
|
@ -88,8 +93,8 @@ const drawDate = () => {
|
|||
// console.log(`${dayString}|${dateString}`);
|
||||
// center date
|
||||
const l = (g.getWidth() - g.stringWidth(dateDisplay)) / 2;
|
||||
const t = centerPx + 37;
|
||||
g.drawString(dateDisplay, l, t);
|
||||
const t = centerY + 37;
|
||||
g.drawString(dateDisplay, l, t, true);
|
||||
// console.log(l, t);
|
||||
};
|
||||
const onMinute = () => {
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New Widget!
|
||||
0.02: Improved calculation, new image for app
|
||||
0.03: Improved display of number
|
||||
|
|
|
@ -1,39 +1,84 @@
|
|||
const storage = require('Storage');
|
||||
let settings;
|
||||
let height = 23;
|
||||
let width = 34;
|
||||
|
||||
var debug = 0; //1 = show debug info
|
||||
|
||||
//write settings to file
|
||||
function updateSettings() {
|
||||
storage.write('daysleft.json', settings);
|
||||
}
|
||||
}
|
||||
|
||||
function resetSettings() {
|
||||
//Define standard settings
|
||||
function resetSettings() {
|
||||
settings = {
|
||||
day : 17,
|
||||
month : 6,
|
||||
year: 2020
|
||||
};
|
||||
updateSettings();
|
||||
}
|
||||
}
|
||||
|
||||
settings = storage.readJSON('daysleft.json',1);
|
||||
if (!settings) resetSettings();
|
||||
settings = storage.readJSON('daysleft.json',1); //read storage
|
||||
if (!settings) resetSettings(); //if settings file was not found, set to standard
|
||||
|
||||
var dd = settings.day,
|
||||
mm = settings.month-1, //month is zero-based
|
||||
var dd = settings.day,
|
||||
mm = settings.month-1, //-1 because month is zero-based
|
||||
yy = settings.year;
|
||||
|
||||
const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
|
||||
const targetDate = new Date(yy, mm, dd);
|
||||
const today = new Date();
|
||||
const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
|
||||
const targetDate = new Date(yy, mm, dd); //is 00:00
|
||||
const today = new Date(); //includes current time
|
||||
|
||||
//create date object with today, but 00:00:00
|
||||
const currentYear = today.getFullYear();
|
||||
const currentMonth = today.getMonth();
|
||||
const currentDay = today.getDate();
|
||||
const todayMorning = new Date (currentYear, currentMonth, currentDay, 0, 0, 0);
|
||||
const currentYear = today.getFullYear();
|
||||
const currentMonth = today.getMonth();
|
||||
const currentDay = today.getDate();
|
||||
const todayMorning = new Date (currentYear, currentMonth, currentDay, 0, 0, 0); //create date object with today, but 00:00:00
|
||||
|
||||
const diffDays = (targetDate - todayMorning) / oneDay;
|
||||
const diffDays = (targetDate - todayMorning) / oneDay; //calculate day difference
|
||||
|
||||
WIDGETS["daysl"]={area:"tl",width:40,draw:function(){
|
||||
function drawWidget() {
|
||||
if (debug == 1) g.drawRect(this.x,this.y,this.x+width,this.y+height); //draw rectangle around widget area
|
||||
g.reset();
|
||||
|
||||
//define font size and string position
|
||||
//small if number has more than 3 digits (positive number)
|
||||
if (diffDays >= 1000) {
|
||||
g.setFont("6x8", 1);
|
||||
g.drawString(diffDays,this.x+12,this.y+12);
|
||||
}};
|
||||
g.drawString(diffDays,this.x+10,this.y+7);
|
||||
}
|
||||
//large if number has 3 digits (positive number)
|
||||
if (diffDays <= 999 && diffDays >= 100) {
|
||||
g.setFont("6x8", 2);
|
||||
g.drawString(diffDays,this.x,this.y+4);
|
||||
}
|
||||
//large if number has 2 digits (positive number)
|
||||
if (diffDays <= 99 && diffDays >= 10) {
|
||||
g.setFont("6x8", 2);
|
||||
g.drawString(diffDays,this.x+6,this.y+4);
|
||||
}
|
||||
//large if number has 1 digit (positive number)
|
||||
if (diffDays <= 9 && diffDays >= 0) {
|
||||
g.setFont("6x8", 2);
|
||||
g.drawString(diffDays,this.x+13,this.y+4);
|
||||
}
|
||||
//large if number has 1 digit (negative number)
|
||||
if (diffDays <= -1 && diffDays >= -9) {
|
||||
g.setFont("6x8", 2);
|
||||
g.drawString(diffDays,this.x+5,this.y+4);
|
||||
}
|
||||
//large if number has 2 digits (negative number)
|
||||
if (diffDays <= -10 && diffDays >= -99) {
|
||||
g.setFont("6x8", 2);
|
||||
g.drawString(diffDays,this.x,this.y+4);
|
||||
}
|
||||
//large if number has 3 digits or more (negative number)
|
||||
if (diffDays <= -100) {
|
||||
g.setFont("6x8", 1);
|
||||
g.drawString(diffDays,this.x,this.y+7);
|
||||
}
|
||||
}
|
||||
|
||||
//draw widget
|
||||
WIDGETS["daysl"]={area:"tl",width:width,draw:drawWidget};
|
|
@ -5,3 +5,4 @@
|
|||
0.05: Show incoming call notification
|
||||
Optimize animation, limit title length
|
||||
0.06: Gadgetbridge App 'Connected' state is no longer toggleable
|
||||
0.07: Move configuration to settings menu
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
function gb(j) {
|
||||
Bluetooth.println(JSON.stringify(j));
|
||||
}
|
||||
|
||||
var mainmenu = {
|
||||
"" : { "title" : "Gadgetbridge" },
|
||||
"Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" },
|
||||
"Find Phone" : function() { E.showMenu(findPhone); },
|
||||
"Exit" : ()=> {load();},
|
||||
};
|
||||
|
||||
var findPhone = {
|
||||
"" : { "title" : "-- Find Phone --" },
|
||||
"On" : _=>gb({t:"findPhone",n:true}),
|
||||
"Off" : _=>gb({t:"findPhone",n:false}),
|
||||
"< Back" : function() { E.showMenu(mainmenu); },
|
||||
};
|
||||
|
||||
E.showMenu(mainmenu);
|
|
@ -0,0 +1,21 @@
|
|||
(function(back) {
|
||||
function gb(j) {
|
||||
Bluetooth.println(JSON.stringify(j));
|
||||
}
|
||||
|
||||
var mainmenu = {
|
||||
"" : { "title" : "Gadgetbridge" },
|
||||
"Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" },
|
||||
"Find Phone" : function() { E.showMenu(findPhone); },
|
||||
"< Back" : back,
|
||||
};
|
||||
|
||||
var findPhone = {
|
||||
"" : { "title" : "-- Find Phone --" },
|
||||
"On" : _=>gb({t:"findPhone",n:true}),
|
||||
"Off" : _=>gb({t:"findPhone",n:false}),
|
||||
"< Back" : function() { E.showMenu(mainmenu); },
|
||||
};
|
||||
|
||||
E.showMenu(mainmenu);
|
||||
})
|
|
@ -0,0 +1 @@
|
|||
0.01: First release
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwhAaXlZEolVVvOj0mq1XOv9/qtWFb8rquj1XV5wBDAA2jvMqNLMqwAsCABBhBAIujqpbWvIsCLowBHMg0qFyVVFQJNDK4YoEAYxjFvIuQwHP6ur5+rDgfU5wBDMI2qCYOsC4XV0bFOwIWBAAeBAIOrMYYsF54sCCIWswQDB52AGBcrFIOtF4gAEMoJfDAAOrCYQuDAIowKFwQWIBIeA52pGQPWLYgAFA4YDBGA4uDEwQYFGQvPL4IuKC4wwHFglWAIQYIYoQuFCYwDGqrqFF4YYCYBKeHHwgRLlZhCLowMBKIIubWAtWF4PXBQRdEBAIBHGAoTRCIRfCDQQvBLofXB4NVBIQcDFweAOYdWp9WqwrDGA8ABoRJFAAOswFOqtUwBNFeQYVCwMqp4ABqwbDCowvCAgKOGf4N5aAIwKKIVPpwRBGQOBFw5fCIgZfGwFVlT/BqtVBQQwFUAVWFwMAlYvCL6mBqkqDgNUF4RLGAgVPFwMAklPwD0GX5gOCXoReBJgSvDIwWrAoN6py/Cp58DCYxQBVIYwHqyQBbgL6EX4qQDFwRdFLAifBaoQaEAJIuDCYWrEgoTIGAerWIJfHGRZdECZ5fD0bQBIwJgEIoynEGBJxIAAYPBwHNlUq6owBMIZ4OMKQPC0eiqsr53PX4guOwBhOComk0ejqpfB53OJZAeDU4lVvN5OQQXKBIeA0RfBvNV5wwBMI4uD1oLDFoN4AQJEMBYWl0fOL4NUL4QwCPw4BEwN4AAejvGACZaMBLoRfGAIWr1Z8HwGkFQRIBDgekwAVGFoOAB4QTDqgvBFwQDD1Wk1el1YsBv4oDAIoAB0d/GQOlAIV/CpF51ZfFAIgAEUoOiAJYmEAAoHDvOBFxWqAIWpFxwnDOJABBquJ1QwM5oDCMYYDDAIN/5+r6CABHRKOBmVewIwCYY4sC0bGB678B1ekZYIAB0ulwOlvWkIQLJCMY0yq2sr2sMJYABp96vQnB0tPz4FBBANzAAWj5pdI0dWq0zr2Ir2rMJKQCvNIp9PudIuYDBAIV0FwSMFL4d/LoMzL4WBwIwD6hhH5ujuZXBFAIDDAIOdFwPNL4hdCwBdCq15AgMrAQLDB52pRYYACBIWjvGdK4NJAQOdvIlB5oXB0QwBLoWjqsrAAaSCGANVGAJHBSQjBEAAINBewIDCLYIBCAAJfDv5dCLAIvBvIEDAAJoBwGqDQSUBY4htDBwIBBAoIwDL4WjvNdhAvCAAYFGhDGCY4IAB1QABFwQwDv4BB1V/0eA0mALINdP4IpGMYcAAIQABGAIxDAAIFBruCroAGq1eFALkDmdeD4IjDGQYCCBQYDBCgIqBAJAoBAQIDCmeBCoIDCGgIfBLooADL4YBCJAIiCAANdAIQoCAI4ABAYdWKQQDDMooEBlVPBwJfCGAwABFxABDSAZYGLo1OvFOIgQaBLYZhFAIsyFgYAEFAUqpxUBFYQ="))
|
|
@ -0,0 +1,68 @@
|
|||
const bob = require("heatshrink").decompress(atob("nk8hAaXlYLWAEsqvN/0gBBql5lQ2tquj1XV5wBJ52j0hACPsdP1QsBAQQAGBIIBF51/P8OkN5R1GIxF5HLmAFgoDLPZfOpzmZ6vPFwomCPaA6DAYOjeq2A1YyCdI4HGQJQ8F1T2SJ4Oq1XW1es1mtAQOrPoPUAIh3J54ZHIAR5S62s64cBwIBGQIOqHQK4HKQYVDAAIFC1g+BHh9VHAQAFDwQDDHoJ5E54BB6AaBKQ5YGqo6MwJzGHQ4BDeIj/BR4JxDABY8BvI6OOYgaEHwZADHgQ6BZA42GAIusPJNW64eFqzJDlcrERA8BHQI2FqwaBDYYGBPI45GCoIgCLoVWQ5NWXA2rKhaiGLAwOGEAmADxJPDVA51ElQaMC4ouEWALdEHRg8Dc4woCDJo8EAIYxCHQQIFHiwaRegJ5EcYWsHgbrKbBA8GDSrNDO4wfRKgR3FDSh3CN4UrdwZbSHYZ5DHajMFHYQGCHalWO4jtQDQwABwAGCAAQfTKoK0EHahwCeARdFHakASIZWVZ4Q8CO4YgWO4QbCO6hWGEIKYZKzZ3DLog7UG4I6C1lWDSdWO4bpCO4bwUwKYEHajMDwOAlUkLojTUd4gaTZoRWC0YIB1eJLqo4EWiqRE0mjlcr1QkEeKFWOooBCHiB2CC4WA5wzB52rEQgfPHQwABAYJXOHQ2iO4XO6omFEJh1BEAgBGPJlWDIQbC0ej50qgHV1XPEwohKcwRbEvJ3EBQTrLFomkOwOjlR3C5w8GMAR8ClYuBLIgOCvN4HgIZFDQYbBlaOBR4YNCwA5B0XOpzvBHgWqTw4AFxB1EvQ6BAAI8GDZILEdgQBCqp3DPIRfIEQwABvJ1CvGkvGiwA6IAYoBCv6wCAAVOlQ6DAIWkL5ABEwN40Z1CAYJfCv7zEAJNWOYZ3KAIWq5yYHFYLOBLIrVCAIh7BOIzpECoYDDpw7BHAQDG1WqwGkAIN/CwIABLY4LDAAZ9BwAABvLCBC5IBBvOrO44BEAAmjAIPN0XOAJyHIAAgPEquBHBi4BAId+HwWiHxqJDRpYBDq2I1R3LIAQ6BAAOpPogABGgIDDOomk0nP5pIGd42Aq1ewI8CeZI6CHAJhCEAIDCdIo2B0er1esAQIZBC4Z9JlVW1leeKGp0es5+s6+s6ABB0oFBAIervWr0ulub7OqtWmdexJ4BGxB5G0V6pF6wItB0t6p9PvQABvINBudJudPzwXCHQwBDlY6BO4WIwPPPJbvDvA0BFgNzAAIDGugGCzrtHdYh1DAIOBrzxBPIgAIeIXNHgoBCGwYADzoVB0fNOpMyHQdW5+Bro7BHgQAB6jxJAAOjOYhxCAIukOoPN5ujdZFWqyyD0d6AwUrquBwAuB1I1FHgRJBMoQ9BWg1zzw0BDYI6B0R3DAAJ1BvMyp8rAAV4IQWBIodewAeCHAZ5IAAJoBAAXHHAJWDO4TtEdYQvEHgejAwIKClcqIQRdDXYbzFeoQBIGwIDDOot/VgQ6FAAIGBlgBCAAMzmZPBF4LzDACB1FAAOi1WjvFVr0zGYQ7GAAMAAYpPBwNeAIOIwOrfYOA1eA1WkAIWjAIekv4PBwCVBruBq5eBEYIABlcBF4wCEHw55CHwQABIQQBBABkzAILlCHQR1CFYavEPgsAAAIDEDQNdAwQAaHQNWEwQ0DHAh3KleBLoI7dHQKuFWQo0EAIsISoKdBHbyyHNgwADlVVpwEBDANWro7fd4Q6HO495vF5QgIYCd75eBHYUINAN5lQ3EA"));
|
||||
|
||||
const locale = require("locale");
|
||||
|
||||
const black = 0x0000;
|
||||
const white = 0xFFFF;
|
||||
|
||||
let hour;
|
||||
let minute;
|
||||
let date;
|
||||
|
||||
function draw() {
|
||||
const d = new Date();
|
||||
|
||||
const newHour = ('0' + d.getHours()).substr(-2);
|
||||
const newMinute = ('0' + d.getMinutes()).substr(-2);
|
||||
const newDate = locale.date(d).trim();
|
||||
|
||||
g.setFontAlign(0, 0, 0);
|
||||
|
||||
if (newHour !== hour) {
|
||||
g.setFontVector(48);
|
||||
g.setColor(black);
|
||||
g.drawString(hour, 64, 92);
|
||||
g.setColor(white);
|
||||
g.drawString(newHour, 64, 92);
|
||||
hour = newHour;
|
||||
}
|
||||
|
||||
if (newMinute !== minute) {
|
||||
g.setFontVector(48);
|
||||
g.setColor(black);
|
||||
g.drawString(minute, 172, 92);
|
||||
g.setColor(white);
|
||||
g.drawString(newMinute, 172, 92);
|
||||
minute = newMinute;
|
||||
}
|
||||
|
||||
if (newDate !== date) {
|
||||
g.setFontVector(12);
|
||||
g.setColor(black);
|
||||
g.drawString(date, 120, 228);
|
||||
g.setColor(0xFFFF);
|
||||
g.drawString(newDate, 120, 228);
|
||||
date = newDate;
|
||||
}
|
||||
}
|
||||
|
||||
function drawAll() {
|
||||
hour = '';
|
||||
minute = '';
|
||||
date = '';
|
||||
g.drawImage(bob, 0, 0, { scale: 4 });
|
||||
draw();
|
||||
}
|
||||
|
||||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) {
|
||||
drawAll();
|
||||
}
|
||||
});
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
setInterval(draw, 1000);
|
||||
drawAll();
|
||||
|
||||
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
|
After Width: | Height: | Size: 5.5 KiB |
|
@ -5,3 +5,6 @@
|
|||
0.06: Remove distance setting as there's a separate app for Locale now
|
||||
0.07: Added vibrate as beep workaround
|
||||
0.08: Add support for app/widget settings
|
||||
0.09: Move Welcome into App/widget settings
|
||||
0.10: Added LCD wake-up settings
|
||||
Adds LCD brightness setting
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
(() => {
|
||||
var settings = require('Storage').readJSON('setting.json', true);
|
||||
if (settings != undefined) {
|
||||
Bangle.setOptions(settings.options);
|
||||
}
|
||||
})()
|
|
@ -10,4 +10,16 @@
|
|||
clock: null, // a string for the default clock's name
|
||||
"12hour" : false, // 12 or 24 hour clock?
|
||||
// welcomed : undefined/true (whether welcome app should show)
|
||||
brightness: 1, // LCD brightness from 0 to 1
|
||||
options: {
|
||||
wakeOnBTN1: true,
|
||||
wakeOnBTN2: true,
|
||||
wakeOnBTN3: true,
|
||||
wakeOnFaceUp: false,
|
||||
wakeOnTouch: false,
|
||||
wakeOnTwist: true,
|
||||
twistThreshold: 819.2,
|
||||
twistMaxY: -800,
|
||||
twistTimeout: 1000
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,21 @@ function updateSettings() {
|
|||
storage.write('setting.json', settings);
|
||||
}
|
||||
|
||||
function updateOptions() {
|
||||
updateSettings();
|
||||
Bangle.setOptions(settings.options)
|
||||
}
|
||||
|
||||
function gToInternal(g) {
|
||||
// converts g to Espruino internal unit
|
||||
return g * 8192;
|
||||
}
|
||||
|
||||
function internalToG(u) {
|
||||
// converts Espruino internal unit to g
|
||||
return u / 8192
|
||||
}
|
||||
|
||||
function resetSettings() {
|
||||
settings = {
|
||||
ble: true, // Bluetooth enabled by default
|
||||
|
@ -18,22 +33,34 @@ function resetSettings() {
|
|||
vibrate: true, // Vibration enabled by default. App must support
|
||||
beep: "vib", // Beep enabled by default. App must support
|
||||
timezone: 0, // Set the timezone for the device
|
||||
HID : false, // BLE HID mode, off by default
|
||||
HID: false, // BLE HID mode, off by default
|
||||
clock: null, // a string for the default clock's name
|
||||
"12hour" : false, // 12 or 24 hour clock?
|
||||
brightness: 1, // LCD brightness from 0 to 1
|
||||
// welcomed : undefined/true (whether welcome app should show)
|
||||
options: {
|
||||
wakeOnBTN1: true,
|
||||
wakeOnBTN2: true,
|
||||
wakeOnBTN3: true,
|
||||
wakeOnFaceUp: false,
|
||||
wakeOnTouch: false,
|
||||
wakeOnTwist: true,
|
||||
twistThreshold: 819.2,
|
||||
twistMaxY: -800,
|
||||
twistTimeout: 1000
|
||||
}
|
||||
};
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
settings = storage.readJSON('setting.json',1);
|
||||
settings = storage.readJSON('setting.json', 1);
|
||||
if (!settings) resetSettings();
|
||||
|
||||
const boolFormat = v => v ? "On" : "Off";
|
||||
|
||||
function showMainMenu() {
|
||||
var beepV = [ false,true,"vib" ];
|
||||
var beepN = [ "Off","Piezo","Vibrate" ];
|
||||
var beepV = [false, true, "vib"];
|
||||
var beepN = ["Off", "Piezo", "Vibrate"];
|
||||
const mainmenu = {
|
||||
'': { 'title': 'Settings' },
|
||||
'Make Connectable': makeConnectable,
|
||||
|
@ -72,14 +99,25 @@ function showMainMenu() {
|
|||
Bangle.setLCDTimeout(settings.timeout);
|
||||
}
|
||||
},
|
||||
'LCD Brightness': {
|
||||
value: settings.brightness,
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
onchange: v => {
|
||||
settings.brightness = v || 1;
|
||||
updateSettings();
|
||||
Bangle.setLCDBrightness(settings.brightness);
|
||||
}
|
||||
},
|
||||
'Beep': {
|
||||
value: 0|beepV.indexOf(settings.beep),
|
||||
min:0,max:2,
|
||||
format: v=>beepN[v],
|
||||
value: 0 | beepV.indexOf(settings.beep),
|
||||
min: 0, max: 2,
|
||||
format: v => beepN[v],
|
||||
onchange: v => {
|
||||
settings.beep = beepV[v];
|
||||
if (v==1) { analogWrite(D18,0.5,{freq:2000});setTimeout(()=>D18.reset(),200) } // piezo
|
||||
else if (v==2) { analogWrite(D13,0.1,{freq:2000});setTimeout(()=>D13.reset(),200) } // vibrate
|
||||
if (v==1) { analogWrite(D18,0.5,{freq:2000});setTimeout(()=>D18.reset(),200); } // piezo
|
||||
else if (v==2) { analogWrite(D13,0.1,{freq:2000});setTimeout(()=>D13.reset(),200); } // vibrate
|
||||
updateSettings();
|
||||
}
|
||||
},
|
||||
|
@ -91,18 +129,10 @@ function showMainMenu() {
|
|||
updateSettings();
|
||||
if (settings.vibrate) {
|
||||
VIBRATE.write(1);
|
||||
setTimeout(()=>VIBRATE.write(0), 10);
|
||||
setTimeout(() => VIBRATE.write(0), 10);
|
||||
}
|
||||
}
|
||||
},
|
||||
'Welcome App': {
|
||||
value: !settings.welcomed,
|
||||
format: boolFormat,
|
||||
onchange: v => {
|
||||
settings.welcomed = v?undefined:true;
|
||||
updateSettings();
|
||||
}
|
||||
},
|
||||
'Locale': showLocaleMenu,
|
||||
'Select Clock': showClockMenu,
|
||||
'HID': {
|
||||
|
@ -114,14 +144,101 @@ function showMainMenu() {
|
|||
}
|
||||
},
|
||||
'Set Time': showSetTimeMenu,
|
||||
'LCD Wake-Up': showWakeUpMenu,
|
||||
'App/widget settings': showAppSettingsMenu,
|
||||
'Reset Settings': showResetMenu,
|
||||
'Turn Off': Bangle.off,
|
||||
'< Back': ()=> {load();}
|
||||
'< Back': () => { load(); }
|
||||
};
|
||||
return E.showMenu(mainmenu);
|
||||
}
|
||||
|
||||
function showWakeUpMenu() {
|
||||
const wakeUpMenu = {
|
||||
'': { 'title': 'LCD Wake-Up' },
|
||||
'< Back': showMainMenu,
|
||||
'Wake On BTN1': {
|
||||
value: settings.options.wakeOnBTN1,
|
||||
format: boolFormat,
|
||||
onchange: () => {
|
||||
settings.options.wakeOnBTN1 = !settings.options.wakeOnBTN1;
|
||||
updateOptions();
|
||||
}
|
||||
},
|
||||
'Wake On BTN2': {
|
||||
value: settings.options.wakeOnBTN2,
|
||||
format: boolFormat,
|
||||
onchange: () => {
|
||||
settings.options.wakeOnBTN2 = !settings.options.wakeOnBTN2;
|
||||
updateOptions();
|
||||
}
|
||||
},
|
||||
'Wake On BTN3': {
|
||||
value: settings.options.wakeOnBTN3,
|
||||
format: boolFormat,
|
||||
onchange: () => {
|
||||
settings.options.wakeOnBTN3 = !settings.options.wakeOnBTN3;
|
||||
updateOptions();
|
||||
}
|
||||
},
|
||||
'Wake on FaceUp': {
|
||||
value: settings.options.wakeOnFaceUp,
|
||||
format: boolFormat,
|
||||
onchange: () => {
|
||||
settings.options.wakeOnFaceUp = !settings.options.wakeOnFaceUp;
|
||||
updateOptions();
|
||||
}
|
||||
},
|
||||
'Wake on Touch': {
|
||||
value: settings.options.wakeOnTouch,
|
||||
format: boolFormat,
|
||||
onchange: () => {
|
||||
settings.options.wakeOnTouch = !settings.options.wakeOnTouch;
|
||||
updateOptions();
|
||||
}
|
||||
},
|
||||
'Wake On Twist': {
|
||||
value: settings.options.wakeOnTwist,
|
||||
format: boolFormat,
|
||||
onchange: () => {
|
||||
settings.options.wakeOnTwist = !settings.options.wakeOnTwist;
|
||||
updateOptions();
|
||||
}
|
||||
},
|
||||
'Twist Threshold': {
|
||||
value: internalToG(settings.options.twistThreshold),
|
||||
min: -0.5,
|
||||
max: 0.5,
|
||||
step: 0.01,
|
||||
onchange: v => {
|
||||
settings.options.twistThreshold = gToInternal(v || 0.1);
|
||||
updateOptions();
|
||||
}
|
||||
},
|
||||
'Twist Max Y': {
|
||||
value: settings.options.twistMaxY,
|
||||
min: -1500,
|
||||
max: 1500,
|
||||
step: 100,
|
||||
onchange: v => {
|
||||
settings.options.twistMaxY = v || -800;
|
||||
updateOptions();
|
||||
}
|
||||
},
|
||||
'Twist Timeout': {
|
||||
value: settings.options.twistTimeout,
|
||||
min: 0,
|
||||
max: 2000,
|
||||
step: 100,
|
||||
onchange: v => {
|
||||
settings.options.twistTimeout = v || 1000;
|
||||
updateOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
return E.showMenu(wakeUpMenu)
|
||||
}
|
||||
|
||||
function showLocaleMenu() {
|
||||
const localemenu = {
|
||||
'': { 'title': 'Locale' },
|
||||
|
@ -138,7 +255,7 @@ function showLocaleMenu() {
|
|||
},
|
||||
'Clock Style': {
|
||||
value: !!settings["12hour"],
|
||||
format : v => v?"12hr":"24hr",
|
||||
format: v => v ? "12hr" : "24hr",
|
||||
onchange: v => {
|
||||
settings["12hour"] = v;
|
||||
updateSettings();
|
||||
|
@ -166,33 +283,33 @@ function showResetMenu() {
|
|||
}
|
||||
|
||||
function makeConnectable() {
|
||||
try { NRF.wake(); } catch(e) {}
|
||||
try { NRF.wake(); } catch (e) { }
|
||||
Bluetooth.setConsole(1);
|
||||
var name="Bangle.js "+NRF.getAddress().substr(-5).replace(":","");
|
||||
E.showPrompt(name+"\nStay Connectable?",{title:"Connectable"}).then(r=>{
|
||||
if (settings.ble!=r) {
|
||||
var name = "Bangle.js " + NRF.getAddress().substr(-5).replace(":", "");
|
||||
E.showPrompt(name + "\nStay Connectable?", { title: "Connectable" }).then(r => {
|
||||
if (settings.ble != r) {
|
||||
settings.ble = r;
|
||||
updateSettings();
|
||||
}
|
||||
if (!r) try { NRF.sleep(); } catch(e) {}
|
||||
if (!r) try { NRF.sleep(); } catch (e) { }
|
||||
showMainMenu();
|
||||
});
|
||||
}
|
||||
function showClockMenu() {
|
||||
var clockApps = require("Storage").list(/\.info$/).map(app=>{
|
||||
var clockApps = require("Storage").list(/\.info$/).map(app => {
|
||||
try { return require("Storage").readJSON(app); }
|
||||
catch (e) {}
|
||||
}).filter(app=>app.type=="clock").sort((a, b) => a.sortorder - b.sortorder);
|
||||
catch (e) { }
|
||||
}).filter(app => app.type == "clock").sort((a, b) => a.sortorder - b.sortorder);
|
||||
const clockMenu = {
|
||||
'': {
|
||||
'title': 'Select Clock',
|
||||
},
|
||||
'< Back': showMainMenu,
|
||||
};
|
||||
clockApps.forEach((app,index) => {
|
||||
clockApps.forEach((app, index) => {
|
||||
var label = app.name;
|
||||
if ((!settings.clock && index === 0) || (settings.clock === app.src)) {
|
||||
label = "* "+label;
|
||||
label = "* " + label;
|
||||
}
|
||||
clockMenu[label] = () => {
|
||||
if (settings.clock !== app.src) {
|
||||
|
@ -203,7 +320,7 @@ function showClockMenu() {
|
|||
};
|
||||
});
|
||||
if (clockApps.length === 0) {
|
||||
clockMenu["No Clocks Found"] = () => {};
|
||||
clockMenu["No Clocks Found"] = () => { };
|
||||
}
|
||||
return E.showMenu(clockMenu);
|
||||
}
|
||||
|
@ -215,7 +332,7 @@ function showSetTimeMenu() {
|
|||
const timemenu = {
|
||||
'': {
|
||||
'title': 'Set Time',
|
||||
'predraw': function() {
|
||||
'predraw': function () {
|
||||
d = new Date();
|
||||
timemenu.Hour.value = d.getHours();
|
||||
timemenu.Minute.value = d.getMinutes();
|
||||
|
@ -234,7 +351,7 @@ function showSetTimeMenu() {
|
|||
onchange: v => {
|
||||
d = new Date();
|
||||
d.setHours(v);
|
||||
setTime(d.getTime()/1000);
|
||||
setTime(d.getTime() / 1000);
|
||||
}
|
||||
},
|
||||
'Minute': {
|
||||
|
@ -245,7 +362,7 @@ function showSetTimeMenu() {
|
|||
onchange: v => {
|
||||
d = new Date();
|
||||
d.setMinutes(v);
|
||||
setTime(d.getTime()/1000);
|
||||
setTime(d.getTime() / 1000);
|
||||
}
|
||||
},
|
||||
'Second': {
|
||||
|
@ -256,7 +373,7 @@ function showSetTimeMenu() {
|
|||
onchange: v => {
|
||||
d = new Date();
|
||||
d.setSeconds(v);
|
||||
setTime(d.getTime()/1000);
|
||||
setTime(d.getTime() / 1000);
|
||||
}
|
||||
},
|
||||
'Date': {
|
||||
|
@ -267,7 +384,7 @@ function showSetTimeMenu() {
|
|||
onchange: v => {
|
||||
d = new Date();
|
||||
d.setDate(v);
|
||||
setTime(d.getTime()/1000);
|
||||
setTime(d.getTime() / 1000);
|
||||
}
|
||||
},
|
||||
'Month': {
|
||||
|
@ -278,7 +395,7 @@ function showSetTimeMenu() {
|
|||
onchange: v => {
|
||||
d = new Date();
|
||||
d.setMonth(v - 1);
|
||||
setTime(d.getTime()/1000);
|
||||
setTime(d.getTime() / 1000);
|
||||
}
|
||||
},
|
||||
'Year': {
|
||||
|
@ -289,16 +406,16 @@ function showSetTimeMenu() {
|
|||
onchange: v => {
|
||||
d = new Date();
|
||||
d.setFullYear(v);
|
||||
setTime(d.getTime()/1000);
|
||||
setTime(d.getTime() / 1000);
|
||||
}
|
||||
}
|
||||
};
|
||||
return E.showMenu(timemenu);
|
||||
}
|
||||
|
||||
function showAppSettingsMenu(){
|
||||
function showAppSettingsMenu() {
|
||||
let appmenu = {
|
||||
'': {'title': 'App Settings'},
|
||||
'': { 'title': 'App Settings' },
|
||||
'< Back': showMainMenu,
|
||||
}
|
||||
const apps = storage.list(/\.info$/)
|
||||
|
@ -306,10 +423,10 @@ function showAppSettingsMenu(){
|
|||
.filter(app => app && app.settings)
|
||||
.sort((a, b) => a.sortorder - b.sortorder)
|
||||
if (apps.length === 0) {
|
||||
appmenu['No app has settings'] = () => {};
|
||||
appmenu['No app has settings'] = () => { };
|
||||
}
|
||||
apps.forEach(function (app) {
|
||||
appmenu[app.name] = () => {showAppSettings(app)};
|
||||
appmenu[app.name] = () => { showAppSettings(app) };
|
||||
})
|
||||
E.showMenu(appmenu)
|
||||
}
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
0.01: New App!
|
||||
0.02: Add swipe support and doucle tap to run application
|
||||
0.03: Close launcher when lcd turn off
|
||||
0.04: Complete rewrite to add animation and loop ( issue #210 )
|
|
@ -1,4 +1,6 @@
|
|||
Bangle.setLCDMode("120x120");
|
||||
g.clear();
|
||||
g.flip();
|
||||
|
||||
const Storage = require("Storage");
|
||||
|
||||
|
@ -14,99 +16,144 @@ function getApps(){
|
|||
});
|
||||
}
|
||||
|
||||
const selected = 0;
|
||||
const apps = getApps();
|
||||
const HEIGHT = g.getHeight();
|
||||
const WIDTH = g.getWidth();
|
||||
const HALF = WIDTH/2;
|
||||
const ANIMATION_FRAME = 3;
|
||||
const ANIMATION_STEP = HALF / ANIMATION_FRAME;
|
||||
|
||||
function prev(){
|
||||
if (selected>=0) {
|
||||
selected--;
|
||||
}
|
||||
drawMenu();
|
||||
function getPosition(index){
|
||||
return (index*HALF);
|
||||
}
|
||||
|
||||
function next() {
|
||||
if (selected+1<apps.length) {
|
||||
selected++;
|
||||
}
|
||||
drawMenu();
|
||||
}
|
||||
let current_app = 0;
|
||||
let target = 0;
|
||||
let slideOffset = 0;
|
||||
|
||||
function run() {
|
||||
if(selected < 0) return load();
|
||||
if (!apps[selected].src) return;
|
||||
if (Storage.read(apps[selected].src)===undefined) {
|
||||
E.showMessage("App Source\nNot found");
|
||||
setTimeout(drawMenu, 2000);
|
||||
} else {
|
||||
E.showMessage("Loading...");
|
||||
load(apps[selected].src);
|
||||
}
|
||||
}
|
||||
const back = {
|
||||
name: 'BACK',
|
||||
back: true
|
||||
};
|
||||
|
||||
function getCurrentApp(){
|
||||
return apps[selected];
|
||||
}
|
||||
const apps = [back].concat(getApps());
|
||||
apps.push(back);
|
||||
|
||||
function getNextApp(){
|
||||
return apps[selected+1];
|
||||
}
|
||||
|
||||
function drawFallbackIcon(){
|
||||
function noIcon(x, y, size){
|
||||
const half = size/2;
|
||||
g.setColor(1,1,1);
|
||||
g.fillRect(72, 40, 168, 136);
|
||||
g.setColor(0,0,0);
|
||||
g.setFont('6x8', 8);
|
||||
g.drawString('?', 124, 88);
|
||||
g.setFontAlign(-0,0);
|
||||
const fontSize = Math.floor(size / 30 * 2);
|
||||
g.setFont('6x8', fontSize);
|
||||
if(fontSize) g.drawString('-?-', x+1.5, y);
|
||||
g.drawRect(x-half, y-half, x+half, y+half);
|
||||
}
|
||||
|
||||
function drawArrow(x, y, size, dir){
|
||||
size = size || 10;
|
||||
dir = dir || 1;
|
||||
g.moveTo(x, y).lineTo(x+(size*dir), y-size).lineTo(x+(size*dir),y+size).lineTo(x, y);
|
||||
}
|
||||
function drawIcons(offset){
|
||||
apps.forEach((app, i) => {
|
||||
const x = getPosition(i) + HALF - offset;
|
||||
const y = HALF - (HALF*0.3);//-(HALF*0.7);
|
||||
let diff = (x - HALF);
|
||||
if(diff < 0) diff *=-1;
|
||||
let size = 30;
|
||||
if((diff*0.5) < size) size -= (diff*0.5);
|
||||
else size = 0;
|
||||
|
||||
function drawMenu(){
|
||||
const scale = size / 30;
|
||||
if(size){
|
||||
let c = size / 30 * 2;
|
||||
c = c -1;
|
||||
if(c < 0) c = 0;
|
||||
|
||||
if(selected < 0){
|
||||
g.clear();
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont('6x8', 2);
|
||||
g.drawString('Back', 120, 120);
|
||||
drawArrow(220, 120, 10, -1);
|
||||
if(app.back){
|
||||
g.setFont('6x8', 1);
|
||||
g.setFontAlign(0, -1);
|
||||
g.setColor(c,c,c);
|
||||
g.drawString('Back', HALF, HALF);
|
||||
return;
|
||||
}
|
||||
|
||||
const app = getCurrentApp();
|
||||
g.clear();
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont('6x8', 2);
|
||||
if(!app) return g.drawString('???', 120, 120);
|
||||
g.drawString(app.name, 120, 160);
|
||||
if (app.icon) icon = Storage.read(app.icon);
|
||||
if (icon) try {g.drawImage(icon, 120-48, 40, { scale: 2 });} catch(e){ drawFallbackIcon(); }
|
||||
else drawFallbackIcon();
|
||||
|
||||
// icon
|
||||
const icon = app.icon ? Storage.read(app.icon) : null;
|
||||
if(icon){
|
||||
try {
|
||||
g.drawImage(icon, x-(scale*24), y-(scale*24), { scale: scale });
|
||||
} catch(e){
|
||||
noIcon(x, y, size);
|
||||
}
|
||||
}else{
|
||||
noIcon(x, y, size);
|
||||
}
|
||||
//text
|
||||
g.setFont('6x8', 1);
|
||||
g.setFontAlign(0, -1);
|
||||
g.setColor(c,c,c);
|
||||
g.drawString(app.name, HALF, HEIGHT - (HALF*0.7));
|
||||
|
||||
const type = app.type ? app.type : 'App';
|
||||
const version = app.version ? app.version : '0.00';
|
||||
const info = type+' v'+version;
|
||||
g.setFontAlign(-1,1);
|
||||
g.drawString(info, 20, 220);
|
||||
|
||||
const count = (selected+1)+'/'+apps.length;
|
||||
g.setFontAlign(1,1);
|
||||
g.drawString(count, 220, 220);
|
||||
|
||||
drawArrow(20, 120, 10, 1);
|
||||
if(getNextApp()) drawArrow(220, 120, 10, -1);
|
||||
g.setFontAlign(0,1);
|
||||
g.setFont('4x6', 0.25);
|
||||
g.setColor(c,c,c);
|
||||
g.drawString(info, HALF, 110, { scale: scale });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
drawMenu();
|
||||
function draw(ignoreLoop){
|
||||
g.clear();
|
||||
drawIcons(slideOffset);
|
||||
g.flip();
|
||||
if(slideOffset == target) return;
|
||||
if(slideOffset < target) slideOffset+= ANIMATION_STEP;
|
||||
else if(slideOffset > target) slideOffset -= ANIMATION_STEP;
|
||||
if(!ignoreLoop) draw();
|
||||
}
|
||||
|
||||
// Physical buttons
|
||||
setWatch(prev, BTN1, {repeat:true});
|
||||
setWatch(next, BTN3, {repeat:true});
|
||||
function animateTo(index){
|
||||
target = getPosition(index);
|
||||
draw();
|
||||
}
|
||||
function goTo(index){
|
||||
current_app = index;
|
||||
target = getPosition(index);
|
||||
slideOffset = target;
|
||||
draw(true);
|
||||
}
|
||||
|
||||
goTo(1);
|
||||
|
||||
function prev(){
|
||||
if(current_app == 0) goTo(apps.length-1);
|
||||
current_app -= 1;
|
||||
if(current_app < 0) current_app = 0;
|
||||
animateTo(current_app);
|
||||
}
|
||||
|
||||
function next(){
|
||||
if(current_app == apps.length-1) goTo(0);
|
||||
current_app += 1;
|
||||
if(current_app > apps.length-1) current_app = apps.length-1;
|
||||
animateTo(current_app);
|
||||
}
|
||||
|
||||
function run() {
|
||||
const app = apps[current_app];
|
||||
if(app.back) return load();
|
||||
if (Storage.read(app.src)===undefined) {
|
||||
E.showMessage("App Source\nNot found");
|
||||
setTimeout(draw, 2000);
|
||||
} else {
|
||||
Bangle.setLCDMode();
|
||||
g.clear();
|
||||
g.flip();
|
||||
E.showMessage("Loading...");
|
||||
load(app.src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setWatch(prev, BTN1, { repeat: true });
|
||||
setWatch(next, BTN3, { repeat: true });
|
||||
setWatch(run, BTN2, {repeat:true,edge:"falling"});
|
||||
|
||||
// Screen event
|
||||
|
@ -128,3 +175,8 @@ Bangle.on('swipe', dir => {
|
|||
if(dir == 1) prev();
|
||||
else next();
|
||||
});
|
||||
|
||||
// close launcher when lcd is off
|
||||
Bangle.on('lcdPower', on => {
|
||||
if(!on) return load();
|
||||
});
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Animate balloon intro
|
||||
0.03: BTN3 now won't restart when at the end
|
||||
0.04: Fix regression after tweaks to Storage.readJSON
|
||||
0.05: Move configuration into App/widget settings
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// The welcome app is special, and gets to use global settings
|
||||
(function(back) {
|
||||
let settings = require('Storage').readJSON('setting.json', 1) || {}
|
||||
E.showMenu({
|
||||
'': { 'title': 'Welcome App' },
|
||||
'Run again': {
|
||||
value: !settings.welcomed,
|
||||
format: v => v ? 'Yes' : 'No',
|
||||
onchange: v => {
|
||||
settings.welcomed = v ? undefined : true
|
||||
require('Storage').write('setting.json', settings)
|
||||
},
|
||||
},
|
||||
'< Back': back,
|
||||
})
|
||||
})
|
|
@ -3,3 +3,5 @@
|
|||
0.04: Ensure redrawing works with variable size widget system
|
||||
0.05: Change color depending on battery level, cloned from widbat
|
||||
0.06: Show battery percentage as text
|
||||
0.07: Add settings: percentage/color/charger icon
|
||||
0.08: Draw percentage as inverted on monochrome battery
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// This file should contain exactly one function, which shows the app's settings
|
||||
/**
|
||||
* @param {function} back Use back() to return to settings menu
|
||||
*/
|
||||
(function(back) {
|
||||
const SETTINGS_FILE = 'widbatpc.settings.json'
|
||||
const COLORS = ['By Level', 'Green', 'Monochrome']
|
||||
|
||||
// initialize with default settings...
|
||||
let s = {
|
||||
'color': COLORS[0],
|
||||
'percentage': true,
|
||||
'charger': true,
|
||||
}
|
||||
// ...and overwrite them with any saved values
|
||||
// This way saved values are preserved if a new version adds more settings
|
||||
const storage = require('Storage')
|
||||
const saved = storage.readJSON(SETTINGS_FILE, 1) || {}
|
||||
for (const key in saved) {
|
||||
s[key] = saved[key]
|
||||
}
|
||||
|
||||
// creates a function to safe a specific setting, e.g. save('color')(1)
|
||||
function save(key) {
|
||||
return function (value) {
|
||||
s[key] = value
|
||||
storage.write(SETTINGS_FILE, s)
|
||||
WIDGETS["batpc"].reload()
|
||||
}
|
||||
}
|
||||
|
||||
const onOffFormat = b => (b ? 'on' : 'off')
|
||||
const menu = {
|
||||
'': { 'title': 'Battery Widget' },
|
||||
'< Back': back,
|
||||
'Percentage': {
|
||||
value: s.percentage,
|
||||
format: onOffFormat,
|
||||
onchange: save('percentage'),
|
||||
},
|
||||
'Charging Icon': {
|
||||
value: s.charger,
|
||||
format: onOffFormat,
|
||||
onchange: save('charger'),
|
||||
},
|
||||
'Color': {
|
||||
format: () => s.color,
|
||||
onchange: function () {
|
||||
// cycles through options
|
||||
const oldIndex = COLORS.indexOf(s.color)
|
||||
const newIndex = (oldIndex + 1) % COLORS.length
|
||||
s.color = COLORS[newIndex]
|
||||
save('color')(s.color)
|
||||
},
|
||||
},
|
||||
}
|
||||
E.showMenu(menu)
|
||||
})
|
|
@ -1,20 +1,62 @@
|
|||
(function(){
|
||||
const DEFAULTS = {
|
||||
'color': 'By Level',
|
||||
'percentage': true,
|
||||
'charger': true,
|
||||
}
|
||||
const COLORS = {
|
||||
'white': -1,
|
||||
'charging': 0x07E0, // "Green"
|
||||
'high': 0x05E0, // slightly darker green
|
||||
'ok': 0xFD20, // "Orange"
|
||||
'low':0xF800, // "Red"
|
||||
}
|
||||
const SETTINGS_FILE = 'widbatpc.settings.json'
|
||||
|
||||
let settings
|
||||
function loadSettings() {
|
||||
settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {}
|
||||
}
|
||||
function setting(key) {
|
||||
if (!settings) { loadSettings() }
|
||||
return (key in settings) ? settings[key] : DEFAULTS[key]
|
||||
}
|
||||
|
||||
const levelColor = (l) => {
|
||||
if (Bangle.isCharging()) return 0x07E0; // "Green"
|
||||
if (l >= 50) return 0x05E0; // slightly darker green
|
||||
if (l >= 15) return 0xFD20; // "Orange"
|
||||
return 0xF800; // "Red"
|
||||
// "charging" is very bright -> percentage is hard to read, "high" is ok(ish)
|
||||
const green = setting('percentage') ? COLORS.high : COLORS.charging
|
||||
switch (setting('color')) {
|
||||
case 'Monochrome': return COLORS.white; // no chance of reading the percentage here :-(
|
||||
case 'Green': return green;
|
||||
case 'By Level': // fall through
|
||||
default:
|
||||
if (setting('charger')) {
|
||||
// charger icon -> always make percentage readable
|
||||
if (Bangle.isCharging() || l >= 50) return green;
|
||||
} else {
|
||||
// no icon -> brightest green to indicate charging, even when showing percentage
|
||||
if (Bangle.isCharging()) return COLORS.charging;
|
||||
if (l >= 50) return COLORS.high;
|
||||
}
|
||||
if (l >= 15) return COLORS.ok;
|
||||
return COLORS.low;
|
||||
}
|
||||
}
|
||||
const chargerColor = () => {
|
||||
return (setting('color') === 'Monochrome') ? COLORS.white : COLORS.charging
|
||||
}
|
||||
|
||||
function setWidth() {
|
||||
WIDGETS["bat"].width = 40 + (Bangle.isCharging()?16:0);
|
||||
WIDGETS["batpc"].width = 40;
|
||||
if (Bangle.isCharging() && setting('charger')) {
|
||||
WIDGETS["batpc"].width += 16;
|
||||
}
|
||||
}
|
||||
function draw() {
|
||||
var s = 39;
|
||||
var x = this.x, y = this.y;
|
||||
const l = E.getBattery(), c = levelColor(l);
|
||||
if (Bangle.isCharging()) {
|
||||
g.setColor(c).drawImage(atob(
|
||||
if (Bangle.isCharging() && setting('charger')) {
|
||||
g.setColor(chargerColor()).drawImage(atob(
|
||||
"DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y);
|
||||
x+=16;
|
||||
}
|
||||
|
@ -22,18 +64,40 @@ function draw() {
|
|||
g.fillRect(x,y+2,x+s-4,y+21);
|
||||
g.clearRect(x+2,y+4,x+s-6,y+19);
|
||||
g.fillRect(x+s-3,y+10,x+s,y+14);
|
||||
g.setColor(c).fillRect(x+4,y+6,x+4+l*(s-12)/100,y+17);
|
||||
const l = E.getBattery(),
|
||||
c = levelColor(l);
|
||||
const xl = x+4+l*(s-12)/100
|
||||
g.setColor(c).fillRect(x+4,y+6,xl,y+17);
|
||||
g.setColor(-1);
|
||||
g.setFontAlign(-1,-1);
|
||||
if (!setting('percentage')) {
|
||||
return;
|
||||
}
|
||||
let gfx = g
|
||||
if (setting('color') === 'Monochrome') {
|
||||
// draw text inverted on battery level
|
||||
gfx = Graphics.createCallback(240, 240, 1,
|
||||
(x,y) => {g.setPixel(x,y,x<=xl?0:-1)})
|
||||
}
|
||||
gfx.setFontAlign(-1,-1);
|
||||
if (l >= 100) {
|
||||
g.setFont('4x6', 2);
|
||||
g.drawString(l, x + 6, y + 7);
|
||||
gfx.setFont('4x6', 2);
|
||||
gfx.drawString(l, x + 6, y + 7);
|
||||
} else {
|
||||
if (l < 10) x+=6;
|
||||
g.setFont('6x8', 2);
|
||||
g.drawString(l, x + 6, y + 4);
|
||||
gfx.setFont('6x8', 2);
|
||||
gfx.drawString(l, x + 6, y + 4);
|
||||
}
|
||||
}
|
||||
// reload widget, e.g. when settings have changed
|
||||
function reload() {
|
||||
loadSettings()
|
||||
// need to redraw all widgets, because changing the "charger" setting
|
||||
// can affect the width and mess with the whole widget layout
|
||||
setWidth()
|
||||
g.clear();
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
|
||||
Bangle.on('charging',function(charging) {
|
||||
if(charging) Bangle.buzz();
|
||||
setWidth();
|
||||
|
@ -43,7 +107,7 @@ Bangle.on('charging',function(charging) {
|
|||
var batteryInterval;
|
||||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) {
|
||||
WIDGETS["bat"].draw();
|
||||
WIDGETS["batpc"].draw();
|
||||
// refresh once a minute if LCD on
|
||||
if (!batteryInterval)
|
||||
batteryInterval = setInterval(draw, 60000);
|
||||
|
@ -54,6 +118,6 @@ Bangle.on('lcdPower', function(on) {
|
|||
}
|
||||
}
|
||||
});
|
||||
WIDGETS["bat"]={area:"tr",width:40,draw:draw};
|
||||
WIDGETS["batpc"]={area:"tr",width:40,draw:draw,reload:reload};
|
||||
setWidth();
|
||||
})()
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
0.01: Only tested on the emulator.
|
||||
0.02: Adapted to new App code layout
|
||||
0.03: Optimized rendering for the background
|
||||
0.04: Only buzz on high confidence (>85%)
|
||||
0.05: Improved buzz timing and rendering
|
||||
0.06: Removed debug outputs, fixed rendering for upper limit, improved rendering for +/- icons, changelog version order fixed
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwhC/AH4AVgnd5tABI3c7oJGAAUs5gAC4gJDpgJD4QWGhoMDAAPQBJYADBgoABBJYAChgJD5oDC4AJEAAfAC4fcBIfUDYYJEEogWCgQJEoYSHAAsgIw3MmYqIn89JAoXFn5DH4f/+YXFWQnE/4GEAAXP///ZgooE4X/ngvMPAQXEBoIXHHIJfDC4ss5nf+f9OosjFwgXF5oTBp8z+gMBMQPTn5dBNIgXCAwPDEQM/mQmCJQNP/8zDIJRDO4SnB6fz7k/poXEJwIJBmanGhvMl//loxC7nE/jUCon/6gzBC4PQC4MDKIJFDn9M4YXB5nUKYbACmAXBgE/+YMBOoMvngXDJIKDB6YvBOwRgDaoINB788p5wDn7HELwQABghWCBoPD/s/YwNN5i+Bc4dAC4bBCC4fyPIPU+Z0BDAZGEJAffYgPC+ZxBG4KkB6f/C4JGEAAQsBcIX/+QEBCgP9A4IXBCwwwB5pxDPYJoDcgIuIGASJH5rvBAwIWIeYQABl5jBAAXDIwLrCABCcC76gDAoP0RgwAFYYJ7DJAcsFxYABaYJ7DAAXECxhJEAAgWOPQgACIpoADUwb1BCyBJERZgYKkAXUglACygA/AH4AFA=="))
|
|
@ -0,0 +1,330 @@
|
|||
/* eslint-disable no-undef */
|
||||
const Setter = {
|
||||
NONE: "none",
|
||||
UPPER: 'upper',
|
||||
LOWER: 'lower'
|
||||
};
|
||||
|
||||
const shortBuzzTimeInMs = 80;
|
||||
const longBuzzTimeInMs = 400;
|
||||
|
||||
let upperLimit = 130;
|
||||
let upperLimitChanged = true;
|
||||
|
||||
let lowerLimit = 100;
|
||||
let lowerLimitChanged = true;
|
||||
|
||||
let limitSetter = Setter.NONE;
|
||||
|
||||
let currentHeartRate = 0;
|
||||
let hrConfidence = -1;
|
||||
let hrChanged = true;
|
||||
let confidenceChanged = true;
|
||||
|
||||
let setterHighlightTimeout;
|
||||
|
||||
function renderUpperLimitBackground() {
|
||||
g.setColor(1,0,0);
|
||||
g.fillRect(125,40, 210, 70);
|
||||
g.fillRect(180,70, 210, 200);
|
||||
|
||||
//Round top left corner
|
||||
g.fillEllipse(115,40,135,70);
|
||||
|
||||
//Round top right corner
|
||||
g.setColor(0,0,0);
|
||||
g.fillRect(205,40, 210, 45);
|
||||
g.setColor(1,0,0);
|
||||
g.fillEllipse(190,40,210,50);
|
||||
|
||||
//Round inner corner
|
||||
g.fillRect(174,71, 179, 76);
|
||||
g.setColor(0,0,0);
|
||||
g.fillEllipse(160,71,179,82);
|
||||
|
||||
//Round bottom
|
||||
g.setColor(1,0,0);
|
||||
g.fillEllipse(180,190, 210, 210);
|
||||
}
|
||||
|
||||
function renderLowerLimitBackground() {
|
||||
g.setColor(0,0,1);
|
||||
g.fillRect(10, 180, 100, 210);
|
||||
g.fillRect(10, 50, 40, 180);
|
||||
|
||||
//Rounded top
|
||||
g.setColor(0,0,1);
|
||||
g.fillEllipse(10,40, 40, 60);
|
||||
|
||||
//Round bottom right corner
|
||||
g.setColor(0,0,1);
|
||||
g.fillEllipse(90,180,110,210);
|
||||
|
||||
//Round inner corner
|
||||
g.setColor(0,0,1);
|
||||
g.fillRect(40,175,45,180);
|
||||
g.setColor(0,0,0);
|
||||
g.fillEllipse(41,170,60,179);
|
||||
|
||||
//Round bottom left corner
|
||||
g.setColor(0,0,0);
|
||||
g.fillRect(10,205, 15, 210);
|
||||
g.setColor(0,0,1);
|
||||
g.fillEllipse(10,200,30,210);
|
||||
}
|
||||
|
||||
function drawTrainingHeartRate() {
|
||||
//Only redraw if the display is on
|
||||
if (Bangle.isLCDOn()) {
|
||||
renderUpperLimit();
|
||||
|
||||
renderCurrentHeartRate();
|
||||
|
||||
renderLowerLimit();
|
||||
|
||||
renderConfidenceBars();
|
||||
}
|
||||
|
||||
buzz();
|
||||
}
|
||||
|
||||
function renderUpperLimit() {
|
||||
if(!upperLimitChanged) { return; }
|
||||
|
||||
g.setColor(1,0,0);
|
||||
g.fillRect(125,40, 210, 70);
|
||||
|
||||
if(limitSetter === Setter.UPPER){
|
||||
g.setColor(255,255, 0);
|
||||
} else {
|
||||
g.setColor(255,255,255);
|
||||
}
|
||||
g.setFontVector(13);
|
||||
g.drawString("Upper: " + upperLimit, 125, 50);
|
||||
|
||||
upperLimitChanged = false;
|
||||
}
|
||||
|
||||
function renderCurrentHeartRate() {
|
||||
if(!hrChanged) { return; }
|
||||
|
||||
g.setColor(255,255,255);
|
||||
g.fillRect(55, 110, 165, 150);
|
||||
|
||||
g.setColor(0,0,0);
|
||||
g.setFontVector(24);
|
||||
g.setFontAlign(1, -1, 0);
|
||||
g.drawString(currentHeartRate, 130, 117);
|
||||
|
||||
//Reset alignment to defaults
|
||||
g.setFontAlign(-1, -1, 0);
|
||||
|
||||
hrChanged = false;
|
||||
}
|
||||
|
||||
function renderLowerLimit() {
|
||||
if(!lowerLimitChanged) { return; }
|
||||
|
||||
g.setColor(0,0,1);
|
||||
g.fillRect(10, 180, 100, 210);
|
||||
|
||||
if(limitSetter === Setter.LOWER){
|
||||
g.setColor(255,255, 0);
|
||||
} else {
|
||||
g.setColor(255,255,255);
|
||||
}
|
||||
g.setFontVector(13);
|
||||
g.drawString("Lower: " + lowerLimit, 20,190);
|
||||
|
||||
lowerLimitChanged = false;
|
||||
}
|
||||
|
||||
function renderConfidenceBars(){
|
||||
if(!confidenceChanged) { return; }
|
||||
|
||||
if(hrConfidence >= 85){
|
||||
g.setColor(0, 255, 0);
|
||||
} else if (hrConfidence >= 50) {
|
||||
g.setColor(255, 255, 0);
|
||||
} else if(hrConfidence >= 0){
|
||||
g.setColor(255, 0, 0);
|
||||
} else {
|
||||
g.setColor(255, 255, 255);
|
||||
}
|
||||
|
||||
g.fillRect(45, 110, 55, 150);
|
||||
g.fillRect(165, 110, 175, 150);
|
||||
|
||||
confidenceChanged = false;
|
||||
}
|
||||
|
||||
function renderPlusMinusIcons() {
|
||||
if (limitSetter === Setter.NONE) {
|
||||
g.setColor(0, 0, 0);
|
||||
} else {
|
||||
g.setColor(1, 1, 1);
|
||||
}
|
||||
|
||||
g.setFontVector(14);
|
||||
|
||||
//+ for Btn1
|
||||
g.drawString("+", 222, 50);
|
||||
|
||||
//- for Btn3
|
||||
g.drawString("-", 222,165);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function renderHomeIcon() {
|
||||
//Home for Btn2
|
||||
g.setColor(1, 1, 1);
|
||||
g.drawLine(220, 118, 227, 110);
|
||||
g.drawLine(227, 110, 234, 118);
|
||||
|
||||
g.drawPoly([222,117,222,125,232,125,232,117], false);
|
||||
g.drawRect(226,120,229,125);
|
||||
}
|
||||
|
||||
function buzz() {
|
||||
// Do not buzz if not confident
|
||||
if(hrConfidence < 85) { return; }
|
||||
|
||||
if(currentHeartRate > upperLimit)
|
||||
{
|
||||
Bangle.buzz(shortBuzzTimeInMs);
|
||||
setTimeout(() => { Bangle.buzz(shortBuzzTimeInMs); }, shortBuzzTimeInMs * 2);
|
||||
}
|
||||
|
||||
if(currentHeartRate < lowerLimit)
|
||||
{
|
||||
Bangle.buzz(longBuzzTimeInMs);
|
||||
}
|
||||
}
|
||||
|
||||
function onHrm(hrm){
|
||||
if(currentHeartRate !== hrm.bpm){
|
||||
currentHeartRate = hrm.bpm;
|
||||
hrChanged = true;
|
||||
}
|
||||
|
||||
if(hrConfidence !== hrm.confidence) {
|
||||
hrConfidence = hrm.confidence;
|
||||
confidenceChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setLimitSetterToLower() {
|
||||
resetHighlightTimeout();
|
||||
|
||||
limitSetter = Setter.LOWER;
|
||||
|
||||
upperLimitChanged = true;
|
||||
lowerLimitChanged = true;
|
||||
|
||||
renderUpperLimit();
|
||||
renderLowerLimit();
|
||||
renderPlusMinusIcons();
|
||||
}
|
||||
|
||||
function setLimitSetterToUpper() {
|
||||
resetHighlightTimeout();
|
||||
|
||||
limitSetter = Setter.UPPER;
|
||||
|
||||
upperLimitChanged = true;
|
||||
lowerLimitChanged = true;
|
||||
|
||||
renderLowerLimit();
|
||||
renderUpperLimit();
|
||||
renderPlusMinusIcons();
|
||||
}
|
||||
|
||||
function setLimitSetterToNone() {
|
||||
limitSetter = Setter.NONE;
|
||||
|
||||
upperLimitChanged = true;
|
||||
lowerLimitChanged = true;
|
||||
|
||||
renderLowerLimit();
|
||||
renderUpperLimit();
|
||||
renderPlusMinusIcons();
|
||||
}
|
||||
|
||||
function incrementLimit() {
|
||||
resetHighlightTimeout();
|
||||
|
||||
if (limitSetter === Setter.UPPER) {
|
||||
upperLimit++;
|
||||
renderUpperLimit();
|
||||
upperLimitChanged = true;
|
||||
} else if(limitSetter === Setter.LOWER) {
|
||||
lowerLimit++;
|
||||
renderLowerLimit();
|
||||
lowerLimitChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
function decrementLimit(){
|
||||
resetHighlightTimeout();
|
||||
|
||||
if (limitSetter === Setter.UPPER) {
|
||||
upperLimit--;
|
||||
renderUpperLimit();
|
||||
upperLimitChanged = true;
|
||||
} else if(limitSetter === Setter.LOWER) {
|
||||
lowerLimit--;
|
||||
renderLowerLimit();
|
||||
lowerLimitChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
function resetHighlightTimeout() {
|
||||
if (setterHighlightTimeout) {
|
||||
clearTimeout(setterHighlightTimeout);
|
||||
}
|
||||
|
||||
setterHighlightTimeout = setTimeout(setLimitSetterToNone, 2000);
|
||||
}
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
function switchOffApp(){
|
||||
Bangle.setHRMPower(0);
|
||||
Bangle.showLauncher();
|
||||
}
|
||||
|
||||
// special function to handle display switch on
|
||||
Bangle.on('lcdPower', (on) => {
|
||||
g.clear();
|
||||
if (on) {
|
||||
Bangle.drawWidgets();
|
||||
|
||||
renderHomeIcon();
|
||||
renderLowerLimitBackground();
|
||||
renderUpperLimitBackground();
|
||||
lowerLimitChanged = true;
|
||||
upperLimitChanged = true;
|
||||
drawTrainingHeartRate();
|
||||
}
|
||||
});
|
||||
|
||||
Bangle.setHRMPower(1);
|
||||
Bangle.on('HRM', onHrm);
|
||||
|
||||
setWatch(incrementLimit, BTN1, {edge:"rising", debounce:50, repeat:true});
|
||||
setWatch(switchOffApp, BTN2, {edge:"rising", debounce:50, repeat:true});
|
||||
setWatch(decrementLimit, BTN3, {edge:"rising", debounce:50, repeat:true});
|
||||
setWatch(setLimitSetterToLower, BTN4, {edge:"rising", debounce:50, repeat:true});
|
||||
setWatch(setLimitSetterToUpper, BTN5, { edge: "rising", debounce: 50, repeat: true });
|
||||
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
//drawTrainingHeartRate();
|
||||
|
||||
renderHomeIcon();
|
||||
renderLowerLimitBackground();
|
||||
renderUpperLimitBackground();
|
||||
|
||||
// refesh every sec
|
||||
setInterval(drawTrainingHeartRate, 1000);
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="img/mstile-150x150.png"/>
|
||||
<TileColor>#5755d9</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
|
@ -0,0 +1,24 @@
|
|||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#installContainer {
|
||||
position: absolute;
|
||||
bottom: 1em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#installContainer button {
|
||||
background-color: inherit;
|
||||
border: 1px solid white;
|
||||
color: white;
|
||||
font-size: 1em;
|
||||
padding: 0.75em;
|
||||
}
|
||||
|
||||
.floating {
|
||||
position: fixed;
|
||||
|
||||
}
|
BIN
favicon.ico
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 586 B |
After Width: | Height: | Size: 860 B |
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="960.000000pt" height="960.000000pt" viewBox="0 0 960.000000 960.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,960.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M3632 9573 c-94 -64 -135 -159 -146 -338 -3 -38 -7 -90 -10 -115 -3
|
||||
-25 -8 -70 -11 -100 -2 -30 -7 -77 -9 -105 -3 -27 -8 -79 -11 -115 -3 -36 -8
|
||||
-87 -11 -115 -8 -77 -14 -136 -18 -180 -4 -44 -14 -130 -20 -185 -3 -19 -10
|
||||
-80 -16 -135 -6 -55 -13 -111 -16 -125 -4 -25 -13 -91 -19 -140 -15 -123 -21
|
||||
-146 -47 -183 -31 -43 -47 -75 -52 -103 -3 -13 -7 -27 -9 -32 -10 -15 -19 -99
|
||||
-19 -174 l0 -77 -36 -23 c-96 -58 -185 -119 -276 -188 -54 -41 -108 -82 -120
|
||||
-90 -21 -15 -332 -326 -351 -351 -10 -13 -91 -116 -120 -151 -22 -27 -180
|
||||
-271 -193 -298 -7 -14 -29 -57 -50 -96 -42 -77 -134 -283 -148 -329 -2 -5 -10
|
||||
-30 -19 -55 -19 -52 -71 -223 -79 -260 -3 -14 -10 -43 -15 -65 -6 -22 -12 -53
|
||||
-15 -70 -3 -16 -8 -41 -11 -55 -9 -43 -17 -104 -32 -240 -16 -149 -9 -530 13
|
||||
-670 16 -101 34 -203 49 -270 21 -94 21 -92 27 -110 14 -42 39 -127 43 -145 2
|
||||
-11 12 -41 24 -68 11 -26 21 -51 22 -55 1 -4 5 -17 10 -30 5 -13 9 -25 9 -27
|
||||
0 -13 117 -257 164 -340 38 -68 98 -168 106 -175 3 -3 25 -34 50 -70 44 -66
|
||||
130 -177 185 -239 58 -67 170 -185 194 -205 14 -12 34 -30 45 -41 12 -12 50
|
||||
-45 86 -75 36 -30 67 -57 70 -60 3 -3 21 -17 40 -30 19 -13 37 -27 40 -30 10
|
||||
-11 136 -97 212 -144 l76 -47 0 -77 c-1 -131 22 -224 68 -287 30 -39 40 -68
|
||||
49 -135 4 -30 8 -64 10 -75 2 -11 6 -40 9 -65 3 -25 8 -55 10 -67 3 -12 7 -48
|
||||
11 -80 3 -32 8 -76 11 -98 3 -22 7 -56 9 -75 2 -19 6 -60 9 -90 8 -70 13 -119
|
||||
21 -200 4 -36 8 -81 11 -100 3 -19 7 -60 9 -90 2 -30 6 -75 9 -100 3 -25 8
|
||||
-76 11 -115 3 -38 8 -88 10 -110 2 -22 7 -78 11 -125 11 -132 15 -152 51 -223
|
||||
31 -62 84 -114 131 -127 24 -6 378 -10 1019 -10 976 0 983 0 1019 21 21 11 46
|
||||
31 56 45 11 13 26 31 34 39 9 8 12 15 8 15 -4 0 0 8 8 18 13 14 19 30 33 82 5
|
||||
22 16 109 20 175 3 44 8 94 10 110 2 17 7 60 10 95 11 137 16 186 20 225 3 22
|
||||
7 65 10 95 2 30 7 75 10 100 8 70 14 130 20 190 8 74 14 128 20 170 10 71 16
|
||||
118 20 160 2 24 7 61 10 84 24 164 35 209 60 246 52 76 66 128 72 270 3 84 7
|
||||
108 21 118 9 7 73 49 142 94 68 44 142 95 164 114 46 40 50 40 82 15 22 -18
|
||||
50 -20 142 -12 23 2 303 284 319 321 20 46 17 112 -6 151 l-20 32 35 46 c18
|
||||
25 37 51 42 56 52 68 192 286 192 301 0 2 11 22 25 44 14 22 23 40 19 40 -3 0
|
||||
4 13 15 29 12 16 21 32 21 35 0 5 17 45 70 161 21 48 108 303 114 336 3 13 5
|
||||
24 6 24 1 0 3 7 5 15 2 8 12 55 23 104 12 50 19 93 16 97 -2 4 0 10 6 14 6 4
|
||||
8 10 5 15 -11 17 20 23 119 23 55 0 113 4 128 9 57 20 58 28 58 485 -1 313 -4
|
||||
422 -13 434 -23 29 -66 51 -99 49 -98 -6 -195 1 -195 13 -2 85 -133 550 -164
|
||||
582 -5 5 -9 19 -9 32 0 13 -4 23 -10 23 -5 0 -10 6 -10 14 0 8 -6 27 -14 43
|
||||
-8 15 -20 42 -27 58 -8 17 -26 51 -41 78 -15 26 -26 47 -24 47 4 0 -78 142
|
||||
-104 180 -49 75 -60 92 -60 100 0 4 -3 10 -7 12 -5 2 -34 38 -66 81 -53 71
|
||||
-57 80 -44 95 14 16 34 76 32 97 -7 62 -24 86 -154 218 -138 141 -187 177
|
||||
-239 177 -35 0 -94 -19 -104 -34 -4 -6 -27 5 -60 27 -29 20 -87 60 -128 88
|
||||
-141 98 -158 109 -168 109 -23 0 -31 31 -33 124 -2 112 -22 191 -67 264 -38
|
||||
62 -46 89 -56 194 -2 19 -6 43 -9 54 -3 10 -9 50 -12 89 -4 38 -8 72 -10 75
|
||||
-1 3 -5 37 -9 75 -4 39 -8 81 -11 95 -2 14 -6 54 -9 90 -4 36 -8 76 -10 90 -2
|
||||
14 -7 57 -10 95 -4 39 -9 85 -11 103 -2 18 -7 65 -10 105 -3 40 -7 83 -9 97
|
||||
-3 14 -7 61 -10 105 -4 44 -8 91 -10 105 -3 14 -7 68 -11 120 -6 107 -13 156
|
||||
-24 185 -21 55 -57 118 -83 146 -60 62 -4 59 -1091 59 l-994 0 -41 -27z m1338
|
||||
-2207 c14 -4 48 -9 75 -12 28 -2 57 -7 65 -10 8 -3 35 -8 59 -10 23 -2 52 -9
|
||||
62 -15 10 -5 19 -8 19 -5 0 3 15 0 33 -5 17 -6 43 -12 57 -15 14 -3 52 -14 85
|
||||
-25 33 -11 67 -22 75 -24 53 -11 301 -119 390 -168 30 -17 69 -38 86 -48 46
|
||||
-26 208 -132 214 -141 3 -4 23 -19 45 -34 90 -61 331 -289 410 -389 22 -27 43
|
||||
-52 46 -55 26 -21 219 -310 219 -328 0 -6 4 -12 8 -14 25 -10 176 -355 217
|
||||
-493 9 -33 20 -67 23 -75 7 -20 9 -29 17 -69 3 -19 8 -37 10 -41 4 -7 10 -31
|
||||
30 -143 28 -152 36 -250 37 -442 0 -131 -2 -185 -17 -320 -4 -32 -13 -95 -21
|
||||
-132 -2 -13 -6 -35 -9 -50 -13 -69 -31 -151 -35 -158 -1 -3 -3 -8 -4 -12 -11
|
||||
-40 -30 -106 -43 -143 -8 -25 -16 -52 -18 -60 -13 -52 -144 -334 -198 -425
|
||||
-55 -93 -189 -288 -220 -320 -7 -7 -28 -32 -47 -56 -39 -49 -224 -235 -285
|
||||
-288 -169 -144 -528 -373 -567 -363 -5 1 -8 -3 -8 -8 0 -6 -4 -10 -10 -10 -5
|
||||
0 -33 -11 -62 -24 -128 -58 -380 -142 -453 -152 -11 -1 -56 -9 -100 -18 -179
|
||||
-35 -255 -41 -485 -40 -176 0 -289 6 -345 18 -11 2 -41 7 -67 10 -26 4 -69 11
|
||||
-95 16 -26 6 -59 13 -73 15 -14 3 -32 8 -40 11 -8 3 -26 8 -40 11 -32 6 -109
|
||||
29 -180 55 -30 11 -59 21 -65 22 -5 2 -21 8 -35 14 -14 6 -68 30 -120 52 -96
|
||||
42 -191 92 -265 139 -22 14 -42 26 -45 26 -3 0 -16 8 -30 18 -183 131 -191
|
||||
138 -269 202 -129 108 -337 337 -432 475 -24 35 -50 71 -57 78 -6 7 -12 17
|
||||
-12 22 0 5 -6 15 -13 22 -25 28 -154 276 -191 368 -10 25 -23 56 -29 70 -6 14
|
||||
-11 27 -12 30 -4 17 -48 148 -55 165 -19 46 -71 293 -85 410 -23 183 -24 487
|
||||
-1 640 3 22 8 56 10 75 29 234 133 551 262 799 53 103 166 287 204 334 5 7 42
|
||||
53 82 102 39 50 119 138 177 196 133 132 333 299 360 299 6 0 11 4 11 9 0 15
|
||||
185 123 340 198 81 39 254 110 285 118 6 1 17 5 25 8 18 7 91 30 105 33 201
|
||||
49 326 72 435 80 41 3 77 8 79 10 7 6 453 -3 481 -10z"/>
|
||||
<path d="M5703 6467 c-137 -211 -282 -432 -292 -444 -6 -7 -16 -24 -23 -38 -6
|
||||
-14 -14 -25 -18 -25 -4 0 -12 -11 -18 -25 -7 -14 -16 -31 -22 -38 -6 -7 -39
|
||||
-57 -75 -112 -36 -55 -69 -107 -75 -115 -5 -8 -48 -73 -94 -145 -47 -71 -90
|
||||
-135 -95 -142 -6 -7 -11 -17 -11 -23 0 -5 -4 -10 -10 -10 -5 0 -10 -4 -10 -9
|
||||
0 -5 -37 -64 -81 -131 l-81 -123 23 -18 c41 -31 72 -45 76 -34 3 10 84 134
|
||||
123 190 12 17 71 107 132 200 61 94 136 208 167 255 31 47 58 90 61 95 12 24
|
||||
66 100 73 103 4 2 7 7 7 12 0 4 36 62 80 129 44 66 79 124 78 127 -2 3 5 10
|
||||
15 15 9 6 17 15 17 20 0 6 20 39 45 75 25 35 45 68 45 73 0 5 3 11 8 13 4 2
|
||||
33 43 65 92 l57 89 -42 29 c-24 15 -45 28 -48 28 -3 0 -38 -51 -77 -113z"/>
|
||||
<path d="M4619 4871 c-67 -56 -33 -161 53 -161 56 0 98 42 93 94 -7 79 -88
|
||||
115 -146 67z"/>
|
||||
<path d="M5257 4523 c-73 -25 -152 -107 -173 -179 -26 -92 -10 -184 46 -250
|
||||
21 -25 92 -76 110 -80 3 0 21 -8 40 -16 19 -8 78 -32 130 -52 120 -46 152 -66
|
||||
188 -115 24 -33 29 -51 31 -105 5 -146 -85 -218 -267 -212 -104 4 -187 51
|
||||
-251 144 l-23 32 -28 -20 c-15 -11 -33 -20 -38 -20 -24 0 -21 -22 7 -62 89
|
||||
-129 205 -188 361 -182 92 3 110 7 168 36 100 48 161 126 178 228 12 75 4 133
|
||||
-28 196 -41 83 -104 124 -321 208 -133 52 -161 69 -189 123 -25 45 -20 132 9
|
||||
171 55 73 196 88 316 33 24 -11 50 -27 57 -36 18 -22 31 -19 68 16 l33 31 -23
|
||||
25 c-12 13 -55 40 -95 60 -65 32 -83 36 -165 39 -68 2 -106 -1 -141 -13z"/>
|
||||
<path d="M4626 4523 c-3 -4 -6 -357 -6 -785 l0 -779 38 2 c21 2 43 0 49 -4 6
|
||||
-4 14 0 17 8 8 23 7 1555 -1 1556 -47 6 -92 7 -97 2z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.8 KiB |
33
index.html
|
@ -6,6 +6,16 @@
|
|||
<link rel="stylesheet" href="css/spectre.min.css">
|
||||
<link rel="stylesheet" href="css/spectre-exp.min.css">
|
||||
<link rel="stylesheet" href="css/spectre-icons.min.css">
|
||||
<link rel="stylesheet" href="css/pwa.css">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="mask-icon" href="img/safari-pinned-tab.svg" color="#5755d9">
|
||||
<meta name="apple-mobile-web-app-title" content="BangleApps">
|
||||
<meta name="application-name" content="BangleApps">
|
||||
<meta name="msapplication-TileColor" content="#5755d9">
|
||||
<meta name="theme-color" content="#5755d9">
|
||||
<title>Bangle.js App Loader</title>
|
||||
<style>
|
||||
.navbar { background-color: #5755d9; padding: 0.5em 1em 0.5em 1em; }
|
||||
|
@ -55,6 +65,17 @@
|
|||
</section>-->
|
||||
</header>
|
||||
|
||||
<div class="floating">
|
||||
<p id="requireHTTPS" class="hidden">
|
||||
<b>STOP!</b> This page <b>must</b> be served over HTTPS.
|
||||
Please <a>reload this page via HTTPS</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="container" style="padding-top:4px">
|
||||
<p><b>Note:</b> If you have a version of Bangle.js firmware before 2v04, please update to the <a href="https://www.espruino.com/Bangle.js#firmware-updates" target="_blank">latest firmware</a> or
|
||||
<a href="https://banglejs.com/oldapps/">use the legacy app loader</a>.
|
||||
|
@ -117,7 +138,7 @@
|
|||
</div>
|
||||
<div class="container" style="padding-top: 8px;">
|
||||
<p>Check out <a href="https://github.com/espruino/BangleApps" target="_blank">the Source on GitHub</a>, or
|
||||
find out <a href="https://www.espruino.com/Bangle.js+App+Loader" target="_blank">how to add your own app</p>
|
||||
find out <a href="https://www.espruino.com/Bangle.js+App+Loader" target="_blank">how to add your own app</a></p>
|
||||
<p>Using <a href="https://espruino.com/" target="_blank">Espruino</a>, Icons from <a href="https://icons8.com/" target="_blank">icons8.com</a></p>
|
||||
|
||||
<h3>Utilities</h3>
|
||||
|
@ -127,6 +148,15 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="floating hidden">
|
||||
<!-- Install button, hidden by default -->
|
||||
<div id="installContainer" class="hidden">
|
||||
<button id="butInstall" type="button">
|
||||
Install
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://www.puck-js.com/puck.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/ui.js"></script>
|
||||
|
@ -134,5 +164,6 @@
|
|||
<script src="js/appinfo.js"></script>
|
||||
<script src="js/index.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="js/pwa.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
const divInstall = document.getElementById('installContainer');
|
||||
const butInstall = document.getElementById('butInstall');
|
||||
|
||||
window.addEventListener('beforeinstallprompt', (event) => {
|
||||
console.log('👍', 'beforeinstallprompt', event);
|
||||
// Stash the event so it can be triggered later.
|
||||
window.deferredPrompt = event;
|
||||
// Remove the 'hidden' class from the install button container
|
||||
divInstall.classList.toggle('hidden', false);
|
||||
});
|
||||
|
||||
butInstall.addEventListener('click', () => {
|
||||
console.log('👍', 'butInstall-clicked');
|
||||
const promptEvent = window.deferredPrompt;
|
||||
if (!promptEvent) {
|
||||
// The deferred prompt isn't available.
|
||||
return;
|
||||
}
|
||||
// Show the install prompt.
|
||||
promptEvent.prompt();
|
||||
// Log the result
|
||||
promptEvent.userChoice.then((result) => {
|
||||
console.log('👍', 'userChoice', result);
|
||||
// Reset the deferred prompt variable, since
|
||||
// prompt() can only be called once.
|
||||
window.deferredPrompt = null;
|
||||
// Hide the install button.
|
||||
divInstall.classList.toggle('hidden', true);
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('appinstalled', (event) => {
|
||||
console.log('👍', 'appinstalled', event);
|
||||
});
|
||||
|
||||
|
||||
/* Only register a service worker if it's supported */
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('js/service-worker.js');
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn the page must be served over HTTPS
|
||||
* The `beforeinstallprompt` event won't fire if the page is served over HTTP.
|
||||
* Installability requires a service worker with a fetch event handler, and
|
||||
* if the page isn't served over HTTPS, the service worker won't load.
|
||||
*/
|
||||
if (window.location.protocol === 'http:') {
|
||||
const requireHTTPS = document.getElementById('requireHTTPS');
|
||||
const link = requireHTTPS.querySelector('a');
|
||||
link.href = window.location.href.replace('http://', 'https://');
|
||||
requireHTTPS.classList.remove('hidden');
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
self.addEventListener('install', (event) => {
|
||||
console.log('👷', 'install', event);
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
console.log('👷', 'activate', event);
|
||||
return self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function(event) {
|
||||
// console.log('👷', 'fetch', event);
|
||||
event.respondWith(fetch(event.request));
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "BangleApps",
|
||||
"short_name": "BangleApps",
|
||||
"description": "Banglejs App Store",
|
||||
"icons": [
|
||||
{
|
||||
"src": "img/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#5755d9",
|
||||
"background_color": "#5755d9",
|
||||
"display": "standalone",
|
||||
"start_url": "https://banglejs.com/apps/",
|
||||
"scope": "https://banglejs.com/apps/"
|
||||
}
|