Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit 5d84c6d

Browse files
mehmetfvsavkin
authored andcommitted
feat: New touch module including ng-swipe-left/ng-swipe-right directives
Support swipe gesture for touch enabled devices. Closes #1403
1 parent 29f3947 commit 5d84c6d

File tree

5 files changed

+222
-0
lines changed

5 files changed

+222
-0
lines changed

lib/touch/module.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Touch related functionality for AngularDart apps.
3+
*
4+
* To use, install the TouchModule into your main module:
5+
*
6+
* var module = new Module()
7+
* ..install(new TouchModule());
8+
*
9+
* Once the module is installed, you can use decorators such
10+
* as ng-swipe-left or ng-swipe right
11+
*/
12+
13+
library angular.touch;
14+
15+
import 'dart:html' as dom;
16+
import 'package:di/di.dart';
17+
import 'package:angular/core/annotation.dart';
18+
19+
part 'ng_swipe.dart';
20+
21+
class TouchModule extends Module {
22+
TouchModule() {
23+
bind(NgSwipeLeft, toValue: null);
24+
bind(NgSwipeRight, toValue: null);
25+
}
26+
}
27+

lib/touch/ng_swipe.dart

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
part of angular.touch;
2+
3+
/**
4+
* Base class for Swipe Gesture. Decides whether a swipe is performed
5+
* and gives the x, y direction of the swipe.
6+
*/
7+
abstract class _SwipeGesture {
8+
static const int NO_SWIPE = -1;
9+
static const int DOWN = 0;
10+
static const int UP = 1;
11+
static const int LEFT = 2;
12+
static const int RIGHT = 3;
13+
14+
// Less than 100 pixels of move in each direction does not count.
15+
static const int _POS_TOLERANCE = 100;
16+
// If swipe lasts more than 1s, it is not a swipe.
17+
static const int _TIME_TOLERANCE = 1000;
18+
19+
// Function to be called on swipe.
20+
Function fn;
21+
22+
// Subclasses decide on swipe direction whether to call fn or not.
23+
bool get shouldFire;
24+
25+
int _startX;
26+
int _startY;
27+
int _startTime;
28+
int xDirection;
29+
int yDirection;
30+
31+
_SwipeGesture(dom.Element target) {
32+
target.onTouchStart.listen(_handleTouchStartEvent);
33+
target.onTouchEnd.listen(_handleTouchEndEvent);
34+
}
35+
36+
void handleTouchStart(int x, int y, int timestamp) {
37+
// Reset values every time swipe starts
38+
xDirection = NO_SWIPE;
39+
yDirection = NO_SWIPE;
40+
_startX = x;
41+
_startY = y;
42+
_startTime = timestamp;
43+
}
44+
45+
void handleTouchEnd(int x, int y, int timestamp) {
46+
int touchDuration = timestamp - _startTime;
47+
if (touchDuration > _TIME_TOLERANCE) {
48+
return;
49+
}
50+
if (y > _startY + _POS_TOLERANCE) {
51+
yDirection = DOWN;
52+
} else if (y < _startY - _POS_TOLERANCE) {
53+
yDirection = UP;
54+
}
55+
if (x > _startX + _POS_TOLERANCE) {
56+
xDirection = RIGHT;
57+
} else if (x < _startX - _POS_TOLERANCE) {
58+
xDirection = LEFT;
59+
}
60+
if (fn != null && shouldFire) {
61+
fn();
62+
}
63+
}
64+
65+
void _handleTouchStartEvent(dom.TouchEvent ev) {
66+
// Guaranteed to have at least one touch in changedTouches.
67+
dom.Touch t = ev.changedTouches.first;
68+
handleTouchStart(t.client.x, t.client.y, ev.timeStamp);
69+
}
70+
71+
void _handleTouchEndEvent(dom.TouchEvent ev) {
72+
// Guaranteed to have at least one touch in changedTouches.
73+
dom.Touch t = ev.changedTouches.first;
74+
handleTouchEnd(t.client.x, t.client.y, ev.timeStamp);
75+
}
76+
}
77+
78+
/**
79+
* The `ng-swipe-right` directive allows execution of callbacks when user
80+
* swipes her finger to the right.
81+
* Also see [NgSwipeLeft].
82+
*/
83+
@Decorator(
84+
selector: '[ng-swipe-right]',
85+
map: const {'ng-swipe-right':'&fn'})
86+
class NgSwipeRight extends _SwipeGesture {
87+
NgSwipeRight(dom.Element target): super(target);
88+
89+
bool get shouldFire => xDirection == _SwipeGesture.RIGHT &&
90+
yDirection == _SwipeGesture.NO_SWIPE;
91+
}
92+
93+
/**
94+
* The `ng-swipe-left` directive allows execution of callbacks when user
95+
* swipes his finger to the left.
96+
* Also see [NgSwipeRight].
97+
*/
98+
@Decorator(
99+
selector: '[ng-swipe-left]',
100+
map: const {'ng-swipe-left':'&fn'})
101+
class NgSwipeLeft extends _SwipeGesture {
102+
NgSwipeLeft(dom.Element target): super(target);
103+
104+
bool get shouldFire => xDirection == _SwipeGesture.LEFT &&
105+
yDirection == _SwipeGesture.NO_SWIPE;
106+
}

