From 38c4bac4527b8d76f66ec06f4c91b48fa255b1f0 Mon Sep 17 00:00:00 2001 From: Tomasz Grobelny Date: Sun, 2 Dec 2018 20:04:31 +0100 Subject: [PATCH 1/4] Add controls to rotate image right and left Signed-off-by: Tomasz Grobelny --- js/slideshow.js | 8 ++++++++ js/slideshowcontrols.js | 24 ++++++++++++++++++++---- js/slideshowzoomablepreview.js | 21 +++++++++++++++++++-- templates/slideshow.php | 4 ++++ 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/js/slideshow.js b/js/slideshow.js index 576ce70be..17e84cec4 100644 --- a/js/slideshow.js +++ b/js/slideshow.js @@ -36,6 +36,7 @@ // We need 6 hexas for comparison reasons darkBackgroundColour: '#000000', lightBackgroundColour: '#ffffff', + currentRotation: 0, /** * Initialises the slideshow @@ -162,6 +163,8 @@ } this.zoomablePreview.startBigshot(img, this.currentImage, image.mimeType); + this.currentRotation = 0; + this.zoomablePreview.setRotation(0); this._setUrl(image.path); this.controls.show(currentImageId); @@ -180,6 +183,11 @@ }.bind(this)); }, + rotate: function(direction) { + this.currentRotation = (this.currentRotation + direction + 4) % 4; + this.zoomablePreview.setRotation(this.currentRotation); + }, + /** * Loads the image to show in the slideshow and preloads the next one * diff --git a/js/slideshowcontrols.js b/js/slideshowcontrols.js index 31be1b8b3..76239ed64 100644 --- a/js/slideshowcontrols.js +++ b/js/slideshowcontrols.js @@ -151,6 +151,8 @@ if (!isPublic && canShare) { this.showButton('.shareImage'); } + this.showButton('.rotateLeft'); + this.showButton('.rotateRight'); }, /** @@ -161,6 +163,8 @@ this.hideButton('.downloadImage'); this.hideButton('.deleteImage'); this.hideButton('.shareImage'); + this.hideButton('.rotateLeft'); + this.hideButton('.rotateRight'); }, /** @@ -214,6 +218,8 @@ * @private */ _specialButtonSetup: function (makeCallBack) { + this.container.find('.rotateLeft').click(makeCallBack(this._rotateLeft)); + this.container.find('.rotateRight').click(makeCallBack(this._rotateRight)); this.container.find('.downloadImage').click(makeCallBack(this._getImageDownload)); this.container.find('.deleteImage').click(makeCallBack(this._deleteImage)); this.container.find('.shareImage').click(makeCallBack(this.share)); @@ -259,13 +265,11 @@ */ _keyCodeSetup: function (makeCallBack) { $(document).keyup(function (evt) { - if (evt.target.tagName.toLowerCase() === 'input') { - return; - } - var escKey = 27; var leftKey = 37; var rightKey = 39; + var lKey = 76; + var rKey = 82; var spaceKey = 32; var fKey = 70; var zoomOutKeys = [48, 96, 79, 40]; // zeros, o or down key @@ -276,6 +280,10 @@ makeCallBack(this._previous)(evt); } else if (evt.keyCode === rightKey) { makeCallBack(this._next)(evt); + } else if (evt.keyCode === rKey) { + makeCallBack(this._rotateRight)(evt); + } else if (evt.keyCode === lKey) { + makeCallBack(this._rotateLeft)(evt); } else if (evt.keyCode === spaceKey) { makeCallBack(this._playPauseToggle)(evt); } else if (evt.keyCode === fKey) { @@ -478,6 +486,14 @@ nameElement.text(imageName); }, + _rotateLeft: function () { + this.slideshow.rotate(-1); + }, + + _rotateRight: function () { + this.slideshow.rotate(1); + }, + /** * Delete the image from the slideshow * @private diff --git a/js/slideshowzoomablepreview.js b/js/slideshowzoomablepreview.js index e83bc3f37..0968ebbdb 100644 --- a/js/slideshowzoomablepreview.js +++ b/js/slideshowzoomablepreview.js @@ -223,8 +223,18 @@ this.mimeType === 'image/svg+xml') { // The image is larger than the window, or we are fullScreen, // or this is an SVG. Set minimum zoom and call zoomToFit. - this.zoomable.setMinZoom(this.zoomable.getZoomToFitValue()); - this.zoomable.zoomToFit(); + var width = this.zoomable.width; + var height = this.zoomable.height; + // Image is rotated left or right + if (this.rotation % 2 == 1) { + width = this.zoomable.height; + height = this.zoomable.width; + } + var zoomValue = Math.min ( + this.zoomable.fitZoom (width, this.zoomable.container.clientWidth), + this.zoomable.fitZoom (height, this.zoomable.container.clientHeight)); + this.zoomable.setMinZoom(zoomValue); + this.zoomable.moveTo(null, null, zoomValue); } else { // Zoom to the image size. this.zoomable.setMinZoom(0); @@ -232,6 +242,13 @@ } }, + rotation: 0, + setRotation: function(rotation) { + this.rotation = rotation; + this.container.find('.bigshotContainer').find('img').css('transform', 'rotate('+(this.rotation*90)+'deg)'); + this._resetZoom(); + }, + /** * Starts the fullscreen previews * diff --git a/templates/slideshow.php b/templates/slideshow.php index 4115cb103..bdc20b0d6 100644 --- a/templates/slideshow.php +++ b/templates/slideshow.php @@ -7,6 +7,10 @@
+ + Date: Tue, 4 Dec 2018 22:22:01 +0100 Subject: [PATCH 2/4] Save information about image rotation to database Signed-off-by: Tomasz Grobelny --- appinfo/database.xml | 22 ++++++++++++++ appinfo/info.xml | 2 +- appinfo/routes.php | 10 +++++++ js/slideshow.js | 33 ++++++++++++++++++-- lib/AppInfo/Application.php | 20 +++++++++++++ lib/Controller/PreviewController.php | 12 ++++++++ lib/Db/FileProperties.php | 8 +++++ lib/Db/FilePropertiesMapper.php | 27 +++++++++++++++++ lib/Service/FilePropertiesService.php | 43 +++++++++++++++++++++++++++ 9 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 appinfo/database.xml create mode 100644 lib/Db/FileProperties.php create mode 100644 lib/Db/FilePropertiesMapper.php create mode 100644 lib/Service/FilePropertiesService.php diff --git a/appinfo/database.xml b/appinfo/database.xml new file mode 100644 index 000000000..28b46a253 --- /dev/null +++ b/appinfo/database.xml @@ -0,0 +1,22 @@ + + + *dbname* + true + false + utf8 + + *dbprefix*gallery_file_properties + + + id + integer + true + + + modifications + text + false + + +
+
diff --git a/appinfo/info.xml b/appinfo/info.xml index 21b3d3a98..6c38c603b 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -34,7 +34,7 @@ files app and adds a gallery view to public links. Compatible with Firefox, Chrome and Internet Explorer 11 - 18.3.0 + 18.3.1 agpl Olivier Paroz, Robin Appelman Gallery diff --git a/appinfo/routes.php b/appinfo/routes.php index 7c968905c..0941b53d7 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -96,6 +96,16 @@ 'url' => '/preview/{fileId}', 'verb' => 'GET' ], + [ + 'name' => 'preview#get_modifications', + 'url' => '/preview/modifications/{fileId}', + 'verb' => 'GET' + ], + [ + 'name' => 'preview#set_modifications', + 'url' => '/preview/modifications/{fileId}', + 'verb' => 'POST' + ], /** * Public services */ diff --git a/js/slideshow.js b/js/slideshow.js index 17e84cec4..177f9bb7f 100644 --- a/js/slideshow.js +++ b/js/slideshow.js @@ -26,6 +26,7 @@ zoomablePreviewContainer: null, controls: null, imageCache: {}, + imageModificationsCache: {}, /** {Image} */ currentImage: null, errorLoadingImage: false, @@ -136,6 +137,7 @@ * @returns {*} */ show: function (index) { + this.currentImageIndex = index; this.hideErrorNotification(); this.active = true; this.container.show(); @@ -144,7 +146,9 @@ this._hideImage(); this.container.find('.icon-loading-dark').show(); var currentImageId = index; - return this.loadImage(this.images[index]).then(function (img) { + return this.loadImage(this.images[index]).then(function (results) { + var img = results[0]; + var params = results[1]; this.container.css('background-position', '-10000px 0'); // check if we moved along while we were loading @@ -164,7 +168,12 @@ this.zoomablePreview.startBigshot(img, this.currentImage, image.mimeType); this.currentRotation = 0; - this.zoomablePreview.setRotation(0); + for (var i=0;iregisterService( + 'FilePropertiesService', function (IContainer $c) { + return new FilePropertiesService( + $c->query('AppName'), + $c->query('Environment'), + $c->query('Logger'), + $c->query('FilePropertiesMapper') + ); + } + ); + $container->registerService( + 'FilePropertiesMapper', function (IContainer $c) { + return new FilePropertiesMapper( + $c->query('ServerContainer')->getDatabaseConnection() + ); + } + ); $container->registerService( 'PageController', function (IContainer $c) { return new PageController( @@ -169,6 +188,7 @@ public function __construct(array $urlParams = []) { $c->query('ThumbnailService'), $c->query('PreviewService'), $c->query('DownloadService'), + $c->query('FilePropertiesService'), $c->query('EventSource'), $c->query('Logger') ); diff --git a/lib/Controller/PreviewController.php b/lib/Controller/PreviewController.php index 576f7a8f8..e8ac92ecc 100644 --- a/lib/Controller/PreviewController.php +++ b/lib/Controller/PreviewController.php @@ -27,6 +27,7 @@ use OCA\Gallery\Service\ThumbnailService; use OCA\Gallery\Service\PreviewService; use OCA\Gallery\Service\DownloadService; +use OCA\Gallery\Service\FilePropertiesService; use OCA\Gallery\Utility\EventSource; /** @@ -62,6 +63,7 @@ public function __construct( ThumbnailService $thumbnailService, PreviewService $previewService, DownloadService $downloadService, + FilePropertiesService $filePropertiesService, EventSource $eventSource, ILogger $logger ) { @@ -72,6 +74,7 @@ public function __construct( $this->thumbnailService = $thumbnailService; $this->previewService = $previewService; $this->downloadService = $downloadService; + $this->filePropertiesService = $filePropertiesService; $this->eventSource = $eventSource; $this->logger = $logger; } @@ -152,4 +155,13 @@ public function getPreview($fileId, $width, $height) { return $response; } + public function setModifications($fileId) { + $requestBody = file_get_contents('php://input'); + $this->filePropertiesService->setModifications($fileId, $requestBody); + } + + public function getModifications($fileId) { + return new DataResponse(json_decode($this->filePropertiesService->getModifications($fileId)), 200); + } + } diff --git a/lib/Db/FileProperties.php b/lib/Db/FileProperties.php new file mode 100644 index 000000000..b16b35305 --- /dev/null +++ b/lib/Db/FileProperties.php @@ -0,0 +1,8 @@ +findEntity($sql, [$id]); + } + + public function findAll($limit=null, $offset=null) { + $sql = 'SELECT * FROM `*PREFIX*gallery_file_properties`'; + return $this->findEntities($sql, $limit, $offset); + } +} diff --git a/lib/Service/FilePropertiesService.php b/lib/Service/FilePropertiesService.php new file mode 100644 index 000000000..b9c14db17 --- /dev/null +++ b/lib/Service/FilePropertiesService.php @@ -0,0 +1,43 @@ +mapper = $mapper; + } + + public function getModifications($fileId) { + try { + $entity = $this->mapper->find($fileId); + return $entity->getModifications(); + } catch (DoesNotExistException $ex) { + return "{}"; + } + } + + public function setModifications($fileId, $modificationsJson) { + try { + $entity = $this->mapper->find($fileId); + $entity->setModifications($modificationsJson); + $this->mapper->update($entity); + } catch (DoesNotExistException $ex) { + $entity = new FileProperties(); + $entity->setId($fileId); + $entity->setModifications($modificationsJson); + $this->mapper->insert($entity); + } + } +} From b8aeb239a522de40c273b4d1d75d90683d16d3b7 Mon Sep 17 00:00:00 2001 From: Tomasz Grobelny Date: Sat, 8 Dec 2018 23:23:58 +0100 Subject: [PATCH 3/4] Convert dodatbase.xml to migration Signed-off-by: Tomasz Grobelny --- appinfo/database.xml | 22 -------- .../Version1803Date20181208221653.php | 54 +++++++++++++++++++ 2 files changed, 54 insertions(+), 22 deletions(-) delete mode 100644 appinfo/database.xml create mode 100644 lib/Migration/Version1803Date20181208221653.php diff --git a/appinfo/database.xml b/appinfo/database.xml deleted file mode 100644 index 28b46a253..000000000 --- a/appinfo/database.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - *dbname* - true - false - utf8 - - *dbprefix*gallery_file_properties - - - id - integer - true - - - modifications - text - false - - -
-
diff --git a/lib/Migration/Version1803Date20181208221653.php b/lib/Migration/Version1803Date20181208221653.php new file mode 100644 index 000000000..8891576cf --- /dev/null +++ b/lib/Migration/Version1803Date20181208221653.php @@ -0,0 +1,54 @@ +hasTable('gallery_file_properties')) { + $table = $schema->createTable('gallery_file_properties'); + $table->addColumn('id', 'integer', [ + 'notnull' => true, + ]); + $table->addColumn('modifications', 'string', [ + 'notnull' => false, + ]); + } + return $schema; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { + } +} From 8a84ec368edbd55eef11928600e6863635be3803 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 9 Dec 2018 19:06:22 +0000 Subject: [PATCH 4/4] Fix unit tests Signed-off-by: root --- lib/Controller/Preview.php | 12 +++++++----- lib/Controller/PreviewApiController.php | 2 +- lib/Controller/PreviewController.php | 9 ++++----- tests/unit/Controller/PreviewControllerTest.php | 7 +++++++ .../unit/Controller/PreviewPublicControllerTest.php | 1 + 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/Controller/Preview.php b/lib/Controller/Preview.php index 06f4cbcd4..361cb16fd 100644 --- a/lib/Controller/Preview.php +++ b/lib/Controller/Preview.php @@ -83,7 +83,7 @@ private function getThumbnail($fileId, $square, $scale) { /** @type File $file */ list($file, $preview, $status) = $this->getData( - $fileId, $width, $height, $aspect, $animatedPreview, $base64Encode + $fileId, null, $width, $height, $aspect, $animatedPreview, $base64Encode ); if ($preview === null) { $preview = $this->prepareEmptyThumbnail($file, $status); @@ -107,17 +107,19 @@ private function getThumbnail($fileId, $square, $scale) { * @throws NotFoundServiceException */ private function getData( - $fileId, $width, $height, $keepAspect = true, $animatedPreview = true, $base64Encode = false + $fileId, $etag, $width, $height, $keepAspect = true, $animatedPreview = true, $base64Encode = false ) { /** @type File $file */ list($file, $status) = $this->getFile($fileId); try { - if (!is_null($file)) { + if (is_null($file)) { + $data = $this->getErrorData($status); + } else if (!is_null($etag) && $etag === $file->getEtag()) { + $data = [null, Http::STATUS_NOT_MODIFIED]; + } else { $data = $this->getPreviewData( $file, $animatedPreview, $width, $height, $keepAspect, $base64Encode ); - } else { - $data = $this->getErrorData($status); } } catch (ServiceException $exception) { $data = $this->getExceptionData($exception); diff --git a/lib/Controller/PreviewApiController.php b/lib/Controller/PreviewApiController.php index 51f7eb43b..34f05d00a 100644 --- a/lib/Controller/PreviewApiController.php +++ b/lib/Controller/PreviewApiController.php @@ -123,7 +123,7 @@ public function getThumbnails($ids, $square, $scale) { */ public function getPreview($fileId, $width, $height, $nativesvg = false) { /** @type File $file */ - list($file, $preview, $status) = $this->getData($fileId, $width, $height); + list($file, $preview, $status) = $this->getData($fileId, null, $width, $height); if (!$preview) { return new JSONResponse( diff --git a/lib/Controller/PreviewController.php b/lib/Controller/PreviewController.php index e8ac92ecc..aef996f67 100644 --- a/lib/Controller/PreviewController.php +++ b/lib/Controller/PreviewController.php @@ -130,13 +130,12 @@ public function getThumbnails($ids, $square, $scale) { */ public function getPreview($fileId, $width, $height) { /** @type File $file */ - list($file, $status) = $this->getFile($fileId); - if ($this->request->getHeader('If-None-Match') === $file->getEtag()) { - return new DataResponse([], Http::STATUS_NOT_MODIFIED); - } - list($file, $preview, $status) = $this->getData($fileId, $width, $height); + list($file, $preview, $status) = $this->getData($fileId, $this->request->getHeader('If-None-Match'), $width, $height); if (!$preview) { + if ($status === Http::STATUS_NOT_MODIFIED) { + return new DataResponse([], Http::STATUS_NOT_MODIFIED); + } return new JSONResponse( [ 'message' => "I'm truly sorry, but we were unable to generate a preview for this file", diff --git a/tests/unit/Controller/PreviewControllerTest.php b/tests/unit/Controller/PreviewControllerTest.php index 81a70e0e3..4673d5241 100644 --- a/tests/unit/Controller/PreviewControllerTest.php +++ b/tests/unit/Controller/PreviewControllerTest.php @@ -29,6 +29,7 @@ use OCA\Gallery\Service\ThumbnailService; use OCA\Gallery\Service\PreviewService; use OCA\Gallery\Service\DownloadService; +use OCA\Gallery\Service\FilePropertiesService; use OCA\Gallery\Utility\EventSource; use OCA\Gallery\Service\NotFoundServiceException; use OCA\Gallery\Service\InternalServerErrorServiceException; @@ -58,6 +59,8 @@ class PreviewControllerTest extends \OCA\Gallery\Tests\GalleryUnitTest { protected $previewService; /** @var DownloadService */ protected $downloadService; + /** @var FilePropertiesService */ + protected $filePropertiesService; /** @var EventSource */ protected $eventSource; /** @var ILogger */ @@ -92,6 +95,9 @@ public function setUp() { $this->downloadService = $this->getMockBuilder('\OCA\Gallery\Service\DownloadService') ->disableOriginalConstructor() ->getMock(); + $this->filePropertiesService = $this->getMockBuilder('\OCA\Gallery\Service\FilePropertiesService') + ->disableOriginalConstructor() + ->getMock(); $this->eventSource = $this->getMockBuilder('\OCA\Gallery\Utility\EventSource') ->disableOriginalConstructor() ->getMock(); @@ -106,6 +112,7 @@ public function setUp() { $this->thumbnailService, $this->previewService, $this->downloadService, + $this->filePropertiesService, $this->eventSource, $this->logger ); diff --git a/tests/unit/Controller/PreviewPublicControllerTest.php b/tests/unit/Controller/PreviewPublicControllerTest.php index d284c4b72..07579027c 100644 --- a/tests/unit/Controller/PreviewPublicControllerTest.php +++ b/tests/unit/Controller/PreviewPublicControllerTest.php @@ -32,6 +32,7 @@ public function setUp() { $this->thumbnailService, $this->previewService, $this->downloadService, + $this->filePropertiesService, $this->eventSource, $this->logger );