/* * Copyright (C) 2012 Alex Kuiper * * This file is part of PageTurner * * PageTurner is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * PageTurner is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PageTurner. If not, see <http://www.gnu.org/licenses/>.* */ package net.nightwhistler.pageturner.view; import android.os.Build; import android.text.style.ClickableSpan; import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import jedi.option.Option; import net.nightwhistler.pageturner.Configuration; import net.nightwhistler.pageturner.view.bookview.BookView; import net.nightwhistler.pageturner.view.bookview.BookViewListener; import net.nightwhistler.pageturner.view.bookview.HighlightSpan; import net.nightwhistler.pageturner.view.bookview.SelectedWord; import java.util.List; /** * Translates low-level touch and gesture events into more high-level * navigation events. * * @author Alex Kuiper * */ public class NavGestureDetector extends GestureDetector.SimpleOnGestureListener { //Distance to scroll 1 unit on edge slide. private static final int SCROLL_FACTOR = 50; private static final int BOOKVIEW_BLOCK_TIME = 1500; private BookViewListener bookViewListener; private BookView bookView; private DisplayMetrics metrics; public NavGestureDetector( BookView bookView, BookViewListener navListener, DisplayMetrics metrics ) { this.bookView = bookView; this.bookViewListener = navListener; this.metrics = metrics; } @Override public boolean onSingleTapUp(MotionEvent e) { bookView.blockFor( BOOKVIEW_BLOCK_TIME ); //Links get preference List<ClickableSpan> spans = bookView.getLinkAt(e.getX(), e.getY() ); Log.d("NavGestureDetector", "Got " + spans.size() + " ClickableSpans."); if ( spans.size() > 0 ) { for (ClickableSpan span : spans) { span.onClick(bookView); } return true; } List<HighlightSpan> highlightSpans = bookView.getHighlightsAt(e.getX(), e.getY()); Log.d("NavGestureDetector", "Got " + highlightSpans.size() + " HighLightSpans."); if ( highlightSpans.size() > 0 ) { for ( HighlightSpan span: highlightSpans ) { bookView.highlightClicked( span.getHighLight() ); } return true; } final int TAP_RANGE_H = bookView.getWidth() / 5; final int TAP_RANGE_V = bookView.getHeight() / 5; if ( e.getX() < TAP_RANGE_H ) { return bookViewListener.onTapLeftEdge(); } else if (e.getX() > bookView.getWidth() - TAP_RANGE_H ) { return bookViewListener.onTapRightEdge(); } int yBase = bookView.getScrollY(); if ( e.getY() < TAP_RANGE_V + yBase ) { return bookViewListener.onTapTopEdge(); } else if ( e.getY() > (yBase + bookView.getHeight()) - TAP_RANGE_V ) { return bookViewListener.onTapBottomEdge(); } this.bookViewListener.onScreenTap(); return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { float scrollUnitSize = SCROLL_FACTOR * metrics.density; final int TAP_RANGE_H = bookView.getWidth() / 5; float delta = (e1.getY() - e2.getY()) / scrollUnitSize; int level = (int) delta; if ( e1.getX() < TAP_RANGE_H ) { return this.bookViewListener.onLeftEdgeSlide(level); } else if ( e1.getX() > bookView.getWidth() - TAP_RANGE_H ) { return this.bookViewListener.onRightEdgeSlide(level); } return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { float distanceX = e2.getX() - e1.getX(); float distanceY = e2.getY() - e1.getY(); if ( Math.abs(distanceX) > Math.abs(distanceY) ) { bookView.blockFor( BOOKVIEW_BLOCK_TIME ); if ( distanceX > 0 ) { return bookViewListener.onSwipeRight(); } else { return bookViewListener.onSwipeLeft(); } } else if (Math.abs(distanceY) > Math.abs(distanceX) ) { bookView.blockFor( BOOKVIEW_BLOCK_TIME ); if ( distanceY > 0 ) { return bookViewListener.onSwipeUp(); } else { return bookViewListener.onSwipeDown(); } } return false; } @Override public void onLongPress(MotionEvent e) { //On older platforms we generate a popup-event. if ( Build.VERSION.SDK_INT < Configuration.TEXT_SELECTION_PLATFORM_VERSION) { Option<SelectedWord> wordOption = bookView.getWordAt(e.getX(), e.getY() ); wordOption.match( word -> bookViewListener.onWordLongPressed( word.getStartOffset(), word.getEndOffset(), word.getText() ) , () -> {} ); super.onLongPress(e); } } }