Context menu on queue 'Play next' just moves tracks; Starting touch-support for dragging

This commit is contained in:
James Barnsley
2022-01-11 21:26:52 +13:00
parent 4fbae32458
commit c3f3fdd868
13 changed files with 159 additions and 300 deletions

View File

@ -5613,7 +5613,7 @@ h4 .context-menu-trigger, h4 .context-menu-trigger:active {
position: absolute;
left: 0;
}
.list__item--loading {
.list__item--loading, .list__item--transforming {
opacity: 0.5;
cursor: wait !important;
}

File diff suppressed because one or more lines are too long

View File

@ -153408,7 +153408,7 @@ var ContextMenu = function ContextMenu(_ref2) {
};
var onClick = function onClick(e) {
if (ref && ref.current) {
if (ref && ref.current && e.which !== 3) {
var current = ref.current;
if (!current.contains(e.target)) {
@ -153779,7 +153779,11 @@ var ContextMenuItems = function ContextMenuItems(_ref) {
context: context,
"data-qa-node": "Play",
"data-qa-file": "ContextMenuItems"
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Enqueue, {
}), (context === null || context === void 0 ? void 0 : context.type) === 'queue' ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(MoveToPlayNext, {
items: [item],
"data-qa-node": "MoveToPlayNext",
"data-qa-file": "ContextMenuItems"
})) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Enqueue, {
uris: [item.uri],
context: context,
next: true,
@ -153790,7 +153794,7 @@ var ContextMenuItems = function ContextMenuItems(_ref) {
context: context,
"data-qa-node": "Enqueue",
"data-qa-file": "ContextMenuItems"
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Divider, {
})), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Divider, {
"data-qa-node": "Divider",
"data-qa-file": "ContextMenuItems"
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(AddToPlaylist, {
@ -153853,7 +153857,11 @@ var ContextMenuItems = function ContextMenuItems(_ref) {
context: context,
"data-qa-node": "Play",
"data-qa-file": "ContextMenuItems"
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Play, {
}), (context === null || context === void 0 ? void 0 : context.type) === 'queue' ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(MoveToPlayNext, {
items: items,
"data-qa-node": "MoveToPlayNext",
"data-qa-file": "ContextMenuItems"
})) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Play, {
uris: uris,
context: context,
shuffle: true,
@ -153870,7 +153878,7 @@ var ContextMenuItems = function ContextMenuItems(_ref) {
context: context,
"data-qa-node": "Enqueue",
"data-qa-file": "ContextMenuItems"
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Divider, {
})), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Divider, {
"data-qa-node": "Divider",
"data-qa-file": "ContextMenuItems"
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(AddToPlaylist, {
@ -154304,8 +154312,48 @@ var Enqueue = function Enqueue(_ref11) {
}))));
};
var AddToPlaylist = function AddToPlaylist(_ref12) {
var onClick = _ref12.onClick;
var MoveToPlayNext = function MoveToPlayNext(_ref12) {
var items = _ref12.items;
var dispatch = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["useDispatch"])();
var currentTlid = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["useSelector"])(function (state) {
var _state$core$current_t;
return (_state$core$current_t = state.core.current_track) === null || _state$core$current_t === void 0 ? void 0 : _state$core$current_t.tlid;
});
var queue = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["useSelector"])(function (state) {
return state.core.queue || [];
});
var current_track_index = queue.findIndex(function (q) {
return q.tlid === currentTlid;
});
var onClick = function onClick() {
dispatch(Object(_services_mopidy_actions__WEBPACK_IMPORTED_MODULE_9__["reorderTracklist"])(Object(_util_arrays__WEBPACK_IMPORTED_MODULE_14__["arrayOf"])('index', items), current_track_index + 1));
dispatch(Object(_services_ui_actions__WEBPACK_IMPORTED_MODULE_8__["hideContextMenu"])());
};
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: "context-menu__item",
"data-qa-node": "div",
"data-qa-file": "ContextMenuItems"
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
className: "context-menu__item__link",
onClick: onClick,
"data-qa-node": "a",
"data-qa-file": "ContextMenuItems"
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
className: "context-menu__item__label",
"data-qa-node": "span",
"data-qa-file": "ContextMenuItems"
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_4__["I18n"], {
path: "context_menu.play_next",
"data-qa-node": "I18n",
"data-qa-file": "ContextMenuItems"
}))));
};
var AddToPlaylist = function AddToPlaylist(_ref13) {
var onClick = _ref13.onClick;
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: "context-menu__item context-menu__item--has-submenu",
"data-qa-node": "div",
@ -154331,11 +154379,11 @@ var AddToPlaylist = function AddToPlaylist(_ref12) {
})));
};
var Remove = function Remove(_ref13) {
var items = _ref13.items,
_ref13$context = _ref13.context,
type = _ref13$context.type,
uri = _ref13$context.uri;
var Remove = function Remove(_ref14) {
var items = _ref14.items,
_ref14$context = _ref14.context,
type = _ref14$context.type,
uri = _ref14$context.uri;
var dispatch = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["useDispatch"])();
var onClick = function onClick() {
@ -154379,9 +154427,9 @@ var Remove = function Remove(_ref13) {
}))));
};
var Radio = function Radio(_ref14) {
var uris = _ref14.uris,
disabled = _ref14.disabled;
var Radio = function Radio(_ref15) {
var uris = _ref15.uris,
disabled = _ref15.disabled;
var dispatch = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["useDispatch"])();
var onClick = function onClick() {
@ -154409,8 +154457,8 @@ var Radio = function Radio(_ref14) {
}))));
};
var Copy = function Copy(_ref15) {
var uris = _ref15.uris;
var Copy = function Copy(_ref16) {
var uris = _ref16.uris;
var dispatch = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["useDispatch"])();
var onClick = function onClick() {
@ -166927,6 +166975,7 @@ var Track = function Track(_ref2) {
stream_title = _ref2.stream_title,
play_state = _ref2.play_state,
is_selected = _ref2.is_selected,
is_transforming = _ref2.is_transforming,
can_sort = _ref2.can_sort,
show_source_icon = _ref2.show_source_icon,
getItemIndex = _ref2.getItemIndex,
@ -167040,6 +167089,7 @@ var Track = function Track(_ref2) {
"data-qa-file": "Track"
});
if (is_selected(index)) className += ' list__item--selected';
if (is_transforming(index)) className += ' list__item--transforming';
if (isOver) className += ' list__item--drag-over';
if (isDragging) className += ' list__item--dragging';
if (can_sort) className += ' list__item--can-sort';
@ -167048,11 +167098,7 @@ var Track = function Track(_ref2) {
if (item.loading) className += ' list__item--loading';
if (item.is_playable === false) className += ' list__item--disabled';
if (track_middle_column) className += ' list__item--has-middle-column';
if (track_details.length > 0) className += ' list__item--has-details';
var onClick = function onClick(e) {
return events.onClick(item, index, e);
};
if (track_details.length > 0) className += ' list__item--has-details'; // Bind to mouseDown so we can trigger selection updates BEFORE drag starts
var onMouseDown = function onMouseDown(e) {
return events.onMouseDown(item, index, e);
@ -167247,6 +167293,11 @@ var TrackList = function TrackList(_ref) {
dropTarget = _useState4[0],
setDropTarget = _useState4[1];
var _useState5 = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])([]),
_useState6 = _slicedToArray(_useState5, 2),
transformingItems = _useState6[0],
setTransformingItems = _useState6[1];
Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(function () {
window.addEventListener('keydown', onKeyDown, false);
return function () {
@ -167308,24 +167359,11 @@ var TrackList = function TrackList(_ref) {
};
var events = {
onDragStart: function onDragStart(item, index, e) {
var items = getOrUpdateSelected(item, index, e).map(function (_ref2) {
var selectedItem = _ref2.item;
return selectedItem;
});
dragStart(e, context, context, items, selected);
},
onDrop: function onDrop(index) {
reorderTracks(Object(_util_arrays__WEBPACK_IMPORTED_MODULE_8__["arrayOf"])('index', selected), index);
setSelected([]);
setDropTarget(null);
},
onClick: function onClick(item, index, e) {
e.persist();
setSelected(function (prev) {
return nextSelected(prev, item, index, e);
});
},
onMouseDown: function onMouseDown(item, index, e) {
if (selectionIndexByItemIndex(index) === -1) {
e.persist();
@ -167347,9 +167385,12 @@ var TrackList = function TrackList(_ref) {
e.preventDefault();
e.stopPropagation();
e.cancelBubble = true;
var items = getOrUpdateSelected(item, index, e).map(function (_ref3) {
var selectedItem = _ref3.item;
return selectedItem;
var items = getOrUpdateSelected(item, index, e).map(function (_ref2) {
var index = _ref2.index,
item = _ref2.item;
return _objectSpread({
index: index
}, item);
});
showContextMenu(_objectSpread({
e: e,
@ -167384,15 +167425,15 @@ var TrackList = function TrackList(_ref) {
return;
}
removeTracks(selected.map(function (_ref4) {
var index = _ref4.index;
removeTracks(selected.map(function (_ref3) {
var index = _ref3.index;
return index;
}));
};
var selectionIndexByItemIndex = function selectionIndexByItemIndex(index) {
return selected && selected.length > 0 ? selected.findIndex(function (_ref5) {
var selectedIndex = _ref5.index;
return selected && selected.length > 0 ? selected.findIndex(function (_ref4) {
var selectedIndex = _ref4.index;
return selectedIndex === index;
}) : -1;
}; // Based on a single track's event, procure the next selected array and update the state
@ -167420,10 +167461,10 @@ var TrackList = function TrackList(_ref) {
var alreadySelected = selectionIndexByItemIndex(index);
if (e.shiftKey) {
var _ref6 = selected[selected.length - 1] || {
var _ref5 = selected[selected.length - 1] || {
index: index
},
lastSelectedIndex = _ref6.index;
lastSelectedIndex = _ref5.index;
var next = [].concat(_toConsumableArray(prev), [{
index: index,
@ -167468,14 +167509,14 @@ var TrackList = function TrackList(_ref) {
}
var is_selected = function is_selected(index) {
return selected.find(function (_ref7) {
var i = _ref7.index;
return selected.find(function (_ref6) {
var i = _ref6.index;
return index === i;
});
};
var is_drag_over = function is_drag_over(index) {
return dropTarget === index;
var is_transforming = function is_transforming(index) {
return transformingItems.indexOf(index) > -1;
};
var getDragItem = function getDragItem(item, index) {
@ -167503,7 +167544,7 @@ var TrackList = function TrackList(_ref) {
getDragItem: getDragItem,
can_sort: context === null || context === void 0 ? void 0 : context.can_edit,
is_selected: is_selected,
is_drag_over: is_drag_over,
is_transforming: is_transforming,
mini_zones: slim_mode || Object(_util_helpers__WEBPACK_IMPORTED_MODULE_7__["isTouchDevice"])(),
events: events
},
@ -172525,6 +172566,7 @@ var MopidyMiddleware = function () {
queue = _store$getState$core.queue;
if (current_track) {
// TODO: Refactor this to findIndex
for (var i = 0; i < queue.length; i += 1) {
if (queue[i].tlid === current_track.tlid) {
at_position = i + 1;
@ -172534,6 +172576,9 @@ var MopidyMiddleware = function () {
}
}
console.debug({
at_position: at_position
}, action);
store.dispatch(uiActions.startProcess(action.type, {
content: Object(_locale__WEBPACK_IMPORTED_MODULE_4__["i18n"])('services.mopidy.adding_uris', {
count: remaining

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -140,7 +140,7 @@
// Release details
// These are automatically injected to built HTML
var build = "1641802627";
var build = "1641803483";
var version = "3.60.1";
// Construct the script tag

View File

@ -112,7 +112,7 @@ const ContextMenu = ({
const onScroll = () => hideContextMenu();
const onClick = (e) => {
if (ref && ref.current) {
if (ref && ref.current && e.which !== 3) {
const { current } = ref;
if (!current.contains(e.target)) {
hideContextMenu();

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { compact, uniq } from 'lodash';
import { uniq } from 'lodash';
import { I18n } from '../../locale';
import Link from '../Link';
import Icon from '../Icon';
@ -25,6 +25,7 @@ import {
enqueueURIs,
enqueueAlbum,
enqueuePlaylist,
reorderTracklist,
} from '../../services/mopidy/actions';
import {
following,
@ -130,8 +131,16 @@ const ContextMenuItems = ({
return (
<>
<Play uris={[item.uri]} context={context} />
<Enqueue uris={[item.uri]} context={context} next />
<Enqueue uris={[item.uri]} context={context} />
{context?.type === 'queue' ? (
<>
<MoveToPlayNext items={[item]} />
</>
) : (
<>
<Enqueue uris={[item.uri]} context={context} next />
<Enqueue uris={[item.uri]} context={context} />
</>
)}
<Divider />
<AddToPlaylist uris={[item.uri]} onClick={onSubmenu} />
{provider === 'spotify' && <Library uri={item.uri} />}
@ -163,9 +172,17 @@ const ContextMenuItems = ({
return (
<>
<Play uris={uris} context={context} />
<Play uris={uris} context={context} shuffle />
<Enqueue uris={uris} context={context} next />
<Enqueue uris={uris} context={context} />
{context?.type === 'queue' ? (
<>
<MoveToPlayNext items={items} />
</>
) : (
<>
<Play uris={uris} context={context} shuffle />
<Enqueue uris={uris} context={context} next />
<Enqueue uris={uris} context={context} />
</>
)}
<Divider />
<AddToPlaylist uris={uris} onClick={onSubmenu} />
{/* No support for adding/removing/checking library for multiple URIs (yet) */}
@ -443,6 +460,28 @@ const Enqueue = ({
);
};
const MoveToPlayNext = ({
items,
}) => {
const dispatch = useDispatch();
const currentTlid = useSelector((state) => state.core.current_track?.tlid);
const queue = useSelector((state) => state.core.queue || []);
const current_track_index = queue.findIndex((q) => q.tlid === currentTlid);
const onClick = () => {
dispatch(reorderTracklist(arrayOf('index', items), current_track_index + 1));
dispatch(hideContextMenu());
};
return (
<div className="context-menu__item">
<a className="context-menu__item__link" onClick={onClick}>
<span className="context-menu__item__label">
<I18n path="context_menu.play_next" />
</span>
</a>
</div>
);
};
const AddToPlaylist = ({
onClick,
}) => {

View File

@ -59,6 +59,7 @@ const Track = ({
stream_title,
play_state,
is_selected,
is_transforming,
can_sort,
show_source_icon,
getItemIndex,
@ -134,6 +135,7 @@ const Track = ({
const track_middle_column = <MiddleColumn context={context} item={item} />;
if (is_selected(index)) className += ' list__item--selected';
if (is_transforming(index)) className += ' list__item--transforming';
if (isOver) className += ' list__item--drag-over';
if (isDragging) className += ' list__item--dragging';
if (can_sort) className += ' list__item--can-sort';
@ -144,7 +146,7 @@ const Track = ({
if (track_middle_column) className += ' list__item--has-middle-column';
if (track_details.length > 0) className += ' list__item--has-details';
const onClick = (e) => events.onClick(item, index, e);
// Bind to mouseDown so we can trigger selection updates BEFORE drag starts
const onMouseDown = (e) => events.onMouseDown(item, index, e);
const onDoubleClick = (e) => events.onDoubleClick(item, index, e);
const onContextMenu = (e) => events.onContextMenu(item, index, e);

View File

@ -37,6 +37,7 @@ const TrackList = ({
}) => {
const [selected, setSelected] = useState([]);
const [dropTarget, setDropTarget] = useState(null);
const [transformingItems, setTransformingItems] = useState([]);
useEffect(() => {
window.addEventListener('keydown', onKeyDown, false);
@ -91,19 +92,11 @@ const TrackList = ({
}
const events = {
onDragStart: (item, index, e) => {
const items = getOrUpdateSelected(item, index, e).map(({ item: selectedItem }) => selectedItem);
dragStart(e, context, context, items, selected);
},
onDrop: (index) => {
reorderTracks(arrayOf('index', selected), index);
setSelected([]);
setDropTarget(null);
},
onClick: (item, index, e) => {
e.persist();
setSelected((prev) => nextSelected(prev, item, index, e));
},
onMouseDown: (item, index, e) => {
if (selectionIndexByItemIndex(index) === -1) {
e.persist();
@ -120,7 +113,9 @@ const TrackList = ({
e.preventDefault();
e.stopPropagation();
e.cancelBubble = true;
const items = getOrUpdateSelected(item, index, e).map(({ item: selectedItem }) => selectedItem);
const items = getOrUpdateSelected(item, index, e).map(
({ index, item }) => ({ index, ...item }),
);
showContextMenu({
e,
@ -206,7 +201,7 @@ const TrackList = ({
}
const is_selected = (index) => selected.find(({ index: i }) => index === i);
const is_drag_over = (index) => dropTarget === index;
const is_transforming = (index) => transformingItems.indexOf(index) > -1;
const getDragItem = (item, index) => {
let selectedForDrag = selected;
if (selectionIndexByItemIndex(index) === -1) {
@ -232,7 +227,7 @@ const TrackList = ({
getDragItem,
can_sort: context?.can_edit,
is_selected,
is_drag_over,
is_transforming,
mini_zones: slim_mode || isTouchDevice(),
events,
}}

View File

@ -993,6 +993,7 @@ const MopidyMiddleware = (function () {
queue,
} = store.getState().core;
if (current_track) {
// TODO: Refactor this to findIndex
for (let i = 0; i < queue.length; i += 1) {
if (queue[i].tlid === current_track.tlid) {
at_position = i + 1;
@ -1002,6 +1003,8 @@ const MopidyMiddleware = (function () {
}
}
console.debug({ at_position }, action)
store.dispatch(uiActions.startProcess(
action.type,
{

View File

@ -187,7 +187,8 @@
}
}
&--loading {
&--loading,
&--transforming {
opacity: 0.5;
cursor: wait !important;
}