Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,19 @@
define([
'require',
'exports',
'module',
'cropResizeRotate'
], function (require, exports, module) {
'use strict';
var cropResizeRotate = require('cropResizeRotate');
module.exports = function (imageBlob, metadata, thumbnailSize, done) {
cropResizeRotate(imageBlob, null, thumbnailSize, null, metadata, function (error, resizedBlob) {
if (error) {
console.error('Error while resizing image: ' + error);
done(imageBlob);
return;
}
done(resizedBlob);
});
};
});

View file

@ -0,0 +1,84 @@
define([
'require',
'exports',
'module',
'asyncStorage',
'debug',
'format'
], function (require, exports, module) {
'use strict';
var asyncStorage = require('asyncStorage');
var debug = require('debug')('dcf');
var format = require('format');
var dcfConfigLoaded = false;
var deferredArgs = null;
var defaultSeq = {
file: 1,
dir: 100
};
var dcfConfig = {
key: 'dcf_key',
seq: null,
postFix: 'MZLLA',
prefix: {
video: 'VID_',
image: 'IMG_'
},
ext: {
video: '3gp',
image: 'jpg'
}
};
exports.init = function () {
debug('initializing');
exports.checkFileCounter(function () {
if (deferredArgs) {
var args = deferredArgs;
exports.createDCFFilename(args.storage, args.type, args.callback);
deferredArgs = null;
}
debug('initialized');
});
};
exports.checkFileCounter = function (callback) {
asyncStorage.getItem(dcfConfig.key, function (value) {
dcfConfigLoaded = true;
dcfConfig.seq = value ? value : defaultSeq;
if (callback) {
callback();
}
});
};
exports.createDCFFilename = function (storage, type, callback) {
if (!dcfConfigLoaded) {
deferredArgs = {
storage: storage,
type: type,
callback: callback
};
return;
}
var dir = 'DCIM/' + dcfConfig.seq.dir + dcfConfig.postFix + '/';
var filename = dcfConfig.prefix[type] + format.padLeft(dcfConfig.seq.file, 4, '0') + '.' + dcfConfig.ext[type];
var filepath = dir + filename;
var req = storage.get(filepath);
req.onsuccess = function () {
dcfConfig.seq.file = 1;
dcfConfig.seq.dir += 1;
asyncStorage.setItem(dcfConfig.key, dcfConfig.seq, function () {
exports.createDCFFilename(storage, type, callback);
});
};
req.onerror = function () {
if (dcfConfig.seq.file < 9999) {
dcfConfig.seq.file += 1;
} else {
dcfConfig.seq.file = 1;
dcfConfig.seq.dir += 1;
}
asyncStorage.setItem(dcfConfig.key, dcfConfig.seq, function () {
callback(filepath, filename, dir);
});
};
};
});

View file

@ -0,0 +1,26 @@
define([
'require',
'exports',
'module',
'format'
], function (require, exports, module) {
'use strict';
var format = require('format');
function digits(value) {
return format.padLeft(value, 2, '0');
}
module.exports = function (ms) {
var totalSeconds = ms / 1000;
var seconds = Math.round(totalSeconds % 60);
var minutes = Math.floor(totalSeconds / 60);
var hours;
if (minutes < 60) {
return digits(minutes) + ':' + digits(seconds);
} else {
hours = Math.floor(minutes / 60);
minutes = Math.round(minutes % 60);
return hours + ':' + digits(minutes) + ':' + digits(seconds);
}
return '';
};
});

View file

@ -0,0 +1,51 @@
define([
'require',
'exports',
'module',
'GestureDetector'
], function (require, exports, module) {
'use strict';
var GestureDetector = require('GestureDetector');
module.exports = addPanAndZoomHandlers;
function addPanAndZoomHandlers(frame, swipeCallback) {
var container = frame.container;
var gestureDetector = new GestureDetector(container);
gestureDetector.startDetecting();
var swipeAmount = 0;
container.addEventListener('dbltap', handleDoubleTap);
container.addEventListener('transform', handleTransform);
container.addEventListener('pan', handlePan);
if (swipeCallback) {
container.addEventListener('swipe', handleSwipe);
}
function handleDoubleTap(e) {
var scale;
if (frame.fit.scale > frame.fit.baseScale) {
scale = frame.fit.baseScale / frame.fit.scale;
} else {
scale = 2;
}
frame.zoom(scale, e.detail.clientX, e.detail.clientY, 200);
}
function handleTransform(e) {
frame.zoom(e.detail.relative.scale, e.detail.midpoint.clientX, e.detail.midpoint.clientY);
}
function handlePan(e) {
var dx = e.detail.relative.dx;
var dy = e.detail.relative.dy;
if (swipeCallback) {
dx += swipeAmount;
swipeAmount = frame.pan(dx, dy);
swipeCallback(swipeAmount);
} else {
frame.pan(dx, dy);
}
}
function handleSwipe(e) {
if (swipeAmount !== 0) {
swipeCallback(swipeAmount, e.detail.vx);
swipeAmount = 0;
}
}
}
});

