PhotoViewerPage.java
/*
* Copyright (C) 2000 - 2025 Silverpeas
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "https://www.silverpeas.org/legal/floss_exception.html"
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.silverpeas.mobile.client.apps.media.pages;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Image;
import org.silverpeas.mobile.client.common.app.View;
import org.silverpeas.mobile.client.common.event.touch.TouchCopy;
import org.silverpeas.mobile.client.common.navigation.UrlUtils;
import org.silverpeas.mobile.client.components.base.PageContent;
import org.silverpeas.mobile.shared.dto.media.PhotoDTO;
/**
* @author: svu
*/
public class PhotoViewerPage extends PageContent implements View, TouchStartHandler,
TouchEndHandler, TouchMoveHandler, TouchCancelHandler {
interface PhotoViewerPageUiBinder extends UiBinder<HTMLPanel, PhotoViewerPage> {
}
@UiField HTMLPanel viewer;
private Image img;
private static PhotoViewerPageUiBinder uiBinder = GWT.create(PhotoViewerPageUiBinder.class);
private int touchCount;
private double ratio;
private double distance = 0.0;
private double zoomLevel = 1.0;
private double initialZoomLevel = 1.0;
private long initialTranslationX, initialTranslationY = 0;
private long currentTranslationX, currentTranslationY = 0;
private String translation = "";
private int startx, starty = 0;
private enum State {
READY, INVALID, ONE_FINGER, TWO_FINGER;
}
private State state, previousState;
private TouchCopy touchStart1;
private TouchCopy touchStart2;
public PhotoViewerPage() {
initWidget(uiBinder.createAndBindUi(this));
state = State.READY;
previousState = state;
Document.get().getElementsByTagName("body").getItem(0).getStyle().setOverflowY(Style.Overflow.HIDDEN);
}
public void setDataPhoto(final String dataPhoto) {
this.img = new Image(dataPhoto);
img.setStyleName("photo");
img.addTouchStartHandler(this);
img.addTouchEndHandler(this);
img.addTouchMoveHandler(this);
img.addTouchCancelHandler(this);
viewer.add(img);
}
public void setDataPhoto(final PhotoDTO photo) {
String url = UrlUtils.getSilverpeasServicesLocation();
url += "gallery/" + photo.getInstance() + "/photos/" + photo.getId() + "/content?resolution=ORIGINAL";
this.img = new Image(url);
img.setStyleName("photo");
img.addTouchStartHandler(this);
img.addTouchEndHandler(this);
img.addTouchMoveHandler(this);
img.addTouchCancelHandler(this);
viewer.add(img);
}
@Override
public void onTouchCancel(final TouchCancelEvent event) {
touchCount--;
if (touchCount <= 0) {
previousState = State.ONE_FINGER;
reset();
} else {
if (state == State.TWO_FINGER) {
previousState = State.TWO_FINGER;
state = State.ONE_FINGER;
} else {
if (touchCount == 2) {
state = State.TWO_FINGER;
previousState = State.TWO_FINGER;
}
}
}
}
@Override
public void onTouchEnd(final TouchEndEvent event) {
touchCount--;
if (touchCount <= 0) {
previousState = State.ONE_FINGER;
reset();
} else {
if (state == State.TWO_FINGER) {
previousState = State.TWO_FINGER;
state = State.ONE_FINGER;
} else {
if (touchCount == 2) {
state = State.TWO_FINGER;
previousState = State.TWO_FINGER;
}
}
}
}
@Override
public void onTouchMove(final TouchMoveEvent event) {
int left = img.getAbsoluteLeft();
int top = img.getAbsoluteTop();
int x1,y1,x2,y2;
switch (state) {
case ONE_FINGER:
if (previousState.equals(State.TWO_FINGER) == false) {
Touch touch = event.getTouches().get(0);
x1 = touch.getPageX();
y1 = touch.getPageY();
if (startx != 0 && starty != 0) {
currentTranslationX = Math.round((x1 - startx) / initialZoomLevel) + initialTranslationX;
currentTranslationY = Math.round((y1 - starty) / initialZoomLevel) + initialTranslationY;
translation = "translate(" + currentTranslationX + "px," + currentTranslationY + "px)";
applyTransformation(initialZoomLevel, translation);
} else {
startx = x1;
starty = y1;
}
}
break;
case TWO_FINGER:
Touch touch1 = event.getTouches().get(0);
Touch touch2 = event.getTouches().get(1);
x1 = touch1.getPageX() - left;
y1 = touch1.getPageY() - top;
x2 = touch2.getPageX() - left;
y2 = touch2.getPageY() - top;
double newDistance = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
calculateZoomLevel(newDistance);
applyTransformation(zoomLevel, translation);
if (distance == 0.0) {
distance = newDistance;
}
break;
default:
state = State.INVALID;
break;
}
}
private void applyTransformation(double zoom, String translation) {
img.getElement().setAttribute("style","-webkit-transform: scale(" + zoom + ") " + translation);
}
private double calculateZoomLevel(double newDistance) {
ratio = (newDistance / distance);
if (ratio >= 1) {
zoomLevel = ratio + initialZoomLevel;
} else {
zoomLevel = initialZoomLevel - (1 / ratio);
}
if (zoomLevel < 1) zoomLevel = 1;
return zoomLevel;
};
@Override
public void onTouchStart(final TouchStartEvent event) {
touchCount++;
switch (state) {
case READY:
touchStart1 = TouchCopy.copy(event.getTouches().get(0));
startx = touchStart1.getPageX();
starty = touchStart1.getPageY();
state = State.ONE_FINGER;
break;
case ONE_FINGER:
touchStart2 = TouchCopy.copy(event.getTouches().get(1));
distance = (int) Math.sqrt(Math.pow(touchStart1.getPageX() - touchStart2.getPageX(), 2) + Math.pow(touchStart1.getPageY() - touchStart2.getPageY(), 2));
state = State.TWO_FINGER;
break;
default:
state = State.INVALID;
break;
}
}
@Override
public void stop() {
Document.get().getElementsByTagName("body").getItem(0).getStyle().clearOverflowY();
super.stop();
}
private void reset() {
initialZoomLevel = zoomLevel;
initialTranslationX = currentTranslationX;
initialTranslationY = currentTranslationY;
touchCount = 0;
distance = 0.0;
startx = 0;
starty = 0;
state = State.READY;
}
}