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.
374
overrides/system.gaiamobile.org/fxa/style/fxa.css
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* Basic and shared styles of the structure
|
||||
* */
|
||||
html, body {
|
||||
font-size: 62.5%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
color: #000;
|
||||
background: #f4f4f4;
|
||||
}
|
||||
|
||||
html, body * {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
input {
|
||||
-moz-user-select: text;
|
||||
}
|
||||
|
||||
.vertical {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section[role="region"] {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
body {
|
||||
background: url(bg_light.png);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.7rem;
|
||||
font-weight: 400;
|
||||
line-height: 2.3rem;
|
||||
margin: 0 0 1rem;
|
||||
text-align: start;
|
||||
}
|
||||
h3:-moz-dir(rtl) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
label {
|
||||
width:100%;
|
||||
display:block;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Navigation bar based on a flex model
|
||||
* * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.navigation {
|
||||
position: absolute;
|
||||
background: #f4f4f4;
|
||||
border-top: 0.1rem solid #a6a6a6;
|
||||
padding: .75rem 1.5rem;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
left: 0;
|
||||
right:0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Overwrite this property from Building Blocks */
|
||||
html[dir="ltr"] .navigation button { margin-left: 0.5rem; }
|
||||
html[dir="rtl"] .navigation button { margin-right: 0.5rem; }
|
||||
|
||||
html[dir="ltr"] .navigation button.start { margin-left: 0.5rem; }
|
||||
html[dir="rtl"] .navigation button.start { margin-right: 0.5rem; }
|
||||
|
||||
.navigation button.start,
|
||||
.navigation button.end {
|
||||
width: calc((100% / 2) - 0.5rem);
|
||||
position: relative;
|
||||
}
|
||||
html[dir="ltr"] .navigation button.start,
|
||||
html[dir="ltr"] .navigation button.end { float: left; }
|
||||
html[dir="rtl"] .navigation button.start,
|
||||
html[dir="rtl"] .navigation button.end { float: right; }
|
||||
|
||||
/* When there is only one option, we remove the margin */
|
||||
|
||||
.navigation-single-button button.start {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigation.navigation-single-button button.end {
|
||||
margin: 0;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.navigation-back-only button {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navigation-back-only button.end {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigation-done #fxa-module-back,
|
||||
.navigation-done #fxa-module-next {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fxa-module-done {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigation-done #fxa-module-done {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Steps & Container
|
||||
* All steps are contained in several views inside
|
||||
* 'step-container'. We will use HTML 'import' polyfill
|
||||
* and lazy load of the views. A view is a set of steps.
|
||||
* * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.bb-steps {
|
||||
margin: 0.5rem 1.5rem;
|
||||
}
|
||||
|
||||
#step-container {
|
||||
height: calc(100% - 6.3rem - 5rem);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ff_account,
|
||||
.screen {
|
||||
font-family: sans-serif;
|
||||
font-size: 1.7rem;
|
||||
line-height:2.3rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
overflow: scroll;
|
||||
display: none;
|
||||
padding: 1.5rem 2.5rem;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.screen p.fxa-intro {
|
||||
text-align: start;
|
||||
line-height: 2.3rem;
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
.screen p {
|
||||
text-align: start;
|
||||
line-height: 1.9rem;
|
||||
font-size: 1.5rem;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
.current {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Intro screen styles
|
||||
*/
|
||||
|
||||
#fxa-hello-user {
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#fxa-user-email,
|
||||
#fxa-user-set-email {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p.fine-print {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.6rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verification Screen Styles
|
||||
*/
|
||||
|
||||
ul.fxa-verification-wrapper {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.fxa-verification-wrapper li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Password screen styles
|
||||
*/
|
||||
|
||||
#show-pw-wrapper {
|
||||
width: 100%;
|
||||
display: block;
|
||||
margin: 0 -1.5rem;
|
||||
}
|
||||
|
||||
#show-pw-wrapper p {
|
||||
display: block;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
html[dir="ltr"] #show-pw-wrapper p { float: left; }
|
||||
html[dir="rtl"] #show-pw-wrapper p { float: right; }
|
||||
|
||||
html[dir="ltr"] #show-pw-wrapper > label { float: left; }
|
||||
html[dir="rtl"] #show-pw-wrapper > label { float: right; }
|
||||
|
||||
/* Animate next screen */
|
||||
.currentToPrev {
|
||||
display:block;
|
||||
}
|
||||
html[dir="ltr"] .currentToPrev {
|
||||
animation: currentToLeft var(--transition-duration) forwards;
|
||||
}
|
||||
html[dir="rtl"] .currentToPrev {
|
||||
animation: currentToRight var(--transition-duration) forwards;
|
||||
}
|
||||
|
||||
.nextToCurrent {
|
||||
display:block;
|
||||
}
|
||||
html[dir="ltr"] .nextToCurrent {
|
||||
animation: rightToCurrent var(--transition-duration) forwards;
|
||||
}
|
||||
html[dir="rtl"] .nextToCurrent {
|
||||
animation: leftToCurrent var(--transition-duration) forwards;
|
||||
}
|
||||
|
||||
/* Animate prev screen */
|
||||
.prevToCurrent {
|
||||
display: block;
|
||||
}
|
||||
html[dir="ltr"] .prevToCurrent {
|
||||
animation: leftToCurrent var(--transition-duration) forwards;
|
||||
}
|
||||
html[dir="rtl"] .prevToCurrent {
|
||||
animation: rightToCurrent var(--transition-duration) forwards;
|
||||
}
|
||||
|
||||
.currentToNext {
|
||||
display: block;
|
||||
}
|
||||
html[dir="ltr"] .currentToNext {
|
||||
animation: currentToRight var(--transition-duration) forwards;
|
||||
}
|
||||
html[dir="rtl"] .currentToNext {
|
||||
animation: currentToLeft var(--transition-duration) forwards;
|
||||
}
|
||||
|
||||
@keyframes currentToLeft {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(-100%); }
|
||||
}
|
||||
@keyframes rightToCurrent {
|
||||
0% { transform: translateX(100%); }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
@keyframes leftToCurrent {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
@keyframes currentToRight {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
|
||||
.current {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.screen a {
|
||||
text-decoration: underline;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.fxa-logo {
|
||||
background-image: image-set(url("fxa_logo.png") 1x, url("fxa_logo@1.5x.png") 1.5x, url("fxa_logo@2x.png") 2x, url("fxa_logo@2.25x.png") 2.25x);
|
||||
background-size: 14rem auto;
|
||||
background-repeat: no-repeat;
|
||||
margin: 0 auto;
|
||||
width: 14rem;
|
||||
height: 15rem;
|
||||
}
|
||||
|
||||
p.fxa-envelope {
|
||||
background-image: image-set(url("fxa_envelope.png") 1x, url("fxa_envelope@1.5x.png") 1.5x, url("fxa_envelope@2x.png") 2x, url("fxa_envelope@2.25x.png") 2.25x);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 7rem;
|
||||
padding-inline-start: 8rem;
|
||||
padding-top: 1rem;
|
||||
line-height: 2rem;
|
||||
min-height: 6.4rem;
|
||||
max-width:100%;
|
||||
overflow: hidden; /* short email addresses will only take up one line*/
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
html[dir="ltr"] p.fxa-envelope { background-position: left top; }
|
||||
html[dir="rtl"] p.fxa-envelope { background-position: right top; }
|
||||
|
||||
#fxa-error-overlay {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Overlay:
|
||||
* IMPORTANT: Avoid to use 'visibility' or 'opacity' due
|
||||
* to performance issues. For hiding, use 'display:none;''
|
||||
* * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#fxa-overlay {
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
font-size: 2rem;
|
||||
background-color: rgba(200,200,200,0.9);
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#fxa-overlay.show {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
form[role=dialog] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form[role=dialog].show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Classes to ensure functionality
|
||||
*/
|
||||
|
||||
a.disabled {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button.icon-dialog select {
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
BIN
overrides/system.gaiamobile.org/fxa/style/fxa_envelope@1.5x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
overrides/system.gaiamobile.org/fxa/style/fxa_envelope@2.25x.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
overrides/system.gaiamobile.org/fxa/style/fxa_envelope@2x.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
overrides/system.gaiamobile.org/fxa/style/fxa_logo@1.5x.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
overrides/system.gaiamobile.org/fxa/style/fxa_logo@2.25x.png
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
overrides/system.gaiamobile.org/fxa/style/fxa_logo@2x.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
1300
overrides/system.gaiamobile.org/js/app_chrome.js
Normal file
53
overrides/system.gaiamobile.org/js/battery_icon.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* global BaseIcon */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
var BatteryIcon = function(manager) {
|
||||
BaseIcon.call(this, manager);
|
||||
};
|
||||
BatteryIcon.prototype = Object.create(BaseIcon.prototype);
|
||||
BatteryIcon.prototype.name = 'BatteryIcon';
|
||||
BatteryIcon.prototype.update = function() {
|
||||
if (!this.element) {
|
||||
return;
|
||||
}
|
||||
var battery = this.manager._battery;
|
||||
if (!battery || !Number.isFinite(battery.level)) {
|
||||
this.hide();
|
||||
return;
|
||||
}
|
||||
this.show();
|
||||
var icon = this.element;
|
||||
var previousLevel = parseInt(icon.dataset.level, 10);
|
||||
var previousCharging = (icon.dataset.charging === 'true');
|
||||
|
||||
icon.dataset.charging = battery.charging;
|
||||
var level = Math.floor(battery.level * 10) * 10;
|
||||
|
||||
this.debug('previous level: ', previousLevel);
|
||||
this.debug('current level:', level);
|
||||
|
||||
if (previousLevel === level &&
|
||||
previousCharging === battery.charging) {
|
||||
return;
|
||||
}
|
||||
|
||||
icon.dataset.level = level;
|
||||
navigator.mozL10n.setAttributes(
|
||||
icon,
|
||||
battery.charging ? 'statusbarBatteryCharging' : 'statusbarBattery',
|
||||
{level: level}
|
||||
);
|
||||
this.previousCharging = battery.charging;
|
||||
this.publish('changed');
|
||||
};
|
||||
|
||||
BatteryIcon.prototype.view = function view() {
|
||||
return `<div id="statusbar-battery"
|
||||
class="sb-icon sb-icon-battery"
|
||||
role="listitem">
|
||||
</div>`;
|
||||
};
|
||||
|
||||
exports.BatteryIcon = BatteryIcon;
|
||||
}(window));
|
||||
263
overrides/system.gaiamobile.org/js/dialer_agent.js
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
'use strict';
|
||||
|
||||
/* global SettingsListener, SettingsURL, CallscreenWindow, applications */
|
||||
/* global Service, LazyLoader, toneUpgrader */
|
||||
/* r=? dialer+system peers for changes in this file. */
|
||||
|
||||
(function(exports) {
|
||||
/**
|
||||
*
|
||||
* The delay between an incoming phone call and the first ring or vibration
|
||||
* needs to be as short as possible.
|
||||
*
|
||||
* This simple module keeps the ringtone (blob) around and starts alerting the
|
||||
* user as soon as a new incoming call is detected via the mozTelephony API.
|
||||
* And it opens an AttentionWindow with the preloaded callscreen app inside.
|
||||
*
|
||||
* We also listen for the sleep and volumedown hardware buttons to provide
|
||||
* the user with an easy way to stop the ringing.
|
||||
*
|
||||
* @example
|
||||
* var dialerAgent = new DialerAgent();
|
||||
* dialerAgent.start(); // Attach the event listeners.
|
||||
* dialerAgent.stop(); // Deattach the event listeners.
|
||||
*
|
||||
* @class DialerAgent
|
||||
* @requires SettingsListener
|
||||
* @requires SettingsURL
|
||||
* @requires Service
|
||||
* @requires LazyLoader
|
||||
*
|
||||
**/
|
||||
|
||||
var DialerAgent = function DialerAgent() {
|
||||
var telephony = navigator.mozTelephony;
|
||||
if (!telephony) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._telephony = telephony;
|
||||
|
||||
this._started = false;
|
||||
this._shouldVibrate = true;
|
||||
this._alerting = false;
|
||||
this._vibrateInterval = null;
|
||||
|
||||
var player = new Audio();
|
||||
this._player = player;
|
||||
// XXX: This will need to be updated for bug 961967
|
||||
// (audio competing in system app)
|
||||
player.mozAudioChannelType = 'ringer';
|
||||
player.preload = 'metadata';
|
||||
player.loop = true;
|
||||
this.freeCallscreenWindow = this.freeCallscreenWindow.bind(this);
|
||||
this.makeFakeNotification = this.makeFakeNotification.bind(this);
|
||||
};
|
||||
|
||||
DialerAgent.prototype.freeCallscreenWindow = function() {
|
||||
/* Free the callscreen window unless there are active calls or the
|
||||
* callscreen is visible. */
|
||||
if (this._callscreenWindow && !this.onCall() &&
|
||||
!this._callscreenWindow.isVisible()) {
|
||||
this._callscreenWindow.free();
|
||||
}
|
||||
};
|
||||
|
||||
DialerAgent.prototype.start = function da_start() {
|
||||
if (!this._telephony) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._started) {
|
||||
throw 'Instance should not be start()\'ed twice.';
|
||||
}
|
||||
this._started = true;
|
||||
|
||||
SettingsListener.observe('audio.volume.notification', 7, function(value) {
|
||||
this._playRing();
|
||||
}.bind(this));
|
||||
|
||||
SettingsListener.observe('dialer.ringtone', '', function(value) {
|
||||
LazyLoader.load(['shared/js/settings_url.js']).then(function() {
|
||||
var phoneSoundURL = new SettingsURL();
|
||||
|
||||
this._player.pause();
|
||||
this._player.src = phoneSoundURL.set(value);
|
||||
this._playRing();
|
||||
}.bind(this)).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
// We have new default ringtones in 2.0, so check if the version is upgraded
|
||||
// then execute the necessary migration.
|
||||
if (Service.query('justUpgraded')) {
|
||||
LazyLoader.load('js/tone_upgrader.js').then(() => {
|
||||
toneUpgrader.perform('ringtone');
|
||||
});
|
||||
}
|
||||
|
||||
SettingsListener.observe('vibration.enabled', true, function(value) {
|
||||
this._shouldVibrate = !!value;
|
||||
}.bind(this));
|
||||
|
||||
this._telephony.addEventListener('callschanged', this);
|
||||
|
||||
window.addEventListener('sleep', this);
|
||||
window.addEventListener('wake', this);
|
||||
window.addEventListener('volumedown', this);
|
||||
window.addEventListener('mozmemorypressure', this.freeCallscreenWindow);
|
||||
|
||||
this._callscreenWindow = new CallscreenWindow();
|
||||
this._callscreenWindow.hide();
|
||||
|
||||
if (applications && applications.ready) {
|
||||
this.makeFakeNotification();
|
||||
} else {
|
||||
window.addEventListener('applicationready', this.makeFakeNotification);
|
||||
}
|
||||
|
||||
Service.registerState('onCall', this);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
DialerAgent.prototype.makeFakeNotification = function() {
|
||||
window.removeEventListener('applicationready', this.makeFakeNotification);
|
||||
this._callscreenWindow && this._callscreenWindow.makeNotification();
|
||||
};
|
||||
|
||||
DialerAgent.prototype.stop = function da_stop() {
|
||||
if (!this._started) {
|
||||
return;
|
||||
}
|
||||
this._started = false;
|
||||
|
||||
this._telephony.removeEventListener('callschanged', this);
|
||||
|
||||
window.removeEventListener('sleep', this);
|
||||
window.removeEventListener('wake', this);
|
||||
window.removeEventListener('volumedown', this);
|
||||
window.removeEventListener('mozmemorypressure', this.freeCallscreenWindow);
|
||||
|
||||
Service.unregisterState('onCall', this);
|
||||
|
||||
// TODO: should remove the settings listener once the helper
|
||||
// allows it.
|
||||
// See bug 981373.
|
||||
};
|
||||
|
||||
DialerAgent.prototype.handleEvent = function da_handleEvent(evt) {
|
||||
if (evt.type === 'volumedown') {
|
||||
this._stopAlerting();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((evt.type === 'sleep') && this._alerting) {
|
||||
this._stopAlerting();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((evt.type === 'sleep') && this.onCall()) {
|
||||
// Hangup all calls
|
||||
this._telephony.calls.forEach(call => call.hangUp());
|
||||
|
||||
if (this._telephony.conferenceGroup.calls.length > 0) {
|
||||
this._telephony.conferenceGroup.hangUp();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((evt.type === 'wake') && this.onCall()) {
|
||||
Service.request('turnScreenOn');
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.type !== 'callschanged') {
|
||||
return;
|
||||
}
|
||||
|
||||
var calls = this._telephony.calls;
|
||||
if (calls.length === 0) {
|
||||
Service.request('turnScreenOn');
|
||||
return;
|
||||
}
|
||||
|
||||
var calling = calls.some(function(call) {
|
||||
if (['incoming', 'dialing', 'alerting', 'connected', 'held'].indexOf(call.state) !== -1) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (calling) {
|
||||
this.openCallscreen();
|
||||
}
|
||||
|
||||
var incomingCall = calls[calls.length - 1];
|
||||
if (this._alerting || incomingCall.state !== 'incoming') {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
self._startAlerting();
|
||||
|
||||
incomingCall.addEventListener('statechange', function callStateChange() {
|
||||
incomingCall.removeEventListener('statechange', callStateChange);
|
||||
|
||||
self._stopAlerting();
|
||||
});
|
||||
};
|
||||
|
||||
DialerAgent.prototype._playRing = function da_playRing () {
|
||||
// Notice that, even we are in the vibration mode, we would still play the
|
||||
// silence ringer. That is because when the incoming call is coming, other
|
||||
// playing sound should be paused. Therefore, we need to a silence ringer
|
||||
// to compete for the audio output.
|
||||
if (this._alerting) {
|
||||
this._player.play();
|
||||
}
|
||||
};
|
||||
|
||||
DialerAgent.prototype._startAlerting = function da_startAlerting() {
|
||||
this._alerting = true;
|
||||
|
||||
if ('vibrate' in navigator && this._shouldVibrate) {
|
||||
this._vibrateInterval = window.setInterval(function vibrate() {
|
||||
navigator.vibrate([200]);
|
||||
}, 600);
|
||||
navigator.vibrate([200]);
|
||||
}
|
||||
|
||||
this._playRing();
|
||||
};
|
||||
|
||||
DialerAgent.prototype._stopAlerting = function da_stopAlerting() {
|
||||
var player = this._player;
|
||||
|
||||
this._alerting = false;
|
||||
if (player && player.readyState > player.HAVE_NOTHING) {
|
||||
player.pause();
|
||||
player.currentTime = 0;
|
||||
}
|
||||
|
||||
window.clearInterval(this._vibrateInterval);
|
||||
};
|
||||
|
||||
DialerAgent.prototype.openCallscreen = function() {
|
||||
if (this._callscreenWindow) {
|
||||
this._callscreenWindow.ensure();
|
||||
this._callscreenWindow.requestOpen();
|
||||
}
|
||||
};
|
||||
|
||||
DialerAgent.prototype.onCall = function() {
|
||||
var numOpenLines = this._telephony.calls.length +
|
||||
(this._telephony.conferenceGroup.calls.length ? 1 : 0);
|
||||
|
||||
return (numOpenLines > 0);
|
||||
};
|
||||
|
||||
exports.DialerAgent = DialerAgent;
|
||||
}(window));
|
||||
87
overrides/system.gaiamobile.org/js/lockscreen_agent.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
Copyright 2012, Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/* globals IACHandler */
|
||||
|
||||
/**
|
||||
* Forward all relevant events in System to the LockScreen frame.
|
||||
* System --> LockScreen
|
||||
*/
|
||||
'use strict';
|
||||
(function(exports) {
|
||||
var LockScreenAgent = function(frame) {
|
||||
this.configs = {
|
||||
listens: [
|
||||
'lockscreen-notification-request-append',
|
||||
'lockscreen-notification-request-clear',
|
||||
'emergency-call-leave',
|
||||
'screenchange',
|
||||
'timeformatchange',
|
||||
'iac-mediacomms',
|
||||
'appterminated', // for the music playback widget
|
||||
'bluetoothprofileconnectionchange',
|
||||
'lockscreen-request-mediacommand',
|
||||
'lockscreen-appclosed' // necessary for state manager
|
||||
]
|
||||
};
|
||||
this.frame = frame;
|
||||
};
|
||||
|
||||
LockScreenAgent.prototype.start = function() {
|
||||
this.startEventListeners();
|
||||
};
|
||||
|
||||
LockScreenAgent.prototype.startEventListeners = function() {
|
||||
this.configs.listens.forEach((ename) => {
|
||||
window.addEventListener(ename, this);
|
||||
});
|
||||
};
|
||||
|
||||
LockScreenAgent.prototype.handleEvent = function(event) {
|
||||
// XXX: This is a special case: it do not forward System events to
|
||||
// LockScreen frame. Instead of, the event flow is:
|
||||
//
|
||||
// LockScreen -> System -> (this agent) -> IAC
|
||||
//
|
||||
// This is because WHEN we're in the inner iframe, comapre to the real
|
||||
// app frame, LockScreen can't get the IAC port to communicate with
|
||||
// media apps. So we need an agent to forward it.
|
||||
//
|
||||
// @see LockScreenMediaPlaybackWidget#handleEvent
|
||||
if ('lockscreen-request-mediacommand' === event.type) {
|
||||
var port = IACHandler ?
|
||||
IACHandler.getPort('mediacomms') : null;
|
||||
if (!port) {
|
||||
return;
|
||||
}
|
||||
port.postMessage( { command: event.detail } );
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX: Before we make LockScreen really as an iframe,
|
||||
// do nothing and let events pass through.
|
||||
// After we put LockScreen in an iframe, re-create the event and
|
||||
// dispatch it to LockScreen's window.
|
||||
};
|
||||
|
||||
LockScreenAgent.prototype.stop = function() {
|
||||
this.configs.listens.forEach((ename) => {
|
||||
window.removeEventListener(ename, this);
|
||||
});
|
||||
};
|
||||
exports.LockScreenAgent = LockScreenAgent;
|
||||
})(window);
|
||||
|
||||
290
overrides/system.gaiamobile.org/js/lockscreen_window.js
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
/* globals LockScreenAgent, LazyLoader */
|
||||
/* global Service */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
var AppWindow = window.AppWindow;
|
||||
|
||||
/**
|
||||
* This window is inherit the AppWindow, and modifies some properties
|
||||
* different from the later.
|
||||
*
|
||||
* @constructor LockScreenWindow
|
||||
* @augments AppWindow
|
||||
*/
|
||||
var LockScreenWindow = function() {
|
||||
// Before we make lockscreen as an app (Bug 898348 ), which would
|
||||
// own its own manifest, we must mock a manifest for him.
|
||||
this.configs = {
|
||||
url: window.location.href,
|
||||
manifest: {
|
||||
orientation: ['default']
|
||||
},
|
||||
name: 'Lockscreen',
|
||||
// No manifestURL + no chrome would cause a default chrome app
|
||||
manifestURL: window.location.href.replace('system', 'lockscreen') +
|
||||
'/manifest.webapp',
|
||||
origin: window.location.origin.replace('system', 'lockscreen'),
|
||||
inputWindow: {
|
||||
resizeMode: false
|
||||
}
|
||||
};
|
||||
this.iframe = this.createFrame();
|
||||
if (!this.iframe || !this.iframe.parentNode) {
|
||||
// XXX: Lockscreen DOM elements are not copied.
|
||||
return;
|
||||
}
|
||||
|
||||
LazyLoader.load(['js/lockscreen_agent.js']).then(() => {
|
||||
this.lockScreenAgent = new LockScreenAgent(this.iframe);
|
||||
this.lockScreenAgent.start();
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
AppWindow.call(this, this.configs);
|
||||
window.dispatchEvent(new CustomEvent('lockscreen-frame-bootstrap', {
|
||||
detail: this
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* @borrows AppWindow.prototype as LockScreenWindow.prototype
|
||||
* @memberof LockScreenWindow
|
||||
*/
|
||||
LockScreenWindow.prototype = Object.create(AppWindow.prototype);
|
||||
|
||||
LockScreenWindow.prototype.constructor = LockScreenWindow;
|
||||
|
||||
LockScreenWindow.prototype.isLockscreen = true;
|
||||
|
||||
LockScreenWindow.SUB_COMPONENTS = {
|
||||
'transitionController': 'AppTransitionController',
|
||||
'statusbar': 'AppStatusbar'
|
||||
};
|
||||
|
||||
LockScreenWindow.REGISTERED_EVENTS = AppWindow.REGISTERED_EVENTS;
|
||||
|
||||
/**
|
||||
* We still need this before we put the lockreen inside an iframe.
|
||||
*
|
||||
* @type LockScreen
|
||||
* @memberof LockScreenWindow
|
||||
*/
|
||||
LockScreenWindow.prototype.lockscreen = null;
|
||||
|
||||
LockScreenWindow.prototype.HIERARCHY_MANAGER = 'LockScreenWindowManager';
|
||||
|
||||
/**
|
||||
* We would maintain our own events by other components.
|
||||
*
|
||||
* @type string
|
||||
* @memberof LockScreenWindow
|
||||
*/
|
||||
LockScreenWindow.prototype.eventPrefix = 'lockscreen-app';
|
||||
|
||||
/**
|
||||
* Different animation from the original window.
|
||||
*
|
||||
* @type string
|
||||
* @memberof LockScreenWindow
|
||||
*/
|
||||
LockScreenWindow.prototype.openAnimation = 'immediate';
|
||||
|
||||
/**
|
||||
* Different animation from the original window.
|
||||
*
|
||||
* @type string
|
||||
* @memberof LockScreenWindow
|
||||
*/
|
||||
LockScreenWindow.prototype.closeAnimation = 'fade-out';
|
||||
|
||||
LockScreenWindow.prototype._DEBUG = false;
|
||||
|
||||
/**
|
||||
* LockScreenWindow has its own styles.
|
||||
*
|
||||
* @type string
|
||||
* @memberof LockScreenWindow
|
||||
*/
|
||||
LockScreenWindow.prototype.CLASS_LIST = 'appWindow lockScreenWindow';
|
||||
LockScreenWindow.prototype.CLASS_NAME = 'LockScreenWindow';
|
||||
|
||||
LockScreenWindow.prototype._resize = function aw__resize() {
|
||||
var height, width;
|
||||
|
||||
// We want the lockscreen to go below the Statusbar
|
||||
height = Service.query('LayoutManager.height') || window.innerHeight;
|
||||
width = Service.query('LayoutManager.width') || window.innerWidth;
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.element.style.width = this.width + 'px';
|
||||
this.element.style.height = this.height + 'px';
|
||||
|
||||
this.resized = true;
|
||||
|
||||
/**
|
||||
* Fired when the app is resized.
|
||||
*
|
||||
* @event LockScreenWindow#lockscreen-appresize
|
||||
*/
|
||||
this.publish('resize');
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the iframe and load it.
|
||||
*
|
||||
* @this {LockScreenWindow}
|
||||
* @memberof LockScreenWindow
|
||||
*/
|
||||
LockScreenWindow.prototype.createFrame =
|
||||
function lsw_createFrame() {
|
||||
// XXX: Before we can make LockScreen as a real app,
|
||||
// we need these.
|
||||
var frame = document.getElementById('lockscreen-frame');
|
||||
if (!frame) {
|
||||
// XXX: This means we failed to build the system app.
|
||||
// So from now on we will try to go without lockscreen.
|
||||
frame = document.createElement('div');
|
||||
}
|
||||
frame.setVisible = function() {};
|
||||
// XXX: real mozbrowser iframes would own these methods.
|
||||
frame.addNextPaintListener = function(cb) {
|
||||
cb();
|
||||
};
|
||||
frame.removeNextPaintListener = function() {};
|
||||
frame.getScreenshot = function() {
|
||||
// Mock the request.
|
||||
return {
|
||||
get onsuccess() {return null;},
|
||||
set onsuccess(cb) {
|
||||
var mockEvent = {
|
||||
target: {result: null}
|
||||
};
|
||||
cb(mockEvent);
|
||||
}
|
||||
};
|
||||
};
|
||||
frame.removeAttribute('hidden');
|
||||
return frame;
|
||||
};
|
||||
|
||||
LockScreenWindow.prototype.getNotificationContainer =
|
||||
function lsw_getNotificationContainer() {
|
||||
// XXX: After we make LockScreen as an app, needn't this anymore.
|
||||
return document.getElementById(
|
||||
'notifications-lockscreen-container');
|
||||
};
|
||||
|
||||
LockScreenWindow.prototype._resize =
|
||||
function lsw__resize() {
|
||||
var height, width;
|
||||
this.debug('force RESIZE...');
|
||||
if (this.inputWindow && typeof this.inputWindow.isActive === 'function' &&
|
||||
this.inputWindow.isActive()) {
|
||||
/**
|
||||
* The event is dispatched on the app window only when keyboard is up.
|
||||
*
|
||||
* @access private
|
||||
* @event LockScreenWindow~_withkeyboard
|
||||
*/
|
||||
this.broadcast('withkeyboard');
|
||||
} else {
|
||||
/**
|
||||
* The event is dispatched on the LockScreen window only
|
||||
* when keyboard is hidden.
|
||||
*
|
||||
* @access private
|
||||
* @event LockScreenWindow~_withoutkeyboard
|
||||
*/
|
||||
this.broadcast('withoutkeyboard');
|
||||
}
|
||||
height = this.layoutHeight();
|
||||
width = this.layoutWidth();
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.element.style.width = this.width + 'px';
|
||||
this.element.style.height = this.height + 'px';
|
||||
|
||||
this.browser.element.style.width = '';
|
||||
this.browser.element.style.height = '';
|
||||
|
||||
this.resized = true;
|
||||
if (this.screenshotOverlay) {
|
||||
this.screenshotOverlay.style.visibility = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the app is resized.
|
||||
*
|
||||
* @event LockScreenWindow#lockscreen-appresize
|
||||
*/
|
||||
this.publish('resize');
|
||||
this.debug('W:', this.width, 'H:', this.height);
|
||||
};
|
||||
|
||||
// XXX Bug 1085226: Before we make LockScreen use real keyboard, we need this.
|
||||
LockScreenWindow.prototype.layoutHeight =
|
||||
function lwm_layoutHeight() {
|
||||
// Whether we can resize or not (depends on if the content
|
||||
// is inside an iframe or not).
|
||||
if (!this.configs.inputWindow.resizeMode) {
|
||||
return window.innerHeight;
|
||||
}
|
||||
var softwareButtonHeight = this.isActive() ?
|
||||
0 : (Service.query('SoftwareButtonManager.height') || 0);
|
||||
var inputWindowHeight = 0;
|
||||
if (this.states.instance && this.states.instance.inputWindow &&
|
||||
typeof this.states.instance.inputWindow.isActive === 'function' &&
|
||||
this.states.instance.inputWindow.isActive()) {
|
||||
inputWindowHeight = this.configs.inputWindow.height;
|
||||
}
|
||||
var height = window.innerHeight -
|
||||
inputWindowHeight -
|
||||
softwareButtonHeight;
|
||||
|
||||
// Normalizing the height so that it always translates to an integral
|
||||
// number of device pixels
|
||||
var dpx = window.devicePixelRatio;
|
||||
if ((height * dpx) % 1 !== 0) {
|
||||
height = Math.ceil(height * dpx) / dpx;
|
||||
}
|
||||
|
||||
return height;
|
||||
};
|
||||
|
||||
LockScreenWindow.prototype.layoutWidth =
|
||||
function() {
|
||||
return window.innerWidth;
|
||||
};
|
||||
|
||||
LockScreenWindow.prototype.lockOrientation =
|
||||
function() {
|
||||
// XXX: When we turn the screen on, try to lock the orientation
|
||||
// until it works. It may fail at the moment the screenchange
|
||||
// event has been fired, so we may need to try it several times.
|
||||
var tryLockOrientation = () => {
|
||||
if (screen.mozLockOrientation('portrait-primary')) {
|
||||
if (!this.orientationLockID) {
|
||||
throw new Error('No orientation ID. This function should only' +
|
||||
'be invoked as a interval callback');
|
||||
}
|
||||
window.clearInterval(this.orientationLockID);
|
||||
this.orientationLockID = null;
|
||||
}
|
||||
};
|
||||
if (Service.query('isOnRealDevice')) {
|
||||
if (this.orientationLockID) {
|
||||
// The previous one still present and was not cleared,
|
||||
// so do nothing.
|
||||
return;
|
||||
}
|
||||
this.orientationLockID =
|
||||
window.setInterval(tryLockOrientation, 4);
|
||||
// 4ms is the minimum interval according to W3C#setTimeout standard.
|
||||
}
|
||||
};
|
||||
|
||||
exports.LockScreenWindow = LockScreenWindow;
|
||||
})(window);
|
||||
834
overrides/system.gaiamobile.org/js/notification_screen.js
Normal file
|
|
@ -0,0 +1,834 @@
|
|||
/* global LazyLoader, MediaPlaybackWidget, Service,
|
||||
SettingsListener, SettingsURL, toneUpgrader, mozIntl */
|
||||
|
||||
'use strict';
|
||||
|
||||
var NotificationScreen = {
|
||||
name: 'NotificationScreen',
|
||||
TOASTER_TIMEOUT: 3500,
|
||||
TRANSITION_FRACTION: 0.30,
|
||||
TRANSITION_DURATION: 200,
|
||||
SWIPE_INERTIA: 100,
|
||||
TAP_THRESHOLD: 10,
|
||||
SCROLL_THRESHOLD: 10,
|
||||
CLEAR_DELAY: 80,
|
||||
|
||||
_notification: null,
|
||||
_containerWidth: null,
|
||||
_touchStartX: 0,
|
||||
_touchStartY: 0,
|
||||
_touchPosX: 0,
|
||||
_touching: false,
|
||||
_isTap: false,
|
||||
_toasterTimeout: null,
|
||||
|
||||
lockscreenPreview: true,
|
||||
silent: false,
|
||||
vibrates: true,
|
||||
isResending: false,
|
||||
resendReceived: 0,
|
||||
resendExpecting: 0,
|
||||
|
||||
/* These applications' notifications will be added in the "priority"
|
||||
* notification group
|
||||
*/
|
||||
PRIORITY_APPLICATIONS: [
|
||||
window.location.origin.replace('system.', 'network-alerts.') +
|
||||
'/manifest.webapp'
|
||||
],
|
||||
|
||||
/* These applications' notifications will not be notified, it means we won't
|
||||
* have:
|
||||
* - the banner
|
||||
* - the vibration
|
||||
* - the sound
|
||||
*/
|
||||
SILENT_APPLICATIONS: [
|
||||
window.location.origin.replace('system.', 'network-alerts.') +
|
||||
'/manifest.webapp'
|
||||
],
|
||||
|
||||
getLockScreenContainer: function ns_getLockScreenContainer() {
|
||||
// XXX: Bug 1057198 add this as a workaround before we truly
|
||||
// make LockScreen as an app.
|
||||
var lw = Service.query('LockScreenWindowManager.getInstance');
|
||||
if (lw && lw.getNotificationContainer()) {
|
||||
return lw.getNotificationContainer();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
start: function() {
|
||||
window.addEventListener('mozChromeNotificationEvent', this);
|
||||
this.notificationsContainer =
|
||||
document.getElementById('notifications-container');
|
||||
this.container =
|
||||
document.getElementById('desktop-notifications-container');
|
||||
this.lockScreenContainer = this.getLockScreenContainer();
|
||||
this.toaster = document.getElementById('notification-toaster');
|
||||
this.ambientIndicator = document.getElementById('ambient-indicator');
|
||||
this.toasterIcon = document.getElementById('toaster-icon');
|
||||
this.toasterTitle = document.getElementById('toaster-title');
|
||||
this.toasterDetail = document.getElementById('toaster-detail');
|
||||
this.clearAllButton = document.getElementById('notification-clear');
|
||||
|
||||
['tap', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'wheel'].
|
||||
forEach(function(evt) {
|
||||
this.container.addEventListener(evt, this);
|
||||
this.toaster.addEventListener(evt, this);
|
||||
}, this);
|
||||
|
||||
this.clearAllButton.addEventListener('click', this.clearAll.bind(this));
|
||||
|
||||
// will hold the count of external contributors to the notification
|
||||
// screen
|
||||
this.externalNotificationsCount = 0;
|
||||
this.unreadNotifications = [];
|
||||
|
||||
window.addEventListener('utilitytrayshow', this);
|
||||
// Since UI expect there is a slight delay for the opened notification.
|
||||
window.addEventListener('lockscreen-appclosed', this);
|
||||
window.addEventListener('visibilitychange', this);
|
||||
window.addEventListener('ftuopen', this);
|
||||
window.addEventListener('ftudone', this);
|
||||
window.addEventListener('desktop-notification-resend', this);
|
||||
|
||||
this._sound = 'style/notifications/ringtones/notifier_firefox.opus';
|
||||
|
||||
// set up the media playback widget, but only if |MediaPlaybackWidget| is
|
||||
// defined (we don't define it in tests)
|
||||
LazyLoader.load(['js/media_playback.js']).then(function() {
|
||||
this.mediaPlaybackWidget = new MediaPlaybackWidget(
|
||||
document.getElementById('media-playback-container'),
|
||||
{nowPlayingAction: 'openapp'});
|
||||
}.bind(this))['catch'](function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
var self = this;
|
||||
SettingsListener.observe('notification.ringtone', '', function(value) {
|
||||
LazyLoader.load(['shared/js/settings_url.js']).then(function() {
|
||||
if (!self.ringtoneURL) {
|
||||
self.ringtoneURL = new SettingsURL();
|
||||
}
|
||||
self._sound = self.ringtoneURL.set(value);
|
||||
})['catch'](function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
|
||||
// We have new default ringtones in 2.0, so check if the version is upgraded
|
||||
// then execute the necessary migration.
|
||||
if (Service.query('justUpgraded')) {
|
||||
LazyLoader.load('js/tone_upgrader.js').then(function() {
|
||||
toneUpgrader.perform('alerttone');
|
||||
})['catch'](function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
Service.register('clearAll', this);
|
||||
Service.register('addUnreadNotification', this);
|
||||
Service.register('removeUnreadNotification', this);
|
||||
|
||||
this.resendStoredNotifications();
|
||||
},
|
||||
|
||||
handleEvent: function ns_handleEvent(evt) {
|
||||
switch (evt.type) {
|
||||
case 'mozChromeNotificationEvent':
|
||||
var detail = evt.detail;
|
||||
switch (detail.type) {
|
||||
case 'desktop-notification':
|
||||
this.addNotification(detail);
|
||||
if (this.isResending) {
|
||||
this.resendReceived++;
|
||||
this.isResending = (this.resendReceived < this.resendExpecting);
|
||||
}
|
||||
break;
|
||||
case 'desktop-notification-close':
|
||||
this.removeNotification(detail.id);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'tap':
|
||||
var target = evt.target;
|
||||
this.tap(target);
|
||||
break;
|
||||
case 'touchstart':
|
||||
this.touchstart(evt);
|
||||
break;
|
||||
case 'touchmove':
|
||||
this.touchmove(evt);
|
||||
break;
|
||||
case 'touchend':
|
||||
this.touchend(evt);
|
||||
break;
|
||||
case 'touchcancel':
|
||||
this.touchcancel(evt);
|
||||
break;
|
||||
case 'wheel':
|
||||
this.wheel(evt);
|
||||
break;
|
||||
case 'utilitytrayshow':
|
||||
this.updateTimestamps();
|
||||
this.hideNotificationIndicator();
|
||||
break;
|
||||
case 'visibilitychange':
|
||||
//update timestamps in lockscreen notifications
|
||||
if (!document.hidden) {
|
||||
this.updateTimestamps();
|
||||
}
|
||||
break;
|
||||
case 'ftuopen':
|
||||
this.toaster.removeEventListener('tap', this);
|
||||
break;
|
||||
case 'ftudone':
|
||||
this.toaster.addEventListener('tap', this);
|
||||
this.updateNotificationIndicator();
|
||||
break;
|
||||
case 'desktop-notification-resend':
|
||||
this.resendExpecting = evt.detail.number;
|
||||
if (this.resendExpecting) {
|
||||
this.isResending = true;
|
||||
}
|
||||
break;
|
||||
case 'lockscreen-appclosed':
|
||||
// UX require to delay to clear notifications from
|
||||
// LockScreen for the actionable LockScreen notifications.
|
||||
setTimeout((function() {
|
||||
this.clearLockScreen();
|
||||
}).bind(this), 400);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
cancelSwipe: function ns_cancelSwipe() {
|
||||
var notification = this._notification;
|
||||
this._notification = null;
|
||||
|
||||
// If the notification has been moved, animate it back to its original
|
||||
// position.
|
||||
if (this._touchPosX) {
|
||||
notification.addEventListener('transitionend',
|
||||
function trListener() {
|
||||
notification.removeEventListener('transitionend', trListener);
|
||||
notification.classList.remove('snapback');
|
||||
});
|
||||
notification.classList.add('snapback');
|
||||
}
|
||||
|
||||
notification.style.transform = '';
|
||||
},
|
||||
|
||||
// Swipe handling
|
||||
touchstart: function ns_touchstart(evt) {
|
||||
if (evt.touches.length !== 1) {
|
||||
if (this._touching) {
|
||||
this._touching = false;
|
||||
this.cancelSwipe();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var target = evt.touches[0].target;
|
||||
if (!target.dataset.notificationId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._notification = target;
|
||||
this._containerWidth = this.container.clientWidth;
|
||||
this._touchStartX = evt.touches[0].pageX;
|
||||
this._touchStartY = evt.touches[0].pageY;
|
||||
this._touchPosX = 0;
|
||||
this._touchStartTime = evt.timeStamp;
|
||||
this._touching = true;
|
||||
this._isTap = true;
|
||||
},
|
||||
|
||||
touchmove: function ns_touchmove(evt) {
|
||||
if (!this._touching) {
|
||||
return;
|
||||
}
|
||||
|
||||
var touchDiffY = evt.touches[0].pageY - this._touchStartY;
|
||||
|
||||
// The notification being touched is the toast
|
||||
if (this._notification.classList.contains('displayed')) {
|
||||
if (touchDiffY < 0) {
|
||||
this.closeToast();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we're swiping on a notification, which should only be allowed
|
||||
// when the utility tray is fully open.
|
||||
if (evt.touches.length !== 1 ||
|
||||
!Service.query('UtilityTray.shown') ||
|
||||
(this._isTap && Math.abs(touchDiffY) >= this.SCROLL_THRESHOLD)) {
|
||||
this._touching = false;
|
||||
this.cancelSwipe();
|
||||
return;
|
||||
}
|
||||
|
||||
this._touchPosX = evt.touches[0].pageX - this._touchStartX;
|
||||
if (Math.abs(this._touchPosX) >= this.TAP_THRESHOLD) {
|
||||
this._isTap = false;
|
||||
this.notificationsContainer.style.overflow = 'hidden';
|
||||
}
|
||||
if (!this._isTap) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation(); // Prevent this event from bubbling up to the tray.
|
||||
this._notification.style.transform =
|
||||
'translateX(' + this._touchPosX + 'px)';
|
||||
}
|
||||
},
|
||||
|
||||
touchend: function ns_touchend(evt) {
|
||||
if (!this._touching) {
|
||||
return;
|
||||
}
|
||||
|
||||
evt.preventDefault();
|
||||
this._touching = false;
|
||||
|
||||
this.notificationsContainer.style.overflow = '';
|
||||
|
||||
if (this._isTap) {
|
||||
var event = new CustomEvent('tap', {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
this._notification.dispatchEvent(event);
|
||||
this._notification = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Taking speed into account to detect swipes
|
||||
var deltaT = evt.timeStamp - this._touchStartTime;
|
||||
var speed = this._touchPosX / deltaT;
|
||||
var inertia = speed * this.SWIPE_INERTIA;
|
||||
var finalDelta = Math.abs(this._touchPosX + inertia);
|
||||
|
||||
if (finalDelta >
|
||||
this._containerWidth * this.TRANSITION_FRACTION) {
|
||||
if (this._touchPosX < 0) {
|
||||
this._notification.classList.add('left');
|
||||
}
|
||||
|
||||
var durationLeft = (1 - (finalDelta / this._containerWidth)) *
|
||||
this.TRANSITION_DURATION;
|
||||
this.swipeCloseNotification(durationLeft);
|
||||
} else {
|
||||
this.cancelSwipe();
|
||||
}
|
||||
},
|
||||
|
||||
touchcancel: function ns_touchcancel(evt) {
|
||||
if (this._touching) {
|
||||
evt.preventDefault();
|
||||
this._touching = false;
|
||||
this.cancelSwipe();
|
||||
}
|
||||
},
|
||||
|
||||
wheel: function ns_wheel(evt) {
|
||||
if (evt.deltaMode === evt.DOM_DELTA_PAGE && evt.deltaX) {
|
||||
this._notification = evt.target;
|
||||
this.swipeCloseNotification();
|
||||
}
|
||||
},
|
||||
|
||||
tap: function ns_tap(node) {
|
||||
var notificationId = node.dataset.notificationId;
|
||||
var notificationNode = this.container.querySelector(
|
||||
'[data-notification-id="' + notificationId + '"]');
|
||||
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('mozContentNotificationEvent', true, true, {
|
||||
type: 'desktop-notification-click',
|
||||
id: notificationId
|
||||
});
|
||||
window.dispatchEvent(event);
|
||||
|
||||
window.dispatchEvent(new CustomEvent('notification-clicked', {
|
||||
detail: {
|
||||
id: notificationId
|
||||
}
|
||||
}));
|
||||
|
||||
// Desktop notifications are removed when they are clicked (see bug 890440)
|
||||
if (notificationNode &&
|
||||
notificationNode.dataset.type === 'desktop-notification' &&
|
||||
notificationNode.dataset.obsoleteAPI === 'true') {
|
||||
this.closeNotification(notificationNode);
|
||||
}
|
||||
|
||||
if (node == this.toaster) {
|
||||
this.closeToast();
|
||||
} else {
|
||||
Service.request('UtilityTray:hide');
|
||||
}
|
||||
},
|
||||
|
||||
updateTimestamps: function ns_updateTimestamps() {
|
||||
var timestamps = [...document.querySelectorAll('.timestamp')];
|
||||
var formatter = mozIntl._gaia.RelativeDate(navigator.languages, {
|
||||
style: 'short'
|
||||
});
|
||||
|
||||
timestamps.forEach(timestamp => {
|
||||
formatter.formatElement(
|
||||
timestamp, new Date(timestamp.dataset.timestamp));
|
||||
});
|
||||
},
|
||||
|
||||
updateToaster: function ns_updateToaster(detail, type, dir) {
|
||||
if (detail.icon) {
|
||||
this.toasterIcon.src = detail.icon;
|
||||
this.toasterIcon.hidden = false;
|
||||
} else {
|
||||
this.toasterIcon.hidden = true;
|
||||
}
|
||||
|
||||
this.toaster.dataset.notificationId = detail.id;
|
||||
this.toaster.dataset.type = type;
|
||||
this.toaster.lang = detail.lang;
|
||||
|
||||
this.toasterTitle.textContent = detail.title;
|
||||
this.toasterTitle.dir = dir;
|
||||
this.toasterDetail.textContent = detail.text;
|
||||
this.toasterDetail.dir = dir;
|
||||
},
|
||||
|
||||
addNotification: function ns_addNotification(detail) {
|
||||
// LockScreen window may not opened while this singleton got initialized.
|
||||
this.lockScreenContainer = this.getLockScreenContainer();
|
||||
|
||||
var manifestURL = detail.manifestURL || '';
|
||||
var behavior = detail.mozbehavior || {};
|
||||
var isPriorityNotification =
|
||||
this.PRIORITY_APPLICATIONS.indexOf(manifestURL) !== -1;
|
||||
var dir = detail.dir === 'ltr' || detail.dir === 'rtl' ?
|
||||
detail.dir : 'auto';
|
||||
|
||||
var notificationContainer =
|
||||
(isPriorityNotification) ?
|
||||
this.container.querySelector('.priority-notifications') :
|
||||
this.container.querySelector('.other-notifications');
|
||||
|
||||
// We need to animate the ambient indicator when the toast
|
||||
// timesout, so we skip updating it here, by passing a skip bool
|
||||
this.addUnreadNotification(detail.id, true);
|
||||
|
||||
var notificationNode = document.createElement('div');
|
||||
notificationNode.classList.add('notification');
|
||||
notificationNode.setAttribute('role', 'link');
|
||||
notificationNode.setAttribute('tabindex', 0);
|
||||
|
||||
notificationNode.dataset.notificationId = detail.id;
|
||||
notificationNode.dataset.noClear = behavior.noclear ? 'true' : 'false';
|
||||
notificationNode.lang = detail.lang;
|
||||
|
||||
notificationNode.dataset.obsoleteAPI = 'false';
|
||||
if (typeof detail.id === 'string' &&
|
||||
detail.id.indexOf('app-notif-') === 0) {
|
||||
notificationNode.dataset.obsoleteAPI = 'true';
|
||||
}
|
||||
var type = detail.type || 'desktop-notification';
|
||||
notificationNode.dataset.type = type;
|
||||
notificationNode.dataset.manifestURL = manifestURL;
|
||||
var icon;
|
||||
if (detail.icon) {
|
||||
icon = document.createElement('img');
|
||||
icon.src = detail.icon;
|
||||
icon.setAttribute('role', 'presentation');
|
||||
notificationNode.appendChild(icon);
|
||||
}
|
||||
|
||||
var titleContainer = document.createElement('div');
|
||||
titleContainer.classList.add('title-container');
|
||||
|
||||
var title = document.createElement('div');
|
||||
title.classList.add('title');
|
||||
title.textContent = detail.title;
|
||||
title.dir = dir;
|
||||
|
||||
titleContainer.appendChild(title);
|
||||
|
||||
var time = document.createElement('span');
|
||||
var timestamp = detail.timestamp ? new Date(detail.timestamp) : new Date();
|
||||
time.classList.add('timestamp');
|
||||
time.dataset.timestamp = timestamp;
|
||||
var formatter = mozIntl._gaia.RelativeDate(navigator.languages, {
|
||||
style: 'short'
|
||||
});
|
||||
formatter.formatElement(time, timestamp);
|
||||
titleContainer.appendChild(time);
|
||||
|
||||
notificationNode.appendChild(titleContainer);
|
||||
|
||||
var message = document.createElement('div');
|
||||
message.classList.add('detail');
|
||||
var messageContent = document.createElement('div');
|
||||
messageContent.classList.add('detail-content');
|
||||
messageContent.textContent = detail.text;
|
||||
messageContent.dir = dir;
|
||||
message.appendChild(messageContent);
|
||||
notificationNode.appendChild(message);
|
||||
|
||||
var notifSelector = '[data-notification-id="' + detail.id + '"]';
|
||||
var oldNotif = notificationContainer.querySelector(notifSelector);
|
||||
if (oldNotif) {
|
||||
// The whole node cannot be replaced because CSS animations are re-started
|
||||
oldNotif.replaceChild(titleContainer,
|
||||
oldNotif.querySelector('.title-container'));
|
||||
oldNotif.replaceChild(message, oldNotif.querySelector('.detail'));
|
||||
var oldIcon = oldNotif.querySelector('img');
|
||||
if (icon) {
|
||||
oldIcon ? oldIcon.src = icon.src : oldNotif.insertBefore(icon,
|
||||
oldNotif.firstChild);
|
||||
} else if (oldIcon) {
|
||||
oldNotif.removeChild(oldIcon);
|
||||
}
|
||||
// but we still need to update type and lang.
|
||||
oldNotif.dataset.type = type;
|
||||
oldNotif.lang = detail.lang;
|
||||
|
||||
notificationNode = oldNotif;
|
||||
} else {
|
||||
notificationContainer.insertBefore(notificationNode,
|
||||
notificationContainer.firstElementChild);
|
||||
}
|
||||
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('mozContentNotificationEvent', true, true, {
|
||||
type: 'desktop-notification-show',
|
||||
id: detail.id
|
||||
});
|
||||
window.dispatchEvent(event);
|
||||
|
||||
// We turn the screen on if needed in order to let
|
||||
// the user see the notification toaster unless we're on a call
|
||||
if (!Service.query('screenEnabled') &&
|
||||
!behavior.noscreen &&
|
||||
!Service.query('onCall') &&
|
||||
(!Service.query('locked') || this.lockscreenPreview)) {
|
||||
Service.request('turnScreenOn');
|
||||
}
|
||||
|
||||
var notify = !('noNotify' in detail) &&
|
||||
// don't notify for network-alerts notifications
|
||||
(this.SILENT_APPLICATIONS.indexOf(manifestURL) === -1);
|
||||
|
||||
// Notification toaster
|
||||
if (notify) {
|
||||
this.updateToaster(detail, type, dir);
|
||||
if (this.lockscreenPreview || !window.Service.query('locked')) {
|
||||
this.toaster.classList.add('displayed');
|
||||
|
||||
if (this._toasterTimeout) {
|
||||
clearTimeout(this._toasterTimeout);
|
||||
}
|
||||
|
||||
this._toasterTimeout = setTimeout((function() {
|
||||
this.closeToast();
|
||||
this._toasterTimeout = null;
|
||||
}).bind(this), this.TOASTER_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
// Adding it to the lockscreen if locked and the privacy setting
|
||||
// does not prevent it.
|
||||
if (Service.query('locked') && this.lockscreenPreview) {
|
||||
this.addLockScreenNotification(detail.id,
|
||||
notificationNode.cloneNode(true));
|
||||
}
|
||||
|
||||
if (notify && !this.isResending &&
|
||||
(!Service.query('locked') || this.lockscreenPreview)) {
|
||||
if (!this.silent && !behavior.nosound) {
|
||||
var ringtonePlayer = new Audio();
|
||||
var telephony = window.navigator.mozTelephony;
|
||||
|
||||
ringtonePlayer.src = behavior.soundFile || this._sound;
|
||||
|
||||
if (telephony && telephony.active) {
|
||||
ringtonePlayer.mozAudioChannelType = 'telephony';
|
||||
ringtonePlayer.volume = 0.3;
|
||||
} else {
|
||||
ringtonePlayer.mozAudioChannelType = 'notification';
|
||||
}
|
||||
ringtonePlayer.play();
|
||||
window.setTimeout(function smsRingtoneEnder() {
|
||||
ringtonePlayer.pause();
|
||||
ringtonePlayer.removeAttribute('src');
|
||||
ringtonePlayer.load();
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
if (this.vibrates && !behavior.novibrate) {
|
||||
var pattern = [200, 200, 200];
|
||||
if (behavior.vibrationPattern && behavior.vibrationPattern.length &&
|
||||
behavior.vibrationPattern[0] > 0) {
|
||||
pattern = behavior.vibrationPattern;
|
||||
}
|
||||
|
||||
// bug 1030310: disable vibration for the email app when asleep
|
||||
// bug 1050023: disable vibration for downloads when asleep
|
||||
var vibrateWhenAsleep =
|
||||
type.indexOf('download-notification-downloading') === -1 &&
|
||||
manifestURL.indexOf('email.gaiamobile.org') === -1;
|
||||
|
||||
if (vibrateWhenAsleep || !document.hidden) {
|
||||
navigator.vibrate(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// must be at least one notification now
|
||||
this.clearAllButton.disabled = false;
|
||||
|
||||
return notificationNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Give a notification node and add it to LockScreen via event.
|
||||
*/
|
||||
addLockScreenNotification: function ns_addLockScreenNotification(id, node) {
|
||||
window.dispatchEvent(
|
||||
new window.CustomEvent('lockscreen-notification-request-append', { detail:
|
||||
{
|
||||
id: id,
|
||||
node: node
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
swipeCloseNotification: function ns_swipeCloseNotification(duration) {
|
||||
var notification = this._notification;
|
||||
this._notification = null;
|
||||
|
||||
var toaster = this.toaster;
|
||||
var self = this;
|
||||
notification.addEventListener('transitionend', function trListener() {
|
||||
notification.removeEventListener('transitionend', trListener);
|
||||
|
||||
self.closeNotification(notification);
|
||||
|
||||
if (notification != toaster) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Putting back the toaster in a clean state for the next notification
|
||||
toaster.style.display = 'none';
|
||||
setTimeout(function nextLoop() {
|
||||
toaster.style.MozTransition = '';
|
||||
toaster.style.MozTransform = '';
|
||||
toaster.classList.remove('displayed');
|
||||
toaster.classList.remove('disappearing');
|
||||
|
||||
setTimeout(function nextLoop() {
|
||||
toaster.style.display = 'block';
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
notification.classList.add('disappearing');
|
||||
duration = duration || this.TRANSITION_DURATION;
|
||||
notification.style.transitionDuration = duration + 'ms';
|
||||
notification.style.transform = '';
|
||||
},
|
||||
|
||||
addUnreadNotification: function ns_addUnreadNotification(id, skipUpdate) {
|
||||
if (Service.query('UtilityTray.shown')) {
|
||||
return;
|
||||
}
|
||||
this.unreadNotifications.push(id);
|
||||
if (!skipUpdate) {
|
||||
this.updateNotificationIndicator();
|
||||
}
|
||||
},
|
||||
|
||||
removeUnreadNotification: function ns_removeUnreadNotification(id) {
|
||||
var notifIndex = this.unreadNotifications.indexOf(id);
|
||||
if (notifIndex > -1) {
|
||||
this.unreadNotifications.splice(notifIndex, 1);
|
||||
}
|
||||
this.updateNotificationIndicator();
|
||||
},
|
||||
|
||||
hideNotificationIndicator: function ns_hideNotificationIndicator() {
|
||||
if (this.unreadNotifications.length > 0) {
|
||||
this.unreadNotifications = [];
|
||||
}
|
||||
this.updateNotificationIndicator();
|
||||
},
|
||||
|
||||
updateNotificationIndicator: function ns_updateNotificationIndicator() {
|
||||
if (this.unreadNotifications.length) {
|
||||
// If the ftu is running we should not show the ambient indicator
|
||||
// because the statusbar is not accessible
|
||||
if (Service.query('isFtuRunning')) {
|
||||
return;
|
||||
}
|
||||
this.ambientIndicator.classList.add('unread');
|
||||
navigator.mozL10n.setAttributes(
|
||||
this.ambientIndicator,
|
||||
'statusbarNotifications-unread',
|
||||
{n: this.unreadNotifications.length}
|
||||
);
|
||||
} else {
|
||||
this.ambientIndicator.classList.remove('unread');
|
||||
this.ambientIndicator.removeAttribute('aria-label');
|
||||
}
|
||||
|
||||
Service.request('UtilityTray:updateNotificationCount');
|
||||
},
|
||||
|
||||
closeToast: function ns_closeToast() {
|
||||
this.toaster.classList.remove('displayed');
|
||||
this.updateNotificationIndicator();
|
||||
},
|
||||
|
||||
closeNotification: function ns_closeNotification(notificationNode) {
|
||||
var notificationId = notificationNode.dataset.notificationId;
|
||||
this.removeNotification(notificationId);
|
||||
},
|
||||
|
||||
removeLockScreenNotification:
|
||||
function ns_removeLockScreenNotification(notificationId) {
|
||||
var lockScreenNotificationNode;
|
||||
var notifSelector = '[data-notification-id="' + notificationId + '"]';
|
||||
this.lockScreenContainer = this.getLockScreenContainer();
|
||||
if (this.lockScreenContainer) {
|
||||
lockScreenNotificationNode =
|
||||
this.lockScreenContainer.querySelector(notifSelector);
|
||||
}
|
||||
|
||||
if (lockScreenNotificationNode) {
|
||||
var lockScreenNotificationParentNode =
|
||||
lockScreenNotificationNode.parentNode;
|
||||
lockScreenNotificationParentNode.removeChild(lockScreenNotificationNode);
|
||||
window.dispatchEvent(
|
||||
new window.CustomEvent('lockscreen-notification-request-remove', {
|
||||
containerEmpty: !lockScreenNotificationParentNode.firstElementChild
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
removeNotification: function ns_removeNotification(notificationId) {
|
||||
var notifSelector = '[data-notification-id="' + notificationId + '"]';
|
||||
var notificationNode = this.container.querySelector(notifSelector);
|
||||
if (notificationNode) {
|
||||
notificationNode.remove();
|
||||
}
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('mozContentNotificationEvent', true, true, {
|
||||
type: 'desktop-notification-close',
|
||||
id: notificationId
|
||||
});
|
||||
window.dispatchEvent(event);
|
||||
// UX require to give a tiny delay for actionable notification on
|
||||
// LockScreen.
|
||||
setTimeout((function() {
|
||||
this.removeLockScreenNotification(notificationId);
|
||||
}).bind(this), 400);
|
||||
|
||||
this.removeUnreadNotification(notificationId);
|
||||
if (!this.container.querySelector('.notification')) {
|
||||
// no notifications left
|
||||
this.clearAllButton.disabled = true;
|
||||
}
|
||||
},
|
||||
|
||||
clearAll: function ns_clearAll() {
|
||||
var notifications = this.container.querySelectorAll('.notification');
|
||||
var clearable = [].slice.apply(notifications)
|
||||
.filter(function isClearable(notification) {
|
||||
return notification.dataset.noClear !== 'true';
|
||||
});
|
||||
var notification;
|
||||
this.clearAllButton.disabled = true;
|
||||
// When focus is on a disabled element, Gecko will not dispatch any keyboard
|
||||
// events to it (the disabled element) and its parent.
|
||||
// The clearAll Button is focused but disabled right away after
|
||||
// user click it. We need to blur the focus immediately, otherwise System
|
||||
// app could not receive any keyboard events. See more detail on
|
||||
// http://bugzil.la/1106844
|
||||
this.clearAllButton.blur();
|
||||
if (!clearable.length) {
|
||||
return;
|
||||
}
|
||||
// Adding a callback to the last cleared notification to defer
|
||||
// the destroying of the notifications after the last disappear
|
||||
var lastClearable = clearable[clearable.length - 1];
|
||||
var removeAll = (function removeAll() {
|
||||
lastClearable.removeEventListener('transitionend', removeAll);
|
||||
for (var notification of clearable) {
|
||||
this.closeNotification(notification);
|
||||
}
|
||||
}).bind(this);
|
||||
lastClearable.addEventListener('transitionend', removeAll);
|
||||
|
||||
var disappearingClass = document.dir === 'ltr' ?
|
||||
'disappearing-via-clear-all' : 'disappearing-via-clear-all-left';
|
||||
for (var index = 0, max = clearable.length; index < max; index++) {
|
||||
notification = clearable[index];
|
||||
notification.style.transitionDelay = (this.CLEAR_DELAY * index) + 'ms';
|
||||
notification.classList.add(disappearingClass);
|
||||
notification.style.transform = '';
|
||||
}
|
||||
},
|
||||
|
||||
clearLockScreen: function ns_clearLockScreen() {
|
||||
// The LockScreenWindow may not be instantiated yet.
|
||||
if (!this.lockScreenContainer) {
|
||||
return;
|
||||
}
|
||||
while (this.lockScreenContainer.firstElementChild) {
|
||||
var element = this.lockScreenContainer.firstElementChild;
|
||||
this.lockScreenContainer.removeChild(element);
|
||||
}
|
||||
window.dispatchEvent(
|
||||
new window.CustomEvent('lockscreen-notification-request-clear'));
|
||||
},
|
||||
|
||||
resendStoredNotifications: function() {
|
||||
if ('mozSettings' in navigator && navigator.mozSettings) {
|
||||
var key = 'notifications.resend';
|
||||
var req = navigator.mozSettings.createLock().get(key);
|
||||
req.onsuccess = req.onerror = function onsuccess() {
|
||||
var resendEnabled = req.result[key] || false;
|
||||
if (!resendEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var resendCallback = (function(number) {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('desktop-notification-resend',
|
||||
{ detail: { number: number } }));
|
||||
}).bind(this);
|
||||
|
||||
if ('mozChromeNotifications' in navigator) {
|
||||
navigator.mozChromeNotifications.
|
||||
mozResendAllNotifications(resendCallback);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SettingsListener.observe(
|
||||
'lockscreen.notifications-preview.enabled', true, function(value) {
|
||||
|
||||
NotificationScreen.lockscreenPreview = value;
|
||||
});
|
||||
|
||||
SettingsListener.observe('audio.volume.notification', 7, function(value) {
|
||||
NotificationScreen.silent = (value === 0);
|
||||
});
|
||||
|
||||
SettingsListener.observe('vibration.enabled', true, function(value) {
|
||||
NotificationScreen.vibrates = value;
|
||||
});
|
||||
690
overrides/system.gaiamobile.org/js/screen_manager.js
Normal file
|
|
@ -0,0 +1,690 @@
|
|||
'use strict';
|
||||
|
||||
/* globals SettingsListener, Service,
|
||||
ScreenBrightnessTransition, ScreenWakeLockManager,
|
||||
ScreenAutoBrightness, LazyLoader */
|
||||
|
||||
(function(exports) {
|
||||
var ScreenManager = {
|
||||
name: 'ScreenManager',
|
||||
|
||||
/*
|
||||
* return the current screen status
|
||||
* Must not mutate directly - use toggleScreen/turnScreenOff/turnScreenOn.
|
||||
* Listen to 'screenchange' event to properly handle status changes
|
||||
* This value can be "out of sync" with real mozPower value,
|
||||
* we do this to give screen some time to flash before actual turn off.
|
||||
*/
|
||||
screenEnabled: false,
|
||||
|
||||
/**
|
||||
* If user is unlocking, postpone the timeout counter.
|
||||
*/
|
||||
_unlocking: false,
|
||||
|
||||
/*
|
||||
* before idle-screen-off, invoke a nice dimming to the brightness
|
||||
* to notify the user that the screen is about to be turn off.
|
||||
* The user can cancel the idle-screen-off by touching the screen
|
||||
* and by pressing a button (trigger onactive callback on Idle API)
|
||||
*
|
||||
*/
|
||||
_inTransition: false,
|
||||
|
||||
/*
|
||||
* Whether the device light is enabled or not
|
||||
* sync with setting 'screen.automatic-brightness'
|
||||
*/
|
||||
_deviceLightEnabled: true,
|
||||
|
||||
/*
|
||||
* Preferred brightness without considering device light nor dimming
|
||||
* sync with setting 'screen.brightness'
|
||||
*/
|
||||
_userBrightness: 1,
|
||||
_savedBrightness: 1,
|
||||
|
||||
/*
|
||||
* This property will host a ScreenBrightnessTransition instance
|
||||
* and control the brightness transition for us.
|
||||
* Eventually we want to move all brightness controls
|
||||
* (including auto-brightness toggle and calculation) out of this module.
|
||||
*/
|
||||
_screenBrightnessTransition: null,
|
||||
|
||||
/*
|
||||
* ScreenAutoBrightness instance
|
||||
* manages the devicelight events and adjusts the screen brightness
|
||||
* automatically
|
||||
*/
|
||||
_screenAutoBrightness: null,
|
||||
|
||||
/**
|
||||
* Timeout to black the screen when locking.
|
||||
*/
|
||||
LOCKING_TIMEOUT: 10,
|
||||
|
||||
/*
|
||||
* Wait for _dimNotice milliseconds during idle-screen-off
|
||||
*/
|
||||
_dimNotice: 10 * 1000,
|
||||
|
||||
/*
|
||||
* We track the value of the idle timeout pref in this variable.
|
||||
*/
|
||||
_idleTimeout: 0,
|
||||
_idleTimerId: 0,
|
||||
|
||||
/*
|
||||
* To track the reason caused screen off?
|
||||
*/
|
||||
_screenOffBy: null,
|
||||
_screenOffTimeout: 0,
|
||||
|
||||
/*
|
||||
* Request wakelock during in_call state.
|
||||
* To ensure turnScreenOff by proximity event is protected by wakelock for
|
||||
* early suspend only.
|
||||
*/
|
||||
_cpuWakeLock: null,
|
||||
|
||||
/*
|
||||
* A screen reader feature to allow screen brightness to remain 0
|
||||
* regardless of the enabled state of the screen. This allows the user to
|
||||
* conserve battery and have more privacy while still using the touchscreen.
|
||||
*/
|
||||
_screenShade: false,
|
||||
|
||||
start: function() {
|
||||
window.addEventListener('attentionopening', this);
|
||||
window.addEventListener('attentionopened', this);
|
||||
window.addEventListener('sleep', this);
|
||||
window.addEventListener('wake', this);
|
||||
window.addEventListener('nfc-tech-discovered', this);
|
||||
window.addEventListener('nfc-tech-lost', this);
|
||||
window.addEventListener('requestshutdown', this);
|
||||
|
||||
// User is unlocking by sliding or other methods.
|
||||
window.addEventListener('unlocking-start', this);
|
||||
window.addEventListener('unlocking-stop', this);
|
||||
|
||||
// When secure app is on, do not turn the screen off.
|
||||
// And when it's down, reset the timeout.
|
||||
window.addEventListener('secure-appopened', this);
|
||||
window.addEventListener('secure-appterminated', this);
|
||||
|
||||
window.addEventListener('logohidden', this);
|
||||
|
||||
// User is actively using the screen reader.
|
||||
window.addEventListener('accessibility-action', this);
|
||||
|
||||
this.screen = document.getElementById('screen');
|
||||
|
||||
LazyLoader.load([
|
||||
'js/screen_auto_brightness.js',
|
||||
'js/screen_brightness_transition.js'
|
||||
]).then(function() {
|
||||
this._screenBrightnessTransition = new ScreenBrightnessTransition();
|
||||
|
||||
this._screenAutoBrightness = new ScreenAutoBrightness();
|
||||
this._screenAutoBrightness.onbrightnesschange = function(brightness) {
|
||||
this.setScreenBrightness(brightness, true);
|
||||
}.bind(this);
|
||||
|
||||
this._screenBrightnessTransition.ontransitionbegin =
|
||||
this._screenAutoBrightness.pause.bind(this._screenAutoBrightness);
|
||||
this._screenBrightnessTransition.ontransitionend =
|
||||
this._screenAutoBrightness.resume.bind(this._screenAutoBrightness);
|
||||
|
||||
}.bind(this))['catch'](function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
var self = this;
|
||||
var power = navigator.mozPower;
|
||||
|
||||
// Start the screen wake lock manager so it will monitor screen wake lock
|
||||
// for us. We will need to re-config the screen timeout
|
||||
// when the lock state is changed.
|
||||
//
|
||||
// Noted that getting a lock while the screen is off will not
|
||||
// turn on the screen, since no frame is considered visible by Gecko when
|
||||
// the screen is off. See discussion in bug 818840.
|
||||
this._wakeLockManager = new ScreenWakeLockManager();
|
||||
this._wakeLockManager.onwakelockchange =
|
||||
this._reconfigScreenTimeout.bind(this);
|
||||
this._wakeLockManager.start();
|
||||
|
||||
this._firstOn = false;
|
||||
SettingsListener.observe('screen.timeout', 60,
|
||||
function screenTimeoutChanged(value) {
|
||||
if (typeof value !== 'number') {
|
||||
value = parseInt(value);
|
||||
}
|
||||
self._idleTimeout = value;
|
||||
self._setIdleTimeout(self._idleTimeout);
|
||||
|
||||
if (!self._firstOn) {
|
||||
self._firstOn = true;
|
||||
|
||||
// During boot up, the brightness was set by bootloader as 0.5,
|
||||
// Let's set the API value to that so setScreenBrightness() can
|
||||
// dim nicely to value set by user.
|
||||
power.screenBrightness = 0.5;
|
||||
|
||||
// Turn screen on with dim.
|
||||
self.turnScreenOn(false);
|
||||
}
|
||||
});
|
||||
|
||||
SettingsListener.observe('screen.automatic-brightness', true,
|
||||
function deviceLightSettingChanged(value) {
|
||||
self.setDeviceLightEnabled(value);
|
||||
});
|
||||
|
||||
SettingsListener.observe('screen.brightness', 1,
|
||||
function brightnessSettingChanged(value) {
|
||||
// Profiles from the legacy range control may contain numeric strings.
|
||||
var brightness = Number(value);
|
||||
if (!Number.isFinite(brightness)) return;
|
||||
self._userBrightness = Math.max(0, Math.min(1, brightness));
|
||||
// Follow the slider immediately; lock/wake transitions keep their fades.
|
||||
self.setScreenBrightness(self._userBrightness, true);
|
||||
});
|
||||
|
||||
var telephony = window.navigator.mozTelephony;
|
||||
if (telephony) {
|
||||
telephony.addEventListener('callschanged', this);
|
||||
}
|
||||
Service.registerState('screenEnabled', this);
|
||||
Service.register('turnScreenOn', this);
|
||||
Service.register('turnScreenOff', this);
|
||||
Service.register('turnShadeOn', this);
|
||||
Service.register('turnShadeOff', this);
|
||||
},
|
||||
|
||||
_getNumOfCalls: function scm_getNumOfCalls() {
|
||||
if (navigator.mozTelephony) {
|
||||
return navigator.mozTelephony.calls.length +
|
||||
(navigator.mozTelephony.conferenceGroup.calls.length ? 1 : 0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent: function scm_handleEvent(evt) {
|
||||
var telephony = window.navigator.mozTelephony;
|
||||
var call;
|
||||
|
||||
switch (evt.type) {
|
||||
case 'attentionopening':
|
||||
case 'attentionopened':
|
||||
if (!this.enabled) {
|
||||
this.turnScreenOn();
|
||||
}
|
||||
break;
|
||||
case 'devicelight':
|
||||
if (!this._deviceLightEnabled || !this.screenEnabled ||
|
||||
this._inTransition) {
|
||||
return;
|
||||
}
|
||||
this._screenAutoBrightness &&
|
||||
this._screenAutoBrightness.autoAdjust(evt.value);
|
||||
break;
|
||||
|
||||
case 'sleep':
|
||||
// If calls are present then the power button will be handled by the
|
||||
// dialer agent.
|
||||
if (this._getNumOfCalls() === 0) {
|
||||
this.turnScreenOff(true, 'powerkey');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'wake':
|
||||
// If calls are present then the power button will be handled by the
|
||||
// dialer agent.
|
||||
if (this._getNumOfCalls() === 0) {
|
||||
this.turnScreenOn();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'accessibility-action':
|
||||
this._reconfigScreenTimeout();
|
||||
break;
|
||||
|
||||
case 'nfc-tech-discovered':
|
||||
case 'nfc-tech-lost':
|
||||
if (this._inTransition) {
|
||||
this.turnScreenOn();
|
||||
} else {
|
||||
this._reconfigScreenTimeout();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'unlocking-start':
|
||||
this._setUnlocking();
|
||||
break;
|
||||
|
||||
// When secure app is on, do not turn the screen off.
|
||||
// And when it's down, reset the timeout.
|
||||
case 'secure-appopened':
|
||||
case 'secure-appterminated':
|
||||
this._reconfigScreenTimeout();
|
||||
break;
|
||||
case 'unlocking-stop':
|
||||
this._resetUnlocking();
|
||||
break;
|
||||
|
||||
case 'userproximity':
|
||||
if (Service.query('Bluetooth.isSCOProfileConnected') ||
|
||||
telephony.speakerEnabled ||
|
||||
Service.query('isHeadsetConnected')) {
|
||||
// XXX: Remove this hack in Bug 868348
|
||||
// We shouldn't access headset status from statusbar.
|
||||
if (this._screenOffBy == 'proximity') {
|
||||
this.turnScreenOn();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (evt.near) {
|
||||
this.turnScreenOff(true, 'proximity');
|
||||
} else {
|
||||
this.turnScreenOn();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'callschanged':
|
||||
if (this._getNumOfCalls() === 0) {
|
||||
this._uninstallProximityListener();
|
||||
break;
|
||||
}
|
||||
|
||||
// If the _cpuWakeLock is already set we are in a multiple
|
||||
// call setup, the user will be notified by a tone.
|
||||
if (this._cpuWakeLock) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Enable the user proximity sensor once the call is connected.
|
||||
call = telephony.calls[0];
|
||||
if (call.state === 'dialing') {
|
||||
this._installProximityListener();
|
||||
} else {
|
||||
call.addEventListener('statechange', this);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'statechange':
|
||||
call = evt.target;
|
||||
if (['connected', 'alerting'].indexOf(call.state) === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// The call is connected (MT call) or alerting/dialing (MO call).
|
||||
// Remove the statechange listener and enable the user proximity
|
||||
// sensor.
|
||||
call.removeEventListener('statechange', this);
|
||||
|
||||
this._installProximityListener();
|
||||
break;
|
||||
|
||||
// Reconfig screen time out after booting.
|
||||
case 'logohidden':
|
||||
window.removeEventListener('logohidden', this);
|
||||
this._reconfigScreenTimeout();
|
||||
break;
|
||||
|
||||
case 'lockscreen-appclosing' :
|
||||
case 'lockpanelchange' :
|
||||
window.removeEventListener('lockscreen-appclosing', this);
|
||||
window.removeEventListener('lockpanelchange', this);
|
||||
// Prevent racing: wakeLockManager may broadcast the message
|
||||
// before this event, so one lockscreen event is actually representing
|
||||
// different meanings depends on that.
|
||||
//
|
||||
// This happens partly because this handler doesn't enter the
|
||||
// '_reconfigScreenTimeout' as other handlers may do, but in fact
|
||||
// the centralized design of putting all different timeouts in one
|
||||
// management function is not a good idea, because that fuzzes the
|
||||
// real intention of each branch. So maybe a more complete solution
|
||||
// is to decentralize that function, and make every small timeout
|
||||
// configuring functions more clear.
|
||||
//
|
||||
// Another reason why just to set the timeout is bad because it
|
||||
// depends on the event order heavily without checking any status
|
||||
// at the moment the event comes. To perform such check can prevent
|
||||
// that, too.
|
||||
if (!this._wakeLockManager.isHeld) {
|
||||
this._setIdleTimeout(this._idleTimeout, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'requestshutdown':
|
||||
this.turnScreenOn();
|
||||
if (evt.detail && evt.detail.startPowerOff) {
|
||||
evt.detail.startPowerOff(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
toggleScreen: function scm_toggleScreen() {
|
||||
if (this.screenEnabled) {
|
||||
// Currently there is no one used toggleScreen, so just set reason as
|
||||
// toggle. If it is used by someone in the future, we can rename it.
|
||||
this.turnScreenOff(true, 'toggle');
|
||||
} else {
|
||||
this.turnScreenOn();
|
||||
}
|
||||
},
|
||||
|
||||
turnShadeOn: function scm_turnShadeOn() {
|
||||
this._screenShade = true;
|
||||
// Remember the current screen brightness. We will restore it when
|
||||
// we turn the shade back on.
|
||||
this._savedBrightness = navigator.mozPower.screenBrightness;
|
||||
this.setScreenBrightness(0, true);
|
||||
},
|
||||
|
||||
turnShadeOff: function scm_turnShadeOff() {
|
||||
// Bug 1185036: If the screen was disable with the shade on, we won't
|
||||
// the screen won't turn on again until the user puts their finger on the
|
||||
// screen again.
|
||||
var brightness = this._savedBrightness || this._userBrightness || 1;
|
||||
this._screenShade = false;
|
||||
this.setScreenBrightness(brightness, true);
|
||||
},
|
||||
|
||||
turnScreenOff: function scm_turnScreenOff(instant, reason) {
|
||||
if (!this.screenEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
if (reason) {
|
||||
this._screenOffBy = reason;
|
||||
}
|
||||
|
||||
// Remember the current screen brightness. We will restore it when
|
||||
// we turn the screen back on.
|
||||
self._savedBrightness = navigator.mozPower.screenBrightness;
|
||||
|
||||
// Remove the cpuWakeLock and listening of proximity event, if screen is
|
||||
// turned off by power key.
|
||||
if (this._cpuWakeLock != null && this._screenOffBy == 'powerkey') {
|
||||
window.removeEventListener('userproximity', this);
|
||||
this._cpuWakeLock.unlock();
|
||||
this._cpuWakeLock = null;
|
||||
}
|
||||
|
||||
var screenOff = function scm_screenOff() {
|
||||
self._setIdleTimeout(0);
|
||||
|
||||
if (self._deviceLightEnabled) {
|
||||
window.removeEventListener('devicelight', self);
|
||||
}
|
||||
|
||||
window.removeEventListener('lockscreen-appclosing', self);
|
||||
window.removeEventListener('lockpanelchange', self);
|
||||
self.screenEnabled = false;
|
||||
self._inTransition = false;
|
||||
clearTimeout(self._screenOffTimeout);
|
||||
self._screenOffTimeout = setTimeout(function realScreenOff() {
|
||||
self.setScreenBrightness(0, true);
|
||||
// Sometimes the ScreenManager.screenEnabled and
|
||||
// mozPower.screenEnabled values are out of sync.
|
||||
// Since the rest of the world relies only on
|
||||
// the value of ScreenManager.screenEnabled it can be some situations
|
||||
// where the screen is off but ScreenManager think it is on... (see
|
||||
// bug 822463). Ideally a callback should have been used, like
|
||||
// ScreenManager.getScreenState(function(value) { ...} ); but there
|
||||
// are too many places to change that for now.
|
||||
self.screenEnabled = false;
|
||||
navigator.mozPower.screenEnabled = false;
|
||||
navigator.mozPower.keyLightEnabled = false;
|
||||
self._screenAutoBrightness && self._screenAutoBrightness.pause();
|
||||
}, 20);
|
||||
|
||||
self.fireScreenChangeEvent();
|
||||
};
|
||||
|
||||
if (instant) {
|
||||
screenOff();
|
||||
return true;
|
||||
}
|
||||
|
||||
this.setScreenBrightness(0.1, false);
|
||||
this._inTransition = true;
|
||||
setTimeout(function noticeTimeout() {
|
||||
if (!self._inTransition) {
|
||||
return;
|
||||
}
|
||||
|
||||
screenOff();
|
||||
}, self._dimNotice);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
turnScreenOn: function scm_turnScreenOn(instant) {
|
||||
clearTimeout(this._screenOffTimeout);
|
||||
if (this.screenEnabled) {
|
||||
if (this._inTransition) {
|
||||
// Cancel the dim out
|
||||
this._inTransition = false;
|
||||
this.setScreenBrightness(this._savedBrightness, true);
|
||||
this._reconfigScreenTimeout();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Actually turn the screen on.
|
||||
var power = navigator.mozPower;
|
||||
if (power) {
|
||||
power.screenEnabled = true;
|
||||
power.keyLightEnabled = true;
|
||||
}
|
||||
this.screenEnabled = true;
|
||||
|
||||
// Set the brightness before the screen is on.
|
||||
this.setScreenBrightness(this._savedBrightness, instant);
|
||||
|
||||
// Resume auto brightness, which is paused when the screen is turned off.
|
||||
this._screenAutoBrightness && this._screenAutoBrightness.resume();
|
||||
|
||||
// If we are in a call or a conference call and there
|
||||
// is no cpuWakeLock, we would get one here.
|
||||
var telephony = window.navigator.mozTelephony;
|
||||
var ongoingConference = telephony && telephony.conferenceGroup &&
|
||||
telephony.conferenceGroup.calls.length;
|
||||
if (!this._cpuWakeLock && telephony &&
|
||||
(telephony.calls.length || ongoingConference)) {
|
||||
|
||||
var connected = telephony.calls.some(function(call) {
|
||||
if (call.state == 'connected') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (connected || ongoingConference) {
|
||||
this._cpuWakeLock = navigator.requestWakeLock('cpu');
|
||||
window.addEventListener('userproximity', this);
|
||||
}
|
||||
}
|
||||
|
||||
// Attaching the event listener effectively turn on the hardware
|
||||
// device light sensor, which _must be_ done after power.screenEnabled.
|
||||
if (this._deviceLightEnabled) {
|
||||
window.addEventListener('devicelight', this);
|
||||
}
|
||||
|
||||
this._reconfigScreenTimeout();
|
||||
this.fireScreenChangeEvent();
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_reconfigScreenTimeout: function scm_reconfigScreenTimeout() {
|
||||
// Remove idle timer if screen wake lock is acquired or
|
||||
// if no app has been displayed yet.
|
||||
if (this._wakeLockManager.isHeld ||
|
||||
(!Service.query('AppWindowManager.getActiveWindow') &&
|
||||
!Service.query('locked'))) {
|
||||
this._setIdleTimeout(0);
|
||||
// The screen should be turn off with shorter timeout if
|
||||
// it was never unlocked.
|
||||
} else if (!this._unlocking) {
|
||||
if (Service.query('getTopMostWindow') &&
|
||||
Service.query('getTopMostWindow').CLASS_NAME ===
|
||||
'LockScreenWindow') {
|
||||
this._setIdleTimeout(this.LOCKING_TIMEOUT, true);
|
||||
window.addEventListener('lockscreen-appclosing', this);
|
||||
window.addEventListener('lockpanelchange', this);
|
||||
} else {
|
||||
this._setIdleTimeout(this._idleTimeout, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* If user is unlocking, postpone the timeout counter.
|
||||
*
|
||||
* @this {ScreenManager}
|
||||
*/
|
||||
_setUnlocking: function scm_setUnlocking() {
|
||||
this._unlocking = true;
|
||||
|
||||
// Need to cancel it: the last set timeout would still be triggered.
|
||||
window.clearIdleTimeout(this._idleTimerId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the state of user unlocking.
|
||||
*
|
||||
* @this {ScreenManager}
|
||||
*/
|
||||
_resetUnlocking: function scm_resetUnlocking() {
|
||||
this._unlocking = false;
|
||||
this._reconfigScreenTimeout();
|
||||
},
|
||||
|
||||
setScreenBrightness: function scm_setScreenBrightness(brightness, instant) {
|
||||
// Don't touch the brightness if the screen shade is on.
|
||||
if (this._screenShade && !!brightness) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._targetBrightness = brightness;
|
||||
var power = navigator.mozPower;
|
||||
if (!power) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop the current transition
|
||||
if (this._screenBrightnessTransition &&
|
||||
this._screenBrightnessTransition.isRunning) {
|
||||
this._screenBrightnessTransition.abort();
|
||||
}
|
||||
|
||||
if (typeof instant !== 'boolean') {
|
||||
instant = true;
|
||||
}
|
||||
|
||||
if (instant) {
|
||||
power.screenBrightness = brightness;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._screenBrightnessTransition) {
|
||||
this._screenBrightnessTransition.transitionTo(this._targetBrightness);
|
||||
} else {
|
||||
power.screenBrightness = this._targetBrightness;
|
||||
}
|
||||
},
|
||||
|
||||
setDeviceLightEnabled: function scm_setDeviceLightEnabled(enabled) {
|
||||
if (!enabled && this._deviceLightEnabled) {
|
||||
// Disabled -- set the brightness back to preferred brightness
|
||||
this.setScreenBrightness(this._userBrightness, false);
|
||||
}
|
||||
this._deviceLightEnabled = enabled;
|
||||
|
||||
this._screenAutoBrightness &&
|
||||
this._screenAutoBrightness.reset();
|
||||
|
||||
if (!this.screenEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable/enable device light sensor accordingly.
|
||||
// This will also toggle the actual hardware, which
|
||||
// must be done while the screen is on.
|
||||
if (enabled) {
|
||||
window.addEventListener('devicelight', this);
|
||||
} else {
|
||||
window.removeEventListener('devicelight', this);
|
||||
}
|
||||
},
|
||||
|
||||
_setIdleTimeout: function scm_setIdleTimeout(time, instant) {
|
||||
window.clearIdleTimeout(this._idleTimerId);
|
||||
|
||||
// Reset the idled state back to false.
|
||||
this._idled = false;
|
||||
|
||||
// 0 is the value used to disable idle timer by user and by us.
|
||||
if (time === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var idleCallback = function idle_proxy() {
|
||||
self.turnScreenOff(instant, 'idle_timeout');
|
||||
};
|
||||
var activeCallback = function active_proxy() {
|
||||
self.turnScreenOn(true);
|
||||
};
|
||||
|
||||
var finalTimeout =
|
||||
instant ? time * 1000 : (time * 1000) - this._dimNotice;
|
||||
this._idleTimerId = window.setIdleTimeout(idleCallback,
|
||||
activeCallback, finalTimeout);
|
||||
},
|
||||
|
||||
fireScreenChangeEvent: function scm_fireScreenChangeEvent() {
|
||||
var detail = { screenEnabled: this.screenEnabled };
|
||||
|
||||
// Tell others the cause of screen-off.
|
||||
detail.screenOffBy = this._screenOffBy;
|
||||
|
||||
var evt = new CustomEvent('screenchange',
|
||||
{ bubbles: true, cancelable: false,
|
||||
detail: detail });
|
||||
window.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
_installProximityListener: function() {
|
||||
if (this._cpuWakeLock) {
|
||||
return;
|
||||
}
|
||||
this._cpuWakeLock = navigator.requestWakeLock('cpu');
|
||||
window.addEventListener('userproximity', this);
|
||||
},
|
||||
|
||||
_uninstallProximityListener: function() {
|
||||
window.removeEventListener('userproximity', this);
|
||||
|
||||
if (this._cpuWakeLock) {
|
||||
this._cpuWakeLock.unlock();
|
||||
this._cpuWakeLock = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.ScreenManager = ScreenManager;
|
||||
}(window));
|
||||
|
||||
441
overrides/system.gaiamobile.org/js/wifi.js
Normal file
|
|
@ -0,0 +1,441 @@
|
|||
/* global LazyLoader, Service, SettingsListener,
|
||||
WifiIcon, WifiWakeLockManager */
|
||||
|
||||
'use strict';
|
||||
(function(exports) {
|
||||
var Wifi = {
|
||||
name: 'Wifi',
|
||||
|
||||
// Sync with mozSettings wifi.enabled key with an observer.
|
||||
// Note that there is a timing difference with _enabled and enabled.
|
||||
wifiEnabled: true,
|
||||
|
||||
// True if we have disabled the wifi so we would remember to quietly turn
|
||||
// it back on.
|
||||
// (TODO: this should be named wifiDisabledByTimeout)
|
||||
wifiDisabledByWakelock: false,
|
||||
|
||||
// Without an wifi wake lock, wait for screenOffTimeout milliseconds
|
||||
// to turn wifi off after the conditions are met.
|
||||
// If it's set to 0, wifi will never be turn off.
|
||||
// This is in sync with mozSettings wifi.screen_off_timeout.
|
||||
screenOffTimeout: 0,
|
||||
|
||||
// When wifiSleepMode is true and the screenOffTimeout is not zero,
|
||||
// Wi-Fi will be automatically turned off during sleep to save battery
|
||||
// power.
|
||||
// This is in sync with mozSettings wifi.sleepMode.
|
||||
wifiSleepMode: false,
|
||||
|
||||
// if Wifi is enabled but disconnected, try to scan for networks every
|
||||
// kScanInterval ms.
|
||||
kScanInterval: 20 * 1000,
|
||||
|
||||
_scanTimer: null,
|
||||
|
||||
// Sync with the hardware (mozWifiManager) state by listening to the
|
||||
// two events.
|
||||
_enabled: false,
|
||||
|
||||
get enabled() {
|
||||
return this._enabled;
|
||||
},
|
||||
|
||||
// true if there is an alarm or if there is an alarm being set.
|
||||
_hasAlarm: false,
|
||||
|
||||
// keep the id returned by mozAlarms API
|
||||
_alarmId: null,
|
||||
|
||||
start: function() {
|
||||
if (!window.navigator.mozSettings) {
|
||||
console.error('Wifi: No mozSettings!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.navigator.mozWifiManager) {
|
||||
console.error('Wifi: No mozWifiManager!');
|
||||
return;
|
||||
}
|
||||
|
||||
this.wifiManager = window.navigator.mozWifiManager;
|
||||
|
||||
LazyLoader.load(['js/captive_portal.js']);
|
||||
Service.request('stepReady', '#wifi').then(function() {
|
||||
return LazyLoader.load(['js/wifi_icon.js']);
|
||||
}.bind(this)).then(function() {
|
||||
this.icon = new WifiIcon(this);
|
||||
this.icon.start();
|
||||
}.bind(this))['catch'](function(err) { // XXX: workaround gjslint
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
window.addEventListener('screenchange', this);
|
||||
|
||||
var battery = window.navigator.battery;
|
||||
battery.addEventListener('chargingchange', this);
|
||||
|
||||
|
||||
// If wifi is turned off by us and phone got rebooted,
|
||||
// bring wifi back.
|
||||
var name = 'wifi.disabled_by_wakelock';
|
||||
var req = SettingsListener.getSettingsLock().get(name);
|
||||
req.onsuccess = function gotWifiDisabledByWakelock() {
|
||||
if (!req.result[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-enable wifi and reset wifi.disabled_by_wakelock
|
||||
// SettingsListener.getSettingsLock() always return invalid lock
|
||||
// in our usage here.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=793239
|
||||
var lock = navigator.mozSettings.createLock();
|
||||
lock.set({ 'wifi.enabled': true });
|
||||
lock.set({ 'wifi.disabled_by_wakelock': false });
|
||||
};
|
||||
|
||||
this._wakeLockManager = new WifiWakeLockManager();
|
||||
this._wakeLockManager.onwakelockchange = this.maybeToggleWifi.bind(this);
|
||||
this._wakeLockManager.start();
|
||||
|
||||
var self = this;
|
||||
var wifiManager = window.navigator.mozWifiManager;
|
||||
// when wifi is really enabled, emit event to notify QuickSettings
|
||||
wifiManager.onenabled = function onWifiEnabled() {
|
||||
self._enabled = true;
|
||||
var evt = document.createEvent('CustomEvent');
|
||||
evt.initCustomEvent('wifi-enabled',
|
||||
/* canBubble */ true, /* cancelable */ false, null);
|
||||
window.dispatchEvent(evt);
|
||||
self.icon && self.icon.update();
|
||||
};
|
||||
|
||||
// when wifi is really disabled, emit event to notify QuickSettings
|
||||
wifiManager.ondisabled = function onWifiDisabled() {
|
||||
this._enabled = false;
|
||||
var evt = document.createEvent('CustomEvent');
|
||||
evt.initCustomEvent('wifi-disabled',
|
||||
/* canBubble */ true, /* cancelable */ false, null);
|
||||
window.dispatchEvent(evt);
|
||||
if (self.icon) {
|
||||
self.icon.update();
|
||||
}
|
||||
};
|
||||
|
||||
// when wifi status change, emit event to notify Statusbar/UpdateManager
|
||||
wifiManager.onstatuschange = function onWifiDisabled() {
|
||||
var evt = document.createEvent('CustomEvent');
|
||||
evt.initCustomEvent('wifi-statuschange',
|
||||
/* canBubble */ true, /* cancelable */ false, null);
|
||||
window.dispatchEvent(evt);
|
||||
self.icon && self.icon.update();
|
||||
};
|
||||
|
||||
wifiManager.onconnectioninfoupdate = function() {
|
||||
self.icon && self.icon.update();
|
||||
};
|
||||
|
||||
SettingsListener.observe(
|
||||
'wifi.screen_off_timeout', 600000, function(value) {
|
||||
self.screenOffTimeout = value;
|
||||
});
|
||||
|
||||
SettingsListener.observe('wifi.sleepMode', true, function(value) {
|
||||
self.wifiSleepMode = value;
|
||||
});
|
||||
|
||||
Service.registerState('enabled', this);
|
||||
|
||||
// Track the wifi.enabled mozSettings value
|
||||
SettingsListener.observe('wifi.enabled', true, function(value) {
|
||||
if (!wifiManager && value) {
|
||||
self.wifiEnabled = false;
|
||||
|
||||
// roll back the setting value to notify the UIs
|
||||
// that wifi interface is not available
|
||||
if (value) {
|
||||
SettingsListener.getSettingsLock().set({
|
||||
'wifi.enabled': false
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
self.wifiEnabled = value;
|
||||
if (self.icon) {
|
||||
self.icon && self.icon.update();
|
||||
}
|
||||
|
||||
clearTimeout(self._scanTimer);
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If wifi is enabled but disconnected.
|
||||
// we would need to call getNetworks() continuously
|
||||
// so we could join known wifi network
|
||||
self._scanTimer = setInterval(function wifi_scan() {
|
||||
if (wifiManager.connection.status == 'disconnected') {
|
||||
wifiManager.getNetworks();
|
||||
}
|
||||
}, self.kScanInterval);
|
||||
});
|
||||
},
|
||||
|
||||
handleEvent: function wifi_handleEvent(evt) {
|
||||
this.maybeToggleWifi();
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the status of screen, wifi wake lock, and power source
|
||||
* and turn on/off wifi accordingly.
|
||||
*
|
||||
* You can think of this as a gigantic state machine where the input
|
||||
* is the states and the output is triggering the timer to turn wifi off,
|
||||
* or turning the wifi back on (if it is turned off by us).
|
||||
*
|
||||
* |--------------------------------|---------------------|
|
||||
* | Conditions | |
|
||||
* |--------|-----------|-----------| End state |
|
||||
* | Screen | Power | Wake lock | |
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
* | off | unplugged | not hold | set timer to off (1)|
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
* | off | unplugged | hold | turn back on |
|
||||
* | | | | if turned off by |
|
||||
* | | | | timer (2) |
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
* | off | plugged | not hold | turn back on |
|
||||
* | | | | if turned off by |
|
||||
* | | | | timer (3) |
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
* | off | plugged | hold | turn back on |
|
||||
* | | | | if turned off by |
|
||||
* | | | | timer (4) |
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
* | on | unplugged | not hold | turn back on |
|
||||
* | | | | if turned off by |
|
||||
* | | | | timer (5) |
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
* | on | unplugged | hold | turn back on |
|
||||
* | | | | if turned off by |
|
||||
* | | | | timer (6) |
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
* | on | plugged | not hold | turn back on |
|
||||
* | | | | if turned off by |
|
||||
* | | | | timer (7) |
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
* | on | plugged | hold | turn back on |
|
||||
* | | | | if turned off by |
|
||||
* | | | | timer (8) |
|
||||
* |--------|-----------|-----------|---------------------|
|
||||
*
|
||||
* The rest of the code are housekeepers making sure we keep an CPU lock
|
||||
* during the operations, and try not to set the timer twice etc.
|
||||
*
|
||||
* It is also assumed setting mozSettings w/ the same value would be a
|
||||
* no-op with no side effects so we don't really protect that.
|
||||
*
|
||||
* As the entry point to of the state machine, it is very important to
|
||||
* keep this function making the right decisions at all times.
|
||||
*/
|
||||
maybeToggleWifi: function wifi_maybeToggleWifi() {
|
||||
// Keep CPU awake to ensure the flow is done.
|
||||
var cpuLock = navigator.requestWakeLock('cpu');
|
||||
|
||||
var releaseCpuLock = function() {
|
||||
if (cpuLock) {
|
||||
cpuLock.unlock();
|
||||
cpuLock = null;
|
||||
}
|
||||
|
||||
if (timeoutId) {
|
||||
window.clearTimeout(timeoutId);
|
||||
timeoutId = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// To prevent the CPU awake forever (if anything goes run)
|
||||
var timeoutId = window.setTimeout(releaseCpuLock, 30000);
|
||||
|
||||
// Do nothing if we are being disabled.
|
||||
if (!this.screenOffTimeout) {
|
||||
releaseCpuLock();
|
||||
return;
|
||||
}
|
||||
|
||||
var battery = window.navigator.battery;
|
||||
var wifiManager = window.navigator.mozWifiManager;
|
||||
if (!battery || !wifiManager ||
|
||||
// We don't need to do anything if wifi is not disabled by system app.
|
||||
(!this.wifiEnabled && !this.wifiDisabledByWakelock)) {
|
||||
releaseCpuLock();
|
||||
return;
|
||||
}
|
||||
|
||||
var lock = SettingsListener.getSettingsLock();
|
||||
// Let's quietly turn off wifi if there is no wake lock and
|
||||
// the screen is off and we are not on a power source.
|
||||
if (!Service.query('screenEnabled') && !battery.charging &&
|
||||
!this._wakeLockManager.isHeld) {
|
||||
// We still need to turn of wifi even if there is no Alarm API
|
||||
if (!navigator.mozAlarms) {
|
||||
console.warn('Turning off wifi without sleep timer because' +
|
||||
' Alarm API is not available');
|
||||
this.sleep();
|
||||
releaseCpuLock();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set System Message Handler,
|
||||
// so we will be notified when alarm goes off.
|
||||
this.setSystemMessageHandler();
|
||||
|
||||
// When user wants to allow wifi off then start with a timer,
|
||||
// only turn off wifi till timeout.
|
||||
if (this.wifiSleepMode === true) {
|
||||
// maybeToggleWifi state machine state #1
|
||||
|
||||
// We should not try to set more than one alarms.
|
||||
if (this._hasAlarm) {
|
||||
releaseCpuLock();
|
||||
return;
|
||||
}
|
||||
|
||||
this._hasAlarm = true;
|
||||
var date = new Date(Date.now() + this.screenOffTimeout);
|
||||
var req = navigator.mozAlarms.add(date, 'ignoreTimezone', 'wifi-off');
|
||||
req.onsuccess = function wifi_offAlarmSet() {
|
||||
this._alarmId = req.result;
|
||||
releaseCpuLock();
|
||||
}.bind(this);
|
||||
req.onerror = function wifi_offAlarmSetFailed() {
|
||||
console.warn('Fail to set wifi sleep timer on Alarm API. ' +
|
||||
'Turn off wifi immediately.');
|
||||
this._hasAlarm = false;
|
||||
this.sleep();
|
||||
releaseCpuLock();
|
||||
}.bind(this);
|
||||
} else {
|
||||
releaseCpuLock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ... and quietly turn it back on or cancel the timer otherwise
|
||||
else {
|
||||
// maybeToggleWifi state machine state #2 to #8
|
||||
if (this._alarmId) {
|
||||
navigator.mozAlarms.remove(this._alarmId);
|
||||
this._hasAlarm = false;
|
||||
this._alarmId = null;
|
||||
}
|
||||
|
||||
// If wifi is enabled but disconnected.
|
||||
// we would need to call getNetworks()
|
||||
// so we could join known wifi network
|
||||
if (this.wifiEnabled &&
|
||||
wifiManager.connection.status == 'disconnected') {
|
||||
wifiManager.getNetworks();
|
||||
}
|
||||
|
||||
// We don't need to do anything if
|
||||
// we didn't disable wifi at first place.
|
||||
if (!this.wifiDisabledByWakelock) {
|
||||
releaseCpuLock();
|
||||
return;
|
||||
}
|
||||
|
||||
this.wifiDisabledByWakelock = false;
|
||||
|
||||
if (this.wifiEnabled) {
|
||||
releaseCpuLock();
|
||||
return;
|
||||
}
|
||||
|
||||
// turn wifi back on.
|
||||
lock.set({ 'wifi.enabled': true });
|
||||
lock.set({ 'wifi.disabled_by_wakelock': false });
|
||||
window.addEventListener('wifi-enabled', function() {
|
||||
releaseCpuLock();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Quietly turn off wifi for real, set wifiDisabledByWakelock to true
|
||||
// so we will turn it back on.
|
||||
sleep: function wifi_sleep() {
|
||||
// The |sleep| might be triggered when an alarm comes.
|
||||
// If the CPU is in suspend mode at this moment, alarm servcie would wake
|
||||
// up the CPU to run the handler and turn it back to suspend immediately
|
||||
// |sleep| is finished.
|
||||
// In this case, we acquire a CPU wake lock to prevent
|
||||
// the CPU goes to suspend mode before the switching is done.
|
||||
var wakeLockForWifi = navigator.requestWakeLock('cpu');
|
||||
|
||||
var releaseWakeLockForWifi = function() {
|
||||
if (wakeLockForWifi) {
|
||||
wakeLockForWifi.unlock();
|
||||
wakeLockForWifi = null;
|
||||
}
|
||||
if (timeoutId) {
|
||||
window.clearTimeout(timeoutId);
|
||||
timeoutId = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// To prevent the CPU awake forever (if wifi cannot be disabled)
|
||||
var timeoutId = window.setTimeout(releaseWakeLockForWifi, 30000);
|
||||
|
||||
// Remember that it was turned off by us.
|
||||
this.wifiDisabledByWakelock = true;
|
||||
|
||||
var request = null;
|
||||
var lock = SettingsListener.getSettingsLock();
|
||||
|
||||
// Actually turn off the wifi
|
||||
var wakeLockForSettings = navigator.requestWakeLock('cpu');
|
||||
lock.set({ 'wifi.enabled': false });
|
||||
window.addEventListener('wifi-disabled', releaseWakeLockForWifi);
|
||||
|
||||
// Keep this value in disk so if the phone reboots we'll
|
||||
// be able to turn the wifi back on.
|
||||
request = lock.set({ 'wifi.disabled_by_wakelock': true });
|
||||
request.onsuccess = function() { wakeLockForSettings.unlock(); };
|
||||
request.onerror = request.onsuccess;
|
||||
},
|
||||
|
||||
// Register for handling system message,
|
||||
// this cannot be done during |start()| because of bug 797803
|
||||
setSystemMessageHandler: function wifi_setSystemMessageHandler() {
|
||||
if (this._systemMessageHandlerRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._systemMessageHandlerRegistered = true;
|
||||
navigator.mozSetMessageHandler('alarm', function gotAlarm(message) {
|
||||
if (message.data !== 'wifi-off') {
|
||||
return;
|
||||
}
|
||||
|
||||
this._hasAlarm = false;
|
||||
this._alarmId = null;
|
||||
|
||||
// Wifi shall not sleep if the condition to turn this off has changed.
|
||||
// (Alarm should have been removed when condition changes, but for
|
||||
// reason unknown to us it still triggers.)
|
||||
var battery = window.navigator.battery;
|
||||
if (Service.query('screenEnabled') ||
|
||||
battery.charging ||
|
||||
this._wakeLockManager.isHeld) {
|
||||
console.error(
|
||||
'Wifi: mozAlarms should be cancelled but still triggers.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.sleep();
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
exports.Wifi = Wifi;
|
||||
}(window));
|
||||
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 625 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
458
overrides/system.gaiamobile.org/lockscreen/style/lockscreen.css
Normal file
|
|
@ -0,0 +1,458 @@
|
|||
/**
|
||||
* NOTICE: This file should be kept in sync with
|
||||
* callscreen/style/lockscreen.css
|
||||
**/
|
||||
|
||||
/**
|
||||
* BiDi note: because this stylesheet is 'scoped', instead of:
|
||||
* html[dir="rtl"] #volume { ... }
|
||||
* we must use:
|
||||
* #volume:-moz-dir(rtl) { ... }
|
||||
*/
|
||||
|
||||
#lockscreen {
|
||||
--panel-transition-secs: var(--transition-duration);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
visibility: visible;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
#screen.active-statusbar > #lockscreen {
|
||||
top: 4rem;
|
||||
height: calc(100% - 4rem);
|
||||
}
|
||||
|
||||
#lockscreen.unlocked {
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because of performance issue, we need to use an individual
|
||||
* background element instead of setting the background inside the container.
|
||||
*
|
||||
* This would be a step toward removing the overhead while a large container
|
||||
* contains children and do the opacity animation, which would cost lot on
|
||||
* temporary surfaces.
|
||||
**/
|
||||
#lockscreen-background, #lockscreen-masked-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
|
||||
/* Must match the CSS background rule of #screen in system.css */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
-moz-user-select: none;
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#lockscreen-background {
|
||||
background-color: #000;
|
||||
background-size: cover; /* Possible memory over-consumption with huge images, it should be removed for improving stability*/
|
||||
background-position: 50% 50%;
|
||||
}
|
||||
|
||||
#lockscreen-masked-background {
|
||||
background-size: 100% 100%;
|
||||
transition: background-image var(--transition-duration) ease,
|
||||
background-color var(--transition-duration) ease;
|
||||
}
|
||||
|
||||
#lockscreen-masked-background.blank {
|
||||
background: rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
#screen.lockscreen-camera > #lockscreen-camera {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* When switching lock-camera off,
|
||||
* transition time should be delayed to prevent homescreen appears.
|
||||
* (Let lockscreen appears first)
|
||||
*/
|
||||
#screen:not(.lockscreen-camera) > #lockscreen-camera {
|
||||
transition-delay: var(--transition-duration);
|
||||
}
|
||||
|
||||
#lockscreen-camera {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#lockscreen-camera > iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#lockscreen.no-transition {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#lockscreen-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
#lockscreen .lockscreen-panel {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 50%;
|
||||
visibility: hidden;
|
||||
transition: visibility var(--panel-transition-secs) ease, transform var(--panel-transition-secs) ease;
|
||||
}
|
||||
|
||||
.lockscreen-background::before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because of the individual background element, the slide would appear
|
||||
* after the passcode pad got invoked, so we need to hide it here.
|
||||
*/
|
||||
[data-panel="passcode"] #notifications-lockscreen-container,
|
||||
[data-panel="passcode"] #lockscreen-notification-arrow,
|
||||
[data-panel="passcode"] #lockscreen-media-container,
|
||||
[data-panel="passcode"] #lockscreen-icon-container {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
[data-panel="main"] #lockscreen-panel-main,
|
||||
[data-panel="passcode"] #lockscreen-panel-main,
|
||||
[data-panel="emergency-call"] #lockscreen-panel-emergency-call {
|
||||
visibility: inherit;
|
||||
}
|
||||
|
||||
[data-panel="main"] #lockscreen-alt-camera {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
[data-panel="passcode"] #lockscreen-alt-camera.lockscreen-icon {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
#lockscreen-header {
|
||||
z-index: 9999;
|
||||
position: absolute;
|
||||
top: 3rem; /* 3rem = height of status bar */
|
||||
left: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 1.5rem 2.4rem 0;
|
||||
color: #fff;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[data-panel="main"] #lockscreen-header {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
[data-panel="camera"] #lockscreen-header,
|
||||
[data-panel="emergency-call"] #lockscreen-header {
|
||||
transform: translateY(0);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#lockscreen-conn-states {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
font-weight: 300;
|
||||
font-size: 1.4rem;
|
||||
padding-bottom: 1.4rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#lockscreen-conn-states span:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#lockscreen-conn-states span:first-child {
|
||||
display: inline-block;
|
||||
margin-inline-end: 0.8rem;
|
||||
}
|
||||
|
||||
#lockscreen-conn-states span:last-child {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* For some reason display: inline-block disregards hidden attribute */
|
||||
#lockscreen-conn-states span[hidden],
|
||||
#lockscreen-conn-states[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#lockscreen-clock-time {
|
||||
line-height: 0.9;
|
||||
margin: -1.4rem 0 0;
|
||||
margin-inline-start: -0.4rem;
|
||||
font-weight: 200;
|
||||
font-size: 8.5rem;
|
||||
}
|
||||
|
||||
#lockscreen-date {
|
||||
display: inline-block;
|
||||
}
|
||||
#lockscreen-date, #lockscreen-alarm {
|
||||
font-weight: 300;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#lockscreen-alarm::after {
|
||||
content: ' ';
|
||||
top: 3px;
|
||||
background-image: url('./images/alarm_icon.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 1.5rem;
|
||||
width: 15px;
|
||||
display: inline-block;
|
||||
height: 15px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.has-alarm {
|
||||
display: inline-block;
|
||||
}
|
||||
.no-alarms {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#lockscreen-clock-time, #lockscreen-date, #lockscreen-alarm {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#lockscreen-charging {
|
||||
font-weight: 300;
|
||||
font-size: 1.2rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#lockscreen-area {
|
||||
position: absolute;
|
||||
height: 8.6rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
#lockscreen .lockscreen-icon-area {
|
||||
height: 10rem;
|
||||
position: absolute;
|
||||
border-style: none;
|
||||
transition: opacity var(--panel-transition-secs) ease;
|
||||
}
|
||||
|
||||
#lockscreen .lockscreen-icon {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#lockscreen-area-slide {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#lockscreen .touched .lockscreen-icon {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#lockscreen .lockscreen-icon-right {
|
||||
right: calc(50% - 14rem);
|
||||
}
|
||||
|
||||
#lockscreen .lockscreen-icon-left {
|
||||
left: calc(50% - 14rem);
|
||||
}
|
||||
|
||||
@media (min-width:768px) {
|
||||
#lockscreen .lockscreen-icon-right {
|
||||
right: calc(50% - 20.5rem);
|
||||
}
|
||||
|
||||
#lockscreen .lockscreen-icon-left {
|
||||
left: calc(50% - 20.5rem);
|
||||
}
|
||||
|
||||
#lockscreen-header {
|
||||
padding-inline-start: 6rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
#lockscreen-date {
|
||||
padding-top: 0.5rem;
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
:-moz-any(.touched, #screen:not(.locked), #screen.attention, #lockscreen:not([data-panel="main"]))
|
||||
:-moz-any(#lockscreen-left-arrow, #lockscreen-right-arrow) {
|
||||
display: none;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
#lockscreen-area-unlock > div {
|
||||
background-image: image-set(url("./images/lockscreen_unlock.png") 1x, url("images/lockscreen_unlock@1.5x.png") 1.5x, url("images/lockscreen_unlock@2x.png") 2x, url("images/lockscreen_unlock@2.25x.png") 2.25x);
|
||||
background-position: 1.1rem center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 3rem;
|
||||
margin-top: 1.9rem;
|
||||
}
|
||||
|
||||
#lockscreen .lockscreen-icon-left, .lockscreen-icon-right {
|
||||
z-index: 16;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Compensation for the effects after enabling the pointer-event attribute. */
|
||||
#lockscreen .lockscreen-icon-left:active, .lockscreen-icon-right:active {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#lockscreen-area-camera > div {
|
||||
background-image: image-set(url("./images/lockscreen_camera.png") 1x, url("images/lockscreen_camera@1.5x.png") 1.5x, url("images/lockscreen_camera@2x.png") 2x, url("images/lockscreen_camera@2.25x.png") 2.25x);
|
||||
background-position: 1.85rem center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 3rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#lockscreen-alt-camera.lockscreen-icon {
|
||||
border-radius: 2.5rem;
|
||||
background-color: rgba(255, 255, 255, 0.25);
|
||||
box-sizing: border-box;
|
||||
pointer-events: auto;
|
||||
opacity: 0.1;
|
||||
transition: opacity var(--panel-transition-secs) ease;
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
margin-top: 5rem;
|
||||
}
|
||||
#lockscreen-alt-camera.lockscreen-icon:-moz-dir(ltr) { float: right; }
|
||||
#lockscreen-alt-camera.lockscreen-icon:-moz-dir(rtl) { float: left; }
|
||||
|
||||
#lockscreen-alt-camera-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
pointer-events: auto;
|
||||
background-image: image-set(url("./images/pin_camera.png") 1x, url("images/pin_camera@1.5x.png") 1.5x, url("images/pin_camera@2x.png") 2x, url("images/pin_camera@2.25x.png") 2.25x);
|
||||
background-position: 1rem center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 3rem;
|
||||
}
|
||||
|
||||
#lockscreen-panel-emergency-call {
|
||||
/* > camera, unlock icons > canvas */
|
||||
z-index: 32;
|
||||
}
|
||||
|
||||
#lockscreen-panel-emergency-call {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
#lockscreen-panel-emergency-call::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
#lockscreen-panel-emergency-call > iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
[data-panel="emergency-call"] #lockscreen-panel-emergency-call {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
#lockscreen-area-handle {
|
||||
position: absolute;
|
||||
background-image: image-set(url("./images/handle.png") 1x, url("images/handle@1.5x.png") 1.5x, url("images/handle@2x.png") 2x);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 2rem;
|
||||
border-top: 0.1rem solid transparent;
|
||||
top: -2rem;
|
||||
height: 0.9rem;
|
||||
width: 100%;
|
||||
transition:
|
||||
transform var(--panel-transition-secs) ease,
|
||||
opacity var(--panel-transition-secs) ease;
|
||||
}
|
||||
|
||||
#lockscreen-icon-container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 10rem;
|
||||
pointer-events: none;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
#lockscreen .touched #lockscreen-icon-container {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#lockscreen .touched .lockscreen-icon-area {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#lockscreen-canvas-wrapper {
|
||||
position: absolute;
|
||||
bottom: 0.75rem;
|
||||
z-index: 8;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#lockscreen-message {
|
||||
position: relative;
|
||||
top: 18rem;
|
||||
offset-inline-start: 0;
|
||||
word-wrap: break-word;
|
||||
text-align: center;
|
||||
overflow-y: auto;
|
||||
line-height: 1.4rem;
|
||||
z-index: 16;
|
||||
margin: auto;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid #e6e6e6;
|
||||
padding: 5px;
|
||||
width: 27rem;
|
||||
min-height: 5rem;
|
||||
max-height: 10rem;
|
||||
background-color: #fafafa;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
color: black;
|
||||
}
|
||||
|
|
@ -0,0 +1,375 @@
|
|||
/**
|
||||
* BiDi note: because this stylesheet is 'scoped', instead of:
|
||||
* html[dir="rtl"] #volume { ... }
|
||||
* we must use:
|
||||
* #volume:-moz-dir(rtl) { ... }
|
||||
*/
|
||||
|
||||
/* Individual style; to avoid utility tray patches to break lockscreen notitifications. */
|
||||
#notifications-lockscreen-container .notification {
|
||||
position: relative;
|
||||
height: 6rem;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.9rem;
|
||||
border-top: 0.1rem solid transparent;
|
||||
border-bottom: 0.1rem solid transparent;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification:first-child {
|
||||
border-top-color: black;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification div {
|
||||
pointer-events: none;
|
||||
}
|
||||
:-moz-dir(ltr) #notifications-lockscreen-container .notification div {
|
||||
text-align: left;
|
||||
}
|
||||
:-moz-dir(rtl) #notifications-lockscreen-container .notification div {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > div.title-container {
|
||||
margin-top: 1rem;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > div {
|
||||
width: calc(100% - 6.5rem);
|
||||
margin-inline-start: 5rem;
|
||||
color: #bfbfbf;
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.9rem;
|
||||
min-height: 1.9rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > img {
|
||||
display: block;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
margin: 1.5rem 1rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
:-moz-dir(ltr) #notifications-lockscreen-container .notification > img { float: left; }
|
||||
:-moz-dir(rtl) #notifications-lockscreen-container .notification > img { float: right; }
|
||||
|
||||
#notifications-lockscreen-container .notification > div.title-container .title {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
margin-inline-end: .5rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification.actionable {
|
||||
/* Can't set border as none because it affects layout,
|
||||
* so we do this to hide them */
|
||||
border-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification.actionable > div {
|
||||
/* 18rem is the magic number to make sure it get truncated before the actionable button */
|
||||
/* ideally it should be */
|
||||
/* width: calc(100% - var(--padleft-button) - var(--width-actionable-button)); */
|
||||
/* but it would fail and make the content too short. */
|
||||
width: 18rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification.actionable > div:first-of-type {
|
||||
width: 18.5rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification.actionable .timestamp {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: -1.1rem;
|
||||
offset-inline-start: 0;
|
||||
height: 6rem;
|
||||
background-color: rgba(51, 51, 51, 0.3);
|
||||
z-index: -1; /* make this as 'background' */
|
||||
opacity: 0.0;
|
||||
transition: opacity .25s ease-out;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification.actionable::before {
|
||||
opacity: 1.0;
|
||||
transition: opacity .25s ease-out;
|
||||
}
|
||||
|
||||
/* for the border */
|
||||
#notifications-lockscreen-container .notification::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: calc(100% - 4.8rem);
|
||||
top: -1.1rem;
|
||||
offset-inline-start: 0;
|
||||
height: 6rem;
|
||||
z-index: -1; /* make this as 'background' */
|
||||
border-top: none;
|
||||
border-bottom: 0.1rem solid rgba(255, 255, 255, 0.3);
|
||||
margin-inline-start: 2.4rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container > div:last-child::after {
|
||||
border-bottom: 0.1rem solid rgba(255, 255, 255, 0.0);
|
||||
}
|
||||
|
||||
/* since CSS don't have 'previous' selector */
|
||||
#notifications-lockscreen-container .notification.actionable::after,
|
||||
#notifications-lockscreen-container .notification.previous-actionable::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .button-actionable {
|
||||
border-inline-start: 0.1rem rgba(255, 255, 255, 0.15) solid;
|
||||
color: rgba(0, 202, 242, 1);
|
||||
display: inline-block;
|
||||
|
||||
|
||||
font-size: var(--button-label-size);
|
||||
font-family: "Fira Sans";
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
position: absolute;
|
||||
|
||||
/* from the border line to the text */
|
||||
padding-inline-start: var(--padleft-button);
|
||||
|
||||
/* 0.3rem is the magic number to make it (with the border) vertical-align: middle*/
|
||||
top: 0.3rem;
|
||||
|
||||
/* 100% - the actionable area + the margin of the actionable area */
|
||||
/* The 0.8rem is for alignment of the position of previous timestamp */
|
||||
/* The 0.3rem is for centering the vertical bar of the button */
|
||||
offset-inline-start: calc(100% - var(--width-actionable-button) + 1.4rem);
|
||||
height: 3.5rem;
|
||||
line-height: 3.3rem; /* to make the lable vertical-align: middle */
|
||||
transition-property: color, text;
|
||||
transition-duration: 0.25s;
|
||||
transition-timing-function: linear, ease-in;
|
||||
}
|
||||
|
||||
/* When the notification be touched and the button has been tapped */
|
||||
#notifications-lockscreen-container .notification.actionable.activated .button-actionable,
|
||||
#notifications-lockscreen-container .button-actionable.activated {
|
||||
color: rgba(0, 202, 242, 0.2);
|
||||
}
|
||||
|
||||
/* notifications */
|
||||
|
||||
/* in "normal" mode (there is no widget)
|
||||
* desired vertical position is centered in the space
|
||||
* between date and slider
|
||||
* for big screen, we allow four notifications,
|
||||
* for small screen, we allow three notification
|
||||
* that would be (for four notifications)
|
||||
* (100% - 16.3rem (header) - 3rem (statusbar)
|
||||
* - 10rem (slider) - 24.6rem (4xNotifications height)) / 2
|
||||
* + 16.3rem + 3rem
|
||||
*/
|
||||
|
||||
#notifications-lockscreen-container {
|
||||
--width-actionable-button: 8.3rem;
|
||||
--padleft-button: 1.1rem;
|
||||
--button-label-size: 1.4rem;
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: calc(50% - 7.65rem);
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 24.6rem;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* in collapsed mode (there is a widget)
|
||||
* desired vertical position is manually adjusted for big screen,
|
||||
* and for big screen we allow three notifications
|
||||
* for small screen, we allow two notification; they are
|
||||
* vertically centered between date and music player widget
|
||||
*/
|
||||
#notifications-lockscreen-container.collapsed {
|
||||
top: calc(50% - 8.7rem);
|
||||
height: 17.7rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container.masked-both {
|
||||
mask: url('lockscreen_container_mask.svg#fade_mask_both');
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container.masked-top {
|
||||
mask: url('lockscreen_container_mask.svg#solid_mask_top');
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container.masked-top.top-actionable {
|
||||
mask: none;
|
||||
}
|
||||
|
||||
@media (max-height:480px) {
|
||||
/* small screen, normal mode: for three notifications...
|
||||
* (100% - 16.3rem (header) - 3rem (statusbar)
|
||||
* - 10rem (slider) - 18.8rem (3xNotifications height)) / 2
|
||||
* + 16.3rem + 3rem
|
||||
*/
|
||||
|
||||
#notifications-lockscreen-container {
|
||||
top: calc(50% - 4.7rem);
|
||||
height: 18.8rem;
|
||||
}
|
||||
|
||||
/* small screen, collapsed mode: for one notification...
|
||||
* manally adjusted according to UX; 1x Notification is 5.8rem
|
||||
* UX specifies in bug 1023500 that the container should not be scrollable
|
||||
* (so there is no mask either)
|
||||
*
|
||||
* Bug 1115921 specifies that in this condition, the notification should
|
||||
* be vertically centered, thus 2.5rem which puts it in the middle
|
||||
*/
|
||||
#notifications-lockscreen-container.collapsed {
|
||||
top: calc(50% - 2.5rem);
|
||||
height: 5.8rem;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container.collapsed.masked-top,
|
||||
#notifications-lockscreen-container.collapsed.masked-both {
|
||||
mask: none;
|
||||
}
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification {
|
||||
position: relative;
|
||||
background-color: transparent;
|
||||
border-top: none;
|
||||
/* delegate border to :after element while keeping layout correct */
|
||||
border-bottom: 0.1rem solid rgba(0, 0, 0, 0);
|
||||
height: 4.8rem;
|
||||
margin: 0;
|
||||
padding-inline-start: 2.4rem;
|
||||
padding-inline-end: 2.4rem;
|
||||
width: calc(100% - 4.8rem);
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container.collapsed .notification:last-child {
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > div {
|
||||
width: calc(100% - 3.6rem);
|
||||
margin-inline-start: 3.6rem;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > .title-container div:first-of-type {
|
||||
width: calc(100% - 9.4rem);
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > div.detail {
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > div.detail .detail-content {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > .title-container .timestamp {
|
||||
margin-top: 0.1rem;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
|
||||
flex: initial;
|
||||
top: -.2rem;
|
||||
offset-inline-end: 1.5rem;
|
||||
padding: 0;
|
||||
max-width: 6.5rem;
|
||||
font-size: 1.2rem;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
line-height: 1.6rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#notifications-lockscreen-container .notification > img {
|
||||
margin-top: 0.8rem;
|
||||
margin-inline-start: 0;
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
}
|
||||
|
||||
#lockscreen-notification-arrow {
|
||||
width: calc(100% - 5.2rem);
|
||||
height: 1.6rem;
|
||||
background-image: image-set(url("./images/lockscreen_notification_arrow.png") 1x, url("images/lockscreen_notification_arrow@1.5x.png") 1.5x, url("images/lockscreen_notification_arrow@2x.png") 2x, url("images/lockscreen_notification_arrow@2.25x.png") 2.25x);
|
||||
background-repeat: no-repeat;
|
||||
background-position: calc(50% + 0.25rem) center;
|
||||
/* hide it while we adjust no layout */
|
||||
border-top: 0.1rem solid rgba(255, 255, 255, 0.0);
|
||||
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
background-size: 1.6rem 1.6rem;
|
||||
margin: 0 2.4rem;
|
||||
|
||||
opacity: 0;
|
||||
transition: opacity var(--transition-duration) ease;
|
||||
}
|
||||
:-moz-dir(ltr) #lockscreen-notification-arrow { left: 0; }
|
||||
:-moz-dir(rtl) #lockscreen-notification-arrow { right: 0; }
|
||||
|
||||
#lockscreen-notification-arrow.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* please see how we calculate top and max-height of
|
||||
* #notifications-lockscreen-container to place the arrow's top.
|
||||
* the last offset in calc is to make sure hairlines align together,
|
||||
* and is empirical values.
|
||||
*/
|
||||
#lockscreen-notification-arrow {
|
||||
top: calc(50% - 7.65rem + 24.6rem - 1.2rem);
|
||||
}
|
||||
|
||||
#lockscreen-notification-arrow.collapsed {
|
||||
/* manually adjusted */
|
||||
top: calc(50% - 8.7rem + 17.7rem - 0.05rem);
|
||||
}
|
||||
|
||||
@media (max-height:480px) {
|
||||
#lockscreen-notification-arrow {
|
||||
top: calc(50% - 4.7rem + 18.8rem - 1.1rem);
|
||||
}
|
||||
|
||||
#lockscreen-notification-arrow.collapsed {
|
||||
/* UX specifies in bug 1023500 that the notifications
|
||||
container should not be scrollable with collapsed */
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 718 B |
|
After Width: | Height: | Size: 1 KiB |
|
After Width: | Height: | Size: 935 B |
|
After Width: | Height: | Size: 397 B |
|
After Width: | Height: | Size: 650 B |
436
overrides/system.gaiamobile.org/mobile_id/style/mobile_id.css
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 10px;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: hidden !important;
|
||||
font-family: 'MozTT', sans-serif;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
section[role="region"] {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #ccc;
|
||||
text-decoration: none !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.disabled *{
|
||||
text-decoration: none !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We have a 'magic' button which translates with us through the
|
||||
* proccess. This is called 'multistate-button' or 'msb'
|
||||
*/
|
||||
|
||||
.multistate-button {
|
||||
width: 200%;
|
||||
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
transition: all .3s ease;
|
||||
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.msb-button-step {
|
||||
height: 4rem;
|
||||
width: calc(50% - 2rem);
|
||||
|
||||
float: left;
|
||||
margin: 0 1rem;
|
||||
|
||||
background: #00AACC;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 2rem;
|
||||
line-height: 4rem;
|
||||
text-decoration: none;
|
||||
font-size: 1.8rem;
|
||||
font-style: italic;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.msb-button-step progress {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some buttons which have different states
|
||||
*/
|
||||
|
||||
.states-wrapper {
|
||||
height: 12rem;
|
||||
transform: translateY(-4rem);
|
||||
transition: all .3s ease;
|
||||
}
|
||||
|
||||
.state-resend .states-wrapper div span:first-child{
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background: url(images/warning.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.state-allow .states-wrapper{
|
||||
transform: translateY(0);
|
||||
}
|
||||
.state-connecting .states-wrapper{
|
||||
transform: translateY(-4rem);
|
||||
}
|
||||
.state-resend .states-wrapper{
|
||||
transform: translateY(0);
|
||||
}
|
||||
.state-verify .states-wrapper{
|
||||
transform: translateY(-4rem);
|
||||
}
|
||||
.state-verifying .states-wrapper{
|
||||
transform: translateY(-8rem);
|
||||
}
|
||||
.state-verified > .states-wrapper{
|
||||
transform: translateY(-12rem);
|
||||
}
|
||||
|
||||
.state-verified {
|
||||
background: #5F9B0A;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.state-resend {
|
||||
background: #B90000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
We will contain the three main panels of the Mobile ID flow:
|
||||
- [1] Selection of the phone number
|
||||
- [2] Add verification code (if required)
|
||||
- [3] Feedback screen
|
||||
*/
|
||||
|
||||
#verification-code-timer {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#verification-code-timer.show {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.panels-container {
|
||||
height: calc(100% - 11.3rem);
|
||||
width: 400%;
|
||||
overflow: hidden;
|
||||
|
||||
transition: all .6s ease;
|
||||
}
|
||||
|
||||
.panel {
|
||||
height: 100%;
|
||||
width: 25%;
|
||||
|
||||
float: left;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: scroll;
|
||||
|
||||
background: white;
|
||||
}
|
||||
|
||||
p.explanation {
|
||||
font-size: 1.9rem;
|
||||
font-weight: 300;
|
||||
line-height: 2.2rem;
|
||||
}
|
||||
|
||||
div, span, p, label {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/*
|
||||
[1] Selection of the phone number
|
||||
*/
|
||||
|
||||
.msisdn-selection-panel p.explanation {
|
||||
padding: 2rem 1rem 1rem 2rem;
|
||||
font-size: 1.9rem;
|
||||
font-weight: 300;
|
||||
line-height: 2.2rem;
|
||||
}
|
||||
|
||||
.msisdn-overflow-shield {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.msisdn-selection-wrapper {
|
||||
width: 200%;
|
||||
transition: all .3s ease;
|
||||
}
|
||||
|
||||
.msisdn-selection-wrapper div{
|
||||
padding: 0 2rem 1rem 2rem;
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can select one of the pre-popopulated MSISDN
|
||||
*/
|
||||
|
||||
ul.phone-options-list {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
list-style: none;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
ul.phone-options-list li {
|
||||
height: 5rem;
|
||||
position: relative;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
vertical-align: baseline;
|
||||
font-size: 1.7rem;
|
||||
line-height: 5.5rem;
|
||||
border-bottom: .1rem solid #ccc;
|
||||
}
|
||||
|
||||
ul.phone-options-list li:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
ul.phone-options-list li input {
|
||||
display: none;
|
||||
float: right;
|
||||
}
|
||||
|
||||
ul.phone-options-list li span.icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
float: left;
|
||||
margin-top: 1rem;
|
||||
margin-right: 1rem;
|
||||
|
||||
background-image: url(images/simcards.png);
|
||||
background-position: 0 0;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
ul.phone-options-list li span.sim1 {
|
||||
background-image: url(images/simcards.png);
|
||||
background-position: 0 0;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
ul.phone-options-list li span.sim2 {
|
||||
background-image: url(images/simcards.png);
|
||||
background-position: 0 -3rem;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
ul.phone-options-list li span.primary {
|
||||
background-image: image-set(url("images/Telf_tick.png") 1x, url("images/Telf_tick@1.5x.png") 1.5x, url("images/Telf_tick@2x.png") 2x, url("images/Telf_tick@2.25x.png") 2.25x);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
|
||||
ul.phone-options-list li span.radio-mask {
|
||||
width: 5rem;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
ul.phone-options-list li input:checked + span.radio-mask {
|
||||
background-image: image-set(url("images/checked.png") 1x, url("images/checked@1.5x.png") 1.5x, url("images/checked@2x.png") 2x);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
#add-msisdn {
|
||||
width: 100%;
|
||||
|
||||
margin-top: 2rem;
|
||||
font-size: 1.5rem;
|
||||
color: #858585;
|
||||
text-decoration: underline;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
/*
|
||||
If we type the MSISDN manually
|
||||
*/
|
||||
|
||||
#do-automatic-msisdn {
|
||||
width: 100%;
|
||||
|
||||
padding: 1rem;
|
||||
box-sizing: border-box;
|
||||
font-size: 1.5rem;
|
||||
color: #858585;
|
||||
text-decoration: underline;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
ul.msisdn-form {
|
||||
width: 100%;
|
||||
|
||||
margin-top: 6rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.msisdn-form li{
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
ul.msisdn-form li{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.msisdn-form li button{
|
||||
height: 4rem;
|
||||
width: 5rem;
|
||||
padding-right: 2rem;
|
||||
text-align: center;
|
||||
line-height: 4.2rem;
|
||||
}
|
||||
|
||||
ul.msisdn-form li input{
|
||||
height: 4rem;
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
ul.msisdn-form li:last-child{
|
||||
width: calc(100% - 7.3rem);
|
||||
}
|
||||
|
||||
.button-select-wrapper {
|
||||
width: 7rem !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
overflow: hidden !important;
|
||||
text-overflow: unset !important;
|
||||
}
|
||||
|
||||
.button-select-wrapper select {
|
||||
width: calc(100% + 1.9rem) !important;
|
||||
font-size: 1.6rem;
|
||||
text-align: left;
|
||||
height: 100%;
|
||||
background: none;
|
||||
border: none;
|
||||
padding-left: .6rem !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/*
|
||||
[2] Add verification code (if required)
|
||||
*/
|
||||
|
||||
.verification-panel {
|
||||
padding: 2rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.verification-panel p {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#verification-code {
|
||||
width: 100%;
|
||||
height: 5rem;
|
||||
|
||||
margin-top: 4rem;
|
||||
margin-bottom: 2rem;
|
||||
font-size: 3rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input.error {
|
||||
border: .1rem solid #B90000;
|
||||
animation: error-dance .5s;
|
||||
animation-iteration-count: 2;
|
||||
}
|
||||
|
||||
@keyframes error-dance {
|
||||
0% { transform: rotate(0); }
|
||||
25% { transform: rotate(1deg); }
|
||||
50% { transform: rotate(0); }
|
||||
75% { transform: rotate(1deg); }
|
||||
100% { transform: rotate(0deg); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
#verification-timer {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/*
|
||||
[3] Feedback screen
|
||||
*/
|
||||
|
||||
.done-panel {
|
||||
background-repeat: no-repeat;
|
||||
background-size: 49%;
|
||||
background-position: center 60%;
|
||||
}
|
||||
|
||||
.done-panel-gif {
|
||||
background-image: url(images/animation.gif);
|
||||
}
|
||||
|
||||
.done-panel p {
|
||||
padding: 2rem 1rem;
|
||||
box-sizing: border-box;
|
||||
font-size: 2.2rem;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
#legend {
|
||||
text-align: center;
|
||||
display: block;
|
||||
padding-top: 0.8rem;
|
||||
padding-left: 1.3rem;
|
||||
}
|
||||
|
After Width: | Height: | Size: 946 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 946 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,71 @@
|
|||
gaia-checkbox {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#checkbox {
|
||||
display: block;
|
||||
width: 100%;
|
||||
/* Normal gaia-checkboxes are the heights of their parents. */
|
||||
height: 100%;
|
||||
position: relative;
|
||||
background: none;
|
||||
}
|
||||
|
||||
#checkbox span {
|
||||
font-size: 1.9rem;
|
||||
font-weight: normal;
|
||||
color: var(--label-color);
|
||||
line-height: 3rem;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
min-width: 2.2rem;
|
||||
min-height: 2.2rem;
|
||||
width: 100%;
|
||||
padding-inline-end: 2.2rem;
|
||||
/* Override inheriting nowrap from legacy lists building blocks. */
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* Inline gaia-checkboxes are the heights of their parents. */
|
||||
#checkbox.inline {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#checkbox:not(.invisible) span:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
offset-inline-end: 0;
|
||||
top: 50%;
|
||||
margin: -1.2rem 0 0;
|
||||
margin-inline-start: -1.2rem;
|
||||
width: 2.2rem;
|
||||
height: 2.2rem;
|
||||
}
|
||||
|
||||
#checkbox.inline span {
|
||||
padding-inline-start: 3rem;
|
||||
padding-inline-end: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#checkbox.inline span:after {
|
||||
offset-inline-start: 1.2rem;
|
||||
offset-inline-end: unset;
|
||||
margin: -1.2rem 0 0;
|
||||
margin-inline-start: -1.2rem;
|
||||
}
|
||||
|
||||
#checkbox:not(.invisible) span:after {
|
||||
background: image-set(url("images/default.png") 1x, url("images/default@1.5x.png") 1.5x, url("images/default@2x.png") 2x, url("images/default@2.25x.png") 2.25x) no-repeat center top / 2.2rem auto;
|
||||
}
|
||||
|
||||
#checkbox.checked span:after {
|
||||
background-position: center bottom;
|
||||
}
|
||||
|
||||
/* 'Dangerous' checkboxes */
|
||||
#checkbox.danger span:after {
|
||||
background-image: image-set(url("images/danger.png") 1x, url("images/danger@1.5x.png") 1.5x, url("images/danger@2x.png") 2x, url("images/danger@2.25x.png") 2.25x);
|
||||
}
|
||||
|
After Width: | Height: | Size: 400 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 558 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 3 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 4 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2 KiB |
|
After Width: | Height: | Size: 2 KiB |
|
|
@ -0,0 +1,409 @@
|
|||
.icon[data-app-state="loading"]:after {
|
||||
content: "";
|
||||
background: no-repeat top center image-set(url("images/app_install_spinner.png") 1x, url("images/app_install_spinner@1.5x.png") 1.5x, url("images/app_install_spinner@2x.png") 2x, url("images/app_install_spinner@2.25x.png") 2.25x);
|
||||
background-size: contain;
|
||||
height: 8.4rem;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
/**
|
||||
Keyframe must be defined outside of the web component.
|
||||
See bug 1018269
|
||||
*/
|
||||
|
||||
animation: rotate 2.25s linear infinite;
|
||||
}
|
||||
|
||||
.icon[data-app-state="loading"] {
|
||||
/**
|
||||
We must align this value with the value of [data-app-state]:after height the background size
|
||||
here is overridden at the element level elsewhere which causes the spinner to be aligned too
|
||||
low.
|
||||
*/
|
||||
background-size: 8.4rem !important;
|
||||
background-image: image-set(url("images/app_installing.png") 1x, url("images/app_installing@1.5x.png") 1.5x, url("images/app_installing@2x.png") 2x, url("images/app_installing@2.25x.png") 2.25x) !important;
|
||||
}
|
||||
|
||||
.icon[data-app-state="unrecoverable"] {
|
||||
background-image: image-set(url("images/app_install_unrecoverable.png") 1x, url("images/app_install_unrecoverable@1.5x.png") 1.5x, url("images/app_install_unrecoverable@2x.png") 2x, url("images/app_install_unrecoverable@2.25x.png") 2.25x) !important;
|
||||
}
|
||||
|
||||
.icon[data-app-state="error"] {
|
||||
background-image: image-set(url("images/app_install_failed.png") 1x, url("images/app_install_failed@1.5x.png") 1.5x, url("images/app_install_failed@2x.png") 2x, url("images/app_install_failed@2.25x.png") 2.25x) !important;
|
||||
}
|
||||
|
||||
.icon[data-app-state="paused"] {
|
||||
background-image: image-set(url("images/app_install_canceled.png") 1x, url("images/app_install_canceled@1.5x.png") 1.5x, url("images/app_install_canceled@2x.png") 2x, url("images/app_install_canceled@2.25x.png") 2.25x) !important;
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
transform-origin: 0 0;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
background: no-repeat top center;
|
||||
z-index: 3;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.icon.launching {
|
||||
opacity: .65;
|
||||
}
|
||||
|
||||
/* XXX: Override the .remove element */
|
||||
.edit-mode .collection.hovered .remove {
|
||||
background: image-set(url("images/add.png") 1x, url("images/add@1.5x.png") 1.5x, url("images/add@2x.png") 2x, url("images/add@2.25x.png") 2.25x) no-repeat;
|
||||
background-size: 2rem;
|
||||
}
|
||||
|
||||
.icon p {
|
||||
pointer-events: none;
|
||||
height: 3.2rem;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.icon .title {
|
||||
display: inline-block;
|
||||
margin-top: 0.1rem;
|
||||
/* We need this rule in order not to hide the drop shadow */
|
||||
padding: 0 0.2rem 1rem;
|
||||
text-shadow: 0.1rem 0.1rem 0.3rem rgba(0, 0, 0, 0.3),
|
||||
0.2rem 0.4rem 1rem rgba(0, 0, 0, 0.4);
|
||||
font-size: 1.4rem;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: calc(100% - 0.4rem);
|
||||
box-sizing: border-box;
|
||||
vertical-align: top;
|
||||
transition: opacity var(--transition-duration);
|
||||
}
|
||||
|
||||
/* We allow more space for text in the search app by hooking into the text-rows attribute on gaia-grid. */
|
||||
[text-rows="3"] .icon .title {
|
||||
height: 5.8rem;
|
||||
}
|
||||
|
||||
[cols="4"] .icon .title {
|
||||
/* Font size is the same independent on grid configuration */
|
||||
font-size: calc(1.2rem * 1.333);
|
||||
margin-top: 0.5rem;
|
||||
line-height: 1.94rem;
|
||||
}
|
||||
|
||||
.edit-mode .icon.collapsed {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.icon.collapsed .title {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.icon.hidden {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.divider {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
padding-top: 2.3rem;
|
||||
border-left: 0.6rem solid transparent;
|
||||
border-right: 0.6rem solid transparent;
|
||||
box-sizing: border-box;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
[cols="4"] .divider {
|
||||
padding-top: 1.6rem;
|
||||
}
|
||||
|
||||
.divider span.spacer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.5));
|
||||
margin: 0 25%;
|
||||
width: 50%;
|
||||
height: 0.2rem;
|
||||
transition: opacity var(--transition-duration);
|
||||
}
|
||||
|
||||
.dragging .icon.active:not(.hidden) {
|
||||
z-index: 6;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.dragging .divider:not(.group),
|
||||
.icon:not(.active),
|
||||
.dropped {
|
||||
transition: transform var(--transition-duration),
|
||||
opacity var(--transition-duration);
|
||||
}
|
||||
|
||||
.icon.active {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.edit-mode .icon .remove {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0.1rem;
|
||||
left: 0.5rem;
|
||||
width: 2.6rem;
|
||||
height: 2.6rem;
|
||||
background: image-set(url("images/remove.png") 1x, url("images/remove@1.5x.png") 1.5x, url("images/remove@2x.png") 2x, url("images/remove@2.25x.png") 2.25x) no-repeat;
|
||||
background-size: 2rem;
|
||||
/*
|
||||
Ensure that remove is on top of the icon and has some extra
|
||||
padding so it is easy to click.
|
||||
*/
|
||||
z-index: 200;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.icon .remove,
|
||||
.icon.collapsed .remove,
|
||||
.edit-mode .icon.active .remove {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.edit-mode .icon.editable .title {
|
||||
background-color: rgba(132, 132, 132, 0.7);
|
||||
border-radius: 2rem;
|
||||
margin-top: .4rem;
|
||||
padding: 0 1rem;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
Disable events for placeholders, so we don't trigger touch events in edit mode.
|
||||
We only do this in edit-mode, otherwise we might trigger entering edit mode
|
||||
instead of the context menu.
|
||||
*/
|
||||
.edit-mode .placeholder {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#confirm-message {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.dragging .group.active {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.divider.group {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.group > span {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
transition: background-color var(--transition-duration),
|
||||
opacity var(--transition-duration);
|
||||
}
|
||||
|
||||
.group:not(.active):not(.newly-created) > span {
|
||||
transition: background-color var(--transition-duration),
|
||||
opacity var(--transition-duration),
|
||||
transform var(--transition-duration);
|
||||
}
|
||||
|
||||
.group.active > span {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.group .header {
|
||||
height: 4rem;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.group .header span,
|
||||
.group .header button {
|
||||
position: absolute;
|
||||
height: 4rem;
|
||||
top: 0;
|
||||
|
||||
background-position: center top;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 2rem;
|
||||
|
||||
transition: transform 0.25s, opacity 0.25s;
|
||||
}
|
||||
|
||||
.group .header .gripper {
|
||||
left: calc(50% - 4.2rem);
|
||||
width: 8.4rem;
|
||||
background-image: image-set(url("images/move_gripper.png") 1x, url("images/move_gripper@1.5x.png") 1.5x, url("images/move_gripper@2x.png") 2x, url("images/move_gripper@2.25x.png") 2.25x);
|
||||
opacity: 0;
|
||||
transform: translate(0, -100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.edit-mode .group:not(.collapsed) .header .gripper {
|
||||
opacity: 1;
|
||||
transform: translate(0, 0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.group .header .toggle {
|
||||
width: 5.34rem;
|
||||
right: 0;
|
||||
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
background-color: transparent;
|
||||
background-image: image-set(url("images/collapse_arrow.png") 1x, url("images/collapse_arrow@1.5x.png") 1.5x, url("images/collapse_arrow@2x.png") 2x, url("images/collapse_arrow@2.25x.png") 2.25x);
|
||||
transform-origin: 50% 1.6rem;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.group .header .toggle.toggling {
|
||||
opacity: 0.5;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
|
||||
.group.collapsed .header .toggle {
|
||||
transform: translateY(2rem) rotateZ(180deg);
|
||||
}
|
||||
|
||||
.group.active .header .toggle {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.group .background {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
height: 0.1rem;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
.group.odd:not(.newly-created) .background,
|
||||
.edit-mode .group:not(.newly-created) .background {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.group.active .background {
|
||||
background-color: rgba(51, 51, 51, 0.9);
|
||||
}
|
||||
|
||||
.group.hovering .background,
|
||||
.group.drop-target .background {
|
||||
background-color: rgba(27, 185, 225, 0.5);
|
||||
}
|
||||
|
||||
.group .shadow {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.edit-mode .group.active .shadow {
|
||||
background-color: transparent;
|
||||
box-shadow: 0 0.9rem 1.2rem rgba(0, 0, 0, 0.63);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.group .separator {
|
||||
margin: 0;
|
||||
height: 0.8rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.group .separator > span {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform 0.25s, opacity 0.25s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.group.odd .separator {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.group.odd .separator > span {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.edit-mode .group .separator,
|
||||
.edit-mode .group .separator > span {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* For preventing entering edit mode when long-pressing on a placeholder */
|
||||
.edit-mode .group .background,
|
||||
.edit-mode .group .shadow,
|
||||
|
||||
.group.collapsed .header,
|
||||
.group.collapsed .background,
|
||||
.group.collapsed .shadow {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.edit-mode .group.collapsed .background {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.dragging .group:not(.active) .separator {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.dragging .group:not(.active):not(.invalid-drop) .separator > span {
|
||||
background-color: #0095dd;
|
||||
transform: scaleY(0.325);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.dragging .group.hovered:not(.active) .separator > span {
|
||||
transform: scaleY(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* A hint element for dragging items to the top of the group */
|
||||
.edit-mode::after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 0.8rem;
|
||||
z-index: 2;
|
||||
opacity: 0;
|
||||
background-color: #0095dd;
|
||||
|
||||
position: relative;
|
||||
top: -0.8rem;
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
.edit-mode.hover-over-top::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Shift container downwards when hovering over the top to reveal the group
|
||||
* creation hint.
|
||||
*/
|
||||
.edit-mode {
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
|
||||
.edit-mode.hover-over-top {
|
||||
transform: translateY(0.8rem);
|
||||
}
|
||||
|
||||
/* RTL View */
|
||||
:-moz-dir(rtl) .group .header .toggle {
|
||||
left: 0;
|
||||
right: unset;
|
||||
}
|
||||
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 378 B |
|
After Width: | Height: | Size: 485 B |
|
After Width: | Height: | Size: 321 B |
|
After Width: | Height: | Size: 562 B |
|
After Width: | Height: | Size: 674 B |
|
|
@ -0,0 +1,314 @@
|
|||
/* ----------------------------------
|
||||
* gaia_menu
|
||||
* ---------------------------------- */
|
||||
|
||||
/* default alignment follows the UI direction, not the content direction */
|
||||
:-moz-dir(ltr) [dir] { text-align: left; }
|
||||
:-moz-dir(rtl) [dir] { text-align: right; }
|
||||
|
||||
/* Main dialog setup */
|
||||
gaia-menu {
|
||||
background-color: #2d2d2d;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 0 0 7rem;
|
||||
/**
|
||||
* Using "font-size: 0" to avoid the unwanted visual space (about 3px) created
|
||||
* by white spaces and line breaks in the code between inline-block elements.
|
||||
*/
|
||||
font-size: 0;
|
||||
color: #fff;
|
||||
display: block;
|
||||
transition: transform ease-in-out var(--transition-duration),
|
||||
visibility var(--transition-duration);
|
||||
}
|
||||
|
||||
gaia-menu[hidden] {
|
||||
transform: translateY(100%);
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
gaia-menu:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 0.1rem;
|
||||
height: 100%;
|
||||
margin-inline-start: -0.1rem;
|
||||
}
|
||||
|
||||
header {
|
||||
-moz-box-sizing: border-box;
|
||||
font-size: 1.6rem;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
height: 5rem;
|
||||
line-height: 4.9rem;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
font-weight: normal;
|
||||
padding: 0 3rem;
|
||||
border-bottom: 0.1rem solid #616262;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
font-size: 1.6rem;
|
||||
line-height: 4.9rem;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* Generic set of actions in toolbar */
|
||||
header menu.toolbar {
|
||||
height: 100%;
|
||||
margin: 0 -3rem;
|
||||
margin-inline-start: 1rem;
|
||||
padding: 0;
|
||||
}
|
||||
header:-moz-dir(ltr) menu.toolbar { float: right; }
|
||||
header:-moz-dir(rtl) menu.toolbar { float: left; }
|
||||
|
||||
header menu.toolbar a,
|
||||
header menu.toolbar button {
|
||||
-moz-box-sizing: border-box;
|
||||
position: relative;
|
||||
width: auto;
|
||||
min-width: 5rem;
|
||||
height: 4.9rem;
|
||||
margin-bottom: 0;
|
||||
padding: 0 1rem;
|
||||
border-radius: 0;
|
||||
line-height: 4.9rem;
|
||||
background: none;
|
||||
text-align: center;
|
||||
text-shadow: none;
|
||||
z-index: 5;
|
||||
}
|
||||
header:-moz-dir(ltr) menu.toolbar a,
|
||||
header:-moz-dir(ltr) menu.toolbar button {
|
||||
float: left;
|
||||
}
|
||||
header:-moz-dir(rtl) menu.toolbar a,
|
||||
header:-moz-dir(rtl) menu.toolbar button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
header a,
|
||||
header button {
|
||||
border: none;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
font-weight: 400;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.1em;
|
||||
color: #fff;
|
||||
border-radius: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Pressed state */
|
||||
header a:active .icon:after,
|
||||
header button:active .icon:after,
|
||||
header menu.toolbar a:active,
|
||||
header menu.toolbar button:active {
|
||||
background: #008aaa;
|
||||
}
|
||||
|
||||
/* Disabled state */
|
||||
header menu.toolbar a[aria-disabled="true"],
|
||||
header menu.toolbar button[disabled] {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Icon definitions */
|
||||
header .icon {
|
||||
position: relative;
|
||||
float: none;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 4rem;
|
||||
height: 4.9rem;
|
||||
margin: 0 -1rem;
|
||||
background: transparent no-repeat center center / 3rem auto;
|
||||
font-size: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header .icon.icon-close {
|
||||
background-image: image-set(url("images/icons/close.png") 1x, url("images/icons/close@1.5x.png") 1.5x, url("images/icons/close@2x.png") 2x, url("images/icons/close@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
header .icon.icon-back {
|
||||
background-image: image-set(url("images/icons/back.png") 1x, url("images/icons/back@1.5x.png") 1.5x, url("images/icons/back@2x.png") 2x, url("images/icons/back@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
/* Navigation links (back, cancel, etc) */
|
||||
header > button,
|
||||
header > a {
|
||||
width: 5rem;
|
||||
height: 4.9rem;
|
||||
background: none;
|
||||
overflow: visible;
|
||||
margin: 0 -1rem;
|
||||
margin-inline-start: -3rem;
|
||||
position: relative;
|
||||
}
|
||||
header:-moz-dir(ltr) > button,
|
||||
header:-moz-dir(ltr) > a {
|
||||
float: left;
|
||||
}
|
||||
header:-moz-dir(rtl) > button,
|
||||
header:-moz-dir(rtl) > a {
|
||||
float: right;
|
||||
}
|
||||
|
||||
header > button::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
header > button .icon,
|
||||
header > a .icon {
|
||||
position: static;
|
||||
display: block;
|
||||
width: 3rem;
|
||||
height: 4.9rem;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
header > button .icon:after,
|
||||
header > a .icon:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
offset-inline-start: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
width: 3rem;
|
||||
height: 4.9rem;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
section {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 7rem;
|
||||
left: 1.5rem;
|
||||
right: 1.5rem;
|
||||
bottom: 2rem;
|
||||
font-size: 1.6rem;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
/* Specific component code */
|
||||
menu {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: calc(100% - 13.5rem); /*header(5rem) + footer(7rem) + padding(1.5rem)*/
|
||||
height: auto;
|
||||
padding-top: 1.5rem;
|
||||
overflow: auto;
|
||||
width: auto;
|
||||
border: none;
|
||||
background: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 7rem;
|
||||
}
|
||||
|
||||
button {
|
||||
width: calc(100% - 3rem);
|
||||
height: 4rem;
|
||||
-moz-box-sizing: border-box;
|
||||
vertical-align: middle;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-weight: normal;
|
||||
line-height: 4rem;
|
||||
outline: none;
|
||||
font-size: 1.6rem;
|
||||
text-shadow: none;
|
||||
padding: 0 1.2rem;
|
||||
margin: 0 1.5rem 1rem;
|
||||
background: rgba(87, 87, 87, 0.8);
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
position: relative;
|
||||
color: #fff;
|
||||
font-family: sans-serif;
|
||||
font-style: italic;
|
||||
}
|
||||
button:-moz-dir(ltr) { text-align: left; }
|
||||
button:-moz-dir(rtl) { text-align: right; }
|
||||
|
||||
span.gaia-menu-cancel {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
background: #4d4d4d;
|
||||
height: 7rem;
|
||||
offset-inline-start: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
span.gaia-menu-cancel button {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
offset-inline-start: 0;
|
||||
color: #333;
|
||||
background: #d8d8d8;
|
||||
text-align: center;
|
||||
border: none;
|
||||
margin-bottom: 1.5rem;
|
||||
border-radius: 2rem;
|
||||
}
|
||||
|
||||
button:nth-last-child(2) {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* Press state */
|
||||
button:active,
|
||||
span.gaia-menu-cancel button:active {
|
||||
background: #00aacc;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
button[disabled] {
|
||||
background-color: rgba(87, 87, 87, 0.8);
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
button[disabled]:last-child {
|
||||
background-color: #e7e7e7;
|
||||
color: #a6a6a6;
|
||||
opacity: 1;
|
||||
}
|
||||
|
After Width: | Height: | Size: 912 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,99 @@
|
|||
.pin-card {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
background-size: cover;
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
font-family: sans-serif;
|
||||
line-height: normal;
|
||||
white-space: normal;
|
||||
font-size: 1.2rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.pin-card > * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.pin-card .background {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 47%;
|
||||
opacity: 0.7;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 0;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.pin-card i {
|
||||
position: absolute;
|
||||
top: .15rem;
|
||||
left: .15rem;
|
||||
width: 3.03rem;
|
||||
height: 3.03rem;
|
||||
background: image-set(url("images/default_icon.png") 1x, url("images/default_icon@1.5x.png") 1.5x, url("images/default_icon@2x.png") 2x, url("images/default_icon@2.25x.png") 2.25x);
|
||||
background-size: 3.5rem 3.5rem;
|
||||
background-position: center center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
position: absolute;
|
||||
top: 4.8rem;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
left: calc(50% - 1.65rem);
|
||||
width: 3.33rem;
|
||||
height: 3.33rem;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.15);
|
||||
background-color: white;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.pin-card .content {
|
||||
position: relative;
|
||||
height: 53%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pin-card header {
|
||||
position: relative;
|
||||
height: 1.6rem;
|
||||
color: #5f5f5f;
|
||||
font-size: 1.4rem;
|
||||
font-style: italic;
|
||||
padding: 0 0.8rem;
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
text-overflow: ellipsis;
|
||||
top: 1.5rem;
|
||||
}
|
||||
|
||||
.pin-card.no-content header {
|
||||
top: 2.5rem;
|
||||
}
|
||||
|
||||
.pin-card.no-content .description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pin-card .description p {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
height: 3rem;
|
||||
line-height: 1.4rem;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 300;
|
||||
color: #5f5f5f;
|
||||
padding: 0 0.8rem;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 1 KiB |
|
After Width: | Height: | Size: 616 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1 KiB |
|
|
@ -0,0 +1,116 @@
|
|||
gaia-switch {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#switch {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background: none;
|
||||
}
|
||||
|
||||
#switch span {
|
||||
font-size: 1.9rem;
|
||||
color: var(--label-color);
|
||||
padding: 1rem 0;
|
||||
line-height: 3rem;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
/* Override inheriting nowrap from legacy lists building blocks. */
|
||||
white-space: normal;
|
||||
}
|
||||
#switch span:-moz-dir(ltr) { float: left; }
|
||||
#switch span:-moz-dir(rtl) { float: right; }
|
||||
|
||||
#switch span:not(:empty) {
|
||||
padding-inline-end: 6rem;
|
||||
}
|
||||
|
||||
#switch input {
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
offset-inline-start: 0;
|
||||
}
|
||||
|
||||
#switch input:checked ~ span::after {
|
||||
background-position: center bottom;
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
* ON/OFF SWITCHES
|
||||
* ---------------------------------- */
|
||||
|
||||
#switch input ~ span::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
offset-inline-end: 0;
|
||||
top: 2.5rem;
|
||||
width: 6rem;
|
||||
margin: -1.4rem 0 0;
|
||||
height: 2.7rem;
|
||||
border-radius: 1.35rem;
|
||||
overflow: hidden;
|
||||
background-color: #e6e6e6;
|
||||
background-image: image-set(url("images/background_off.png") 1x, url("images/background_off@1.5x.png") 1.5x, url("images/background_off@2.25x.png") 2.25x);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 9.2rem 2.7rem;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
#switch input ~ span:-moz-dir(ltr)::after { background-position: -3.2rem 0; }
|
||||
#switch input ~ span:-moz-dir(rtl)::after { background-position: 0 0; }
|
||||
|
||||
/* switch: 'ON' state */
|
||||
#switch input:checked ~ span:-moz-dir(ltr)::after {
|
||||
background-image: image-set(url("images/background.png") 1x, url("images/background@1.5x.png") 1.5x);
|
||||
background-position: 0 0;
|
||||
}
|
||||
#switch input:checked ~ span:-moz-dir(rtl)::after {
|
||||
background-image: image-set(url("images/background_rtl.png") 1x, url("images/background_rtl@1.5x.png") 1.5x);
|
||||
background-position: -3.2rem 0;
|
||||
}
|
||||
|
||||
/* switch: disabled state */
|
||||
#switch input:disabled ~ span::after {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
#switch input.uninit ~ span::after {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* A <details> slot may be specified in addition the the <label>.
|
||||
* When provided, it appears under the <label> and can provide additional context.
|
||||
*/
|
||||
#switch div.details {
|
||||
clear: both;
|
||||
position: relative;
|
||||
top: -1.5rem;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding-top: 0.5rem;
|
||||
padding-inline-start: 0;
|
||||
padding-inline-end: 8rem;
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.6rem;
|
||||
color: #505859;
|
||||
font-style: normal;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* A <a> link slow may be specified in addition to the <label> and <details>.
|
||||
* When provided, it will appear under the <details> section.
|
||||
*/
|
||||
gaia-switch a {
|
||||
position: relative;
|
||||
top: -0.8rem;
|
||||
font-size: 1.7rem;
|
||||
line-height: 2.4rem;
|
||||
font-weight: 400;
|
||||
color: #35679a;
|
||||
}
|
||||
321
overrides/system.gaiamobile.org/shared/style/action_menu.css
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
/* ----------------------------------
|
||||
* Action menu
|
||||
* ---------------------------------- */
|
||||
|
||||
html[dir="ltr"] [role="dialog"][data-type="action"] [dir],
|
||||
html[dir="ltr"] [role="dialog"][data-type="action"] button {
|
||||
text-align: left;
|
||||
}
|
||||
html[dir="rtl"] [role="dialog"][data-type="action"] [dir],
|
||||
html[dir="rtl"] [role="dialog"][data-type="action"] button {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Main dialog setup */
|
||||
[role="dialog"][data-type="action"] {
|
||||
background: #2d2d2d;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 0 0 7rem;
|
||||
/**
|
||||
* Using "font-size: 0" to avoid the unwanted visual space (about 3px) created
|
||||
* by white spaces and line breaks in the code between inline-block elements.
|
||||
*/
|
||||
font-size: 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"]:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 0.1rem;
|
||||
height: 100%;
|
||||
margin-inline-start: -0.1rem;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > header {
|
||||
box-sizing: border-box;
|
||||
font-size: 1.6rem;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
height: 5rem;
|
||||
line-height: 4.9rem;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
font-weight: normal;
|
||||
padding: 0 3rem;
|
||||
border-bottom: 0.1rem solid #616262;
|
||||
}
|
||||
[role="dialog"][data-type="action"] > header * {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > header h1 {
|
||||
font-size: 1.6rem;
|
||||
line-height: 4.9rem;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* Generic set of actions in toolbar */
|
||||
[role="dialog"][data-type="action"] > header menu[type="toolbar"] {
|
||||
height: 100%;
|
||||
margin: 0 -3rem;
|
||||
margin-inline-start: 1rem;
|
||||
padding: 0;
|
||||
}
|
||||
html[dir="ltr"] [role="dialog"][data-type="action"] > header menu[type="toolbar"] { float: right; }
|
||||
html[dir="rtl"] [role="dialog"][data-type="action"] > header menu[type="toolbar"] { float: left; }
|
||||
|
||||
[role="dialog"][data-type="action"] > header menu[type="toolbar"] a,
|
||||
[role="dialog"][data-type="action"] > header menu[type="toolbar"] button {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
width: auto;
|
||||
min-width: 5rem;
|
||||
height: 4.9rem;
|
||||
margin-bottom: 0;
|
||||
padding: 0 1rem;
|
||||
border-radius: 0;
|
||||
line-height: 4.9rem;
|
||||
background: none;
|
||||
text-align: center;
|
||||
text-shadow: none;
|
||||
z-index: 5;
|
||||
}
|
||||
html[dir="ltr"] [role="dialog"][data-type="action"] > header menu[type="toolbar"] a,
|
||||
html[dir="ltr"] [role="dialog"][data-type="action"] > header menu[type="toolbar"] button {
|
||||
float: left;
|
||||
}
|
||||
html[dir="rtl"] [role="dialog"][data-type="action"] > header menu[type="toolbar"] a,
|
||||
html[dir="rtl"] [role="dialog"][data-type="action"] > header menu[type="toolbar"] button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > header a,
|
||||
[role="dialog"][data-type="action"] > header button {
|
||||
border: none;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
font-weight: 400;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.1em;
|
||||
color: #fff;
|
||||
border-radius: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] button::-moz-focus-inner {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Pressed state */
|
||||
[role="dialog"][data-type="action"] > header a:active .icon:after,
|
||||
[role="dialog"][data-type="action"] > header button:active .icon:after,
|
||||
[role="dialog"][data-type="action"] > header menu[type="toolbar"] a:active,
|
||||
[role="dialog"][data-type="action"] > header menu[type="toolbar"] button:active {
|
||||
background: #008aaa !important;
|
||||
}
|
||||
|
||||
/* Disabled state */
|
||||
[role="dialog"][data-type="action"] > header menu[type="toolbar"] a[aria-disabled="true"],
|
||||
[role="dialog"][data-type="action"] > header menu[type="toolbar"] button[disabled] {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Icon definitions */
|
||||
[role="dialog"][data-type="action"] > header .icon {
|
||||
position: relative;
|
||||
float: none;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 4rem;
|
||||
height: 4.9rem;
|
||||
margin: 0 -1rem;
|
||||
background: transparent no-repeat center center / 3rem auto;
|
||||
font-size: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > header .icon.icon-close {
|
||||
background-image: image-set(url("action_menu/images/icons/close.png") 1x, url("action_menu/images/icons/close@1.5x.png") 1.5x, url("action_menu/images/icons/close@2x.png") 2x, url("action_menu/images/icons/close@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
html[dir="ltr"] [role="dialog"][data-type="action"] > header .icon.icon-back {
|
||||
background-image: image-set(url("action_menu/images/icons/left.png") 1x, url("action_menu/images/icons/left@1.5x.png") 1.5x, url("action_menu/images/icons/left@2x.png") 2x, url("action_menu/images/icons/left@2.25x.png") 2.25x);
|
||||
}
|
||||
html[dir="rtl"] [role="dialog"][data-type="action"] > header .icon.icon-back {
|
||||
background-image: image-set(url("action_menu/images/icons/right.png") 1x, url("action_menu/images/icons/right@1.5x.png") 1.5x, url("action_menu/images/icons/right@2x.png") 2x, url("action_menu/images/icons/right@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
/* Navigation links (back, cancel, etc) */
|
||||
[role="dialog"][data-type="action"] > header > button,
|
||||
[role="dialog"][data-type="action"] > header > a {
|
||||
width: 5rem;
|
||||
height: 4.9rem;
|
||||
background: none;
|
||||
overflow: visible;
|
||||
margin: 0 -1rem;
|
||||
margin-inline-start: -3rem;
|
||||
position: relative;
|
||||
}
|
||||
html[dir="ltr"] [role="dialog"][data-type="action"] > header > button,
|
||||
html[dir="ltr"] [role="dialog"][data-type="action"] > header > a {
|
||||
float: left;
|
||||
}
|
||||
html[dir="rtl"] [role="dialog"][data-type="action"] > header > button,
|
||||
html[dir="rtl"] [role="dialog"][data-type="action"] > header > a {
|
||||
float: right;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > header > button::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > header > button .icon,
|
||||
[role="dialog"][data-type="action"] > header > a .icon {
|
||||
position: static;
|
||||
display: block;
|
||||
width: 3rem;
|
||||
height: 4.9rem;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > header > button .icon:after,
|
||||
[role="dialog"][data-type="action"] > header > a .icon:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
offset-inline-start: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
width: 3rem;
|
||||
height: 4.9rem;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
[role="dialog"][data-type="action"] > section {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 7rem;
|
||||
left: 1.5rem;
|
||||
right: 1.5rem;
|
||||
bottom: 2rem;
|
||||
font-size: 1.6rem;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
/* Specific component code */
|
||||
[role="dialog"][data-type="action"] > menu {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: calc(100% - 13.5rem); /*header(5rem) + footer(7rem) + padding(1.5rem)*/
|
||||
height: auto;
|
||||
padding-top: 1.5rem;
|
||||
overflow: auto;
|
||||
width: auto;
|
||||
border: none;
|
||||
background: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 7rem;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > menu > button {
|
||||
width: calc(100% - 3rem);
|
||||
height: 4rem;
|
||||
box-sizing: border-box;
|
||||
vertical-align: middle;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-weight: normal;
|
||||
line-height: 4rem;
|
||||
outline: none;
|
||||
font-size: 1.6rem;
|
||||
text-shadow: none;
|
||||
padding: 0 1.2rem;
|
||||
margin: 0 1.5rem 1rem;
|
||||
background: rgba(87, 87, 87, 0.8);
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
position: relative;
|
||||
color: #fff;
|
||||
font-family: sans-serif;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > menu > .last-button-container {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
background-color: #4d4d4d;
|
||||
height: 7rem;
|
||||
offset-inline-start: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > menu > .last-button-container button {
|
||||
width: calc(100% - 3rem);
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
margin: 0 1.5rem 1.5rem;
|
||||
offset-inline-start: 0;
|
||||
color: #333;
|
||||
background: #d8d8d8;
|
||||
text-align: center;
|
||||
border: none;
|
||||
border-radius: 2rem;
|
||||
line-height: 4rem;
|
||||
font-size: 1.6rem;
|
||||
height: 4rem;
|
||||
font-family: sans-serif;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > menu > button:nth-last-child(2) {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* Press state */
|
||||
[role="dialog"][data-type="action"] > menu button:active {
|
||||
background: #00aacc;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
[role="dialog"][data-type="action"] > menu > button[disabled] {
|
||||
background-color: rgba(87, 87, 87, 0.8);
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="action"] > menu > .last-button-container button[disabled] {
|
||||
background-color: #e7e7e7;
|
||||
color: #a6a6a6;
|
||||
opacity: 1;
|
||||
}
|
||||
|
After Width: | Height: | Size: 321 B |
|
After Width: | Height: | Size: 562 B |
|
After Width: | Height: | Size: 674 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 378 B |
|
After Width: | Height: | Size: 485 B |
|
After Width: | Height: | Size: 220 B |
|
After Width: | Height: | Size: 316 B |
|
After Width: | Height: | Size: 420 B |
378
overrides/system.gaiamobile.org/shared/style/headers.css
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
/* -------------------------------------------------------------------
|
||||
HEADERS: layout
|
||||
Form factor or Skin dependent styles should NOT be defined here.
|
||||
------------------------------------------------------------------- */
|
||||
|
||||
section[role="region"] > header:first-child {
|
||||
position: relative;
|
||||
display: block;
|
||||
z-index: 10;
|
||||
padding: 0;
|
||||
height: 5rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child h1 {
|
||||
font-size: 2.3rem;
|
||||
line-height: 5rem;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0 1rem;
|
||||
height: 100%;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child h1 em {
|
||||
font-weight: 400;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1em;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child menu {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
html[dir="ltr"] section[role="region"] > header:first-child menu {
|
||||
float: right;
|
||||
}
|
||||
html[dir="rtl"] section[role="region"] > header:first-child menu {
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
Buttons
|
||||
---------------------------------- */
|
||||
|
||||
section[role="region"] > header:first-child a,
|
||||
section[role="region"] > header:first-child button {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
min-width: 5rem;
|
||||
width: auto;
|
||||
height: 5rem;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0 1rem;
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
font-size: 1.5rem;
|
||||
line-height: 5rem;
|
||||
border-radius: 0;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
text-shadow: none;
|
||||
font-style: italic;
|
||||
}
|
||||
html[dir="ltr"] section[role="region"] > header:first-child a,
|
||||
html[dir="ltr"] section[role="region"] > header:first-child button {
|
||||
float: left;
|
||||
}
|
||||
html[dir="rtl"] section[role="region"] > header:first-child a,
|
||||
html[dir="rtl"] section[role="region"] > header:first-child button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* Pressed state */
|
||||
section[role="region"] > header:first-child a:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child button::-moz-focus-inner {
|
||||
outline: none;
|
||||
border: none;
|
||||
margin-top: -0.2rem; /* To fix line-height bug (697451) */
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Disabled state */
|
||||
section[role="region"] > header:first-child a[aria-disabled="true"],
|
||||
section[role="region"] > header:first-child button[disabled] {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
Icons
|
||||
---------------------------------- */
|
||||
|
||||
section[role="region"] > header:first-child .icon {
|
||||
display: block;
|
||||
width: 3rem;
|
||||
height: 5rem;
|
||||
background: transparent no-repeat center / 3rem auto;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
Subheader
|
||||
---------------------------------- */
|
||||
|
||||
section[role="region"] > header {
|
||||
z-index: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
section[role="region"] header h2 {
|
||||
margin: 0;
|
||||
padding: 0.8rem 3rem;
|
||||
font-weight: 400;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.8rem;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
HEADER SKIN: default
|
||||
Default values in case we are not overriding them using
|
||||
class="skin-*"
|
||||
----------------------------------------------------------------- */
|
||||
|
||||
section[role="region"] > header:first-child {
|
||||
color: #fff;
|
||||
background-color: #f97c17;
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child h1 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child a,
|
||||
section[role="region"] > header:first-child button {
|
||||
color: rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child a:active,
|
||||
section[role="region"] > header:first-child button:active,
|
||||
section[role="region"] > header:first-child a:hover,
|
||||
section[role="region"] > header:first-child button:hover {
|
||||
background-color: rgba(0,0,0,0.07);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child a:focus,
|
||||
section[role="region"] > header:first-child button:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
Icons
|
||||
---------------------------------- */
|
||||
|
||||
section[role="region"] > header:first-child .icon-add {
|
||||
background-image: image-set(url("headers/images/icons/add.png") 1x, url("headers/images/icons/add@1.5x.png") 1.5x, url("headers/images/icons/add@2x.png") 2x, url("headers/images/icons/add@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child .icon-compose {
|
||||
background-image: image-set(url("headers/images/icons/compose.png") 1x, url("headers/images/icons/compose@1.5x.png") 1.5x, url("headers/images/icons/compose@2x.png") 2x, url("headers/images/icons/compose@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
html[dir="ltr"] section[role="region"] > header:first-child .icon-edit {
|
||||
background-image: image-set(url("headers/images/icons/edit.png") 1x, url("headers/images/icons/edit@1.5x.png") 1.5x, url("headers/images/icons/edit@2x.png") 2x, url("headers/images/icons/edit@2.25x.png") 2.25x);
|
||||
}
|
||||
html[dir="rtl"] section[role="region"] > header:first-child .icon-edit {
|
||||
background-image: image-set(url("headers/images/icons/edit-rtl.png") 1x, url("headers/images/icons/edit-rtl@1.5x.png") 1.5x, url("headers/images/icons/edit-rtl@2x.png") 2x, url("headers/images/icons/edit-rtl@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
html[dir="ltr"] section[role="region"] > header:first-child .icon-send {
|
||||
background-image: image-set(url("headers/images/icons/send.png") 1x, url("headers/images/icons/send@1.5x.png") 1.5x, url("headers/images/icons/send@2x.png") 2x, url("headers/images/icons/send@2.25x.png") 2.25x);
|
||||
}
|
||||
html[dir="rtl"] section[role="region"] > header:first-child .icon-send {
|
||||
background-image: image-set(url("headers/images/icons/send_rtl.png") 1x, url("headers/images/icons/send_rtl@1.5x.png") 1.5x, url("headers/images/icons/send_rtl@2x.png") 2x, url("headers/images/icons/send_rtl@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child .icon-close {
|
||||
background-image: image-set(url("headers/images/icons/close.png") 1x, url("headers/images/icons/close@1.5x.png") 1.5x, url("headers/images/icons/close@2x.png") 2x, url("headers/images/icons/close@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
html[dir="ltr"] section[role="region"] > header:first-child .icon-back {
|
||||
background-image: image-set(url("headers/images/icons/left.png") 1x, url("headers/images/icons/left@1.5x.png") 1.5x, url("headers/images/icons/left@2x.png") 2x, url("headers/images/icons/left@2.25x.png") 2.25x);
|
||||
}
|
||||
html[dir="rtl"] section[role="region"] > header:first-child .icon-back {
|
||||
background-image: image-set(url("headers/images/icons/right.png") 1x, url("headers/images/icons/right@1.5x.png") 1.5x, url("headers/images/icons/right@2x.png") 2x, url("headers/images/icons/right@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child .icon-menu {
|
||||
background-image: image-set(url("headers/images/icons/menu.png") 1x, url("headers/images/icons/menu@1.5x.png") 1.5x, url("headers/images/icons/menu@2x.png") 2x, url("headers/images/icons/menu@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child .icon-user {
|
||||
background-image: image-set(url("headers/images/icons/user.png") 1x, url("headers/images/icons/user@1.5x.png") 1.5x, url("headers/images/icons/user@2x.png") 2x, url("headers/images/icons/user@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child .icon-up {
|
||||
background-image: image-set(url("headers/images/icons/up.png") 1x, url("headers/images/icons/up@1.5x.png") 1.5x, url("headers/images/icons/up@2x.png") 2x, url("headers/images/icons/up@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child .icon-down {
|
||||
background-image: image-set(url("headers/images/icons/down.png") 1x, url("headers/images/icons/down@1.5x.png") 1.5x, url("headers/images/icons/down@2x.png") 2x, url("headers/images/icons/down@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child .icon-options {
|
||||
background-image: image-set(url("headers/images/icons/options.png") 1x, url("headers/images/icons/options@1.5x.png") 1.5x, url("headers/images/icons/options@2x.png") 2x, url("headers/images/icons/options@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
Subheader
|
||||
---------------------------------- */
|
||||
|
||||
section[role="region"] header h2 {
|
||||
color: #424242;
|
||||
border-bottom: solid 0.1rem #e6e6e6;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
HEADER SKIN: comms
|
||||
.skin-comms will override default values
|
||||
----------------------------------------------------------------- */
|
||||
|
||||
.skin-comms section[role="region"] > header:first-child,
|
||||
section[role="region"].skin-comms > header:first-child {
|
||||
background-color: #00adad;
|
||||
}
|
||||
|
||||
.skin-comms section[role="region"] > header:first-child a,
|
||||
.skin-comms section[role="region"] > header:first-child button,
|
||||
section[role="region"].skin-comms > header:first-child a,
|
||||
section[role="region"].skin-comms > header:first-child button {
|
||||
color: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.skin-comms section[role="region"] > header:first-child a:active,
|
||||
.skin-comms section[role="region"] > header:first-child button:active,
|
||||
.skin-comms section[role="region"] > header:first-child a:hover,
|
||||
.skin-comms section[role="region"] > header:first-child button:hover,
|
||||
section[role="region"].skin-comms > header:first-child a:active,
|
||||
section[role="region"].skin-comms > header:first-child button:active,
|
||||
section[role="region"].skin-comms > header:first-child a:hover,
|
||||
section[role="region"].skin-comms > header:first-child button:hover {
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.skin-comms section[role="region"] > header:first-child a:focus,
|
||||
.skin-comms section[role="region"] > header:first-child button:focus,
|
||||
section[role="region"].skin-comms > header:first-child a:focus,
|
||||
section[role="region"].skin-comms > header:first-child button:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
HEADER SKIN: dark
|
||||
.skin-dark will override default values
|
||||
----------------------------------------------------------------- */
|
||||
|
||||
section[role="region"].skin-dark > header:first-child,
|
||||
.skin-dark > section[role="region"] > header:first-child {
|
||||
background-color: #242d33;
|
||||
}
|
||||
|
||||
.skin-dark section[role="region"] > header:first-child a,
|
||||
.skin-dark section[role="region"] > header:first-child button,
|
||||
section[role="region"].skin-dark > header:first-child a,
|
||||
section[role="region"].skin-dark > header:first-child button {
|
||||
color: #00aac5;
|
||||
}
|
||||
|
||||
.skin-dark section[role="region"] > header:first-child a:active,
|
||||
.skin-dark section[role="region"] > header:first-child button:active,
|
||||
.skin-dark section[role="region"] > header:first-child a:hover,
|
||||
.skin-dark section[role="region"] > header:first-child button:hover,
|
||||
section[role="region"].skin-dark > header:first-child a:active,
|
||||
section[role="region"].skin-dark > header:first-child button:active,
|
||||
section[role="region"].skin-dark > header:first-child a:hover,
|
||||
section[role="region"].skin-dark > header:first-child button:hover {
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.skin-dark section[role="region"] > header:first-child a:focus,
|
||||
.skin-dark section[role="region"] > header:first-child button:focus,
|
||||
section[role="region"].skin-dark > header:first-child a:focus,
|
||||
section[role="region"].skin-dark > header:first-child button:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
section[role="region"].skin-dark header h2,
|
||||
.skin-dark > section[role="region"] header h2 {
|
||||
background-color: #2c353b;
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
HEADER SKIN: organic
|
||||
.skin-organic will override default values
|
||||
----------------------------------------------------------------- */
|
||||
|
||||
section[role="region"].skin-organic > header:first-child,
|
||||
.skin-organic section[role="region"] > header:first-child {
|
||||
color: #868692;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
section[role="region"].skin-organic > header:first-child h1,
|
||||
.skin-organic section[role="region"] > header:first-child h1 {
|
||||
color: #868692;
|
||||
}
|
||||
|
||||
section[role="region"].skin-organic > header:first-child a,
|
||||
section[role="region"].skin-organic > header:first-child button,
|
||||
.skin-organic section[role="region"] > header:first-child a,
|
||||
.skin-organic section[role="region"] > header:first-child button {
|
||||
color: #00aac5;
|
||||
}
|
||||
|
||||
section[role="region"].skin-organic > header:first-child a:focus,
|
||||
section[role="region"].skin-organic > header:first-child button:focus,
|
||||
.skin-organic section[role="region"] > header:first-child a:focus,
|
||||
.skin-organic section[role="region"] > header:first-child button:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
Icons
|
||||
---------------------------------- */
|
||||
|
||||
html[dir="ltr"] section[role="region"].skin-organic > header:first-child .icon-back,
|
||||
html[dir="ltr"] .skin-organic section[role="region"] > header:first-child .icon-back {
|
||||
background-image: image-set(url("headers/images/icons/organic/left.png") 1x, url("headers/images/icons/organic/left@1.5x.png") 1.5x, url("headers/images/icons/organic/left@2x.png") 2x, url("headers/images/icons/organic/left@2.25x.png") 2.25x);
|
||||
}
|
||||
html[dir="rtl"] section[role="region"].skin-organic > header:first-child .icon-back,
|
||||
html[dir="rtl"] .skin-organic section[role="region"] > header:first-child .icon-back {
|
||||
background-image: image-set(url("headers/images/icons/organic/right.png") 1x, url("headers/images/icons/organic/right@1.5x.png") 1.5x, url("headers/images/icons/organic/right@2x.png") 2x, url("headers/images/icons/organic/right@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"].skin-organic > header:first-child .icon-close,
|
||||
.skin-organic section[role="region"] > header:first-child .icon-close {
|
||||
background-image: image-set(url("headers/images/icons/organic/close.png") 1x, url("headers/images/icons/organic/close@1.5x.png") 1.5x, url("headers/images/icons/organic/close@2x.png") 2x, url("headers/images/icons/organic/close@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
section[role="region"].skin-organic > header:first-child .icon-add,
|
||||
.skin-organic section[role="region"] > header:first-child .icon-add {
|
||||
background-image: image-set(url("headers/images/icons/organic/add.png") 1x, url("headers/images/icons/organic/add@1.5x.png") 1.5x, url("headers/images/icons/organic/add@2x.png") 2x, url("headers/images/icons/organic/add@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
html[dir="ltr"] section[role="region"].skin-organic > header:first-child .icon-edit,
|
||||
html[dir="ltr"] .skin-organic section[role="region"] > header:first-child .icon-edit {
|
||||
background-image: image-set(url("headers/images/icons/organic/edit.png") 1x, url("headers/images/icons/organic/edit@1.5x.png") 1.5x, url("headers/images/icons/organic/edit@2x.png") 2x, url("headers/images/icons/organic/edit@2.25x.png") 2.25x);
|
||||
}
|
||||
html[dir="rtl"] section[role="region"].skin-organic > header:first-child .icon-edit,
|
||||
html[dir="rtl"] .skin-organic section[role="region"] > header:first-child .icon-edit {
|
||||
background-image: image-set(url("headers/images/icons/organic/edit-rtl.png") 1x, url("headers/images/icons/organic/edit-rtl@1.5x.png") 1.5x, url("headers/images/icons/organic/edit-rtl@2x.png") 2x, url("headers/images/icons/organic/edit-rtl@2.25x.png") 2.25x);
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
Subheader
|
||||
---------------------------------- */
|
||||
|
||||
section[role="region"].skin-organic header h2,
|
||||
.skin-organic section[role="region"] header h2 {
|
||||
background-color: #e7e7e7;
|
||||
color: #4d4d4d;
|
||||
border: none;
|
||||
}
|
||||
|
After Width: | Height: | Size: 171 B |