Skip to content

Commit

Permalink
Merge pull request #21 from BatPio/rework
Browse files Browse the repository at this point in the history
Photos on the map #4
  • Loading branch information
BatPio authored Sep 24, 2017
2 parents afeefe3 + b8c6e4b commit 0c5d478
Show file tree
Hide file tree
Showing 17 changed files with 838 additions and 1 deletion.
14 changes: 14 additions & 0 deletions appinfo/application.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,26 @@
use OC\AppFramework\Utility\SimpleContainer;
use \OCP\AppFramework\App;
use OCA\Maps\Controller\PageController;
use OCA\Maps\Hook\FileHooks;
use OCA\Maps\Service\PhotofilesService;


class Application extends App {
public function __construct (array $urlParams=array()) {
parent::__construct('maps', $urlParams);

$container = $this->getContainer();

$this->getContainer()->registerService('FileHooks', function($c) {
return new FileHooks(
$c->query('ServerContainer')->getRootFolder(),
\OC::$server->query(PhotofilesService::class),
$c->query('ServerContainer')->getLogger(),
$c->query('AppName')
);
});

$this->getContainer()->query('FileHooks')->register();
}

}
35 changes: 35 additions & 0 deletions appinfo/database.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,39 @@
</field>
</declaration>
</table>
<table>
<name>*dbprefix*maps_photos</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<autoincrement>1</autoincrement>
<length>41</length>
</field>
<field>
<name>user_id</name>
<type>text</type>
<notnull>true</notnull>
<length>64</length>
</field>
<field>
<name>file_id</name>
<type>integer</type>
<notnull>true</notnull>
<length>10</length>
</field>
<field>
<name>lat</name>
<type>float</type>
<notnull>true</notnull>
</field>
<field>
<name>lng</name>
<type>float</type>
<notnull>true</notnull>
</field>
</declaration>
</table>
</database>
6 changes: 6 additions & 0 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@
<route>maps.page.index</route>
</navigation>
</navigations>
<types>
<filesystem/>
</types>
<commands>
<command>OCA\Maps\Command\RescanPhotos</command>
</commands>
</info>
5 changes: 4 additions & 1 deletion appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
return [
'routes' => [
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'page#do_echo', 'url' => '/echo', 'verb' => 'POST'],
['name' => 'page#do_echo', 'url' => '/echo', 'verb' => 'POST'],

//photos
['name' => 'photos#getPhotosFromDb', 'url' => '/photos', 'verb' => 'GET'],
]
];
45 changes: 45 additions & 0 deletions css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,48 @@ tr.selected td {
.leaflet-popup-content-wrapper {
border-radius: 3px !important;
}

.leaflet-marker-photo {
border: 2px solid #fff;
box-shadow: 3px 3px 10px #888;
}

.leaflet-marker-photo.photo-marker{
top: -10px;
}

.leaflet-marker-photo.photo-marker:after {
content:"";
position: relative;
bottom: 16px;
border-width: 10px 10px 0;
border-style: solid;
border-color: #fff transparent;
display: block;
width: 0;
margin-left: auto;
margin-right: auto;
}

.leaflet-marker-photo .thumbnail {
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
background-color: white;
}

.leaflet-marker-photo .label {
position: absolute;
top: -7px;
right: -11px;
color: #fff;
background-color: #333;
border-radius: 9px;
height: 18px;
min-width: 18px;
line-height: 12px;
text-align: center;
padding: 3px;
}
155 changes: 155 additions & 0 deletions js/photosController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
function PhotosController () {
this.PHOTO_MARKER_VIEW_SIZE = 40;
this.photosDataLoaded = false;
this.photosRequestInProgress = false;
}

PhotosController.prototype = {

appendToMap : function(map) {
this.map = map;
this.photoLayer = L.markerClusterGroup({
iconCreateFunction : this.getClusterIconCreateFunction(),
showCoverageOnHover : false,
maxClusterRadius: this.PHOTO_MARKER_VIEW_SIZE + 10,
icon: {
iconSize: [this.PHOTO_MARKER_VIEW_SIZE, this.PHOTO_MARKER_VIEW_SIZE]
}
});
this.photoLayer.on('click', this.getPhotoMarkerOnClickFunction());
this.photoLayer.addTo(this.map);
},

showLayer: function() {
if (!this.photosDataLoaded && !this.photosRequestInProgress) {
this.callForImages();
}
if (!this.map.hasLayer(this.photoLayer)) {
this.map.addLayer(this.photoLayer);
}
},

hideLayer: function() {
if (this.map.hasLayer(this.photoLayer)) {
this.map.removeLayer(this.photoLayer);
}
},

getPhotoMarkerOnClickFunction() {
var _app = this;
return function(evt) {
var marker = evt.layer;
var content;
if (marker.data.hasPreview) {
var previewUrl = _app.generatePreviewUrl(marker.data.path);
var img = "<img src=" + previewUrl + "/>";
//Workaround for https://github.com/Leaflet/Leaflet/issues/5484
$(img).on('load', function() {
marker.getPopup().update();
});
content = img;
} else {
content = marker.data.path;
}
marker.bindPopup(content, {
className: 'leaflet-popup-photo',
maxWidth: "auto"
}).openPopup();
}
},

getClusterIconCreateFunction() {
var _app = this;
return function(cluster) {
var marker = cluster.getAllChildMarkers()[0].data;
var iconUrl;
if (marker.hasPreview) {
iconUrl = _app.generatePreviewUrl(marker.path);
} else {
iconUrl = _app.getImageIconUrl();
}
var label = cluster.getChildCount();
return new L.DivIcon(L.extend({
className: 'leaflet-marker-photo cluster-marker',
html: '<div class="thumbnail" style="background-image: url(' + iconUrl + ');"></div>​<span class="label">' + label + '</span>'
}, this.icon));
}
},

createPhotoView: function(markerData) {
var iconUrl;
if (markerData.hasPreview) {
iconUrl = this.generatePreviewUrl(markerData.path);
} else {
iconUrl = this.getImageIconUrl();
}
this.generatePreviewUrl(markerData.path);
return L.divIcon(L.extend({
html: '<div class="thumbnail" style="background-image: url(' + iconUrl + ');"></div>​',
className: 'leaflet-marker-photo photo-marker'
}, markerData, {
iconSize: [this.PHOTO_MARKER_VIEW_SIZE, this.PHOTO_MARKER_VIEW_SIZE],
iconAnchor: [this.PHOTO_MARKER_VIEW_SIZE / 2, this.PHOTO_MARKER_VIEW_SIZE]
}));
},

addPhotosToMap : function(photos) {
var markers = this.preparePhotoMarkers(photos);
this.photoLayer.addLayers(markers);
},

preparePhotoMarkers : function(photos) {
var markers = [];
for (var i = 0; i < photos.length; i++) {
var markerData = {
lat: photos[i].lat,
lng: photos[i].lng,
path: photos[i].path,
albumId: photos[i].folderId,
hasPreview : photos[i].hasPreview
};
var marker = L.marker(markerData, {
icon: this.createPhotoView(markerData)
});
marker.data = markerData;
markers.push(marker);
}
return markers;
},

callForImages: function() {
this.photosRequestInProgress = true;
$.ajax({
'url' : OC.generateUrl('apps/maps/photos'),
'type': 'GET',
'context' : this,
'success': function(response) {
if (response.length == 0) {
//showNoPhotosMessage();
} else {
this.addPhotosToMap(response);
}
this.photosDataLoaded = true;
},
'complete': function(response) {
this.photosRequestInProgress = false;
}
});
},

/* Preview size 32x32 is used in files view, so it sould be generated */
generateThumbnailUrl: function (filename) {
return OC.generateUrl('core') + '/preview.png?file=' + encodeURI(filename) + '&x=32&y=32';
},

/* Preview size 375x211 is used in files details view */
generatePreviewUrl: function (filename) {
return OC.generateUrl('core') + '/preview.png?file=' + encodeURI(filename) + '&x=375&y=211&a=1';
},

getImageIconUrl: function() {
return OC.generateUrl('/apps/theming/img/core/filetypes') + '/image.svg?v=2';
}

};

4 changes: 4 additions & 0 deletions js/script.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
(function($, OC) {
$(function() {
mapController.initMap();
photosController.appendToMap(mapController.map);
photosController.showLayer();

// Popup
$(document).on('click', '#opening-hours-header', function() {
Expand Down Expand Up @@ -65,6 +67,8 @@
}
};

var photosController = new PhotosController();

var searchController = {
isGeocodeabe: function(str) {
var pattern = /^\s*\d+\.?\d*\,\s*\d+\.?\d*\s*$/;
Expand Down
77 changes: 77 additions & 0 deletions lib/Command/RescanPhotos.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

/**
* Nextcloud - maps
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Piotr Bator <prbator@gmail.com>
* @copyright Piotr Bator 2017
*/

namespace OCA\Maps\Command;

use OCP\Encryption\IManager;
use OCP\Files\NotFoundException;
use OCP\IUser;
use OCP\IUserManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

use OCA\Maps\Service\PhotofilesService;

class RescanPhotos extends Command {

protected $userManager;

protected $output;

protected $encryptionManager;

private $photofilesService;

public function __construct(IUserManager $userManager,
IManager $encryptionManager,
PhotofilesService $photofilesService) {
parent::__construct();
$this->userManager = $userManager;
$this->encryptionManager = $encryptionManager;
$this->photofilesService = $photofilesService;
}
protected function configure() {
$this->setName('maps:scan-photos')
->setDescription('Rescan photos GPS exif data')
->addArgument(
'user_id',
InputArgument::OPTIONAL,
'Rescan photos GPS exif data for the given user'
);
}

protected function execute(InputInterface $input, OutputInterface $output) {
if ($this->encryptionManager->isEnabled()) {
$output->writeln('Encryption is enabled. Aborted.');
return 1;
}
$this->output = $output;
$userId = $input->getArgument('user_id');
if ($userId === null) {
$this->userManager->callForSeenUsers(function (IUser $user) {
$this->rescanUserPhotos($user->getUID());
});
} else {
$user = $this->userManager->get($userId);
if ($user !== null) {
$this->rescanUserPhotos($userId);
}
}
return 0;
}

private function rescanUserPhotos($userId) {
$this->photofilesService->rescan($userId);
}
}
Loading

0 comments on commit 0c5d478

Please sign in to comment.