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,397 @@
/* global require, module */
'use strict';
var assert = require('assert');
function Music(client, origin) {
this.client = client;
this.origin = origin || ('app://' + Music.DEFAULT_ORIGIN);
this.actions = client.loader.getActions();
}
module.exports = Music;
Music.DEFAULT_ORIGIN = 'music-oga.gaiamobile.org';
Music.Selector = Object.freeze({
messageOverlay: '#overlay',
firstTile: '.tile',
playlistsTab: '#tabs-playlists',
artistsTab: '#tabs-artists',
songsTab: '#tabs-songs',
albumsTab: '#tabs-albums',
playerCover: '#player-cover',
// search fields
searchField: '#views-search-input',
searchTiles: '#views-tiles-search',
searchTilesField: '#views-tiles-search-input',
searchList: '#views-list-search',
searchListField: '#views-list-search-input',
// search results
searchArtists: '#views-search-artists',
searchAlbums: '#views-search-albums',
searchTitles: '#views-search-titles',
searchNoResult: '#views-search-no-result',
tilesView: '#views-tiles',
listView: '#views-list',
viewsList: '#views-list-anchor',
sublistView: '#views-sublist',
viewsSublist: '#views-sublist-anchor',
sublistViewControls: '#views-sublist-header-controls',
firstListItem: '.list-item',
firstSong: '.list-item',
firstSongSublist: '#views-sublist .list-item',
playerView: '#views-player',
playButton: '#player-controls-play',
progressBar: '#player-seek-bar-progress',
shareButton: '#player-cover-share',
ratingBar: '#player-album-rating',
ratingStarsOn: 'button.star-on',
shareMenu: 'form[data-z-index-level="action-menu"]',
pickDoneButton: '#title-done',
header: '#title',
titleText: '#title-text',
sublistShuffleButton: '#views-sublist-controls-shuffle',
playerIcon: '#title-player'
});
Music.prototype = {
client: null,
get messageOverlay() {
return this.client.findElement(Music.Selector.messageOverlay);
},
get firstTile() {
return this.client.findElement(Music.Selector.firstTile);
},
get playlistsTab() {
return this.client.helper.waitForElement(Music.Selector.playlistsTab);
},
get artistsTab() {
return this.client.helper.waitForElement(Music.Selector.artistsTab);
},
get songsTab() {
return this.client.helper.waitForElement(Music.Selector.songsTab);
},
get albumsTab() {
return this.client.helper.waitForElement(Music.Selector.albumsTab);
},
get firstSong() {
return this.client.helper.waitForElement(Music.Selector.firstSong);
},
get firstSongSublist() {
return this.client.helper.waitForElement(Music.Selector.firstSongSublist);
},
// Helper for the getter.
_getListItems: function(selector) {
this.waitForAList(selector);
var list = this.client.findElement(selector);
assert.ok(list, 'Couldn\'t find element ' + selector);
var list_items = list.findElements('li.list-item', 'css selector');
assert.ok(list_items, 'Coudln\'t find list-items for ' + selector);
return list_items;
},
get firstListItem() {
return this.client.helper.waitForElement(Music.Selector.firstListItem);
},
get listItems() {
return this._getListItems(Music.Selector.viewsList);
},
get songs() {
return this._getListItems(Music.Selector.viewsSublist);
},
get playButton() {
return this.client.findElement(Music.Selector.playButton);
},
get shareButton() {
return this.client.findElement(Music.Selector.shareButton);
},
get title() {
var header = this.client.findElement(Music.Selector.header);
return header.findElement(Music.Selector.titleText);
},
get sublistShuffleButton() {
return this.client.helper.waitForElement(
Music.Selector.sublistShuffleButton);
},
// TODO(gareth): Move this shareMenu stuff into the helper.
get shareMenu() {
// Switch to the system app first.
this.client.switchToFrame();
return this.client.helper.waitForElement(Music.Selector.shareMenu);
},
get progressBar() {
return this.client.findElement(Music.Selector.progressBar);
},
get pickDoneButton() {
return this.client.findElement(Music.Selector.pickDoneButton);
},
get header() {
return this.client.findElement(Music.Selector.header);
},
get playerIcon() {
return this.client.findElement(Music.Selector.playerIcon);
},
get isPlaying() {
return this.playButton.getAttribute('class').indexOf('is-pause') === -1;
},
get songProgress() {
return parseFloat(this.progressBar.getAttribute('value'));
},
launch: function() {
this.client.switchToFrame();
this.client.apps.launch(this.origin);
this.client.apps.switchToApp(this.origin);
this.client.helper.waitForElement('body');
},
close: function() {
this.client.apps.close(this.origin);
},
switchToMe: function(options) {
options = options || {};
this.client.switchToFrame();
// Switch to music even when it is in background.
// We cannot use switchToApp here, because it will wait
// for the app to come to foreground.
if (options.background) {
var musicFrame = this.client.findElement('iframe[src*="' +
this.origin + '"]');
this.client.switchToFrame(musicFrame);
} else {
this.client.apps.switchToApp(this.origin);
}
},
waitForListEnumerate: function() {
this.client.waitFor(function() {
return this.client.executeScript(function() {
return window.wrappedJSObject.ListView.handle.state === 'complete';
});
}.bind(this));
},
waitFinishedScanning: function() {
this.client.waitFor(function() {
return this.client.executeScript(function() {
return window.wrappedJSObject.Database.initialScanComplete === true;
});
}.bind(this));
},
waitForFirstTile: function() {
this.client.helper.waitForElement(Music.Selector.firstTile);
},
waitForMessageOverlayShown: function(shouldBeShown) {
this.client.waitFor(function() {
var volumeShown = this.messageOverlay.displayed();
return volumeShown === shouldBeShown;
}.bind(this));
},
waitForAList: function(selector) {
this.client.waitFor(function() {
return this.client.findElement(selector).displayed();
}.bind(this));
},
// In sublist view.
// XXX allow in list view too.
waitForSongs: function(callback) {
this.client.waitFor(function() {
var songs = this.songs;
return callback(songs);
}.bind(this));
},
waitForListView: function() {
this.client.helper.waitForElement(Music.Selector.listView);
},
waitForSubListView: function() {
this.client.helper.waitForElement(Music.Selector.sublistView);
},
waitForPlayerView: function() {
this.client.helper.waitForElement(Music.Selector.playerView);
},
// Because bug 862156 so we couldn't get the correct displayed value for the
// player icon, instead we use the display property to check the visibility
// of the player icon.
checkPlayerIconShown: function(shouldBeShown) {
var display = this.playerIcon.cssProperty('display');
var result = (display !== 'none');
assert.equal(shouldBeShown, result);
},
showSearchInput: function(viewSelector) {
var tilesView = this.client.findElement(viewSelector);
var chain = this.actions.press(tilesView, 10, 10).perform();
chain.moveByOffset(0, 110).perform();
chain.release().perform();
},
searchArtists: function(searchTerm) {
this.search(Music.Selector.searchList, searchTerm);
},
searchTiles: function(searchTerm) {
this.search(Music.Selector.searchTiles, searchTerm);
},
search: function(viewSelector, searchTerm) {
this.client.findElement(viewSelector).tap();
var input = this.client.helper.waitForElement(Music.Selector.searchField);
assert.ok(input);
input.clear();
this.client.waitFor(input.displayed.bind(input));
input.sendKeys(searchTerm);
},
switchToArtistsView: function() {
this.artistsTab.tap();
},
switchToSongsView: function() {
this.songsTab.tap();
},
switchToAlbumsView: function() {
this.albumsTab.tap();
},
switchToPlaylistsView: function() {
this.playlistsTab.tap();
},
selectAlbum: function(name) {
var list_items = this.listItems;
list_items.filter(function (element) {
return element.findElement('.list-main-title', 'css selector')
.text() === name;
})[0].tap();
},
selectArtist: function(name) {
var list_items = this.listItems;
list_items.filter(function (element) {
return element.findElement('.list-single-title', 'css selector')
.text() === name;
})[0].tap();
},
selectPlaylist: function(name) {
var list_items = this.listItems;
list_items.filter(function (element) {
return element.findElement('.list-playlist-title', 'css selector')
.text() === name;
})[0].tap();
},
// only from a list (song list)
playFirstSong: function() {
this.firstSong.click();
},
// only from a sublist (artist, albums, playlists)
playFirstSongSublist: function() {
this.firstSongSublist.click();
},
tapPlayButton: function() {
this.actions.tap(this.playButton).perform();
},
tapHeaderActionButton: function() {
this.header.tap(25, 25);
},
showSongInfo: function() {
this.client.helper.waitForElement(Music.Selector.playerCover).click();
},
tapRating: function(rating) {
this.showSongInfo();
this.client.helper.waitForElement('button.rating-star[data-rating="' +
rating + '"]').tap();
},
shareWith: function(appName) {
// Allow findElement to fail quickly.
var quickly = this.client.scope({
searchTimeout: 50
});
var shareMenu;
// Wait until the share menu is displayed.
// Try to click the cover image followed by the share button in the case
// that it hides before we get a chance to click it.
this.client.waitFor(function() {
this.showSongInfo();
this.shareButton.tap();
this.client.switchToFrame();
try {
shareMenu = quickly.findElement(Music.Selector.shareMenu);
} catch(e) {
this.client.apps.switchToApp(this.origin);
return false;
}
var isDisplayed = shareMenu.displayed();
this.client.apps.switchToApp(this.origin);
return isDisplayed;
}.bind(this));
var list = this.shareMenu.findElements('button');
for (var i = 0; i < list.length; i++) {
if (list[i].text() === appName) {
list[i].tap();
return;
}
}
},
finishPick: function() {
this.actions.tap(this.pickDoneButton).perform();
}
};