feat(media-player): add full dragging gesture

This commit is contained in:
matt1432 2023-09-26 10:43:37 -04:00
parent 53275e6372
commit 28881bd2dd
3 changed files with 137 additions and 78 deletions

View file

@ -0,0 +1,82 @@
const { Box, Overlay, EventBox } = ags.Widget;
const { Gtk } = imports.gi;
const MAX_OFFSET = 200;
const OFFSCREEN = 500;
const TRANSITION = 'transition: margin 0.5s ease, opacity 3s ease;';
export default ({ properties, connections, params } = {}) => {
let widget = EventBox();
let gesture = Gtk.GestureDrag.new(widget)
widget.child = Overlay({
...params,
properties: [
...properties,
['dragging', false],
],
child: Box({className: 'player'}),
connections: [
...connections,
[gesture, overlay => {
if (overlay.overlays.length <= 1)
return;
overlay._dragging = true;
const offset = gesture.get_offset()[1];
let playerBox = overlay.get_children().at(-1);
if (offset >= 0) {
playerBox.setStyle(`margin-left: ${offset}px;
margin-right: -${offset}px;
${playerBox._bgStyle}`);
}
else {
let newOffset = Math.abs(offset);
playerBox.setStyle(`margin-left: -${newOffset}px;
margin-right: ${newOffset}px;
${playerBox._bgStyle}`);
}
overlay._selected = playerBox;
}, 'drag-update'],
[gesture, overlay => {
if (overlay.overlays.length <= 1)
return;
overlay._dragging = false;
const offset = gesture.get_offset()[1];
let playerBox = overlay.get_children().at(-1);
if (Math.abs(offset) > MAX_OFFSET) {
if (offset >= 0) {
playerBox.setStyle(`${TRANSITION}
margin-left: ${OFFSCREEN}px;
margin-right: -${OFFSCREEN}px;
opacity: 0;
${playerBox._bgStyle}`);
}
else {
playerBox.setStyle(`${TRANSITION}
margin-left: -${OFFSCREEN}px;
margin-right: ${OFFSCREEN}px;
opacity: 0;
${playerBox._bgStyle}`);
}
setTimeout(() => {
overlay.reorder_overlay(playerBox, 0);
playerBox.setStyle(playerBox._bgStyle);
overlay._selected = overlay.get_children().at(-1);
}, 500);
}
else
playerBox.setStyle(`${TRANSITION} ${playerBox._bgStyle}`);
}, 'drag-end'],
],
});
return widget;
};

View file

@ -29,6 +29,7 @@ export const CoverArt = (player, params) => CenterBox({
...params, ...params,
className: 'player', className: 'player',
vertical: true, vertical: true,
properties: [['bgStyle', '']],
connections: [ connections: [
[player, box => { [player, box => {
execAsync(['bash', '-c', `[[ -f "${player.coverPath}" ]] && coloryou "${player.coverPath}"`]) execAsync(['bash', '-c', `[[ -f "${player.coverPath}" ]] && coloryou "${player.coverPath}"`])
@ -36,12 +37,14 @@ export const CoverArt = (player, params) => CenterBox({
if (box) { if (box) {
player.colors.value = JSON.parse(out); player.colors.value = JSON.parse(out);
box.setStyle(`background: radial-gradient(circle, box._bgStyle = `background: radial-gradient(circle,
rgba(0, 0, 0, 0.4) 30%, rgba(0, 0, 0, 0.4) 30%,
${player.colors.value.imageAccent}), ${player.colors.value.imageAccent}),
url("${player.coverPath}"); url("${player.coverPath}");
background-size: cover; background-size: cover;
background-position: center;`); background-position: center;`;
if (!box.get_parent()._dragging)
box.setStyle(box._bgStyle);
} }
}).catch(err => { if (err !== "") print(err) }); }).catch(err => { if (err !== "") print(err) });
}], }],

View file

@ -1,8 +1,8 @@
const { Mpris } = ags.Service; const { Mpris } = ags.Service;
const { Box, CenterBox, Label, Stack, EventBox } = ags.Widget; const { Box, CenterBox, Label } = ags.Widget;
const { Gtk } = imports.gi;
import * as mpris from './mpris.js'; import * as mpris from './mpris.js';
import PlayerGesture from './gesture.js';
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
const Top = player => Box({ const Top = player => Box({
@ -56,7 +56,7 @@ const Center = player => Box({
const Bottom = player => Box({ const Bottom = player => Box({
className: 'bottom', className: 'bottom',
children: [ children: [
mpris.PreviousButton(player, { mpris.PreviousButton(player, {
valign: 'end', valign: 'end',
halign: 'start', halign: 'start',
@ -83,81 +83,55 @@ const PlayerBox = player => mpris.CoverArt(player, {
], ],
}); });
export default () => { export default () => PlayerGesture({
let widget = EventBox(); className: 'media',
properties: [
['players', new Map()],
['setup', false],
['selected'],
],
connections: [
[Mpris, (overlay, busName) => {
if (!busName || overlay._players.has(busName))
return;
let gesture = Gtk.GestureDrag.new(widget) const player = Mpris.getPlayer(busName);
player.colors = ags.Variable();
overlay._players.set(busName, PlayerBox(player));
widget.child = Stack({ let result = [];
className: 'media', overlay._players.forEach(widget => {
properties: [ result.push(widget);
['players', new Map()], });
['previous', 'spotify'],
],
connections: [
[gesture, stack => {
const offset = gesture.get_offset()[1];
if (Math.abs(offset) > 200) {
let players = [];
stack._players.forEach((_, busName) => players.push(Mpris.getPlayer(busName).name));
let current = players.findIndex(player => player === stack.shown);
if (offset > 0) { overlay.overlays = result;
stack.transition = 'slide_right';
if (players[++current]) // Favor spotify
stack.shown = `${players[current]}`; if (!overlay._setup) {
else if (overlay._players.has('org.mpris.MediaPlayer2.spotify')) {
stack.shown = `${players[0]}`; overlay._selected = overlay._players.get('org.mpris.MediaPlayer2.spotify');
}
else {
stack.transition = 'slide_left';
if (players[--current])
stack.shown = `${players[current]}`;
else
stack.shown = `${players.at(-1)}`;
}
stack._previous = stack.shown;
} }
}, 'drag-end'], overlay._setup = true;
}
[Mpris, (stack, busName) => { if (overlay._selected)
if (!busName || stack._players.has(busName)) overlay.reorder_overlay(overlay._selected, -1);
return; }, 'player-added'],
const player = Mpris.getPlayer(busName); [Mpris, (overlay, busName) => {
player.colors = ags.Variable(); if (!busName || !overlay._players.has(busName))
stack._players.set(busName, PlayerBox(player)); return;
let result = []; overlay._players.delete(busName);
stack._players.forEach((widget, busName) => {
result.push([`${Mpris.getPlayer(busName).name}`, widget]);
});
stack.items = result; let result = [];
if (result.find(p => p[0] === stack._previous)) overlay._players.forEach(widget => {
stack.shown = stack._previous; result.push(widget);
else if (stack._players.has('org.mpris.MediaPlayer2.spotify')) });
stack.shown = `spotify`;
}, 'player-added'],
[Mpris, (stack, busName) => { overlay.overlays = result;
if (!busName || !stack._players.has(busName)) if (overlay._selected)
return; overlay.reorder_overlay(overlay._selected, -1);
}, 'player-closed'],
stack._players.delete(busName); ],
})
let result = [];
stack._players.forEach((widget, busName) => {
result.push([`${Mpris.getPlayer(busName).name}`, widget]);
});
stack.items = result;
if (result.find(p => p[0] === stack._previous))
stack.shown = stack._previous;
else if (stack._players.has('org.mpris.MediaPlayer2.spotify'))
stack.shown = `spotify`;
}, 'player-closed'],
],
});
return widget;
};