From 6216e7dfa7abe9152ab003a378cb44e12e799415 Mon Sep 17 00:00:00 2001 From: Chris Garrity <chrisg@media.mit.edu> Date: Mon, 1 Jul 2019 10:20:37 -0400 Subject: [PATCH] improve touch interactions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Play button is larger (easier to touch). Can both start and stop sounds. Sound doesn’t restart on mouseEnter if the sound is already playing. Sound stops if you move off play button Missing: stop button does not revert to play button when the sound finishes. --- src/components/library-item/icon--stop.svg | Bin 0 -> 1887 bytes src/components/library-item/library-item.css | 4 ++-- src/components/library-item/library-item.jsx | 11 +++++++---- src/components/library/library.jsx | 17 ++++++++++++++--- src/containers/library-item.jsx | 10 ++++++++++ 5 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 src/components/library-item/icon--stop.svg diff --git a/src/components/library-item/icon--stop.svg b/src/components/library-item/icon--stop.svg new file mode 100644 index 0000000000000000000000000000000000000000..53837e30c9f0e93279855f364db975e17ae9386f GIT binary patch literal 1887 zcmbVNTW{Jh6n^io@LWx5r8##fK?&8mse7tgjrIqG#3UXejvR-}zu&Q)Kq#<>8HDZQ z<L}%)AEL+Ix<nf)8pf*_yOx6ytx}$`Dv$BU`!ktf)X1dDl9E?6#udkpvzw^d<Y>z> zS;Tnc)jNy|%JM??yA7k;C%%iZgB&#S;ERVwT#UeM)x@}vvYy)ZcDuE<zQsjudyeDS z0N<%hcO|P<mlWMF3~haiXEz8&^o0=gi&j)5l8Y&tuc%B56!?~h?)=ahhxdq}fyD(c z=$a*6xK_&7c4O`k(m_flOFC;LuSs1d`$dwjBHIX!&5Snb?1!L<q#0yH7M)ouvh`7~ zwQLNcc2v+*B9_ItPGmt;HXu_N?e%Y$)*v`0Rjmc+1b7zN>hb_<$x2CuLLjbhjlXJ` ze%WEU-h<`CNnfOXZ|;6nOhPI6;twD{@wQUMhw5SNqR}B<mt^I?8qt!za8Vb$<oO<n zBx5aLK$&@M@*m@jm5>!c0b<R0D^mKstcwIfp-o!?SDGTp_;y}H_OjO&qHtAwL*Qea zoz2(fvY`@XCSjS$m@;qy>ysUGb!f*(&TRbP>zX%AQti0`KDi8X?^8&}sCg?tM|g5s zM|d!C!Fb8VOCkl^p-ob@6tb!wk^Wd-IC1>YbH|X5qjUt4(RecU2U7Q-V7UmmCHFPF z-n9lcCAkn-=i9-9qjyji%`+oW-0le-<(ejMNlq1$8!7lo_lXKhZ+4`oAx3~wswSci z)tZR51Z}#Z70<E($2!=bv{|XgM~Lf9oZW+`LJ>*TEV)?6ST7aJ?#S2;EodDuz9HfV zqi%CQz|<Tv?#?BxNdT~K@T!6C<Xy1!6=>&x8+cbx2gnML*yJ}&xyWEK2luZ4k3IhY z?K=<uz#ibA^rBC}DYbq?Z9}_sFG^@zUA}ppq)fuQfm)f8#<&&b-L2UW?;g65YPr)w z&}EEoyA}o10Kg+5dNchzFn9Z`$HfBwAGYq7J+lt*XXH{%!5W!9s^-3v`p3=}!1_uj Z?ITfhWasCho(WF`hmBrD>Mv||^B1Fm6_Ee{ literal 0 HcmV?d00001 diff --git a/src/components/library-item/library-item.css b/src/components/library-item/library-item.css index 7b7079441..760153eae 100644 --- a/src/components/library-item/library-item.css +++ b/src/components/library-item/library-item.css @@ -208,8 +208,8 @@ justify-content: center; overflow: hidden; /* Mask the icon animation */ - width: 1.5rem; - height: 1.5rem; + width: 2.5rem; + height: 2.5rem; background-color: $sound-primary; color: $ui-white; border-radius: 50%; diff --git a/src/components/library-item/library-item.jsx b/src/components/library-item/library-item.jsx index 3101e4279..f63f92d39 100644 --- a/src/components/library-item/library-item.jsx +++ b/src/components/library-item/library-item.jsx @@ -9,9 +9,11 @@ import classNames from 'classnames'; import bluetoothIconURL from './bluetooth.svg'; import internetConnectionIconURL from './internet-connection.svg'; import playIcon from './icon--play.svg'; +import stopIcon from './icon--stop.svg'; const preventClick = e => { e.stopPropagation(); + e.preventDefault(); }; /* eslint-disable react/prefer-stateless-function */ @@ -141,15 +143,14 @@ class LibraryItemComponent extends React.PureComponent { <div aria-label="Play" className={styles.playButton} - role="button" - tabIndex="0" onClick={preventClick} - onMouseDown={this.props.onPlay} + onMouseDown={this.props.isPlaying ? this.props.onStop : this.props.onPlay} + onMouseLeave={this.props.isPlaying ? this.props.onStop : null} > <img className={styles.playIcon} draggable={false} - src={playIcon} + src={this.props.isPlaying ? stopIcon : playIcon} /> </div> ) : null} @@ -174,6 +175,7 @@ LibraryItemComponent.propTypes = { iconURL: PropTypes.string, insetIconURL: PropTypes.string, internetConnectionRequired: PropTypes.bool, + isPlaying: PropTypes.bool, name: PropTypes.oneOfType([ PropTypes.string, PropTypes.node @@ -185,6 +187,7 @@ LibraryItemComponent.propTypes = { onMouseEnter: PropTypes.func.isRequired, onMouseLeave: PropTypes.func.isRequired, onPlay: PropTypes.func.isRequired, + onStop: PropTypes.func.isRequired, showPlayButton: PropTypes.bool }; diff --git a/src/components/library/library.jsx b/src/components/library/library.jsx index 3be73b34c..0a86c26db 100644 --- a/src/components/library/library.jsx +++ b/src/components/library/library.jsx @@ -43,7 +43,7 @@ class LibraryComponent extends React.Component { 'setFilteredDataRef' ]); this.state = { - selectedItem: null, + playingItem: null, filterQuery: '', selectedTag: ALL_TAG.tag, loaded: false @@ -75,10 +75,20 @@ class LibraryComponent extends React.Component { }); } handleMouseEnter (id) { - if (this.props.onItemMouseEnter) this.props.onItemMouseEnter(this.getFilteredData()[id]); + console.log('Library MouseEnter id:', id, ', playingItem: ', this.state.playingItem); + // don't restart if mouse over already playing item + if (this.props.onItemMouseEnter && this.state.playingItem !== id) { + this.setState({ + playingItem: id + }, this.props.onItemMouseEnter(this.getFilteredData()[id])); + } } handleMouseLeave (id) { - if (this.props.onItemMouseLeave) this.props.onItemMouseLeave(this.getFilteredData()[id]); + if (this.props.onItemMouseLeave) { + this.setState({ + playingItem: null + }, this.props.onItemMouseLeave(this.getFilteredData()[id])); + } } handleFilterChange (event) { this.setState({ @@ -185,6 +195,7 @@ class LibraryComponent extends React.Component { id={index} insetIconURL={dataItem.insetIconURL} internetConnectionRequired={dataItem.internetConnectionRequired} + isPlaying={this.state.playingItem === index} key={typeof dataItem.name === 'string' ? dataItem.name : dataItem.rawURL} name={dataItem.name} showPlayButton={this.props.showPlayButton} diff --git a/src/containers/library-item.jsx b/src/containers/library-item.jsx index 3ffa81485..75f6b2998 100644 --- a/src/containers/library-item.jsx +++ b/src/containers/library-item.jsx @@ -16,6 +16,7 @@ class LibraryItem extends React.PureComponent { 'handleMouseEnter', 'handleMouseLeave', 'handlePlay', + 'handleStop', 'rotateIcon', 'startRotatingIcons', 'stopRotatingIcons' @@ -65,8 +66,14 @@ class LibraryItem extends React.PureComponent { } handlePlay (e) { e.stopPropagation(); // To prevent from bubbling back to handleClick + e.preventDefault(); this.props.onMouseEnter(this.props.id); } + handleStop (e) { + e.stopPropagation(); // To prevent from bubbling back to handleClick + e.preventDefault(); + this.props.onMouseLeave(this.props.id); + } startRotatingIcons () { this.rotateIcon(); this.intervalId = setInterval(this.rotateIcon, 300); @@ -109,6 +116,7 @@ class LibraryItem extends React.PureComponent { id={this.props.id} insetIconURL={this.props.insetIconURL} internetConnectionRequired={this.props.internetConnectionRequired} + isPlaying={this.props.isPlaying} name={this.props.name} showPlayButton={this.props.showPlayButton} onBlur={this.handleBlur} @@ -118,6 +126,7 @@ class LibraryItem extends React.PureComponent { onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} onPlay={this.handlePlay} + onStop={this.handleStop} /> ); } @@ -144,6 +153,7 @@ LibraryItem.propTypes = { id: PropTypes.number.isRequired, insetIconURL: PropTypes.string, internetConnectionRequired: PropTypes.bool, + isPlaying: PropTypes.bool, name: PropTypes.oneOfType([ PropTypes.string, PropTypes.node -- GitLab