feat(ags player): make indicators clickable and big refactor
This commit is contained in:
parent
5b72e6fa0a
commit
04312dcc2c
3 changed files with 93 additions and 105 deletions
|
@ -7,7 +7,7 @@ const MAX_OFFSET = 200;
|
||||||
const OFFSCREEN = 500;
|
const OFFSCREEN = 500;
|
||||||
const ANIM_DURATION = 500;
|
const ANIM_DURATION = 500;
|
||||||
const TRANSITION = `transition: margin ${ANIM_DURATION}ms ease,
|
const TRANSITION = `transition: margin ${ANIM_DURATION}ms ease,
|
||||||
opacity 3s ease;`;
|
opacity ${ANIM_DURATION}ms ease;`;
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
|
@ -24,20 +24,11 @@ export default ({
|
||||||
// Set this prop to differentiate it easily
|
// Set this prop to differentiate it easily
|
||||||
emptyPlayer.empty = true;
|
emptyPlayer.empty = true;
|
||||||
|
|
||||||
widget.add(Overlay({
|
const content = Overlay({
|
||||||
...props,
|
...props,
|
||||||
properties: [
|
properties: [
|
||||||
...properties,
|
...properties,
|
||||||
['dragging', false],
|
['dragging', false],
|
||||||
['showTopOnly', (overlay) => overlay.list()
|
|
||||||
.forEach((over) => {
|
|
||||||
if (over === overlay.list().at(-1)) {
|
|
||||||
over.visible = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
over.visible = false;
|
|
||||||
}
|
|
||||||
})],
|
|
||||||
],
|
],
|
||||||
|
|
||||||
child: emptyPlayer,
|
child: emptyPlayer,
|
||||||
|
@ -52,7 +43,7 @@ export default ({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
overlay._showTopOnly(overlay);
|
overlay.showTopOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow gesture when only one player
|
// Don't allow gesture when only one player
|
||||||
|
@ -128,7 +119,7 @@ export default ({
|
||||||
|
|
||||||
widget.sensitive = true;
|
widget.sensitive = true;
|
||||||
|
|
||||||
overlay._showTopOnly(overlay);
|
overlay.showTopOnly();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -137,10 +128,31 @@ export default ({
|
||||||
}
|
}
|
||||||
}, 'drag-end'],
|
}, 'drag-end'],
|
||||||
],
|
],
|
||||||
}));
|
});
|
||||||
|
|
||||||
widget.child.list = () => widget.child.get_children()
|
widget.add(content);
|
||||||
|
|
||||||
|
// Overlay methods
|
||||||
|
content.list = () => content.get_children()
|
||||||
.filter((ch) => !ch.empty);
|
.filter((ch) => !ch.empty);
|
||||||
|
|
||||||
|
content.includesWidget = (playerW) => {
|
||||||
|
return content.list().find((w) => w === playerW);
|
||||||
|
};
|
||||||
|
|
||||||
|
content.showTopOnly = () => content.list().forEach((over) => {
|
||||||
|
over.visible = over === content.list().at(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
content.moveToTop = (player) => {
|
||||||
|
player.visible = true;
|
||||||
|
content.reorder_overlay(player, -1);
|
||||||
|
timeout(ANIM_DURATION, () => {
|
||||||
|
content.showTopOnly();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
widget.getOverlay = () => content;
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,8 @@ import { execAsync, lookUpIcon, readFileAsync } from 'resource:///com/github/Ayl
|
||||||
import Separator from '../misc/separator.js';
|
import Separator from '../misc/separator.js';
|
||||||
import EventBox from '../misc/cursorbox.js';
|
import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
const ICON_SIZE = 32;
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
mpris: {
|
mpris: {
|
||||||
fallback: 'audio-x-generic-symbolic',
|
fallback: 'audio-x-generic-symbolic',
|
||||||
|
@ -31,7 +33,10 @@ export const CoverArt = (player, props) => CenterBox({
|
||||||
...props,
|
...props,
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
properties: [['bgStyle', '']],
|
properties: [
|
||||||
|
['bgStyle', ''],
|
||||||
|
['player', player],
|
||||||
|
],
|
||||||
|
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
// Give temp cover art
|
// Give temp cover art
|
||||||
|
@ -109,53 +114,39 @@ export const ArtistLabel = (player, props) => Label({
|
||||||
binds: [['label', player, 'track-artists', (a) => a.join(', ') || '']],
|
binds: [['label', player, 'track-artists', (a) => a.join(', ') || '']],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PlayerIcon = (player, { symbolic = true, ...props } = {}) => {
|
export const PlayerIcon = (player, overlay, props) => {
|
||||||
// Get player's icon
|
const playerIcon = (p, widget, over) => EventBox({
|
||||||
const MainIcon = Icon({
|
|
||||||
...props,
|
...props,
|
||||||
className: 'player-icon',
|
tooltipText: p.identity || '',
|
||||||
size: 32,
|
|
||||||
tooltipText: player.identity || '',
|
|
||||||
|
|
||||||
connections: [[player, (self) => {
|
onPrimaryClickRelease: () => {
|
||||||
const name = `${player.entry}${symbolic ? '-symbolic' : ''}`;
|
widget?.moveToTop(over);
|
||||||
|
},
|
||||||
|
|
||||||
lookUpIcon(name) ?
|
child: Icon({
|
||||||
self.icon = name :
|
className: widget ? 'position-indicator' : 'player-icon',
|
||||||
self.icon = icons.mpris.fallback;
|
size: widget ? '' : ICON_SIZE,
|
||||||
}]],
|
|
||||||
|
connections: [[p, (self) => {
|
||||||
|
self.icon = lookUpIcon(p.entry) ?
|
||||||
|
p.entry :
|
||||||
|
icons.mpris.fallback;
|
||||||
|
}]],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Multiple player indicators
|
|
||||||
return Box({
|
return Box({
|
||||||
properties: [['overlay']],
|
|
||||||
connections: [[Mpris, (self) => {
|
connections: [[Mpris, (self) => {
|
||||||
if (!self._overlay) {
|
const thisIndex = overlay.list()
|
||||||
self._overlay = self.get_parent().get_parent().get_parent();
|
.indexOf(self.get_parent().get_parent());
|
||||||
}
|
|
||||||
|
|
||||||
const overlays = self._overlay.list();
|
self.children = overlay.list().map((over, i) => {
|
||||||
|
self.children.push(Separator(2));
|
||||||
|
|
||||||
const playerWidget = overlays.find((overlay) => {
|
return i === thisIndex ?
|
||||||
return overlay === self.get_parent().get_parent();
|
playerIcon(player) :
|
||||||
});
|
playerIcon(over._player, overlay, over);
|
||||||
|
}).reverse();
|
||||||
const index = overlays.indexOf(playerWidget);
|
|
||||||
|
|
||||||
const children = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < overlays.length; ++i) {
|
|
||||||
if (i === index) {
|
|
||||||
children.push(Separator(2));
|
|
||||||
children.push(MainIcon);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
children.push(Separator(2));
|
|
||||||
// TODO: make this clickable to switch
|
|
||||||
children.push(Box({ className: 'position-indicator' }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.children = children.reverse();
|
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -216,11 +207,13 @@ const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
||||||
onHover: (self) => {
|
onHover: (self) => {
|
||||||
self._hovered = true;
|
self._hovered = true;
|
||||||
|
|
||||||
if (prop === 'playBackStatus') {
|
if (prop === 'playBackStatus' && player.colors.value) {
|
||||||
|
const c = player.colors.value;
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
item[1].setCss(`
|
item[1].setCss(`
|
||||||
background-color: ${player.colors.value.hoverAccent};
|
background-color: ${c.hoverAccent};
|
||||||
color: ${player.colors.value.buttonText};
|
color: ${c.buttonText};
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
min-width: 36px;
|
min-width: 36px;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
|
@ -232,11 +225,13 @@ const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
||||||
|
|
||||||
onHoverLost: (self) => {
|
onHoverLost: (self) => {
|
||||||
self._hovered = false;
|
self._hovered = false;
|
||||||
if (prop === 'playBackStatus') {
|
if (prop === 'playBackStatus' && player.colors.value) {
|
||||||
|
const c = player.colors.value;
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
item[1].setCss(`
|
item[1].setCss(`
|
||||||
background-color: ${player.colors.value.buttonAccent};
|
background-color: ${c.buttonAccent};
|
||||||
color: ${player.colors.value.buttonText};
|
color: ${c.buttonText};
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
min-width: 38px;
|
min-width: 38px;
|
||||||
`);
|
`);
|
||||||
|
|
|
@ -10,15 +10,13 @@ import Separator from '../misc/separator.js';
|
||||||
const FAVE_PLAYER = 'org.mpris.MediaPlayer2.spotify';
|
const FAVE_PLAYER = 'org.mpris.MediaPlayer2.spotify';
|
||||||
|
|
||||||
|
|
||||||
const Top = (player) => Box({
|
const Top = (player, overlay) => Box({
|
||||||
className: 'top',
|
className: 'top',
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
mpris.PlayerIcon(player, {
|
mpris.PlayerIcon(player, overlay),
|
||||||
symbolic: false,
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -85,13 +83,13 @@ const Bottom = (player) => Box({
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const PlayerBox = (player) => {
|
const PlayerBox = (player, overlay) => {
|
||||||
const widget = mpris.CoverArt(player, {
|
const widget = mpris.CoverArt(player, {
|
||||||
className: `player ${player.name}`,
|
className: `player ${player.name}`,
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Top(player),
|
Top(player, overlay),
|
||||||
Center(player),
|
Center(player),
|
||||||
Bottom(player),
|
Bottom(player),
|
||||||
],
|
],
|
||||||
|
@ -102,10 +100,8 @@ const PlayerBox = (player) => {
|
||||||
return widget;
|
return widget;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => Box({
|
export default () => {
|
||||||
className: 'media',
|
const content = PlayerGesture({
|
||||||
|
|
||||||
child: PlayerGesture({
|
|
||||||
properties: [
|
properties: [
|
||||||
['players', new Map()],
|
['players', new Map()],
|
||||||
['setup', false],
|
['setup', false],
|
||||||
|
@ -131,39 +127,29 @@ export default () => Box({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the one on top so it stays there
|
// Get the one on top so we can move it up later
|
||||||
let previousFirst = overlay.get_children().at(-1);
|
const previousFirst = overlay.list().at(-1);
|
||||||
|
|
||||||
for (const [key, value] of overlay._players.entries()) {
|
|
||||||
if (value === previousFirst) {
|
|
||||||
previousFirst = key;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the new player
|
// Make the new player
|
||||||
const player = Mpris.getPlayer(busName);
|
const player = Mpris.getPlayer(busName);
|
||||||
|
|
||||||
player.colors = Variable();
|
player.colors = Variable();
|
||||||
overlay._players.set(busName, PlayerBox(player));
|
overlay._players.set(
|
||||||
|
busName,
|
||||||
|
PlayerBox(player, content.getOverlay()),
|
||||||
|
);
|
||||||
overlay.overlays = Array.from(overlay._players.values())
|
overlay.overlays = Array.from(overlay._players.values())
|
||||||
.map((widget) => widget);
|
.map((widget) => widget);
|
||||||
|
|
||||||
// Select favorite player at startup
|
// Select favorite player at startup
|
||||||
if (!overlay._setup && overlay._players.has(FAVE_PLAYER)) {
|
if (!overlay._setup && overlay._players.has(FAVE_PLAYER)) {
|
||||||
overlay.reorder_overlay(
|
overlay.moveToTop(overlay._players.get(FAVE_PLAYER));
|
||||||
overlay._players.get(FAVE_PLAYER),
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
overlay._setup = true;
|
overlay._setup = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move previousFirst on top again
|
// Move previousFirst on top again
|
||||||
else if (overlay._players.get(previousFirst)) {
|
else if (overlay.includesWidget(previousFirst)) {
|
||||||
overlay.reorder_overlay(
|
overlay.moveToTop(previousFirst);
|
||||||
overlay._players.get(previousFirst),
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, 'player-added'],
|
}, 'player-added'],
|
||||||
|
|
||||||
|
@ -173,15 +159,8 @@ export default () => Box({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the one on top so it stays there
|
// Get the one on top so we can move it up later
|
||||||
let previousFirst = overlay.get_children().at(-1);
|
const previousFirst = overlay.list().at(-1);
|
||||||
|
|
||||||
for (const [key, value] of overlay._players.entries()) {
|
|
||||||
if (value === previousFirst) {
|
|
||||||
previousFirst = key;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remake overlays without deleted one
|
// Remake overlays without deleted one
|
||||||
overlay._players.delete(busName);
|
overlay._players.delete(busName);
|
||||||
|
@ -189,13 +168,15 @@ export default () => Box({
|
||||||
.map((widget) => widget);
|
.map((widget) => widget);
|
||||||
|
|
||||||
// Move previousFirst on top again
|
// Move previousFirst on top again
|
||||||
if (overlay._players.has(previousFirst)) {
|
if (overlay.includesWidget(previousFirst)) {
|
||||||
overlay.reorder_overlay(
|
overlay.moveToTop(previousFirst);
|
||||||
overlay._players.get(previousFirst),
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, 'player-closed'],
|
}, 'player-closed'],
|
||||||
],
|
],
|
||||||
}),
|
});
|
||||||
});
|
|
||||||
|
return Box({
|
||||||
|
className: 'media',
|
||||||
|
child: content,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue