Publish Vulpes Preview 15 sources for desktop, Android and Tundra

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

View file

@ -0,0 +1,182 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<meta charset="utf-8">
<meta name="theme-group" content="theme-communications">
<meta name="theme-color" content="var(--header-background)">
<title>Inbox</title>
<!--App Style root.css-->
<link rel="stylesheet" type="text/css" href="/views/shared/style/root.css">
<!-- Stable Building blocks -->
<link rel="stylesheet" type="text/css" href="/shared/style/animations.css">
<link rel="stylesheet" type="text/css" href="/shared/style/action_menu.css">
<link rel="stylesheet" type="text/css" href="/shared/style/option_menu.css">
<link rel="stylesheet" type="text/css" href="/shared/style/buttons.css">
<link rel="stylesheet" type="text/css" href="/shared/style/confirm.css">
<link rel="stylesheet" type="text/css" href="/shared/style/edit_mode.css">
<link rel="stylesheet" type="text/css" href="/shared/style/switches.css">
<link rel="stylesheet" type="text/css" href="/shared/style/lists.css">
<link rel="stylesheet" type="text/css" href="/shared/style/tabs.css" >
<link rel="stylesheet" type="text/css" href="/shared/style/progress_activity.css">
<link rel="stylesheet" type="text/css" href="/shared/style/status.css">
<link rel="stylesheet" type="text/css" href="/shared/elements/gaia-icons/gaia-icons.css">
<!-- App styles -->
<link rel="stylesheet" type="text/css" href="/views/shared/style/sms.css">
<link rel="stylesheet" type="text/css" href="/views/shared/style/panel.css">
<link rel="stylesheet" type="text/css" href="/views/shared/style/edit-mode.css">
<link rel="stylesheet" type="text/css" href="/views/shared/style/notification.css">
<link rel="stylesheet" type="text/css" href="/views/shared/style/common.css">
<link rel="stylesheet" type="text/css" href="/views/inbox/style/inbox.css">
<link rel="stylesheet" type="text/css" href="/views/inbox/style/edit-mode.css">
<!-- Localization -->
<meta name="defaultLanguage" content="en-US">
<meta name="availableLanguages" content="en-US">
<link rel="localization" href="/locales/sms.{locale}.properties">
<link rel="localization" href="/shared/locales/date/date.{locale}.properties">
<script defer src="/mocks/navigator_moz_icc_manager.js"></script>
<!-- Firefox Desktop shims -->
<script defer src="/desktop-mock/navigator_moz_system_messages.js"></script>
<script defer src="/desktop-mock/navigator_moz_settings.js"></script>
<script defer src="/desktop-mock/navigator_moz_mobilemessage.js"></script>
<script defer src="/desktop-mock/navigator_moz_contacts.js"></script>
<!-- Web Components -->
<script defer src="/shared/elements/config.js"></script>
<link rel="stylesheet" type="text/css" href="app://theme.gaiamobile.org/shared/elements/gaia-theme/gaia-theme.css" />
<script async src="/shared/elements/gaia-header/dist/gaia-header.js"></script>
<!-- Shared code -->
<script defer src="/shared/js/intl/l20n.js"></script>
<!-- Should be removed while gecko support navigator.mozHour12 API -->
<script defer src="/shared/js/date_time_helper.js"></script>
<script defer src="/shared/js/template.js"></script>
<script defer src="/shared/js/async_storage.js"></script>
<script defer src="/shared/js/lazy_loader.js"></script>
<script defer src="/shared/js/sticky_header.js"></script>
<script defer src="/shared/js/contact_photo_helper.js"></script>
<script defer src="/shared/js/fb/fb_request.js"></script>
<script defer src="/shared/js/fb/fb_data_reader.js"></script>
<script defer src="/shared/js/fb/fb_reader_utils.js"></script>
<script defer src="/shared/js/event_dispatcher.js"></script>
<script defer src="/views/shared/js/utils.js"></script>
<script defer src="/views/shared/js/navigation.js"></script>
<script defer src="/views/shared/js/inter_instance_event_dispatcher.js"></script>
<script defer src="/views/shared/js/time_headers.js"></script>
<script defer src="/views/shared/js/contacts.js"></script>
<script defer src="/services/js/drafts.js"></script>
<script defer src="/services/js/threads.js"></script>
<script defer src="/views/inbox/js/inbox.js"></script>
<script defer src="/views/shared/js/settings.js"></script>
<script defer src="/lib/bridge/client.js"></script>
<script defer src="/lib/bridge/plugins/stream/client.js"></script>
<script defer src="/services/js/conversation/conversation_client.js"></script>
<script defer src="/services/js/message_manager.js"></script>
<script defer src="/views/shared/js/app.js"></script>
<script defer src="/views/inbox/js/startup.js"></script>
<script defer src="/views/shared/js/bootstrap.js"></script>
<!-- Lazy load scripts
<script defer src="/shared/js/option_menu.js"></script>
<script defer src="/views/shared/js/dialog.js"></script>
<script defer src="/views/shared/js/waiting_screen.js"></script>
<script defer src="/views/shared/js/activity_picker.js"></script>
-->
</head>
<body role="application" class="skin-comms theme-communications">
<iframe src="/views/shared/shim_host.html" class="shim-host" hidden></iframe>
<article id="main-wrapper" class="wrapper">
<section class="panel panel-InboxView" role="region" aria-hidden="true">
<!-- title-start and title-end indicates the button widths respectively
at the start and end of the line -->
<!-- see https://github.com/gaia-components/gaia-header/ for more information -->
<!-- WARNING: the actual value depends on the actual CSS being used in gaia-header -->
<gaia-header class="view-header regular-header" title-start="0" title-end="100">
<h1 data-l10n-id="messages"></h1>
<a href="#/composer" id="threads-composer-link" data-icon="compose" data-l10n-id="composeLink"></a>
<a id="threads-options-button" data-icon="more" data-l10n-id="actionsButton"></a>
<a id="threads-settings-button" data-icon="settings" data-l10n-id="settingsButton"></a>
</gaia-header>
<article id="threads-container" class="view-body edit-container" data-type="list">
</article>
<div id="threads-no-messages">
<div id="no-result-message">
<p data-l10n-id="noMessages-title">No messages</p>
<p data-l10n-id="noMessages-text-2">Start a conversation now</p>
</div>
</div>
<form id="threads-edit-form" role="dialog" data-type="edit">
<section role="region" class="theme-settings">
<gaia-header id="threads-edit-header" action="close" no-font-fit>
<h1 id="threads-edit-mode" data-l10n-id="selectThreads-title"></h1>
<button id="threads-check-uncheck-all-button" class="edit-button" data-l10n-id="select-all"></button>
</gaia-header>
</section>
<div class="bottom-tab" role="region" >
<ul class="bb-tablist">
<li role="presentation">
<button id="threads-delete-button" class="disable-when-dialog-animates" data-action="delete-button"></button>
</li>
<li role="presentation">
<button id="threads-read-unread-button" data-action="mark-as-read"></button>
</li>
</ul>
</div>
</form>
<section id="threads-draft-saved-banner" class="hide" role="status">
<p data-l10n-id="message-draft-saved">Message saved as draft</p>
</section>
<div id="sticky"></div>
</section>
</article>
<article id="loading">
<form role="dialog" data-type="confirm" class="loading-container">
<section>
<p class="loading-header" data-l10n-id="deleting-messages">Deleting messages...</p>
<div role="status">
<progress class="small"></progress>
</div>
</section>
</form>
</article>
<!--
- Templates
-->
<div id="messages-thread-tmpl" class="hide">
<!--
<label class="pack-checkbox negative">
<input type="checkbox" value="${id}" data-mode="${mode}">
<span></span>
</label>
<a href="${hash}">
<aside role="note" class="icon icon-unread icon-draft js-conversation-state"></aside>
<aside class="pack-end threadlist-item-picture"
role="img" aria-label="Contact photo"
data-l10n-id="contact-photo">
<span data-type="img"></span>
</aside>
<p class="threadlist-item-title"><bdi class="ellipsis-dir-fix"></bdi></p>
<p class="summary">
<time data-time-update="true" data-time-only="true" data-time="${timestamp}"></time>
<span class="mms-icon" data-l10n-id="mms-label">MMS</span>
<span dir="auto" class="body-text js-conversation-body ellipsis-dir-fix"></span>
</p>
</a>
-->
</div>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,57 @@
/* global App,
ConversationClient,
Drafts,
InboxView,
InterInstanceEventDispatcher,
LazyLoader,
MessageManager,
Navigation,
Settings,
TimeHeaders,
Utils
*/
(function(exports) {
'use strict';
const LAZY_DEPENDENCIES = [
'/shared/js/option_menu.js',
'/views/shared/js/waiting_screen.js',
'/views/shared/js/dialog.js',
'/views/shared/js/error_dialog.js',
'/views/shared/js/activity_picker.js'
];
function initLazyDependencies() {
return LazyLoader.load(LAZY_DEPENDENCIES).then(() => {
TimeHeaders.init();
Settings.init();
Navigation.setReady();
InterInstanceEventDispatcher.connect();
});
}
exports.Startup = {
init() {
Utils.initializeShimHost(App.instanceId);
ConversationClient.init(App.instanceId);
MessageManager.init();
Navigation.init();
Drafts.init();
InboxView.init();
InboxView.once('visually-loaded', () => {
initLazyDependencies();
});
InboxView.once('fully-loaded', () => {
App.setReady();
});
InboxView.renderThreads();
}
};
})(window);

View file

@ -0,0 +1,36 @@
/*
* This file contains styles for Inbox view edit mode. They complement styles
* from views/shared/style/edit-mode.css that are applied as well.
* View edit mode is activated via Options -> Select threads.
*/
.bb-tablist > li button[data-action="mark-as-read"] {
background-image: url("images/icons/ico_in_markasread_30x30.png");
}
.bb-tablist > li button[data-action="mark-as-unread"] {
background-image: url("images/icons/ico_in_markasunread_30x30.png");
}
.edit #threads-container[data-type="list"] {
height: calc(100% - 10rem);
}
html[dir="ltr"] .edit [data-type="list"] li > a > aside.icon-unread {
transform: translateX(5rem);
}
html[dir="rtl"] .edit [data-type="list"] li > a > aside.icon-unread {
transform: translateX(-5rem);
}
.edit #threads-container aside.pack-end {
margin-inline-start: 4rem;
}
html[dir="ltr"] .edit #threads-container[data-type="list"] aside.pack-end span {
transform: translateX(1.5rem);
}
html[dir="rtl"] .edit #threads-container[data-type="list"] aside.pack-end span {
transform: translateX(-1.5rem);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

View file

@ -0,0 +1,191 @@
#sticky {
position: absolute;
/* The sticky element is positioned at the beginning of the list. */
top: 5rem;
/* The width is not 100% so the scrollbar is visible. */
width: calc(100% - 2rem);
/* The height needs to be kept in sync with the header height. */
height: 3.1rem;
/* Leaving 1rem margin for both side to makes scrollbar visible in LTR/RTL */
margin: 0 1rem;
/* The sticky element needs to be above the list. */
z-index: 2;
/* Hide sticky header when content is not ready */
visibility: hidden;
/* Those style will affect the backgroundImage: -moz-element. */
background: white no-repeat center top;
}
#sticky.has-content {
/* Set sticky header visible only when content is ready */
visibility: visible;
}
#threads-container[data-type="list"] header {
background: #fff;
}
#threads-container[data-type="list"] ul {
padding: 0 1.0rem;
background-color: #fff;
}
#threads-container[data-type="list"] .mms-icon {
display: none;
font-size: 1.5rem;
color: #ff6622;
}
#threads-container[data-type="list"] [data-last-message-type="mms"] .mms-icon {
display: inline;
}
#threads-container[data-type="list"] [data-last-message-type="mms"] .body-text {
display: none;
}
.threadlist-item-picture {
display: none;
}
.threadlist-item-picture.has-picture {
display: block;
}
.threadlist-item .default-picture > span[data-type=img],
.threadlist-item .group-picture > span[data-type=img] {
/* Please keep this image in sync with what is used in js/inbox.js */
background: url('images/default_contact_image.png') top left; /* BiDi proof: CSS sprites */
}
.threadlist-item:nth-child(even) .default-picture > span[data-type=img],
.threadlist-item:nth-child(even) .group-picture > span[data-type=img] {
background-position: bottom right; /* BiDi proof: CSS sprites */
}
.threadlist-item:nth-child(3n+1) .default-picture > span[data-type=img],
.threadlist-item:nth-child(3n+1) .group-picture > span[data-type=img] {
background-position: top right; /* BiDi proof: CSS sprites */
}
.threadlist-item:nth-child(4n+4) .default-picture > span[data-type=img],
.threadlist-item:nth-child(4n+4) .group-picture > span[data-type=img] {
background-position: center center;
}
.threadlist-item-picture.group-picture > span[data-type=img] {
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 2.5rem;
}
/**
* Bug 967878, 979018 -[Messages] Background doesn't
* scroll with the threads causing expensive over-invalidation
*/
#threads-container > div {
background-color: #fff;
}
[data-type="list"] aside.icon-unread {
margin: 0;
width: 1.9rem;
visibility: hidden;
}
[data-type="list"] .unread aside.icon-unread {
background: url("images/unread.png") no-repeat;
background-size: 1rem;
visibility: visible;
}
[data-type="list"] .threadlist-item a * {
pointer-events: none;
}
[data-type="list"] .summary {
display: flex;
}
[data-type="list"] .draft .icon-draft {
background: url("images/draft.png") no-repeat;
background-size: 1.2rem;
visibility: visible;
}
[data-type="list"] .is-draft .pack-end {
opacity: 0.5;
}
[data-type="list"] .is-draft .threadlist-item-title {
font-style: italic;
color: #5f5f5f;
}
/* Override time margin for flex layout */
[data-type="list"] .summary time {
display: inline-block;
margin-inline-end: 1rem;
}
[data-type="list"] .unread .summary time {
color: #1D8399;
}
/* Empty Inbox layout */
#threads-no-messages {
background: url("images/SMS_200x200_bubble.png")
no-repeat center;
background-size: 20rem;
overflow-y: auto;
overflow-x: hidden;
height: calc(100% - 5rem);
width: 100%;
}
#no-result-message {
position: relative;
top: 50%;
width: 27rem;
padding: 2rem 0.5rem;
margin: -8rem auto;
border-top: .1rem solid rgba(96,96,96,.5);
line-height: 3rem;
text-align: start;
font-weight: 300;
font-size: 2.2rem;
color: #606060;
}
#threads-no-messages, .threadlist-is-empty #threads-container {
display: none;
}
/* Using !important to override scoped style in gaia-header component. */
#threads-settings-button, .threadlist-is-empty #threads-options-button {
display: none !important;
}
/* Using flex to center the content. */
.threadlist-is-empty #threads-settings-button {
display: flex !important;
}
.threadlist-is-empty #threads-no-messages {
display: block;
}

