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:
parent
798af8c5ab
commit
0ceddd2662
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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">
|
||||||
|
@ -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,10 +1079,12 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
|||||||
* @param motion target
|
* @param motion target
|
||||||
*/
|
*/
|
||||||
public navigateToMotion(motion: ViewMotion): void {
|
public navigateToMotion(motion: ViewMotion): void {
|
||||||
this.router.navigate(['../' + motion.id], { relativeTo: this.route });
|
if (motion) {
|
||||||
// update the current motion
|
this.router.navigate(['../' + motion.id], { relativeTo: this.route });
|
||||||
this.motion = motion;
|
// update the current motion
|
||||||
this.setSurroundingMotions();
|
this.motion = motion;
|
||||||
|
this.setSurroundingMotions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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'"
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user