View file

@ -0,0 +1,31 @@
define([
'require',
'exports',
'module',
'jpegMetaDataParser'
], function (require, exports, module) {
'use strict';
var parseJpegMetadata = require('jpegMetaDataParser');
module.exports = function (blob, done) {
parseJpegMetadata(blob, onJpegParsed);
function onJpegParsed(metadata) {
metadata.blob = blob;
if (!metadata.preview) {
done(metadata);
return;
}
var start = metadata.preview.start;
var end = metadata.preview.end;
var previewBlob = blob.slice(start, end, 'image/jpeg');
parseJpegMetadata(previewBlob, onSuccess, onError);
function onSuccess(previewMetadata) {
metadata.preview.width = previewMetadata.width;
metadata.preview.height = previewMetadata.height;
done(metadata);
}
function onError() {
done(metadata);
}
}
};
});

View file

@ -0,0 +1,41 @@
define([
'require',
'exports',
'module',
'lib/storage',
'cropResizeRotate'
], function (require, exports, module) {
'use strict';
var Storage = require('lib/storage');
var cropResizeRotate = require('cropResizeRotate');
module.exports = function (options, done) {
var blob = options.blob;
var outputSize = options.width && options.height ? {
width: options.width,
height: options.height
} : options.size || null;
cropResizeRotate(blob, null, outputSize, 'image/jpeg+exif', function (error, resizedBlob) {
if (error) {
console.error('Error while resizing image: ' + error);
done(blob);
return;
}
if (resizedBlob === blob) {
done(blob);
return;
}
var storage = new Storage();
storage.deletePicture(blob.name, addPicture);
function addPicture(error) {
if (error) {
done(blob);
return;
}
storage.addPicture(resizedBlob, { filepath: blob.name }, onSavedPicture);
}
function onSavedPicture(error, filepath, absolutePath, fileBlob) {
done(fileBlob);
}
});
};
});

View file

@ -0,0 +1,75 @@
define([
'require',
'exports',
'module'
], function (require, exports, module) {
'use strict';
module.exports = Sounds;
function Sounds(list) {
this.items = {};
(list || []).forEach(this.add, this);
}
Sounds.prototype.add = function (data) {
var self = this;
var sound = {
name: data.name,
url: data.url,
setting: data.setting,
enabled: false
};
this.items[data.name] = sound;
this.isEnabled(sound, function (value) {
self.setEnabled(sound, value);
self.observeSetting(sound);
});
};
Sounds.prototype.isEnabled = function (sound, done) {
setTimeout(function () {
var mozSettings = navigator.mozSettings;
var key = sound.setting;
if (!mozSettings) {
return;
}
mozSettings.createLock().get(key).onsuccess = onSuccess;
function onSuccess(e) {
var result = e.target.result[key];
done(result);
}
});
};
Sounds.prototype.observeSetting = function (sound) {
var mozSettings = navigator.mozSettings;
var key = sound.setting;
var self = this;
if (mozSettings) {
mozSettings.addObserver(key, function (e) {
self.setEnabled(sound, e.settingValue);
});
}
};
Sounds.prototype.setEnabled = function (sound, value) {
sound.enabled = value;
};
Sounds.prototype.play = function (name) {
var sound = this.items[name];
if (!sound.audio) {
sound.audio = this.createAudio(sound.url);
}
this.playSound(sound);
};
Sounds.prototype.player = function (name) {
return function () {
this.play(name);
}.bind(this);
};
Sounds.prototype.playSound = function (sound) {
if (sound.enabled) {
sound.audio.cloneNode(true).play();
}
};
Sounds.prototype.createAudio = function (url) {
var audio = new Audio(url);
audio.mozAudioChannelType = 'notification';
return audio;
};
});

View file

@ -0,0 +1,20 @@
define(['require'], function (require) {
'use strict';
var StringUtils = {};
StringUtils.toCamelCase = function (str) {
str = str.toLowerCase().replace(/_/g, '-');
return str.replace(/-([a-z])/g, function (g) {
return g[1].toUpperCase();
});
};
StringUtils.toHyphenate = function (str) {
return str.replace(/([a-z][A-Z])/g, function (g) {
return g[0] + '-' + g[1].toLowerCase();
});
};
StringUtils.lastPathComponent = function (path) {
var pathComponents = path.split('/');
return pathComponents[pathComponents.length - 1];
};
return StringUtils;
});