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,49 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<meta charset="utf-8">
<title>Fling Sender</title>
<!-- Building blocks -->
<link rel="stylesheet" type="text/css" href="shared/style/headers.css"></link>
<link rel="stylesheet" type="text/css" href="shared/style/buttons.css"></link>
<link rel="stylesheet" type="text/css" href="shared/style/input_areas.css"></link>
<link rel="stylesheet" type="text/css" href="shared/style/status.css"></link>
<!-- stylesheets of fling sender -->
<link rel="stylesheet" type="text/css" href="style/fling_sender.css">
<script defer src="shared/js/async_storage.js"></script>
<!-- main javascript code -->
<script defer src="js/fling_sender.js"></script>
</head>
<body>
<section role="region" id="video-player-controller">
<header>
<h1>Fling Sender</h1>
</header>
<nav id="video-control-bar" class="control-bar">
<button id="start-btn" type="underlined-text">Start Session</button>
<button id="close-btn" disabled type="underlined-text">Close Session</button>
<br>
URL:
<input type="text" id="url-text-box" disabled value="">
<button id="load-btn" disabled type="underlined-text">Load</button>
<br>
<button id="play-btn" disabled type="underlined-text">Play</button>
<button id="pause-btn" disabled type="underlined-text">Pause</button>
<br/>
<button id="seek-btn" disabled type="underlined-text">Seek to</button>
<input type="text" id="seek-text-box" value="50" disabled>
</nav>
</section>
<section role="region" id="result-panel">
ACK Result:
<div id="ack-result"></div>
Player Status:
<div id="status-result"></div>
</section>
</body>
</html>

View file

@ -0,0 +1,171 @@
/* global Notification, asyncStorage */
(function(exports) {
'use strict';
const PLAYER_URL = 'app://fling-player.gaiamobile.org/index.html';
var seq = 0;
function $(id) {
return document.getElementById(id);
}
function FlingSender() {}
var proto = FlingSender.prototype;
proto.init = function fs_init() {
this._urlBox = $('url-text-box');
this._seekBox = $('seek-text-box');
asyncStorage.getItem('latest-url', function(v) {
if (v) {
this._urlBox.value = v;
}
}.bind(this));
['start-btn', 'close-btn', 'load-btn', 'play-btn', 'pause-btn',
'seek-btn'].forEach(function(id) {
$(id).addEventListener('click', this);
}.bind(this));
if (!window.PresentationRequest) {
return;
}
this._request = new window.PresentationRequest(PLAYER_URL);
this._request.getAvailability().then(
function(aAvailability) {
aAvailability.onchange = function() {
$('start-btn').disabled = !aAvailability.value;
console.log('Device available: ' + aAvailability.value);
};
console.log('Device available: ' + aAvailability.value);
$('start-btn').disabled = !aAvailability.value;
},
function(aError) {
console.log('Error occurred when getting availability: ' + aError);
}
);
};
proto.handleEvent = function fs_handleEvent(evt) {
switch(evt.type) {
case 'message':
this.handleData(evt.data);
break;
case 'click':
switch(evt.target.id) {
case 'start-btn':
this.startSession();
break;
case 'close-btn':
this.closeSession();
break;
case 'load-btn':
asyncStorage.setItem('latest-url', this._urlBox.value);
this.sendCommand('load', {
'url': this._urlBox.value
});
this.sendCommand('device-info', {
'displayName': 'Fling Sender App'
});
break;
case 'play-btn':
this.sendCommand('play');
break;
case 'pause-btn':
this.sendCommand('pause');
break;
case 'seek-btn':
this.sendCommand('seek', {
'time': parseInt(this._seekBox.value, 10)
});
break;
}
break;
}
};
proto.handleData = function fs_handleData(data) {
data = '[' + data.replace(/}{/g, '},{') + ']';
var msgs = JSON.parse(data);
msgs.sort((a, b) => {
return a.seq - b.seq;
});
msgs.forEach((msg) => {
switch(msg.type) {
case 'ack':
this.handleMessage($('ack-result'), msg);
break;
case 'status':
this.handleMessage($('status-result'), msg);
break;
}
});
},
proto.handleMessage = function fs_handleMessage(element, msg) {
element.textContent = JSON.stringify(msg);
};
proto.handleStateChange = function fs_handleStateChange() {
if (!this._session || this._session.state != 'connected') {
this.disableButtons(true);
this._session = null;
if (!this._sessionCloseExpected) {
/*jshint nonew: false */
new Notification('fling player disconnected', {
'body': 'fling player is unexpectedly disconnected.'
});
}
this._sessionCloseExpected = false;
}
};
proto.disableButtons = function fs_disableButtons(disabled) {
['close-btn', 'load-btn', 'play-btn', 'pause-btn', 'seek-btn',
'url-text-box', 'seek-text-box'].forEach(function(id) {
$(id).disabled = disabled;
}.bind(this));
};
proto.startSession = function fs_startSession() {
this._request.start().then(function (session) {
this._session = session;
this._session.onmessage = this.handleEvent.bind(this);
this._session.onstatechange = this.handleStateChange.bind(this);
this.disableButtons(false);
}.bind(this), function fail() {
console.log('start session rejected');
}.bind(this));
};
proto.closeSession = function fs_closeSession() {
if (this._session) {
this._sessionCloseExpected = true;
this._session.terminate();
}
};
proto.sendCommand = function fs_sendCommand(command, data) {
var msg = {
'type': command,
'seq': ++seq
};
if (data) {
for (var k in data) {
msg[k] = data[k];
}
}
this._session.send(JSON.stringify(msg));
};
exports.FlingSender = FlingSender;
window.onload = function() {
window.fs = new FlingSender();
window.fs.init();
};
})(window);

View file

@ -0,0 +1,25 @@
{
"name": "Fling Sender",
"description": "Smart Screen Fling Sender",
"launch_path": "/index.html",
"type": "certified",
"developer": {
"name": "The Gaia Team",
"url": "https://github.com/mozilla-b2g/gaia"
},
"locales": {
"en-US": {
"name": "Fling Sender",
"description": "Smart Screen Fling Sender"
}
},
"permissions": {
"desktop-notification": {},
"presentation": {}
},
"default_locale": "en-US",
"icons": {
"90": "/style/icons/appic_mwc2015_90.png",
"135": "/style/icons/appic_mwc2015_135.png"
}
}

View file

@ -0,0 +1,15 @@
html {
font-size: 10px;
/* We have Fira Sans as default font in real device. But it isn't default in
* browser. That's the main reason this line is here.*/
font-family: "Fira Sans";
}
html, body {
width: 100%;
height: 100%;
overflow: auto;
margin: 0;
padding: 0;
background-color: rgba(0,0,0,0.5);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB