diff --git a/src/components/controls.tsx b/src/components/controls.tsx index fe2e163..8638f23 100644 --- a/src/components/controls.tsx +++ b/src/components/controls.tsx @@ -4,6 +4,7 @@ import PlayArrowIcon from '@material-ui/icons/PlayArrow'; import StopIcon from '@material-ui/icons/Stop'; import SkipNextIcon from '@material-ui/icons/SkipNext'; import SkipPreviousIcon from '@material-ui/icons/SkipPrevious'; +import PauseIcon from '@material-ui/icons/Pause' import IconButton from '@material-ui/core/IconButton'; import Box from '@material-ui/core/Box'; @@ -28,6 +29,11 @@ const useStyles = makeStyles(theme => ({ }, to: {}, }, + '@keyframes blink': { + '50%': { + visibility: 'hidden', + }, + }, container: { display: 'flex', flex: '1 1 auto', @@ -88,6 +94,12 @@ const useStyles = makeStyles(theme => ({ top: 15, left: 1, }, + lcdBlink:{ + animationName: '$blink', + animationTimingFunction: 'step-end', + animationDuration: '1s', + animationIterationCount: 'infinite' + }, button: { // padding: 8, }, @@ -112,11 +124,15 @@ export const Controls = () => { const handleNext = useCallback(() => { dispatch(control('next')); }, [dispatch]); + const handlePause = useCallback(() => { + dispatch(control('pause')); + }, [dispatch]); let message = ``; let trackIndex = deviceStatus?.track ?? null; let deviceState = deviceStatus?.state ?? null; let discPresent = deviceStatus?.discPresent ?? false; + let paused = deviceStatus?.state === "paused"; const tracks = getSortedTracks(disc); if (!discPresent) { message = ``; @@ -187,6 +203,7 @@ export const Controls = () => { handlePrev, handlePlay, handleStop, + handlePause, handleNext, message, @@ -208,6 +225,9 @@ export const Controls = () => { + + + @@ -228,7 +248,7 @@ export const Controls = () => { {message} -
{discPresent && }
+
{discPresent && }
); diff --git a/src/components/main.tsx b/src/components/main.tsx index 7b0ec6c..35765fa 100644 --- a/src/components/main.tsx +++ b/src/components/main.tsx @@ -8,6 +8,7 @@ import { actions as convertDialogActions } from '../redux/convert-dialog-feature import { actions as dumpDialogActions } from '../redux/dump-dialog-feature'; import { formatTimeFromFrames, getTracks } from 'netmd-js'; +import { control } from '../redux/actions'; import { belowDesktop, forAnyDesktop, getSortedTracks, useShallowEqualSelector } from '../utils'; @@ -19,6 +20,8 @@ import AddIcon from '@material-ui/icons/Add'; import DeleteIcon from '@material-ui/icons/Delete'; import EditIcon from '@material-ui/icons/Edit'; import Backdrop from '@material-ui/core/Backdrop'; +import PlayArrowIcon from '@material-ui/icons/PlayArrow'; +import PauseIcon from '@material-ui/icons/Pause' import Table from '@material-ui/core/Table'; import TableBody from '@material-ui/core/TableBody'; @@ -133,12 +136,53 @@ const useStyles = makeStyles(theme => ({ textDecoration: 'underline', textDecorationStyle: 'dotted', }, + controlButtonInTrackCommon: { + width: '.5em', + verticalAlign: 'middle', + }, + playButtonInTrackListPlaying: { + color: theme.palette.primary.main, + display: 'none', + }, + pauseButtonInTrackListPlaying: { + color: theme.palette.primary.main, + display: 'none', + }, + currentControlButton: { + display: 'inline-block', + }, + playButtonInTrackListNotPlaying: { + visibility: 'hidden', + }, + trackRow: { + '&:hover': { + /* For the tracks that aren't currently playing */ + "& $playButtonInTrackListNotPlaying":{ + visibility: 'visible', + }, + "& $trackIndex":{ + display: 'none', + }, + + /* For the current track */ + "& svg:not($currentControlButton)": { + display: 'inline-block', + }, + "& $currentControlButton": { + display: 'none', + } + }, + }, + trackIndex:{ + display: 'inline-block', + } })); export const Main = (props: {}) => { let dispatch = useDispatch(); let disc = useShallowEqualSelector(state => state.main.disc); let deviceName = useShallowEqualSelector(state => state.main.deviceName); + const deviceStatus = useShallowEqualSelector(state => state.main.deviceStatus); const { vintageMode } = useShallowEqualSelector(state => state.appState); const [selected, setSelected] = React.useState([]); @@ -229,6 +273,20 @@ export const Main = (props: {}) => { dispatch(deleteTracks(selected)); }; + const handlePlayTrack = async (event: React.MouseEvent, track: number) => { + if(deviceStatus?.track !== track) + dispatch(control('goto', track)); + if(deviceStatus?.state !== 'playing') + dispatch(control('play')); + }; + + const handleCurrentClick = async (event: React.MouseEvent) => { + if(deviceStatus?.state === 'playing') + dispatch(control('pause')); + else + dispatch(control('play')); + } + if (vintageMode) { const p = { disc, @@ -390,8 +448,26 @@ export const Main = (props: {}) => { key={track.index} onDoubleClick={event => handleRenameDoubleClick(event, track.index)} onClick={event => handleSelectClick(event, track.index)} + className={classes.trackRow} > - {track.index + 1} + + {track.index === deviceStatus?.track ? + + {handleCurrentClick(event); event.stopPropagation();}} /> + {handleCurrentClick(event); event.stopPropagation()}} /> + : + + {track.index + 1} + {handlePlayTrack(event, track.index); event.stopPropagation();}} + /> + } + {track.title || `No Title`} diff --git a/src/components/win95/controls.tsx b/src/components/win95/controls.tsx index ab215c7..901fbea 100644 --- a/src/components/win95/controls.tsx +++ b/src/components/win95/controls.tsx @@ -6,6 +6,7 @@ import PlayArrowIcon from '@material-ui/icons/PlayArrow'; import StopIcon from '@material-ui/icons/Stop'; import SkipNextIcon from '@material-ui/icons/SkipNext'; import SkipPreviousIcon from '@material-ui/icons/SkipPrevious'; +import PauseIcon from '@material-ui/icons/Pause'; import { makeStyles } from '@material-ui/core/styles'; const useStyles = makeStyles(theme => ({ @@ -32,6 +33,7 @@ export const W95Controls = (props: { handlePrev: () => void; handlePlay: () => void; handleStop: () => void; + handlePause: () => void; handleNext: () => void; message: string; discPresent: boolean; @@ -49,6 +51,9 @@ export const W95Controls = (props: { + diff --git a/src/redux/actions.ts b/src/redux/actions.ts index 451258d..3874009 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -14,7 +14,7 @@ import * as mm from 'music-metadata-browser'; import { TitleFormatType, UploadFormat } from './convert-dialog-feature'; import NotificationCompleteIconUrl from '../images/record-complete-notification-icon.png'; -export function control(action: 'play' | 'stop' | 'next' | 'prev' | 'goto', params?: unknown) { +export function control(action: 'play' | 'stop' | 'next' | 'prev' | 'goto' | 'pause', params?: unknown) { return async function(dispatch: AppDispatch, getState: () => RootState) { switch (action) { case 'play': @@ -29,8 +29,11 @@ export function control(action: 'play' | 'stop' | 'next' | 'prev' | 'goto', para case 'prev': await serviceRegistry.netmdService!.prev(); break; + case 'pause': + await serviceRegistry.netmdService!.pause(); + break; case 'goto': - if (params && typeof params === 'number' && params >= 0) { + if (params !== null && params !== undefined && typeof params === 'number' && params >= 0) { await serviceRegistry.netmdService!.gotoTrack(params); } break;