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,68 @@
'use strict';
/* jshint node: true */
var utils = require('utils');
var WallPaperAppBuilder = function(options) {
};
WallPaperAppBuilder.prototype.APP_DIR = 'apps/wallpaper';
WallPaperAppBuilder.prototype.BUILD_DIR = 'build_stage/wallpaper';
WallPaperAppBuilder.prototype.WALLPAPER_PATH = 'resources/';
// set options
WallPaperAppBuilder.prototype.setOptions = function(options) {
var wallpaperDirPath =
[options.STAGE_APP_DIR].concat(this.WALLPAPER_PATH.split('/'));
this.wallpaperDir = utils.getFile.apply(utils, wallpaperDirPath);
this.gaia = utils.gaia.getInstance(options);
this.configPath =
utils.joinPath(options.APP_DIR, 'build', options.GAIA_DEVICE_TYPE);
};
// XXX This inherits the behavior of what's done before in bug 838110
// It did not remove file unlisted in list.json, and the dir name is wrong.
WallPaperAppBuilder.prototype.copyDistributionWallpapers = function() {
if (!this.gaia.distributionDir) {
return;
}
var dir = utils.getFile(this.gaia.distributionDir, 'wallpapers');
if (!dir.exists()) {
return;
}
utils.log('Include wallpapers in distribution directory ...\n');
var dirParent = utils.getFile(this.wallpaperDir.path, '..');
utils.copyDirTo(dir.path, dirParent.path, this.wallpaperDir.leafName);
};
WallPaperAppBuilder.prototype.copyWallpapers = function() {
if (!this.configPath) {
throw new Error('device config path not found');
}
var dir = utils.getFile(this.configPath, 'wallpapers');
if (!dir.exists()) {
return;
}
utils.log('Include wallpapers in app configuration directory ...\n');
var dirParent = utils.getFile(this.wallpaperDir.path, '..');
utils.copyDirTo(dir.path, dirParent.path, this.wallpaperDir.leafName);
};
WallPaperAppBuilder.prototype.execute = function(options) {
utils.copyToStage(options);
this.setOptions(options);
this.copyWallpapers();
this.copyDistributionWallpapers();
};
exports.execute = function(options) {
(new WallPaperAppBuilder()).execute(options);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

View file

@ -0,0 +1,11 @@
[
"default.jpg",
"FXOS_Rocky_Hills_L.jpg",
"FXOS_Violet_Daisy_L.jpg",
"FXOS_Calm_Beach_L.jpg",
"FXOS_Dynamic_Sunset_L.jpg",
"FXOS_Mysterious_Seascape_L.jpg",
"FXOS_leap.jpg",
"FXOS_stance.jpg",
"FXOS_bolt.jpg"
]

110
gaia/apps/wallpaper/js/pick.js Executable file
View file

@ -0,0 +1,110 @@
'use strict';
/* global Downsample, LazyLoader */
var Wallpaper = {
// We're reducing each image to 1/3rd of its original size by displaying
// 3 wallpaper images in each row, decoding each image at 3/8ths of the
// original size still results in an image that is big enough to fit the
// thumbnails since 3/8 > 1/3
thumbnailScale: 3 / 8,
wallpapersUrl: '/resources/list.json',
init: function wallpaper_init() {
var self = this;
if (navigator.mozSetMessageHandler) {
navigator.mozSetMessageHandler('activity', function handler(request) {
var activityName = request.source.name;
if (activityName !== 'pick') {
return;
}
self.startPick(request);
});
}
this.header = document.getElementById('header');
this.wallpapers = document.getElementById('wallpapers');
this.generateWallpaperList();
},
generateWallpaperList: function wallpaper_generateWallpaperList(cb) {
var self = this;
// Get #-moz-samplesize media fragment to downsample while decoding
// so that we can display smaller images without using lot of memory
// See Bug 1011460
var sampleSize = Downsample.sizeNoMoreThan(this.thumbnailScale);
LazyLoader.getJSON(this.wallpapersUrl)
.then(function(json) {
self.wallpapers.innerHTML = '';
json.forEach(function(wallpaper) {
var fileName = 'resources/' + wallpaper;
// Use image tag instead of backgroundImage
// because gecko handles
// memory for off-screen images better
var imgNode = document.createElement('img');
imgNode.alt = '';
imgNode.classList.add('wallpaper');
imgNode.dataset.filename = fileName;
imgNode.src = fileName + sampleSize;
self.wallpapers.appendChild(imgNode);
});
if (cb) {
cb();
}
});
},
startPick: function wallpaper_startPick(request) {
this.pickActivity = request;
this.wallpapers.addEventListener('click', this.pickWallpaper.bind(this));
this.header.addEventListener('action', this.cancelPick.bind(this));
},
pickWallpaper: function wallpaper_pickWallpaper(e) {
// Get the wallpaper file name
var src = e.target.dataset.filename;
// Ignore clicks that are not on one of the images
if (src === '') {
return;
}
if (!this.pickActivity) { return; }
var img = new Image();
img.src = src;
var self = this;
img.onload = function() {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0);
canvas.toBlob(function(blob) {
self.pickActivity.postResult({
type: 'image/jpeg',
blob: blob,
name: src
}, 'image/jpeg');
self.endPick();
}, 'image/jpeg');
};
},
cancelPick: function wallpaper_cancelPick() {
this.pickActivity.postError('cancelled');
this.endPick();
},
endPick: function wallpaper_endPick() {
this.pickActivity = null;
this.header.removeEventListener('action', this.cancelPick);
this.wallpapers.removeEventListener('click', this.pickWallpaper);
}
};
window.addEventListener('load', function pick() {
window.removeEventListener('load', pick);
Wallpaper.init();
});

