Initial work on unofficial amazfit format compatible parser
parent
51a5b42f0c
commit
7a62248f6b
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App
|
||||
0.02: Allow drawing polys
|
||||
0.03: Allow partly importing Amazfit decompiler formatted watchfaces
|
||||
|
|
|
|||
|
|
@ -30,16 +30,23 @@ function prepareImg(resource){
|
|||
}
|
||||
|
||||
function getByPath(object, path, lastElem){
|
||||
//print("getByPath", path,lastElem);
|
||||
var current = object;
|
||||
for (var c of path){
|
||||
if (!current[c]) return undefined;
|
||||
current = current[c];
|
||||
if (path.length) {
|
||||
for (var c of path){
|
||||
if (!current[c]) return undefined;
|
||||
current = current[c];
|
||||
}
|
||||
}
|
||||
if (lastElem!==undefined){
|
||||
if (!current["" + lastElem]) return undefined;
|
||||
//print("Found by lastElem", lastElem);
|
||||
current = current["" + lastElem];
|
||||
}
|
||||
if (typeof current == "function") return undefined;
|
||||
if (typeof current == "function"){
|
||||
//print("current was function");
|
||||
return undefined;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +56,14 @@ function splitNumberToDigits(num){
|
|||
|
||||
function drawNumber(element, offset){
|
||||
var number = numbers[element.Value]();
|
||||
var spacing = element.Spacing ? element.Spacing : 0;
|
||||
var unit = element.Unit;
|
||||
|
||||
var imageIndexMinus = element.ImageIndexMinus;
|
||||
var imageIndexUnit = element.ImageIndexUnit;
|
||||
var numberOfDigits = element.Digits;
|
||||
|
||||
|
||||
//print("drawNumber: ", number, element, offset);
|
||||
if (number) number = number.toFixed(0);
|
||||
|
||||
|
|
@ -59,8 +74,9 @@ function drawNumber(element, offset){
|
|||
var isNegative;
|
||||
var digits;
|
||||
if (number == undefined){
|
||||
isNegative = false;
|
||||
digits = ["minus","minus","minus"];
|
||||
isNegative = true;
|
||||
digits = [];
|
||||
numberOfDigits = 0;
|
||||
} else {
|
||||
isNegative = number < 0;
|
||||
if (isNegative) number *= -1;
|
||||
|
|
@ -68,27 +84,69 @@ function drawNumber(element, offset){
|
|||
}
|
||||
|
||||
//print("digits: ", digits);
|
||||
var numberOfDigits = element.Digits;
|
||||
if (!numberOfDigits) numberOfDigits = digits.length;
|
||||
var firstDigitX = element.X;
|
||||
var firstDigitY = element.Y;
|
||||
var firstImage = getByPath(resources, element.ImagePath, 0);
|
||||
var imageIndex = element.ImageIndex ? element.ImageIndex : 0;
|
||||
|
||||
if (element.Alignment == "BottomRight"){
|
||||
var digitWidth = firstImage.width + element.Spacing;
|
||||
var numberWidth = (numberOfDigits * digitWidth);
|
||||
if (isNegative){
|
||||
numberWidth += firstImage.width + element.Spacing;
|
||||
}
|
||||
//print("Number width: ", numberWidth, firstImage.width, element.Spacing);
|
||||
var firstImage;
|
||||
if (imageIndex){
|
||||
firstImage = getByPath(resources, [], "" + (0 + imageIndex));
|
||||
} else {
|
||||
firstImage = getByPath(resources, element.ImagePath, 0);
|
||||
}
|
||||
|
||||
var minusImage;
|
||||
if (imageIndexMinus){
|
||||
minusImage = getByPath(resources, [], "" + (0 + imageIndexMinus));
|
||||
} else {
|
||||
minusImage = getByPath(resources, element.ImagePath, "minus");
|
||||
}
|
||||
|
||||
var unitImage;
|
||||
//print("Get image for unit", imageIndexUnit);
|
||||
if (imageIndexUnit !== undefined){
|
||||
unitImage = getByPath(resources, [], "" + (0 + imageIndexUnit));
|
||||
//print("Unit image is", unitImage);
|
||||
} else if (element.Unit){
|
||||
unitImage = getByPath(resources, element.ImagePath, getMultistate(element.Unit, "unknown"));
|
||||
}
|
||||
|
||||
var numberWidth = (numberOfDigits * firstImage.width) + (Math.max((numberOfDigits - 1),0) * spacing);
|
||||
if (isNegative && minusImage){
|
||||
//print("Adding to width", minusImage);
|
||||
numberWidth += minusImage.width + spacing;
|
||||
}
|
||||
if (unitImage){
|
||||
//print("Adding to width", unitImage);
|
||||
numberWidth += unitImage.width + spacing;
|
||||
}
|
||||
//print("numberWidth:", numberWidth);
|
||||
|
||||
if (element.Alignment == "Center") {
|
||||
firstDigitX = Math.round(element.X - (numberWidth/2)) + 1;
|
||||
firstDigitY = Math.round(element.Y - (firstImage.height/2)) + 1;
|
||||
} else if (element.Alignment == "BottomRight"){
|
||||
firstDigitX = element.X - numberWidth + 1;
|
||||
firstDigitY = element.Y - firstImage.height + 1;
|
||||
//print("Calculated start " + firstDigitX + "," + firstDigitY + " From:" + element.BottomRightX + " " + firstImage.width + " " + element.Spacing);
|
||||
} else if (element.Alignment == "TopRight") {
|
||||
firstDigitX = element.X - numberWidth + 1;
|
||||
firstDigitY = element.Y;
|
||||
} else if (element.Alignment == "BottomLeft") {
|
||||
firstDigitX = element.X;
|
||||
firstDigitY = element.Y - firstImage.height + 1;
|
||||
}
|
||||
|
||||
var currentX = firstDigitX;
|
||||
if (isNegative){
|
||||
if (isNegative && minusImage){
|
||||
//print("Draw minus at", currentX);
|
||||
if (imageIndexMinus){
|
||||
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "" + (0 + imageIndexMinus));
|
||||
} else {
|
||||
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "minus");
|
||||
}
|
||||
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "minus");
|
||||
currentX += firstImage.width + element.Spacing;
|
||||
currentX += minusImage.width + spacing;
|
||||
}
|
||||
for (var d = 0; d < numberOfDigits; d++){
|
||||
var currentDigit;
|
||||
|
|
@ -99,8 +157,14 @@ function drawNumber(element, offset){
|
|||
currentDigit = 0;
|
||||
}
|
||||
//print("Digit " + currentDigit + " " + currentX);
|
||||
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, currentDigit);
|
||||
currentX += firstImage.width + element.Spacing;
|
||||
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, currentDigit + imageIndex);
|
||||
currentX += firstImage.width + spacing;
|
||||
}
|
||||
if (imageIndexUnit){
|
||||
//print("Draw unit at", currentX);
|
||||
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "" + (0 + imageIndexUnit));
|
||||
} else if (element.Unit){
|
||||
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, getMultistate(element.Unit,"unknown"));
|
||||
}
|
||||
element.lastDrawnValue = number;
|
||||
}
|
||||
|
|
@ -113,13 +177,15 @@ function setColors(properties){
|
|||
|
||||
function drawElement(pos, offset, path, lastElem){
|
||||
//print("drawElement ",pos, offset, path, lastElem);
|
||||
//print("drawElement offset", offset, pos.X, pos.Y);
|
||||
var resource = getByPath(resources, path, lastElem);
|
||||
//print("Got resource", resource);
|
||||
if (resource){
|
||||
//print("resource ",pos, offset, path, lastElem);
|
||||
//print("resource ", resource,pos, offset, path, lastElem);
|
||||
var image = prepareImg(resource);
|
||||
if (image){
|
||||
offset = updateColors(pos, offset);
|
||||
setColors(offset);
|
||||
var imageOffset = updateColors(pos, offset);
|
||||
setColors(imageOffset);
|
||||
//print("drawImage from drawElement", image, pos, offset);
|
||||
var options={};
|
||||
if (pos.RotationValue){
|
||||
|
|
@ -131,7 +197,7 @@ function drawElement(pos, offset, path, lastElem){
|
|||
}
|
||||
//print("options", options);
|
||||
//print("Memory before drawing", process.memory(false));
|
||||
g.drawImage(image ,offset.X + pos.X,offset.Y + pos.Y, options);
|
||||
g.drawImage(image ,(imageOffset.X ? imageOffset.X : 0) + (pos.X ? pos.X : 0),(imageOffset.Y ? imageOffset.Y :0) + (pos.Y ? pos.Y : 0), options);
|
||||
} else {
|
||||
//print("Could not create image from", resource);
|
||||
}
|
||||
|
|
@ -153,12 +219,30 @@ function checkRedraw(element, newValue){
|
|||
}
|
||||
}
|
||||
|
||||
function getValue(value, defaultValue){
|
||||
if (typeof value == "string"){
|
||||
return numbers[value]();
|
||||
}
|
||||
if (value == undefined) return defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
function getMultistate(name, defaultValue){
|
||||
if (typeof name == "string"){
|
||||
return multistates[name]();
|
||||
} else {
|
||||
if (name == undefined) return defaultValue;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function drawScale(scale, offset){
|
||||
//print("drawScale", scale, offset);
|
||||
var segments = scale.Segments;
|
||||
var value = numbers[scale.Value]();
|
||||
var maxValue = scale.MaxValue ? scale.MaxValue : 1;
|
||||
var minValue = scale.MinValue ? scale.MinValue : 0;
|
||||
var maxValue = getValue(scale.MaxValue, 1);
|
||||
var minValue = getValue(scale.MinValue, 0);
|
||||
var imageIndex = scale.ImageIndex !== undefined ? scale.ImageIndex : 0;
|
||||
|
||||
value = value/maxValue;
|
||||
value -= minValue;
|
||||
|
|
@ -171,7 +255,7 @@ function drawScale(scale, offset){
|
|||
|
||||
if (checkRedraw(scale, segmentsToDraw)){
|
||||
for (var i = 0; i < segmentsToDraw; i++){
|
||||
drawElement(segments[i], scaleOffset, scale.ImagePath, i);
|
||||
drawElement(segments[i], scaleOffset, scale.ImagePath, imageIndex + i);
|
||||
}
|
||||
scale.lastDrawnValue = segmentsToDraw;
|
||||
}
|
||||
|
|
@ -182,20 +266,22 @@ function drawDigit(element, offset, digit){
|
|||
}
|
||||
|
||||
function drawImage(image, offset, name){
|
||||
var imageOffset = updateColors(image, offset);
|
||||
if (image.ImagePath) {
|
||||
//print("drawImage", image, offset, name);
|
||||
offset = updateColors(image, offset);
|
||||
if (image.Value && image.Steps){
|
||||
var steps = Math.floor(scaledown(numbers[image.Value](), image.MinValue, image.MaxValue) * (image.Steps - 1));
|
||||
var steps = Math.floor(scaledown(getValue(image.Value), getValue(image.MinValue, 0), getValue(image.MaxValue, 1)) * (image.Steps - 1));
|
||||
//print("Step", steps, "of", image.Steps);
|
||||
drawElement(image, offset, image.ImagePath, "" + steps);
|
||||
drawElement(image, imageOffset, image.ImagePath, "" + steps);
|
||||
} else if (image.ImageIndex !== undefined) {
|
||||
drawElement(image, imageOffset, image.ImagePath, image.ImageIndex);
|
||||
} else {
|
||||
drawElement(image, offset, image.ImagePath, name ? "" + name: undefined);
|
||||
drawElement(image, imageOffset, image.ImagePath, name ? "" + name: undefined);
|
||||
}
|
||||
} else if (image.ImageFile) {
|
||||
var file = require("Storage").readJSON(image.ImageFile);
|
||||
setColors(offset);
|
||||
g.drawImage(prepareImg(file),image.X + offset.X, image.Y + offsetY);
|
||||
setColors(imageOffset);
|
||||
g.drawImage(prepareImg(file),image.X + imageOffset.X, image.Y + imageOffset.Y);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -257,32 +343,35 @@ function getWeatherTemperature(){
|
|||
}
|
||||
|
||||
function updateOffset(element, offset){
|
||||
var newOffset = { X: offset.X, Y: offset.Y };
|
||||
if (element.X) newOffset.X += element.X;
|
||||
if (element.Y) newOffset.Y += element.Y;
|
||||
var newOffset = { X: offset.X ? offset.X : 0, Y: offset.Y ? offset.Y : 0 };
|
||||
if (element && element.X) newOffset.X += element.X;
|
||||
if (element && element.Y) newOffset.Y += element.Y;
|
||||
newOffset = updateColors(element, newOffset);
|
||||
//print("Updated offset from ", offset, "to", newOffset);
|
||||
return newOffset;
|
||||
}
|
||||
|
||||
function updateColors(element, offset){
|
||||
var newOffset = { X: offset.X, Y: offset.Y };
|
||||
newOffset.fg = element.ForegroundColor ? element.ForegroundColor: offset.fg;
|
||||
newOffset.bg = element.BackgroundColor ? element.BackgroundColor: offset.bg;
|
||||
var newOffset = { X: offset.X ? offset.X : 0, Y: offset.Y ? offset.Y : 0 };
|
||||
if (element){
|
||||
newOffset.fg = element.ForegroundColor ? element.ForegroundColor: offset.fg;
|
||||
newOffset.bg = element.BackgroundColor ? element.BackgroundColor: offset.bg;
|
||||
}
|
||||
//print("Updated offset from ", offset, "to", newOffset);
|
||||
return newOffset;
|
||||
}
|
||||
|
||||
function scaledown(value, min, max){
|
||||
print("scaledown", value, min, max);
|
||||
var scaled = E.clip(value,min?min:0,max?max:1);
|
||||
scaled -= min?min:0;
|
||||
scaled /= max?max:1;
|
||||
//print("scaledown", value, min, max);
|
||||
var scaled = E.clip(value,getValue(min,0),getValue(max,1));
|
||||
scaled -= getValue(min,0);
|
||||
scaled /= getValue(max,1);
|
||||
return scaled;
|
||||
}
|
||||
|
||||
function rotate(center, coords, rotation) {
|
||||
var value = scaledown(numbers[rotation.RotationValue](), rotation.MinRotationValue, rotation.MaxRotationValue);
|
||||
value -= rotation.RotationOffset ? rotation.RotationOffset : 0;
|
||||
value *= 360;
|
||||
value -= 180;
|
||||
|
||||
|
|
@ -298,7 +387,9 @@ function rotate(center, coords, rotation) {
|
|||
|
||||
function drawPoly(element, offset){
|
||||
var vertices = [];
|
||||
var primitiveOffset = offset;
|
||||
var primitiveOffset = offset.clone();
|
||||
if (element.X) primitiveOffset.X += element.X;
|
||||
if (element.Y) primitiveOffset.Y += element.Y;
|
||||
|
||||
for (var c of element.Vertices){
|
||||
if (element.RotationValue){
|
||||
|
|
@ -313,7 +404,7 @@ function drawPoly(element, offset){
|
|||
|
||||
if (element.ForegroundColor) g.setColor(element.ForegroundColor);
|
||||
|
||||
if (element.Filled ){
|
||||
if (element.Filled){
|
||||
g.fillPoly(vertices,true);
|
||||
}
|
||||
|
||||
|
|
@ -337,6 +428,8 @@ numbers.Second = () => { return new Date().getSeconds(); };
|
|||
numbers.SecondAnalog = () => { var date = new Date(); return date.getSeconds() + (date.getMilliseconds()/999); };
|
||||
numbers.SecondTens = () => { return Math.floor(new Date().getSeconds()/10); };
|
||||
numbers.SecondOnes = () => { return Math.floor(new Date().getSeconds()%10); };
|
||||
numbers.WeekDay = () => { return new Date().getDay(); };
|
||||
numbers.WeekDayMondayFirst = () => { var day = (new Date().getDay() - 1); if (day < 0) day = 7 + day; return day; };
|
||||
numbers.Day = () => { return new Date().getDate(); };
|
||||
numbers.DayTens = () => { return Math.floor(new Date().getDate()/10); };
|
||||
numbers.DayOnes = () => { return Math.floor(new Date().getDate()%10); };
|
||||
|
|
@ -345,13 +438,14 @@ numbers.MonthTens = () => { return Math.floor((new Date().getMonth() + 1)/10); }
|
|||
numbers.MonthOnes = () => { return Math.floor((new Date().getMonth() + 1)%10); };
|
||||
numbers.Pulse = () => { return pulse; };
|
||||
numbers.Steps = () => { return Bangle.getHealthStatus ? Bangle.getHealthStatus("day").steps : undefined; };
|
||||
numbers.StepsGoal = () => { return stepsgoal; };
|
||||
numbers.Temperature = () => { return temp; };
|
||||
numbers.Pressure = () => { return press; };
|
||||
numbers.Altitude = () => { return alt; };
|
||||
numbers.BatteryPercentage = E.getBattery;
|
||||
numbers.BatteryVoltage = NRF.getBattery;
|
||||
numbers.WeatherCode = getWeatherCode;
|
||||
numbers.WeatherTemperature = () => { var t = getWeatherTemperature().value; return t ? t : undefined; };
|
||||
numbers.WeatherTemperature = () => { return getWeatherTemperature().value; };
|
||||
|
||||
var multistates = {};
|
||||
multistates.Lock = () => { return Bangle.isLocked() ? "on" : "off"; };
|
||||
|
|
@ -365,7 +459,9 @@ multistates.HRM = () => { return Bangle.isHRMOn ? "on" : "off"; };
|
|||
multistates.Barometer = () => { return Bangle.isBarometerOn() ? "on" : "off"; };
|
||||
multistates.Compass = () => { return Bangle.isCompassOn() ? "on" : "off"; };
|
||||
multistates.GPS = () => { return Bangle.isGPSOn() ? "on" : "off"; };
|
||||
multistates.WeatherTemperatureNegative = () => { return getWeatherTemperature().value ? getWeatherTemperature().value : 0 < 0; };
|
||||
multistates.WeatherTemperatureUnit = () => { return getWeatherTemperature().unit; };
|
||||
multistates.StepsGoal = () => { return (numbers.Steps() >= stepsgoal) ? "on": "off"; };
|
||||
|
||||
function drawMultiState(element, offset){
|
||||
//print("drawMultiState", element, offset);
|
||||
|
|
@ -381,6 +477,9 @@ function draw(element, offset){
|
|||
var initial = !element;
|
||||
if (initial){
|
||||
element = face;
|
||||
if (!offset) offset ={};
|
||||
if (!offset.X) offset.X = 0;
|
||||
if (!offset.Y) offset.Y = 0;
|
||||
g.clear();
|
||||
}
|
||||
|
||||
|
|
@ -461,7 +560,7 @@ function initialDraw(){
|
|||
function handleHrm(e){
|
||||
if (e.confidence > 70){
|
||||
pulse = e.bpm;
|
||||
if (!redrawEvents || redrawEvents.includes("HRM")){
|
||||
if (!redrawEvents || redrawEvents.includes("HRM") && !Bangle.isLocked()){
|
||||
//print("Redrawing on HRM");
|
||||
initialDraw();
|
||||
}
|
||||
|
|
@ -472,14 +571,14 @@ function handlePressure(e){
|
|||
alt = e.altitude;
|
||||
temp = e.temperature;
|
||||
press = e.pressure;
|
||||
if (!redrawEvents || redrawEvents.includes("pressure")){
|
||||
if (!redrawEvents || redrawEvents.includes("pressure") && !Bangle.isLocked()){
|
||||
//print("Redrawing on pressure");
|
||||
initialDraw();
|
||||
}
|
||||
}
|
||||
|
||||
function handleCharging(e){
|
||||
if (!redrawEvents || redrawEvents.includes("charging")){
|
||||
if (!redrawEvents || redrawEvents.includes("charging") && !Bangle.isLocked()){
|
||||
//print("Redrawing on charging");
|
||||
initialDraw();
|
||||
}
|
||||
|
|
@ -512,6 +611,8 @@ var defaultRedraw = getByPath(face, ["Properties","Redraw","Default"]) || "Alway
|
|||
var redrawEvents = getByPath(face, ["Properties","Redraw","Events"]);
|
||||
var events = getByPath(face, ["Properties","Events"]);
|
||||
|
||||
var stepsgoal = 2000;
|
||||
|
||||
//print("events", events);
|
||||
//print("redrawEvents", redrawEvents);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,12 +11,22 @@
|
|||
|
||||
<h4>Upload watchface:</h4>
|
||||
|
||||
<p>
|
||||
Select format:</br>
|
||||
<input type="radio" id="useNative" name="mode" checked/>
|
||||
<label for="useNative">Native</label></br>
|
||||
<input type="radio" id="useAmazefit" name="mode"/>
|
||||
<label for="useAmazefit">ALPHA: Decompiled Amazfit</label></br>
|
||||
</p>
|
||||
|
||||
<p>Select watchface folder:</br><input type="file" id="fileLoader" name="files[]" multiple directory="" webkitdirectory="" moxdirectory="" /></p>
|
||||
<p><b>or</b></p>
|
||||
<p>Select watchface zip file: </br><input type="file" id="zipLoader" name="zip"/></p><br/>
|
||||
<button id="btnUpload" class="btn btn-primary">Upload to watch</button>
|
||||
|
||||
<button id="btnUpload" class="btn btn-primary">Upload to watch</button></br>
|
||||
<button id="btnSave" class="btn btn-secondary">Save resources file</button></br>
|
||||
<button id="btnSaveFace" class="btn btn-secondary">Save face file</button></br>
|
||||
<button id="btnSaveZip" class="btn btn-secondary">Save watchface zip file</button></br>
|
||||
<canvas id="canvas" style="display:none;"></canvas></br>
|
||||
<p>Download Demo Watchface here: </br>
|
||||
<a href="digitalretro.zip">digitalretro.zip</a></br>
|
||||
|
|
@ -30,6 +40,468 @@
|
|||
var faceJson;
|
||||
var handledFiles = 0;
|
||||
var expectedFiles = 0;
|
||||
var rootZip = new JSZip();
|
||||
var resourcesZip = rootZip.folder("resources");
|
||||
|
||||
function isNativeFormat(){
|
||||
return document.getElementById("useNative").checked;
|
||||
}
|
||||
|
||||
function convertAmazfitTime(time){
|
||||
var result = {};
|
||||
if (time.Hours){
|
||||
result.Hours = {
|
||||
Tens: convertAmazfitNumber(time.Hours.Tens, "HourTens", 0, 10),
|
||||
Ones: convertAmazfitNumber(time.Hours.Ones, "HourOnes", 0, 10)
|
||||
}
|
||||
result.Hours.Tens.Number.Alignment = "TopLeft";
|
||||
result.Hours.Tens.Number.Spacing = 0;
|
||||
result.Hours.Ones.Number.Alignment = "TopLeft";
|
||||
result.Hours.Ones.Number.Spacing = 0;
|
||||
}
|
||||
if (time.Minutes){
|
||||
result.Minutes = {
|
||||
Tens: convertAmazfitNumber(time.Minutes.Tens, "MinuteTens", 0, 10),
|
||||
Ones: convertAmazfitNumber(time.Minutes.Ones, "MinuteOnes", 0, 10)
|
||||
}
|
||||
result.Minutes.Tens.Number.Alignment = "TopLeft";
|
||||
result.Minutes.Tens.Number.Spacing = 0;
|
||||
result.Minutes.Ones.Number.Alignment = "TopLeft";
|
||||
result.Minutes.Ones.Number.Spacing = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitDate(date){
|
||||
var result = {};
|
||||
if (date.MonthAndDay.Separate.Day) result.Day = convertAmazfitNumber(date.MonthAndDay.Separate.Day, "Day");
|
||||
if (date.MonthAndDay.Separate.Month) result.Month = convertAmazfitNumber(date.MonthAndDay.Separate.Month, "Month");
|
||||
if (date.WeekDay){
|
||||
result.WeekDay = convertAmazfitNumber(date.WeekDay, "WeekDayMondayFirst");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var filesToMove={};
|
||||
|
||||
var zipChangePromise = Promise.resolve();
|
||||
|
||||
function performFileChanges(){
|
||||
var promise = Promise.resolve();
|
||||
//rename all files to just numbers without leading zeroes
|
||||
for (var c in resultJson){
|
||||
console.log("Renaming", c, resultJson[c]);
|
||||
var tmp = resultJson[c];
|
||||
delete resultJson[c];
|
||||
resultJson[Number(c)] = tmp;
|
||||
|
||||
async function modZip(c){
|
||||
console.log("Async modification of ", c)
|
||||
var fileRegex = new RegExp(c + ".*");
|
||||
var fileObject = resourcesZip.file(fileRegex)[0];
|
||||
var fileData = await fileObject.async("uint8array");
|
||||
console.log("Filedata is", fileData);
|
||||
var extension = resourcesZip.file(fileRegex)[0].name.match(/\.[^.]*$/);
|
||||
var newName = Number(c) + extension;
|
||||
|
||||
console.log("Renaming to", newName);
|
||||
resourcesZip.remove(c + extension);
|
||||
resourcesZip.file(newName, fileData);
|
||||
}
|
||||
promise = promise.then(modZip(c));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
console.log("File moves:", filesToMove);
|
||||
|
||||
for (var c in filesToMove){
|
||||
var tmp = resultJson[c];
|
||||
console.log("Handle filemove", c, filesToMove[c], tmp);
|
||||
|
||||
var element = resultJson;
|
||||
var path = filesToMove[c];
|
||||
|
||||
|
||||
async function modZip(c){
|
||||
console.log("Async modification of ", c)
|
||||
var fileRegex = new RegExp(c + ".*");
|
||||
var fileObject = resourcesZip.file(fileRegex)[0];
|
||||
var fileData = await fileObject.async("uint8array");
|
||||
console.log("Filedata is", fileData);
|
||||
var extension = resourcesZip.file(fileRegex)[0].name.match(/\.[^.]*$/);
|
||||
var newName = Number(c) + extension;
|
||||
|
||||
console.log("Copying to", newName);
|
||||
resourcesZip.file(filesToMove[c].join("/") + extension, fileData);
|
||||
}
|
||||
promise = promise.then(modZip(c));
|
||||
|
||||
|
||||
for (var i = 0; i< path.length; i++){
|
||||
if (!element[path[i]]) element[path[i]] = {};
|
||||
if (i == path.length - 1){
|
||||
element[path[i]] = tmp;
|
||||
} else {
|
||||
element = element[path[i]];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
promise.then(()=>{
|
||||
document.getElementById('btnUpload').disabled = true;
|
||||
});
|
||||
console.log("After moves", resultJson);
|
||||
return promise;
|
||||
};
|
||||
|
||||
function convertAmazfitMultistate(multistate, value, minValue, maxValue){
|
||||
var result = {
|
||||
MultiState: {
|
||||
X: multistate.Coordinates.X,
|
||||
Y: multistate.Coordinates.Y,
|
||||
Value: value,
|
||||
ImagePath: [value]
|
||||
}
|
||||
};
|
||||
if (minValue !== undefined) result.MultiState.MinValue = minValue;
|
||||
if (maxValue !== undefined) result.MultiState.MaxValue = maxValue;
|
||||
if (multistate.ImageIndexOn) filesToMove[multistate.ImageIndexOn] = ["status", value, "vibrate"];
|
||||
if (multistate.ImageIndexOff) filesToMove[multistate.ImageIndexOff] = ["status", value, "off"];
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitStatus(status){
|
||||
var result = {};
|
||||
|
||||
if (status.Alarm) result.Alarm = convertAmazfitMultistate(status.Alarm,"Alarm");
|
||||
if (status.Bluetooth) result.Bluetooth = convertAmazfitMultistate(status.Bluetooth,"Bluetooth");
|
||||
if (status.DoNotDisturb) result.DoNotDisturb = convertAmazfitMultistate(status.DoNotDisturb,"Notifications");
|
||||
if (status.Lock) result.Lock = convertAmazfitMultistate(status.Lock,"Lock");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitNumber(element, value, minValue, maxValue){
|
||||
var number = {};
|
||||
var result = {
|
||||
Number: number
|
||||
};
|
||||
if (element.Alignment == "BottomRight"){
|
||||
number.X = element.BottomRightX;
|
||||
number.Y = element.BottomRightY;
|
||||
} else if (element.Alignment == "TopLeft"){
|
||||
number.X = element.TopLeftX;
|
||||
number.Y = element.TopLeftY;
|
||||
} else if (element.Alignment == "TopRight"){
|
||||
number.X = element.BottomRightX;
|
||||
number.Y = element.TopLeftY;
|
||||
} else if (element.Alignment == "BottomLeft"){
|
||||
number.X = element.TopLeftX;
|
||||
number.Y = element.BottomLeftY;
|
||||
} else if (element.Alignment == "Center"){
|
||||
number.X = (element.TopLeftX + (element.BottomRightX - element.TopLeftX)/2),
|
||||
number.Y = (element.TopLeftY + (element.BottomRightY - element.TopLeftY)/2)
|
||||
} else {
|
||||
number.X = element.X,
|
||||
number.Y = element.Y
|
||||
}
|
||||
number.Alignment = element.Alignment;
|
||||
number.Spacing = element.Spacing;
|
||||
number.ImageIndex = element.ImageIndex;
|
||||
number.ImagePath = [];
|
||||
number.Value = value;
|
||||
if (minValue !== undefined) number.MaxValue = maxValue;
|
||||
if (maxValue !== undefined) number.MinValue = minValue;
|
||||
return result;
|
||||
}
|
||||
|
||||
function moveWeatherIcons(icon){
|
||||
filesToMove[icon.ImageIndex + 0] = ["weather", "fallback"];
|
||||
|
||||
// Light clouds
|
||||
filesToMove[icon.ImageIndex + 1] = ["weather", 801];
|
||||
// Cloudy, possible rain
|
||||
filesToMove[icon.ImageIndex + 2] = ["weather", 500];
|
||||
// Cloudy, possible snow
|
||||
filesToMove[icon.ImageIndex + 3] = ["weather", 600];
|
||||
// Clear
|
||||
filesToMove[icon.ImageIndex + 4] = ["weather", 800];
|
||||
// Clouds
|
||||
filesToMove[icon.ImageIndex + 5] = ["weather", 803];
|
||||
// Light Rain
|
||||
filesToMove[icon.ImageIndex + 6] = ["weather", 501];
|
||||
// Light Snow
|
||||
filesToMove[icon.ImageIndex + 7] = ["weather", 601];
|
||||
// Rain
|
||||
filesToMove[icon.ImageIndex + 8] = ["weather", 502];
|
||||
// Snow
|
||||
filesToMove[icon.ImageIndex + 9] = ["weather", 602];
|
||||
// Heavy Snow
|
||||
filesToMove[icon.ImageIndex + 10] = ["weather", 621];
|
||||
// Heavy Rain
|
||||
filesToMove[icon.ImageIndex + 11] = ["weather", 503];
|
||||
// Sandstorm
|
||||
filesToMove[icon.ImageIndex + 12] = ["weather", 751];
|
||||
// Snow and Rain
|
||||
filesToMove[icon.ImageIndex + 13] = ["weather", 616];
|
||||
// Fog
|
||||
filesToMove[icon.ImageIndex + 14] = ["weather", 741];
|
||||
// Mist
|
||||
filesToMove[icon.ImageIndex + 15] = ["weather", 701];
|
||||
// Shower
|
||||
filesToMove[icon.ImageIndex + 16] = ["weather", 521];
|
||||
// Hail
|
||||
filesToMove[icon.ImageIndex + 17] = ["weather", 611];
|
||||
// Hailstorm
|
||||
filesToMove[icon.ImageIndex + 18] = ["weather", 613];
|
||||
// Heavy Shower
|
||||
filesToMove[icon.ImageIndex + 19] = ["weather", 522];
|
||||
// Dust whirls
|
||||
filesToMove[icon.ImageIndex + 20] = ["weather", 731];
|
||||
// Tornado
|
||||
filesToMove[icon.ImageIndex + 21] = ["weather", 781];
|
||||
// Very heavy shower
|
||||
filesToMove[icon.ImageIndex + 22] = ["weather", 531];
|
||||
}
|
||||
|
||||
function convertAmazfitTemperature(temp){
|
||||
var result = {};
|
||||
result = convertAmazfitNumber(temp.Number, "WeatherTemperature");
|
||||
if (temp.MinusImageIndex){
|
||||
result.Number.ImageIndexMinus = temp.MinusImageIndex;
|
||||
}
|
||||
if (temp.DegreesImageIndex){
|
||||
result.Number.ImageIndexUnit = temp.DegreesImageIndex;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitWeather(weather){
|
||||
var result = {};
|
||||
|
||||
if (weather.Temperature && weather.Temperature.Current){
|
||||
if (!result.Temperature) result.Temperature = {};
|
||||
result.Temperature.Current = convertAmazfitTemperature(weather.Temperature.Current);
|
||||
}
|
||||
|
||||
if (weather.Temperature && weather.Temperature.Today){
|
||||
if (!result.Temperature) result.Temperature = {};
|
||||
if (weather.Temperature.Today.Separate){
|
||||
if (weather.Temperature.Today.Separate.Day){
|
||||
result.Temperature.Day = convertAmazfitTemperature(weather.Temperature.Today.Separate.Day);
|
||||
}
|
||||
if (weather.Temperature.Today.Separate.Night){
|
||||
result.Temperature.Night = convertAmazfitTemperature(weather.Temperature.Today.Separate.Night);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (weather.Icon){
|
||||
result.WeatherIcon = {
|
||||
CodedImage: {
|
||||
X: weather.Icon.CustomIcon.X,
|
||||
Y: weather.Icon.CustomIcon.Y,
|
||||
Value: "WeatherCode",
|
||||
ImagePath: ["weather"]
|
||||
}
|
||||
}
|
||||
moveWeatherIcons(weather.Icon.CustomIcon);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitActivity(activity){
|
||||
var result = {};
|
||||
|
||||
if (activity.Steps){
|
||||
result.Steps = convertAmazfitNumber(activity.Steps, "Steps");
|
||||
}
|
||||
if (activity.Pulse){
|
||||
result.Pulse = convertAmazfitNumber(activity.Pulse, "Pulse");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitScale(scale, value, minValue, maxValue){
|
||||
var result = {};
|
||||
result.Scale = {
|
||||
ImageIndex: scale.StartImageIndex,
|
||||
ImagePath: [],
|
||||
Value: value,
|
||||
MaxValue: maxValue,
|
||||
MinValue: minValue
|
||||
};
|
||||
result.Scale.Segments = [];
|
||||
for (var c of scale.Segments){
|
||||
result.Scale.Segments.push({
|
||||
X: c.X,
|
||||
Y: c.Y
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitStepsProgress(steps){
|
||||
var result = {};
|
||||
if (steps.GoalImage){
|
||||
result.Goal = {
|
||||
MultiState: {
|
||||
X: steps.GoalImage.X,
|
||||
Y: steps.GoalImage.Y,
|
||||
Value: "StepsGoal",
|
||||
ImagePath: ["StepsGoal"]
|
||||
}
|
||||
}
|
||||
filesToMove[steps.GoalImage.ImageIndex] = ["StepsGoal", "on"];
|
||||
}
|
||||
if (steps.Linear){
|
||||
result.Scale = convertAmazfitScale(steps.Linear, "Steps", 0, "StepsGoal").Scale;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitBattery(battery){
|
||||
var result = {};
|
||||
if (battery.Scale){
|
||||
result.Scale = convertAmazfitScale(battery.Scale, "BatteryPercentage", 0, 100).Scale;
|
||||
}
|
||||
if (battery.Text){
|
||||
result.Number = convertAmazfitNumber(battery.Text, "BatteryPercentage", 0, 100).Number;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitImage(image){
|
||||
var result = {
|
||||
Image: {
|
||||
X: image.X,
|
||||
Y: image.Y,
|
||||
ImagePath: [],
|
||||
ImageIndex: image.ImageIndex
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertAmazfitColor(color){
|
||||
return "#" + color.substring(2);
|
||||
}
|
||||
|
||||
function convertAmazfitHand(hand, rotationValue, minRotationValue, maxRotationValue){
|
||||
var result = {
|
||||
Filled: !hand.OnlyBorder,
|
||||
X: hand.Center.X,
|
||||
Y: hand.Center.Y,
|
||||
ForegroundColor: convertAmazfitColor(hand.Color),
|
||||
BackgroundColor: convertAmazfitColor(hand.Color),
|
||||
RotationValue: rotationValue,
|
||||
RotationOffset: 0.25,
|
||||
MaxRotationValue: maxRotationValue,
|
||||
MinRotationValue: minRotationValue
|
||||
};
|
||||
|
||||
result.Vertices = []
|
||||
for (var c of hand.Shape){
|
||||
result.Vertices.push(c);
|
||||
}
|
||||
return { Poly: result };
|
||||
}
|
||||
|
||||
function convertAmazfitAnalog(analog){
|
||||
var result = {
|
||||
};
|
||||
|
||||
if (analog.Hours){
|
||||
result.Hours = {};
|
||||
result.Hours.Hand = convertAmazfitHand(analog.Hours, "Hour12Analog", 0, 12);
|
||||
if (analog.Hours.CenterImage){
|
||||
result.Hours.Center = convertAmazfitImage(analog.Hours.CenterImage);
|
||||
}
|
||||
}
|
||||
if (analog.Minutes){
|
||||
result.Minutes = {};
|
||||
result.Minutes.Hand = convertAmazfitHand(analog.Minutes, "Minute", 0, 60);
|
||||
if (analog.Minutes.CenterImage){
|
||||
result.Minutes.Center = convertAmazfitImage(analog.Minutes.CenterImage);
|
||||
}
|
||||
}
|
||||
if (analog.Seconds){
|
||||
result.Seconds = {};
|
||||
result.Seconds = convertAmazfitHand(analog.Seconds, "Second", 0, 60);
|
||||
if (!faceJson.Properties) faceJson.Properties = {};
|
||||
if (!faceJson.Properties.Redraw) faceJson.Properties.Redraw = {};
|
||||
if (!faceJson.Properties.Redraw.Unlocked) faceJson.Properties.Redraw.Unlocked = 1000;
|
||||
if (!faceJson.Properties.Redraw.Unlocked) faceJson.Properties.Redraw.Locked = 15000;
|
||||
if (analog.Seconds.CenterImage){
|
||||
result.Seconds.Center = convertAmazfitImage(analog.Seconds.CenterImage);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function restructureAmazfitFormat(dataString){
|
||||
console.log("Amazfit data:", dataString);
|
||||
|
||||
|
||||
var json = JSON.parse(dataString);
|
||||
faceJson = json;
|
||||
|
||||
if (!json.Properties) faceJson.Properties = {};
|
||||
if (!json.Properties.Redraw) faceJson.Properties.Redraw = {};
|
||||
if (!json.Properties.Redraw.Unlocked) faceJson.Properties.Redraw.Unlocked = 10000;
|
||||
if (!json.Properties.Redraw.Unlocked) faceJson.Properties.Redraw.Locked = 60000;
|
||||
|
||||
var result = {};
|
||||
|
||||
if (json.Background){
|
||||
result.Background = json.Background;
|
||||
result.Background.Image.ImagePath = [];
|
||||
delete result.Background.Preview;
|
||||
}
|
||||
if (json.Time){
|
||||
result.Time = convertAmazfitTime(json.Time);
|
||||
}
|
||||
|
||||
if (json.Date){
|
||||
result.Date = convertAmazfitDate(json.Date);
|
||||
}
|
||||
|
||||
if (json.Status){
|
||||
result.Status = convertAmazfitStatus(json.Status);
|
||||
}
|
||||
|
||||
if (json.Weather){
|
||||
result.Weather = convertAmazfitWeather(json.Weather);
|
||||
}
|
||||
|
||||
if (json.Activity){
|
||||
result.Activity = convertAmazfitActivity(json.Activity);
|
||||
}
|
||||
|
||||
if (json.StepsProgress){
|
||||
result.StepsProgress = convertAmazfitStepsProgress(json.StepsProgress);
|
||||
}
|
||||
|
||||
if (json.Battery){
|
||||
result.Battery = convertAmazfitBattery(json.Battery);
|
||||
}
|
||||
if (json.AnalogDialFace){
|
||||
result.Analog = convertAmazfitAnalog(json.AnalogDialFace);
|
||||
}
|
||||
console.log("Converted to native:", result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
function parseFaceJson(jsonString){
|
||||
if (isNativeFormat()){
|
||||
return JSON.parse(jsonString);
|
||||
} else {
|
||||
return restructureAmazfitFormat(jsonString);
|
||||
}
|
||||
}
|
||||
|
||||
function imageLoaded() {
|
||||
var options = {};
|
||||
|
|
@ -37,7 +509,7 @@
|
|||
options.diffusion = infoJson.diffusion ? infoJson.diffusion : "none";
|
||||
options.compression = infoJson.compression ? infoJson.compression : false;
|
||||
options.alphaToColor = false;
|
||||
options.transparent = false;
|
||||
options.transparent = infoJson.transparent ? infoJson.transparent : false;
|
||||
options.inverted = false;
|
||||
options.autoCrop = false;
|
||||
options.brightness = 0;
|
||||
|
|
@ -45,7 +517,6 @@
|
|||
options.mode = infoJson.color ? infoJson.color : "1bit";
|
||||
options.output = "jsonobject";
|
||||
|
||||
var faceJson;
|
||||
console.log("Loaded image has path", this.path);
|
||||
var jsonPath = this.path.split("/");
|
||||
|
||||
|
|
@ -111,26 +582,45 @@
|
|||
console.log("Expected:", expectedFiles, " handled:", handledFiles);
|
||||
|
||||
if (handledFiles == expectedFiles){
|
||||
document.getElementById('btnSave').disabled = false;
|
||||
document.getElementById('btnUpload').disabled = false;
|
||||
if (!isNativeFormat()) {
|
||||
performFileChanges().then(()=>{
|
||||
rootZip.file("face.json", JSON.stringify(faceJson, null, 2));
|
||||
rootZip.file("info.json", JSON.stringify(infoJson, null, 2));
|
||||
document.getElementById('btnSave').disabled = false;
|
||||
document.getElementById('btnSaveFace').disabled = false;
|
||||
document.getElementById('btnSaveZip').disabled = false;
|
||||
document.getElementById('btnUpload').disabled = false;
|
||||
});
|
||||
} else {
|
||||
document.getElementById('btnSave').disabled = false;
|
||||
document.getElementById('btnSaveFace').disabled = false;
|
||||
document.getElementById('btnUpload').disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleWatchFace(infoFile, faceFile, resourceFiles){
|
||||
var reader = new FileReader();
|
||||
reader.path = infoFile.webkitRelativePath;
|
||||
reader.onload = function(event) {
|
||||
infoJson = JSON.parse(reader.result);
|
||||
if (isNativeFormat()){
|
||||
var reader = new FileReader();
|
||||
reader.path = infoFile.webkitRelativePath;
|
||||
reader.onload = function(event) {
|
||||
infoJson = JSON.parse(reader.result);
|
||||
|
||||
handleFaceJson(faceFile, resourceFiles);
|
||||
};
|
||||
reader.readAsText(infoFile);
|
||||
} else {
|
||||
console.log("Handling amazfit watch face");
|
||||
handleFaceJson(faceFile, resourceFiles);
|
||||
};
|
||||
reader.readAsText(infoFile);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFaceJson(faceFile, resourceFiles){
|
||||
var reader = new FileReader();
|
||||
reader.path = faceFile.webkitRelativePath;
|
||||
reader.onload = function(event) {
|
||||
faceJson = JSON.parse(reader.result);
|
||||
faceJson = parseFaceJson(reader.result);
|
||||
|
||||
handleResourceFiles(resourceFiles);
|
||||
};
|
||||
reader.readAsText(faceFile);
|
||||
|
|
@ -141,8 +631,14 @@
|
|||
console.log('Handle resource file ', current);
|
||||
var reader = new FileReader();
|
||||
console.log("Handling ", current.name, " with path ", current.webkitRelativePath);
|
||||
var filteredPath = current.webkitRelativePath.replace(/.*\/resources\//,"")
|
||||
var filteredPath;
|
||||
if (isNativeFormat()){
|
||||
filteredPath = current.webkitRelativePath.replace(/.*\/resources\//,"");
|
||||
} else {
|
||||
filteredPath = current.webkitRelativePath.replace(/.*\//,"");
|
||||
}
|
||||
reader.path = filteredPath;
|
||||
resourcesZip.file(filteredPath, current);
|
||||
reader.onload = function(event) {
|
||||
var img = new Image();
|
||||
img.path = this.path;
|
||||
|
|
@ -158,6 +654,8 @@
|
|||
expectedFiles = undefined;
|
||||
|
||||
document.getElementById('btnSave').disabled = true;
|
||||
document.getElementById('btnSaveZip').disabled = true;
|
||||
document.getElementById('btnSaveFace').disabled = true;
|
||||
document.getElementById('btnUpload').disabled = true;
|
||||
|
||||
console.log("File select event", event);
|
||||
|
|
@ -171,18 +669,36 @@
|
|||
|
||||
for (var current of event.target.files){
|
||||
console.log('Handle file ', current);
|
||||
if (current.webkitRelativePath.split("/")[1].startsWith("resources")){
|
||||
console.log('Found resource file', current.name);
|
||||
resourceFiles.push(current);
|
||||
expectedFiles = resourceFiles.length;
|
||||
} else if (current.name == "face.json"){
|
||||
console.log('Found face file', current.name);
|
||||
faceFile = current;
|
||||
} else if (current.name == "info.json"){
|
||||
console.log('Found info file', current.name);
|
||||
infoFile = current;
|
||||
if (isNativeFormat()){
|
||||
if (current.webkitRelativePath.split("/")[1].startsWith("resources")){
|
||||
console.log('Found resource file', current.name);
|
||||
resourceFiles.push(current);
|
||||
expectedFiles = resourceFiles.length;
|
||||
} else if (current.name == "face.json"){
|
||||
console.log('Found face file', current.name);
|
||||
faceFile = current;
|
||||
} else if (current.name == "info.json"){
|
||||
console.log('Found info file', current.name);
|
||||
infoFile = current;
|
||||
} else {
|
||||
console.log('Found unsupported file', current.name);
|
||||
}
|
||||
} else {
|
||||
console.log('Found unsupported file', current.name);
|
||||
infoJson = {
|
||||
"color": "3bit",
|
||||
"compression": true,
|
||||
"transparent": true
|
||||
};
|
||||
if (current.name.includes(".png")){
|
||||
console.log('Found resource file', current.name);
|
||||
resourceFiles.push(current);
|
||||
expectedFiles = resourceFiles.length;
|
||||
} else if (current.name.includes(".json")){
|
||||
console.log('Found amazfit file', current.name);
|
||||
faceFile = current;
|
||||
} else {
|
||||
console.log('Found unsupported file', current.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
handleWatchFace(infoFile, faceFile, resourceFiles);
|
||||
|
|
@ -207,6 +723,8 @@
|
|||
{name:"imageclock.img", url:"app-icon.js", evaluate:true},
|
||||
]
|
||||
};
|
||||
|
||||
console.log("Uploading app:", appDef);
|
||||
sendCustomizedApp(appDef);
|
||||
});
|
||||
|
||||
|
|
@ -217,6 +735,8 @@
|
|||
expectedFiles = 0;
|
||||
handledFiles = 0;
|
||||
document.getElementById('btnSave').disabled = true;
|
||||
document.getElementById('btnSaveFace').disabled = true;
|
||||
document.getElementById('btnSaveZip').disabled = true;
|
||||
document.getElementById('btnUpload').disabled = true;
|
||||
JSZip.loadAsync(f).then(function(zip) {
|
||||
|
||||
|
|
@ -228,13 +748,22 @@
|
|||
|
||||
var promise = zip.file("face.json").async("string").then((data)=>{
|
||||
console.log("face.json data", data);
|
||||
faceJson = JSON.parse(data);
|
||||
faceJson = parseFaceJson(data);
|
||||
});
|
||||
|
||||
promise = promise.then(zip.file("info.json").async("string").then((data)=>{
|
||||
console.log("info.json data", data);
|
||||
infoJson = JSON.parse(data);
|
||||
}));
|
||||
if (isNativeFormat()){
|
||||
promise = promise.then(zip.file("info.json").async("string").then((data)=>{
|
||||
console.log("info.json data", data);
|
||||
infoJson = JSON.parse(data);
|
||||
}));
|
||||
} else {
|
||||
infoJson = {
|
||||
"color": "3bit",
|
||||
"compression": true,
|
||||
"transparent": true
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
zip.folder("resources").forEach(function (relativePath, file){
|
||||
console.log("iterating over", relativePath);
|
||||
|
|
@ -274,10 +803,30 @@
|
|||
handleFile(files[0]);
|
||||
}
|
||||
|
||||
function handleZipExport(){
|
||||
rootZip.generateAsync({type:"base64"}).then(function (base64) {
|
||||
var h = document.createElement('a');
|
||||
h.href="data:application/zip;base64," + base64;
|
||||
h.target = '_blank';
|
||||
h.download = "watchface.zip";
|
||||
h.click();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
document.getElementById("btnSaveFace").addEventListener("click", function() {
|
||||
var h = document.createElement('a');
|
||||
h.href = 'data:text/json;charset=utf-8,' + encodeURI(JSON.stringify(faceJson));
|
||||
h.target = '_blank';
|
||||
h.download = "face.json";
|
||||
h.click();
|
||||
});
|
||||
|
||||
document.getElementById('zipLoader').addEventListener('change', handleZipSelect, false);
|
||||
document.getElementById('btnSaveZip').addEventListener('click', handleZipExport, false);
|
||||
document.getElementById('btnSave').disabled = true;
|
||||
document.getElementById('btnSaveFace').disabled = true;
|
||||
document.getElementById('btnSaveZip').disabled = true;
|
||||
document.getElementById('btnUpload').disabled = true;
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "imageclock",
|
||||
"name": "Imageclock",
|
||||
"shortName": "imageclock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"type": "clock",
|
||||
"description": "BETA!!! File formats still subject to change --- This app is a highly customizable watchface. To use it, you need to select a watchface. You can build the watchfaces yourself without programming anything. All you need to do is write some json and create image files.",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
Loading…
Reference in New Issue