Add swipe gestures into motion detail

Adds swipe gestures into motion detail, to nacigate them easily on mobile devices
Animations are left out for now, since they are complex to develop.

Alters the navigation gesture slightly to only work from the edge of a given screen
This commit is contained in:
Sean Engelhardt 2019-02-26 15:30:16 +01:00
parent 798af8c5ab
commit 0ceddd2662
7 changed files with 84 additions and 27 deletions

View File

@ -17,6 +17,16 @@ export abstract class BaseComponent {
*/ */
private titleSuffix = ' - OpenSlides'; private titleSuffix = ' - OpenSlides';
/**
* Holds the coordinates where a swipe gesture was used
*/
protected swipeCoord?: [number, number];
/**
* Holds the time when the user was swiping
*/
protected swipeTime?: number;
/** /**
* Settings for the TinyMCE editor selector * Settings for the TinyMCE editor selector
*/ */

View File

@ -64,6 +64,12 @@ export abstract class BaseViewComponent extends BaseComponent implements OnDestr
} }
} }
/**
* To catch swipe gestures.
* Should be overwritten by children which need swipe gestures
*/
protected swipe(e: TouchEvent, when: string): void {}
/** /**
* automatically dismisses the error snack bar and clears subscriptions * automatically dismisses the error snack bar and clears subscriptions
* if the component is destroyed. * if the component is destroyed.

View File

@ -60,7 +60,9 @@ export abstract class ListViewBaseComponent<V extends BaseViewModel, M extends B
* Constructor for list view bases * Constructor for list view bases
* @param titleService the title serivce * @param titleService the title serivce
* @param translate the translate service * @param translate the translate service
* @param matSnackBar * @param matSnackBar showing errors
* @param filterService filter
* @param sortService sorting
*/ */
public constructor( public constructor(
titleService: Title, titleService: Title,

View File

@ -19,7 +19,7 @@
</div> </div>
<!-- Back and forth buttons --> <!-- Back and forth buttons -->
<div *ngIf="!editMotion" class="extra-controls-slot on-transition-fade"> <div *ngIf="!editMotion && !vp.isMobile" class="extra-controls-slot on-transition-fade">
<div *ngIf="previousMotion"> <div *ngIf="previousMotion">
<button mat-button (click)="navigateToMotion(previousMotion)"> <button mat-button (click)="navigateToMotion(previousMotion)">
<!-- possible icons: <!-- possible icons:
@ -103,7 +103,7 @@
</mat-menu> </mat-menu>
</os-head-bar> </os-head-bar>
<div class="content-container"> <div class="content-container" (touchstart)="swipe($event, 'start')" (touchend)="swipe($event, 'end')">
<!-- Title --> <!-- Title -->
<div class="title on-transition-fade" *ngIf="motion && !editMotion"> <div class="title on-transition-fade" *ngIf="motion && !editMotion">
<div class="title-line"> <div class="title-line">

View File

@ -28,6 +28,7 @@ import {
} from '../motion-change-recommendation/motion-change-recommendation.component'; } from '../motion-change-recommendation/motion-change-recommendation.component';
import { MotionPdfExportService } from '../../services/motion-pdf-export.service'; import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service'; import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
import { NotifyService } from 'app/core/core-services/notify.service'; import { NotifyService } from 'app/core/core-services/notify.service';
import { OperatorService } from 'app/core/core-services/operator.service'; import { OperatorService } from 'app/core/core-services/operator.service';
import { PersonalNoteContent } from 'app/shared/models/users/personal-note'; import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
@ -50,7 +51,6 @@ import { ViewMotionNotificationEditMotion, TypeOfNotificationViewMotion } from '
import { ViewStatuteParagraph } from '../../models/view-statute-paragraph'; import { ViewStatuteParagraph } from '../../models/view-statute-paragraph';
import { ViewTag } from 'app/site/tags/models/view-tag'; import { ViewTag } from 'app/site/tags/models/view-tag';
import { ViewUnifiedChange } from 'app/shared/models/motions/view-unified-change'; import { ViewUnifiedChange } from 'app/shared/models/motions/view-unified-change';
import { Workflow } from 'app/shared/models/motions/workflow'; import { Workflow } from 'app/shared/models/motions/workflow';
/** /**
@ -1079,11 +1079,13 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
* @param motion target * @param motion target
*/ */
public navigateToMotion(motion: ViewMotion): void { public navigateToMotion(motion: ViewMotion): void {
if (motion) {
this.router.navigate(['../' + motion.id], { relativeTo: this.route }); this.router.navigate(['../' + motion.id], { relativeTo: this.route });
// update the current motion // update the current motion
this.motion = motion; this.motion = motion;
this.setSurroundingMotions(); this.setSurroundingMotions();
} }
}
/** /**
* Sets the previous and next motion. Sorts ascending by identifier, and * Sets the previous and next motion. Sorts ascending by identifier, and
@ -1458,4 +1460,34 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
return StateCssClassMapping[this.motion.state.css_class] || ''; return StateCssClassMapping[this.motion.state.css_class] || '';
} }
public swipe(e: TouchEvent, when: string): void {
const coord: [number, number] = [e.changedTouches[0].pageX, e.changedTouches[0].pageY];
const time = new Date().getTime();
if (when === 'start') {
this.swipeCoord = coord;
this.swipeTime = time;
} else if (when === 'end') {
const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]];
const duration = time - this.swipeTime;
if (
duration < 1000 &&
Math.abs(direction[0]) > 30 && // swipe length to be detected
Math.abs(direction[0]) > Math.abs(direction[1] * 3) // 30° should be "horizontal enough"
) {
if (
direction[0] > 0 // swipe left to right
) {
this.navigateToMotion(this.previousMotion);
}
if (
direction[0] < 0 // swipe left to right
) {
this.navigateToMotion(this.nextMotion);
}
}
}
}
} }

View File

@ -3,7 +3,13 @@
<span>({{ getHistoryTimestamp() }})</span> <span>({{ getHistoryTimestamp() }})</span>
<a (click)="timeTravel.resumeTime()" translate>Exit</a> <a (click)="timeTravel.resumeTime()" translate>Exit</a>
</div> </div>
<mat-sidenav-container #siteContainer class="main-container" (backdropClick)="toggleSideNav()"> <mat-sidenav-container
#siteContainer
class="main-container"
(backdropClick)="toggleSideNav()"
(touchstart)="swipe($event, 'start')"
(touchend)="swipe($event, 'end')"
>
<mat-sidenav <mat-sidenav
#sideNav #sideNav
[mode]="vp.isMobile ? 'over' : 'side'" [mode]="vp.isMobile ? 'over' : 'side'"

View File

@ -38,16 +38,6 @@ export class SiteComponent extends BaseComponent implements OnInit {
*/ */
public isLoggedIn: boolean; public isLoggedIn: boolean;
/**
* Holds the coordinates where a swipe gesture was used
*/
private swipeCoord?: [number, number];
/**
* Holds the time when the user was swiping
*/
private swipeTime?: number;
/** /**
* Holds the typed search query. * Holds the typed search query.
*/ */
@ -171,18 +161,29 @@ export class SiteComponent extends BaseComponent implements OnInit {
} else if (when === 'end') { } else if (when === 'end') {
const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]]; const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]];
const duration = time - this.swipeTime; const duration = time - this.swipeTime;
// definition of a "swipe right" gesture to move in the navigation.
// Required mobile view
// works anywhere on the screen, but could be limited
// to the left side of the screen easily if required)
if ( if (
duration < 1000 && duration < 1000 &&
Math.abs(direction[0]) > 30 && // swipe length to be detected Math.abs(direction[0]) > 30 && // swipe length to be detected
Math.abs(direction[0]) > Math.abs(direction[1] * 3) && // 30° should be "horizontal enough" Math.abs(direction[0]) > Math.abs(direction[1] * 3) // 30° should be "horizontal enough"
direction[0] > 0 // swipe left to right
) { ) {
this.toggleSideNav(); // definition of a "swipe right" gesture to move in the navigation
// only works in the far left edge of the screen
if (
direction[0] > 0 && // swipe left to right
this.swipeCoord[0] < 20
) {
this.sideNav.open();
}
// definition of a "swipe left" gesture to remove the navigation
// should only work in mobile mode to prevent unwanted closing of the nav
// works anywhere on the screen
if (
direction[0] < 0 && // swipe left to right
this.vp.isMobile
) {
this.sideNav.close();
}
} }
} }
} }