218
gaia/apps/wallpaper/js/share.js Executable file
View file

@ -0,0 +1,218 @@
'use strict';
/* global GestureDetector, ImageUtils */
window.onload = function() {
navigator.mozSetMessageHandler('activity', function handler(activityRequest) {
var activityName = activityRequest.source.name;
if (activityName !== 'share' && activityName !== 'setwallpaper') {
return;
}
startShare(activityRequest);
});
var preview = document.getElementById('preview');
var cancelButton = document.getElementById('cancel');
var setButton = document.getElementById('set-wallpaper');
var activity;
var blob;
var url;
var gestureDetector = new GestureDetector(preview);
// position of the image while dragging
var posX = 0;
var posY = 0;
// maximum number of pixel we can drag the image
var limitX;
var limitY;
var scale;
var previewImage = document.getElementById('previewImage');
// For the computations below, we need to know the full size of the screen
// in device pixels and the size of the window in CSS pixels. (The window
// and screen sizes can be different if there is a software home button.)
// We also need to ensure that the dimensions match the default orientation
// of the screen, even if the user is holding the device in a different
// orientation, and we want this to work for both phones (portrait) and
// tablets (landscape). This app is supposed to be locked to the default
// device orientation, but when it is launched as an activity from a
// different orientation sometimes it starts up in the wrong screen and
// window size. So we need to be careful to work around that window
// management bug, too.
var screenWidth, screenHeight;
var windowWidth, windowHeight;
if (screen.mozOrientation && screen.mozOrientation.startsWith('landscape')) {
// Since our manifest locks us to default orientation, mozOrientation
// should return that default orientation. If landscape then width is
// the larger dimension
screenWidth = Math.max(screen.width, screen.height);
windowWidth = Math.max(window.innerWidth, window.innerHeight);
screenHeight = Math.min(screen.width, screen.height);
windowHeight = Math.min(window.innerWidth, window.innerHeight);
} else {
// Otherwise, portrait is the default and width is the smaller dimension
screenWidth = Math.min(screen.width, screen.height);
windowWidth = Math.min(window.innerWidth, window.innerHeight);
screenHeight = Math.max(screen.width, screen.height);
windowHeight = Math.max(window.innerWidth, window.innerHeight);
}
// For the screen size we care about device pixels, not CSS pixels
screenWidth = Math.ceil(screenWidth * window.devicePixelRatio);
screenHeight = Math.ceil(screenHeight * window.devicePixelRatio);
function startShare(request) {
cancelButton.addEventListener('click', cancelShare);
gestureDetector.startDetecting();
activity = request;
blob = activity.source.data.blobs[0];
url = URL.createObjectURL(blob);
// Find out the size and type of the image without decoding it.
// If it is a really big jpeg, we'll need to downsample it while
// decoding it so we don't run out of memory.
ImageUtils.getSizeAndType(blob).then(gotImageData, imageDataError);
function imageDataError(err) {
console.error('Could not set wallpaper:', err);
activity.postError('Could not set wallpaper: ' + err);
endShare();
}
function gotImageData(imgdata) {
if (imgdata.type === ImageUtils.JPEG) {
var scale = Math.max(screenWidth / imgdata.width,
screenHeight / imgdata.height);
var fragment = ImageUtils.Downsample.sizeNoMoreThan(scale);
loadImage(url, fragment);
}
else {
loadImage(url);
}
}
function loadImage(url, fragment) {
previewImage.src = url + (fragment ? fragment : '');
previewImage.onload = function() {
previewImage.hidden = false;
// Compute a scale that will make the image at least as big as
// the screen in both dimensions.
var scalex = windowWidth / previewImage.width;
var scaley = windowHeight / previewImage.height;
scale = Math.max(scalex, scaley);
// Apply that scale to the image. Note that scaling width will
// also alter the height to match.
previewImage.width = Math.round(previewImage.width * scale);
// One dimension is now probably bigger than the screen, so figure
// out how to center the image on the screen and compute how much
// the user will be able to pan the image left and right or up
// and down.
limitX = windowWidth - previewImage.width;
limitY = windowHeight - previewImage.height;
posX = Math.round(limitX / 2);
posY = Math.round(limitY / 2);
previewImage.style.transform =
'translate(' + posX + 'px, ' + posY + 'px)';
setButton.addEventListener('click', scaleImage);
previewImage.addEventListener('pan', moveBackground);
};
}
}
function moveBackground(evt) {
var positions = evt.detail.relative;
posX += positions.dx;
if (posX > 0) {
posX = 0;
} else if (posX < limitX) {
posX = limitX;
}
posY += positions.dy;
if (posY > 0) {
posY = 0;
} else if (posY < limitY) {
posY = limitY;
}
previewImage.style.transform = 'translate(' + posX + 'px, ' + posY + 'px)';
}
function scaleImage() {
// Disable set wallpaper button to prevent hammering
// and causing multiple calls to scaleImage.
setButton.disabled = true;
// Create a canvas to have an image that is exactly
// the size of the screen in device pixels.
var canvas = document.createElement('canvas');
// To have an image which matches the device pixel, we need to multiply
// window.devicePixelRatio.
canvas.width = screenWidth;
canvas.height = screenHeight;
var ctx = canvas.getContext('2d');
var w = Math.round(windowWidth / scale);
var h = Math.round(windowHeight / scale);
var x = Math.round(-1 * posX / scale);
var y = Math.round(-1 * posY / scale);
if (x < 0) {
x = 0;
console.error('The value of x shouldn\'t be negative.');
}
if (y < 0) {
y = 0;
console.error('The value of y shouldn\'t be negative.');
}
ctx.drawImage(
previewImage,
x, y, w, h,
0, 0, canvas.width, canvas.height
);
canvas.toBlob(function(newBlob) {
blob = newBlob;
setWallpaper();
}, 'image/jpeg');
}
function setWallpaper() {
// Save the blob as the wallpaper setting
var request = navigator.mozSettings.createLock().set({
'wallpaper.image': blob
});
request.onsuccess = function() {
activity.postResult('shared');
endShare();
};
request.onerror = function() {
console.warn('error setting wallpaper.image:', request.error);
activity.postError('could not set wallpaper: ' + request.error);
endShare();
};
}
function cancelShare() {
activity.postError('cancelled');
endShare();
}
function endShare() {
activity = null;
window.URL.revokeObjectURL(url);
window.URL.revokeObjectURL(previewImage.src);
setButton.removeEventListener('click', scaleImage);
cancelButton.removeEventListener('click', cancelShare);
}
};