View file

@ -0,0 +1,3 @@
{
"extends": "../../../../test/unit/.jshintrc"
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,109 @@
/*global App,
ConversationClient,
Drafts,
InboxView,
InterInstanceEventDispatcher,
LazyLoader,
MessageManager,
MocksHelper,
Navigation,
Settings,
Startup,
TimeHeaders,
Utils
*/
'use strict';
require('/views/shared/test/unit/mock_time_headers.js');
require('/views/shared/test/unit/mock_navigation.js');
require('/views/shared/test/unit/mock_settings.js');
require('/views/shared/test/unit/mock_inter_instance_event_dispatcher.js');
require('/views/shared/test/unit/mock_inbox.js');
require('/views/shared/test/unit/mock_app.js');
require('/views/shared/js/utils.js');
require('/views/shared/test/unit/mock_utils.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
require('/services/test/unit/mock_message_manager.js');
require('/services/test/unit/mock_drafts.js');
require('/services/test/unit/conversation/mock_conversation_client.js');
require('/views/inbox/js/startup.js');
var MocksHelperForInboxStartup = new MocksHelper([
'App',
'ConversationClient',
'Drafts',
'InboxView',
'InterInstanceEventDispatcher',
'LazyLoader',
'MessageManager',
'Navigation',
'Settings',
'TimeHeaders',
'Utils'
]).init();
suite('InboxView Startup', function() {
MocksHelperForInboxStartup.attachTestHelpers();
setup(function() {
this.sinon.spy(App, 'setReady');
this.sinon.spy(MessageManager, 'init');
this.sinon.spy(Navigation, 'init');
this.sinon.spy(InboxView, 'init');
this.sinon.spy(InboxView, 'renderThreads');
this.sinon.spy(TimeHeaders, 'init');
this.sinon.spy(Settings, 'init');
this.sinon.spy(Navigation, 'setReady');
this.sinon.spy(InterInstanceEventDispatcher, 'connect');
this.sinon.stub(InboxView, 'once');
this.sinon.stub(LazyLoader, 'load').returns(Promise.resolve());
this.sinon.stub(ConversationClient, 'init');
this.sinon.spy(Utils, 'initializeShimHost');
this.sinon.stub(Drafts, 'init');
Startup.init();
});
test('correctly initializes dependencies', function() {
sinon.assert.calledWith(Utils.initializeShimHost, App.instanceId);
sinon.assert.calledWith(ConversationClient.init, App.instanceId);
sinon.assert.calledOnce(MessageManager.init);
sinon.assert.calledOnce(Navigation.init);
sinon.assert.calledOnce(Drafts.init);
sinon.assert.calledOnce(InboxView.init);
sinon.assert.calledOnce(InboxView.renderThreads);
});
test('starts non-critical initializations only once view is visually ready',
function() {
// Lazy loading is not started yet and headers are not processed either.
sinon.assert.notCalled(LazyLoader.load);
InboxView.once.withArgs('visually-loaded').yield();
sinon.assert.calledOnce(LazyLoader.load);
});
test('correctly initializes lazy dependencies', function(done) {
InboxView.once.withArgs('visually-loaded').yield();
LazyLoader.load.lastCall.returnValue.then(() => {
sinon.assert.calledOnce(TimeHeaders.init);
sinon.assert.calledOnce(Settings.init);
sinon.assert.calledOnce(Navigation.setReady);
sinon.assert.calledOnce(InterInstanceEventDispatcher.connect);
}).then(done, done);
});
test('app is marked as ready only on fully loaded', function() {
InboxView.once.withArgs('visually-loaded').yield();
sinon.assert.notCalled(App.setReady);
InboxView.once.withArgs('fully-loaded').yield();
sinon.assert.calledOnce(App.setReady);
});
});