From f3d1a91533a17241a064312da08f15c944c7511c Mon Sep 17 00:00:00 2001
From: Chris Garrity <chrisg@media.mit.edu>
Date: Tue, 18 Jun 2019 10:16:55 -0400
Subject: [PATCH] Add play buttons to sound library tiles for touch
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add prop to library items to show a play button. If a play button is present the ‘play on hover’ only applies over the icon rather than the full tile.
---
 src/components/library-item/icon--play.svg   | Bin 0 -> 2150 bytes
 src/components/library-item/library-item.css |  43 +++++++++++++++++++
 src/components/library-item/library-item.jsx |  38 +++++++++++++---
 src/components/library/library.jsx           |   5 ++-
 src/containers/library-item.jsx              |  10 ++++-
 src/containers/sound-library.jsx             |   1 +
 6 files changed, 90 insertions(+), 7 deletions(-)
 create mode 100644 src/components/library-item/icon--play.svg

diff --git a/src/components/library-item/icon--play.svg b/src/components/library-item/icon--play.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7c4f45df771c93f5487fb64479c751600fd001ba
GIT binary patch
literal 2150
zcmb7F-*2Nh5Pt7p;d6D;Rtg6H0OJa>+U;rYrPZ!3yD#@fgA=$CjKDPMf4^fO32oDd
zbEU=}+ut`c{$@x%A9fXb)@@gsI>nR(80mU#^0MBh_}9;GUW`#^vpUZzQ|lDh27g{&
zCEfED?aSO2DHf_ZU{vUGTi6tb%&neFz5i+sDfU7XAfb=|m>CPj2zcu*#f7!at?%#m
zd$Q-mv|FDALEr=abmaC>mG#r5gH$Qy54(7Ig<vFqcpmy&*SgKDX>ZZ$N!xXS1SbrA
z;wp&L4f4>8@zE4|S7uYZWNmhSH{S8Q3DTCf(#xjGUJ`$tk5swt*2}wAXIAHs30q8T
zB=Lu><Ec$I0uBB(8Jx>g{6HmPjEX3vi<odBloEoYJF1A3Q6#8Z2ol5*kD`zx#))EF
z1fg_R#RINHgjhs`6rqge9O7OCgoZ3oQY<(nR0MIT(4AmJ29ilZ7d#{!=;8<-B_LA7
zDw1r$V-kl{Ix8HIl0^}hbL+iyPVhJgqPh8w5hYX@#A<F0h*C^SE*O{{AB(9#oP@%;
z?wmNec7Hh)|6)`^qFll}ikFG+X0uFg%F5~%Ifc=P$UiZ9aZ^P&OebMd4veroN|Qp6
z5v<3%zv|M0{><ZldTqa&zIKua&5p$58IMiMa<At`ve6HwZ3<JF?F(wNyzBvkkq{%(
zjIv8{URIzAz=48VnZ8}?FI7`y7`3|VE2xpK$a1q^HK3mSdk=985ze8{kxs1NH=9md
zltaK!p*aK#KaSu6)*GJj>YQh^yyLhtyT){-)idB%m%+~7gmjMD^!9CpuP(zIZuE)b
z0(oWHhs?I+0X=6`uOY7i^p4?=FcpL98I2$vXKM(SFoH6fS?TEjp$KwhUmECIy8(Ef
zu}i+4JUDv?P7g{OEv~kY1)XdMh5pF48WajWvNcabf2`r@$CY;!;-I<8HBYw*h?Up&
z6`a=3x;A+}Q`rRjm+qddX*|!PEDjEmxlr1y?lz{~rFfV+m3{IeXb;daVJwixg`5^Q
zGt5Clqq{4s8;=9*7gs-^cyHBjx4MHa=KXBT-3Khei2^#w$o7_CM)Cu?rRRJ9=(TBc
zn5-a@4}j<1^WY=r9kv@&a$Gn50FO};3q?6yAm%(}Q5fBz)>xM-bqwQX%;lKC*%fbg
z=S}`b2gd(N-|68MQ~X$E>!;~SO_Qxl3#AEi7*&(vzO6o8ADhVyeA3*<?6zq2CdJq1
w?goHo&CRLYe4sn(>-yU;K9tyL|ANZ?H+$l5-@EnB_{wlv43ort$d^~Y0TNA0e*gdg

literal 0
HcmV?d00001

diff --git a/src/components/library-item/library-item.css b/src/components/library-item/library-item.css
index 5e726a363..128c9f93e 100644
--- a/src/components/library-item/library-item.css
+++ b/src/components/library-item/library-item.css
@@ -7,6 +7,7 @@
     align-items: center;
     justify-content: flex-start;
     flex-basis: 160px;
+    position: relative;
     height: 160px;
     max-width: 160px;
     margin: $space;
@@ -200,3 +201,45 @@
 [dir="rtl"] .coming-soon-text {
     transform: translate(calc(-2 * $space), calc(2 * $space));
 }
+
+.play-button {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    overflow: hidden;  /* Mask the icon animation */
+    width: 1.5rem;
+    height: 1.5rem;
+    background-color: $motion-primary;
+    color: $ui-white;
+    border-radius: 50%;
+    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+    user-select: none;
+    cursor: pointer;
+    transition: all 0.15s ease-out;
+}
+
+.play-button {
+    position: absolute;
+    position: absolute;
+    top: 0.125rem;
+    z-index: auto;
+}
+
+.play-button:focus {
+    outline: none;
+}
+
+.play-icon {
+  width: 50%;
+}
+
+[dir="ltr"] .play-button {
+    right: 0.125rem;
+    padding-left: .125rem;
+}
+
+[dir="rtl"] .play-button {
+    left: 0.125rem;
+    padding-right: .125rem;
+}
diff --git a/src/components/library-item/library-item.jsx b/src/components/library-item/library-item.jsx
index 5af6fb159..3101e4279 100644
--- a/src/components/library-item/library-item.jsx
+++ b/src/components/library-item/library-item.jsx
@@ -8,6 +8,11 @@ import classNames from 'classnames';
 
 import bluetoothIconURL from './bluetooth.svg';
 import internetConnectionIconURL from './internet-connection.svg';
+import playIcon from './icon--play.svg';
+
+const preventClick = e => {
+    e.stopPropagation();
+};
 
 /* eslint-disable react/prefer-stateless-function */
 class LibraryItemComponent extends React.PureComponent {
@@ -115,12 +120,16 @@ class LibraryItemComponent extends React.PureComponent {
                 onClick={this.props.onClick}
                 onFocus={this.props.onFocus}
                 onKeyPress={this.props.onKeyPress}
-                onMouseEnter={this.props.onMouseEnter}
-                onMouseLeave={this.props.onMouseLeave}
+                onMouseEnter={this.props.showPlayButton ? null : this.props.onMouseEnter}
+                onMouseLeave={this.props.showPlayButton ? null : this.props.onMouseLeave}
             >
                 {/* Layers of wrapping is to prevent layout thrashing on animation */}
                 <Box className={styles.libraryItemImageContainerWrapper}>
-                    <Box className={styles.libraryItemImageContainer}>
+                    <Box
+                        className={styles.libraryItemImageContainer}
+                        onMouseEnter={this.props.showPlayButton ? this.props.onMouseEnter : null}
+                        onMouseLeave={this.props.showPlayButton ? this.props.onMouseLeave : null}
+                    >
                         <img
                             className={styles.libraryItemImage}
                             src={this.props.iconURL}
@@ -128,6 +137,22 @@ class LibraryItemComponent extends React.PureComponent {
                     </Box>
                 </Box>
                 <span className={styles.libraryItemName}>{this.props.name}</span>
+                {this.props.showPlayButton ? (
+                    <div
+                        aria-label="Play"
+                        className={styles.playButton}
+                        role="button"
+                        tabIndex="0"
+                        onClick={preventClick}
+                        onMouseDown={this.props.onPlay}
+                    >
+                        <img
+                            className={styles.playIcon}
+                            draggable={false}
+                            src={playIcon}
+                        />
+                    </div>
+                ) : null}
             </Box>
         );
     }
@@ -158,11 +183,14 @@ LibraryItemComponent.propTypes = {
     onFocus: PropTypes.func.isRequired,
     onKeyPress: PropTypes.func.isRequired,
     onMouseEnter: PropTypes.func.isRequired,
-    onMouseLeave: PropTypes.func.isRequired
+    onMouseLeave: PropTypes.func.isRequired,
+    onPlay: PropTypes.func.isRequired,
+    showPlayButton: PropTypes.bool
 };
 
 LibraryItemComponent.defaultProps = {
-    disabled: false
+    disabled: false,
+    showPlayButton: false
 };
 
 export default LibraryItemComponent;
diff --git a/src/components/library/library.jsx b/src/components/library/library.jsx
index 13736d60f..3be73b34c 100644
--- a/src/components/library/library.jsx
+++ b/src/components/library/library.jsx
@@ -187,6 +187,7 @@ class LibraryComponent extends React.Component {
                             internetConnectionRequired={dataItem.internetConnectionRequired}
                             key={typeof dataItem.name === 'string' ? dataItem.name : dataItem.rawURL}
                             name={dataItem.name}
+                            showPlayButton={this.props.showPlayButton}
                             onMouseEnter={this.handleMouseEnter}
                             onMouseLeave={this.handleMouseLeave}
                             onSelect={this.handleSelect}
@@ -227,12 +228,14 @@ LibraryComponent.propTypes = {
     onItemMouseLeave: PropTypes.func,
     onItemSelected: PropTypes.func,
     onRequestClose: PropTypes.func,
+    showPlayButton: PropTypes.bool,
     tags: PropTypes.arrayOf(PropTypes.shape(TagButton.propTypes)),
     title: PropTypes.string.isRequired
 };
 
 LibraryComponent.defaultProps = {
-    filterable: true
+    filterable: true,
+    showPlayButton: false
 };
 
 export default injectIntl(LibraryComponent);
diff --git a/src/containers/library-item.jsx b/src/containers/library-item.jsx
index 6177b916f..3ffa81485 100644
--- a/src/containers/library-item.jsx
+++ b/src/containers/library-item.jsx
@@ -15,6 +15,7 @@ class LibraryItem extends React.PureComponent {
             'handleKeyPress',
             'handleMouseEnter',
             'handleMouseLeave',
+            'handlePlay',
             'rotateIcon',
             'startRotatingIcons',
             'stopRotatingIcons'
@@ -62,6 +63,10 @@ class LibraryItem extends React.PureComponent {
             }, this.stopRotatingIcons);
         }
     }
+    handlePlay (e) {
+        e.stopPropagation(); // To prevent from bubbling back to handleClick
+        this.props.onMouseEnter(this.props.id);
+    }
     startRotatingIcons () {
         this.rotateIcon();
         this.intervalId = setInterval(this.rotateIcon, 300);
@@ -105,12 +110,14 @@ class LibraryItem extends React.PureComponent {
                 insetIconURL={this.props.insetIconURL}
                 internetConnectionRequired={this.props.internetConnectionRequired}
                 name={this.props.name}
+                showPlayButton={this.props.showPlayButton}
                 onBlur={this.handleBlur}
                 onClick={this.handleClick}
                 onFocus={this.handleFocus}
                 onKeyPress={this.handleKeyPress}
                 onMouseEnter={this.handleMouseEnter}
                 onMouseLeave={this.handleMouseLeave}
+                onPlay={this.handlePlay}
             />
         );
     }
@@ -143,7 +150,8 @@ LibraryItem.propTypes = {
     ]),
     onMouseEnter: PropTypes.func.isRequired,
     onMouseLeave: PropTypes.func.isRequired,
-    onSelect: PropTypes.func.isRequired
+    onSelect: PropTypes.func.isRequired,
+    showPlayButton: PropTypes.bool
 };
 
 export default injectIntl(LibraryItem);
diff --git a/src/containers/sound-library.jsx b/src/containers/sound-library.jsx
index e49f1057a..677d93dfb 100644
--- a/src/containers/sound-library.jsx
+++ b/src/containers/sound-library.jsx
@@ -141,6 +141,7 @@ class SoundLibrary extends React.PureComponent {
 
         return (
             <LibraryComponent
+                showPlayButton
                 data={soundLibraryThumbnailData}
                 id="soundLibrary"
                 tags={soundTags}
-- 
GitLab