@@ -14,7 +14,7 @@ import imgNewtab from './img/newtab-white.png';
14
14
* (β’) Add (pop-out?) list view for images/videos in bucket.
15
15
* (β’) Add sorting options/controls.
16
16
* (β’) Add an info icon to show tooltip in mouseover (keyboard shortcuts, etc).
17
- * (β’) Show a loading spinner during loading of each image/video
17
+ * (β’) Show a loading spinner during loading of each image/video.
18
18
* (?) Create a "demo" version of the app using copies of all AWS components and a demo bucket with stock images.
19
19
*
20
20
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
@@ -632,51 +632,88 @@ function useEventListener(eventName, handler, element = window) {
632
632
// Touch interface horizontal swipe functionality
633
633
// [Adapted from https://stackoverflow.com/questions/2264072/detect-a-finger-swipe-through-javascript-on-the-iphone-and-android]
634
634
// TODO: Use React Native to do this instead?
635
- function useHorizonalSwipeNav ( updateIndex , minChangeX = 60 , maxChangeY = 120 ) {
636
- // Variables to hold the start and end coords for each axis
635
+ function useHorizonalSwipeNav ( updateIndex , minChangeX = 150 , maxChangeY = 150 , debug = false ) {
636
+ // Variables to hold the start and end coords for each axis, and a flag to indicate that more than one touch was registered.
637
637
const [ touchCoords , setTouchCoords ] = useState ( {
638
638
startX : null ,
639
639
startY : null ,
640
640
} ) ;
641
+ const [ touchState , setTouchState ] = useState ( {
642
+ multiTouch : false , // whether the current touch event has seen more than a single touch
643
+ initialTouchTime : 0 , // the timestamp of an initial `touchStart` event
644
+ } ) ;
645
+ const MAX_SWIPE_DURATION_MS = 300 ;
641
646
647
+
642
648
// Handler callbacks for the touchstart and touchend events
643
649
const touchStartHandler = useCallback (
644
650
( e ) => {
645
- setTouchCoords ( { startX : e . changedTouches [ 0 ] . screenX , startY : e . changedTouches [ 0 ] . screenY } )
651
+ setTouchCoords ( { startX : e . changedTouches [ 0 ] . screenX , startY : e . changedTouches [ 0 ] . screenY } ) ;
652
+
653
+ // Set `multiTouch` flag if more than one touch is registered at any point during an overall touch event.
654
+ // This will lock out the `touchEndHandler` from responding to swipe events until the touch event ends.
655
+ // Also record the timestamp of this `touchStart` event to measure the duration of the touch event later.
656
+ if ( e . touches . length > 1 ) {
657
+ setTouchState ( { multiTouch : true , initialTouchTime : 0 } ) ;
658
+ }
659
+ else {
660
+ setTouchState ( { multiTouch : false , initialTouchTime : Date . now ( ) } ) ;
661
+ }
662
+
646
663
} , [ ]
647
664
) ;
648
665
const touchEndHandler = useCallback (
649
666
( e ) => {
650
667
if ( ! touchCoords . startX || ! touchCoords . startY ) {
651
- console . log ( "[DEBUG]: Attempted to handle a swipe with 'null' touch coords." ) ;
668
+ if ( debug ) console . log ( "[DEBUG]: Attempted to handle a swipe with 'null' touch coords." ) ;
669
+ return ;
670
+ }
671
+
672
+ // If any touch points are still active, this is a multi-touch event which hasn't ended yet.
673
+ if ( e . touches . length > 0 ) {
652
674
return ;
653
675
}
654
676
677
+ // If no touch points remain and `multiTouch` is `true` here, this is the end of the last touch in a multi-touch event, so skip.
678
+ // If no touch points remain and `multiTouch` is `false` here, this is a single-touch event, so handle the swipe gesture.
679
+ if ( touchState . multiTouch ) {
680
+ setTouchState ( { multiTouch : false , initialTouchTime : 0 } ) ; // Reset `multiTouch` now that the touch event has ended.
681
+ return ;
682
+ }
683
+
684
+ // Check that the single-touch event has finished within the allowed duration.
685
+ if ( ( Date . now ( ) - touchState . initialTouchTime ) > MAX_SWIPE_DURATION_MS ) {
686
+ if ( debug ) console . log ( "[DEBUG]: Swipe gesture took too long and was ignored... | " + `${ Date . now ( ) } - ${ touchState . initialTouchTime } = ${ Date . now ( ) - touchState . initialTouchTime } ` ) ;
687
+ return ;
688
+ }
689
+
690
+
655
691
// Get current state of touch coords (at 'touchend')
656
692
let endX = e . changedTouches [ 0 ] . screenX , endY = e . changedTouches [ 0 ] . screenY ;
657
693
658
694
// Check that the swipe didn't go past the vertical tolerance (maxChangeY)
659
695
// HACK: Should check that the y-coords never go outside of tolerance during the swipe, not just at endpoints?
660
- if ( Math . abs ( endY - touchCoords . startY ) > maxChangeY )
661
- console . log ( "[DEBUG]: Checked for swipe -> No swipe (too far on y-axis)." ) ;
696
+ if ( Math . abs ( endY - touchCoords . startY ) > maxChangeY ) {
697
+ if ( debug ) console . log ( "[DEBUG]: Checked for swipe -> No swipe (too far on y-axis)." ) ;
698
+ }
662
699
663
700
// π Swiped left? π
664
701
else if ( endX < ( touchCoords . startX - minChangeX ) ) {
665
- console . log ( "[DEBUG]: Checked for swipe -> Left swipe (navigating forward)." ) ;
702
+ if ( debug ) console . log ( "[DEBUG]: Checked for swipe -> Left swipe (navigating forward)." ) ;
666
703
// Swipe left = Move right
667
704
updateIndex ( 1 ) ;
668
705
}
669
706
670
707
// π Swiped right? π
671
708
else if ( endX > ( touchCoords . startX + minChangeX ) ) {
672
- console . log ( "[DEBUG]: Checked for swipe -> Right swipe (navigating backward)." ) ;
709
+ if ( debug ) console . log ( "[DEBUG]: Checked for swipe -> Right swipe (navigating backward)." ) ;
673
710
// Swipe right = Move left
674
711
updateIndex ( - 1 ) ;
675
712
}
676
713
677
714
// β No swipe β
678
715
else {
679
- console . log ( "[DEBUG]: Checked for swipe -> No swipe (not far enough on x-axis)." ) ;
716
+ if ( debug ) console . log ( "[DEBUG]: Checked for swipe -> No swipe (not far enough on x-axis)." ) ;
680
717
}
681
718
682
719
// Reset starting touch coords
0 commit comments