18
gaia/apps/wallpaper/jsdoc.json Executable file
View file

@ -0,0 +1,18 @@
{
"name": "wallpaper",
"tags": {
"dictionaries": ["jsdoc"]
},
"source": {
"include": ["apps/wallpaper/js/**/*.js"]
},
"plugins": [
"plugins/markdown",
"plugins/summarize"
],
"opts": {
"private": true,
"recurse": true,
"destination": "docs/wallpaper"
}
}

View file

@ -0,0 +1,3 @@
select-wallpaper = Select wallpaper
cancel = Cancel
set-wallpaper = Set

View file

@ -0,0 +1,64 @@
{
"name": "Wallpaper",
"description": "Gaia Wallpaper Picker",
"type": "certified",
"role": "system",
"orientation": "default",
"developer": {
"name": "The Gaia Team",
"url": "https://github.com/mozilla-b2g/gaia"
},
"permissions": {
"themeable": {},
"settings": {
"access": "readwrite"
},
"moz-extremely-unstable-and-will-change-webcomponents": {}
},
"activities": {
"pick": {
"filters": {
"type": "wallpaper"
},
"disposition": "inline",
"returnValue": true,
"href": "/pick.html"
},
"share": {
"filters": {
"type": "image/*",
"number": 1
},
"disposition": "inline",
"returnValue": true,
"href": "/share.html"
},
"setwallpaper": {
"filters": {
"type": "image/*",
"number": 1
},
"disposition": "inline",
"returnValue": true,
"href": "/share.html"
}
},
"icons": {
"84": "/style/icons/wallpaper_84.png",
"126": "/style/icons/wallpaper_126.png",
"142": "/style/icons/wallpaper_142.png",
"189": "/style/icons/wallpaper_189.png",
"284": "/style/icons/wallpaper_284.png"
},
"locales": {
"en-US": {
"name": "Wallpaper",
"description": "Gaia Wallpaper Picker"
},
"fr": {
"name": "Fond d’écran",
"description": "Sélecteur de fond d’écran de Gaia"
}
},
"default_locale": "en-US"
}