test/_specs.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export 'package:angular/directive/module.dart';
3232
export 'package:angular/formatter/module.dart';
3333
export 'package:angular/routing/module.dart';
3434
export 'package:angular/animate/module.dart';
35+
export 'package:angular/touch/module.dart';
3536
export 'package:angular/mock/module.dart';
3637
export 'package:perf_api/perf_api.dart';
3738

test/angular_spec.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,23 @@ main() {
7070
assertSymbolNamesAreOk(ALLOWED_NAMES, libraryInfo);
7171

7272
});
73+
74+
it('should not export unknown symbols from touch', () {
75+
LibraryInfo libraryInfo;
76+
try {
77+
libraryInfo = getSymbolsFromLibrary("angular.touch");
78+
} on UnimplementedError catch (e) {
79+
return; // Not implemented, quietly skip.
80+
}
81+
82+
var ALLOWED_NAMES = [
83+
"angular.touch.NgSwipeLeft",
84+
"angular.touch.NgSwipeRight",
85+
"angular.touch.TouchModule"
86+
];
87+
assertSymbolNamesAreOk(ALLOWED_NAMES, libraryInfo);
88+
89+
});
7390

7491
it('should not export unknown symbols from angular', () {
7592
// Test is failing? Add new symbols to the "ALLOWED_NAMES" list below.

test/touch/ng_swipe_spec.dart

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
library ng_swipe_spec;
2+
3+
import '../_specs.dart';
4+
5+
/**
6+
* Unfortunately, it is not possible to test swipe using events since
7+
* TouchEvent cannot be constructed using fake dom.Touch elements.
8+
* See: dartbug.com/8314
9+
* TODO(8314): Once this is fixed, should update the tests.
10+
*/
11+
void main() {
12+
describe('ng-swipe-right', () {
13+
NgSwipeRight swipe = new NgSwipeRight(new DivElement());
14+
15+
it('should not fire when distance is not enough', () {
16+
swipe.handleTouchStart(10, 10, 0);
17+
swipe.handleTouchEnd(15, 15, 1);
18+
expect(swipe.shouldFire).toBeFalse();
19+
});
20+
21+
it('should fire on swipe to the right', () {
22+
swipe.handleTouchStart(10, 10, 0);
23+
swipe.handleTouchEnd(130, 15, 1);
24+
expect(swipe.shouldFire).toBeTrue();
25+
});
26+
27+
it('should not fire on swipe to the left', () {
28+
swipe.handleTouchStart(130, 10, 0);
29+
swipe.handleTouchEnd(10, 15, 1);
30+
expect(swipe.shouldFire).toBeFalse();
31+
});
32+
33+
it('should not fire on slow swipe', () {
34+
swipe.handleTouchStart(10, 10, 0);
35+
// 2 seconds later
36+
swipe.handleTouchEnd(130, 15, 2000);
37+
expect(swipe.shouldFire).toBeFalse();
38+
});
39+
40+
41+
});
42+
43+
describe('ng-swipe-left', () {
44+
NgSwipeLeft swipe = new NgSwipeLeft(new DivElement());
45+
46+
it('should not fire when distance is not enough', () {
47+
swipe.handleTouchStart(10, 10, 0);
48+
swipe.handleTouchEnd(15, 15, 1);
49+
expect(swipe.shouldFire).toBeFalse();
50+
});
51+
52+
it('should not fire on swipe to the right', () {
53+
swipe.handleTouchStart(10, 10, 0);
54+
swipe.handleTouchEnd(130, 15, 1);
55+
expect(swipe.shouldFire).toBeFalse();
56+
});
57+
58+
it('should fire on swipe to the left', () {
59+
swipe.handleTouchStart(130, 10, 0);
60+
swipe.handleTouchEnd(10, 15, 1);
61+
expect(swipe.shouldFire).toBeTrue();
62+
});
63+
64+
it('should not fire on swipe on slow swipe', () {
65+
swipe.handleTouchStart(130, 10, 0);
66+
// 2 seconds later
67+
swipe.handleTouchEnd(10, 15, 2000);
68+
expect(swipe.shouldFire).toBeFalse();
69+
});
70+
});
71+
}

0 commit comments

Comments
 (0)