View file

@ -0,0 +1,10 @@
{
"webide": {
"prepackage": {
"command": "make",
"env": ["APP=wallpaper"],
"cwd": "../.."
},
"packageDir": "../../build_stage/wallpaper/"
}
}

33
gaia/apps/wallpaper/pick.html Executable file
View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<meta charset="utf-8" />
<title>Wallpaper</title>
<link rel="stylesheet" href="style/wallpaper.css" type="text/css" />
<!-- Localization -->
<meta name="defaultLanguage" content="en-US">
<meta name="availableLanguages" content="en-US">
<link rel="localization" href="locales/wallpaper.{locale}.properties">
<!-- Shared code -->
<script type="text/javascript" src="shared/js/l10n.js"></script>
<script type="text/javascript" defer src="shared/js/media/downsample.js"></script>
<script type="text/javascript" src="/shared/js/lazy_loader.js"></script>
<!-- Web Components -->
<script defer src="shared/elements/config.js"></script>
<!-- <link rel="stylesheet" type="text/css" href="shared/elements/gaia-icons/gaia-icons.css"> -->
<link rel="stylesheet" type="text/css" href="app://theme.gaiamobile.org/shared/elements/gaia-theme/gaia-theme.css">
<script defer src="shared/elements/gaia-header/dist/gaia-header.js"></script>
<!-- Specific code -->
<script type="text/javascript" defer src="js/pick.js"></script>
</head>
<body class="theme-media">
<section role="region" class="skin-dark">
<gaia-header ignore-dir id="header" action="close">
<h1 data-l10n-id="select-wallpaper"></h1>
</gaia-header>
</section>
<div id="wallpapers"></div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Some files were not shown because too many files have changed in this diff Show more