Rework meta data display on photo page #45

Merged
minnozz merged 5 commits from photo-page into master 2024-01-13 17:23:06 +01:00
4 changed files with 105 additions and 121 deletions

View File

@ -8,6 +8,8 @@
class ViewPhoto extends HTMLController
{
private Image $photo;
public function __construct()
{
// Ensure we're logged in at this point.
@ -19,44 +21,36 @@ class ViewPhoto extends HTMLController
if (empty($photo))
throw new NotFoundException();
$this->photo = $photo->getImage();
Session::resetSessionToken();
parent::__construct($photo->getTitle() . ' - ' . SITE_TITLE);
parent::__construct($this->photo->getTitle() . ' - ' . SITE_TITLE);
if (!empty($_POST))
$this->handleTagging($photo->getImage());
$this->handleTagging();
else
$this->handleViewPhoto($photo);
$this->handleViewPhoto();
}
private function handleViewPhoto(Asset $photo)
private function handleViewPhoto()
{
$page = new PhotoPage($photo->getImage());
$page = new PhotoPage($this->photo);
// Exif data?
$exif = EXIF::fromFile($photo->getFullPath());
if ($exif)
$page->setExif($exif);
// Any (EXIF) meta data?
$metaData = $this->prepareMetaData();
$page->setMetaData($metaData);
// What tag are we browsing?
$tag = isset($_GET['in']) ? Tag::fromId($_GET['in']) : null;
$id_tag = isset($tag) ? $tag->id_tag : null;
// Find previous photo in set.
$previous_url = $photo->getUrlForPreviousInSet($id_tag);
if ($previous_url)
$page->setPreviousPhotoUrl($previous_url);
// ... and the next photo, too.
$next_url = $photo->getUrlForNextInSet($id_tag);
if ($next_url)
$page->setNextPhotoUrl($next_url);
if (isset($tag))
$page->setTag($tag);
$this->page->adopt($page);
$this->page->setCanonicalUrl($photo->getPageUrl());
$this->page->setCanonicalUrl($this->photo->getPageUrl());
}
private function handleTagging(Image $photo)
private function handleTagging()
{
header('Content-Type: text/json; charset=utf-8');
@ -70,7 +64,7 @@ class ViewPhoto extends HTMLController
// We are!
if (!isset($_POST['delete']))
{
$photo->linkTags([(int) $_POST['id_tag']]);
$this->photo->linkTags([(int) $_POST['id_tag']]);
echo json_encode(['success' => true]);
exit;
}
@ -78,9 +72,43 @@ class ViewPhoto extends HTMLController
// ... deleting, that is.
else
{
$photo->unlinkTags([(int) $_POST['id_tag']]);
$this->photo->unlinkTags([(int) $_POST['id_tag']]);
echo json_encode(['success' => true]);
exit;
}
}
private function prepareMetaData()
{
if (!($exif = EXIF::fromFile($this->photo->getFullPath())))
throw new UnexpectedValueException('Photo file not found!');
$metaData = [];
if (!empty($exif->created_timestamp))
$metaData['Date Taken'] = date("j M Y, H:i:s", $exif->created_timestamp);
if ($author = $this->photo->getAuthor())
$metaData['Uploaded by'] = $author->getfullName();
if (!empty($exif->camera))
$metaData['Camera Model'] = $exif->camera;
if (!empty($exif->shutter_speed))
$metaData['Shutter Speed'] = $exif->shutterSpeedFraction();
if (!empty($exif->aperture))
$metaData['Aperture'] = 'f/' . number_format($exif->aperture, 1);
Aaron marked this conversation as resolved Outdated

Maybe re-add the f/ prefix?

Maybe re-add the `f/` prefix?
if (!empty($exif->focal_length))
$metaData['Focal Length'] = $exif->focal_length . ' mm';
Aaron marked this conversation as resolved Outdated

Maybe re-add the mm unit?

Maybe re-add the `mm` unit?
if (!empty($exif->iso))
$metaData['ISO Speed'] = $exif->iso;
if (!empty($exif->software))
$metaData['Software'] = $exif->software;
return $metaData;
}
}

View File

@ -697,11 +697,11 @@ class Asset
$params);
}
public function getUrlForPreviousInSet($id_tag = null)
public function getUrlForPreviousInSet(?Tag $tag)
{
$row = Registry::get('db')->queryAssoc('
SELECT a.*
' . (isset($id_tag) ? '
' . (isset($tag) ? '
FROM assets_tags AS t
INNER JOIN assets AS a ON a.id_asset = t.id_asset
WHERE t.id_tag = {int:id_tag} AND
@ -715,24 +715,24 @@ class Asset
LIMIT 1',
[
'id_asset' => $this->id_asset,
'id_tag' => $id_tag,
'id_tag' => $tag->id_tag,
'date_captured' => $this->date_captured,
]);
if ($row)
{
$obj = self::byRow($row, 'object');
return $obj->getPageUrl() . ($id_tag ? '?in=' . $id_tag : '');
return $obj->getPageUrl() . ($tag ? '?in=' . $tag->id_tag : '');
}
else
return false;
}
public function getUrlForNextInSet($id_tag = null)
public function getUrlForNextInSet(?Tag $tag)
{
$row = Registry::get('db')->queryAssoc('
SELECT a.*
' . (isset($id_tag) ? '
' . (isset($tag) ? '
FROM assets_tags AS t
INNER JOIN assets AS a ON a.id_asset = t.id_asset
WHERE t.id_tag = {int:id_tag} AND
@ -746,14 +746,14 @@ class Asset
LIMIT 1',
[
'id_asset' => $this->id_asset,
'id_tag' => $id_tag,
'id_tag' => $tag->id_tag,
'date_captured' => $this->date_captured,
]);
if ($row)
{
$obj = self::byRow($row, 'object');
return $obj->getPageUrl() . ($id_tag ? '?in=' . $id_tag : '');
return $obj->getPageUrl() . ($tag ? '?in=' . $tag->id_tag : '');
}
else
return false;

View File

@ -523,7 +523,7 @@ a#previous_photo:hover, a#next_photo:hover {
right: 0;
}
#sub_photo h2, #sub_photo h3, #photo_exif_box h3, #user_actions_box h3 {
#sub_photo h2, #sub_photo h3 {
margin-bottom: 1rem;
}
#sub_photo #tag_list {
@ -542,18 +542,17 @@ a#previous_photo:hover, a#next_photo:hover {
opacity: 1.0;
}
#photo_exif_box dt {
.photo_meta {
background-color: var(--bs-body-bg);
box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,0.1);
}
.photo_meta li {
padding: 0.6rem 1rem;
}
.photo_meta h4 {
font-family: 'Coda', sans-serif;
font-size: inherit;
font-weight: bold;
float: left;
clear: left;
width: 120px;
}
#photo_exif_box dt:after {
content: ':';
}
#photo_exif_box dd {
float: left;
margin: 0;
}
@ -583,13 +582,6 @@ a#previous_photo:hover, a#next_photo:hover {
#previous_photo, #next_photo {
display: none;
}
#sub_photo, #photo_exif_box {
float: none;
margin: 30px 0;
padding: 10px;
width: auto;
}
}

View File

@ -8,26 +8,15 @@
class PhotoPage extends Template
{
protected $photo;
private $exif;
private $previous_photo_url = '';
private $next_photo_url = '';
private $photo;
private $metaData;
private $tag;
public function __construct(Image $photo)
{
$this->photo = $photo;
}
public function setPreviousPhotoUrl($url)
{
$this->previous_photo_url = $url;
}
public function setNextPhotoUrl($url)
{
$this->next_photo_url = $url;
}
public function html_main()
{
$this->photoNav();
@ -35,8 +24,12 @@ class PhotoPage extends Template
echo '
<div class="row mt-5">
<div class="col-lg-8">
<div id="sub_photo" class="content-box">
<div class="col-lg-9">
<div id="sub_photo" class="content-box">';
$this->userActions();
echo '
<h2 class="entry-title">', $this->photo->getTitle(), '</h2>';
$this->taggedPeople();
@ -45,10 +38,9 @@ class PhotoPage extends Template
echo '
</div>
</div>
<div class="col-lg-4">';
<div class="col-lg-3">';
$this->photoMeta();
$this->userActions();
echo '
</div>
@ -86,18 +78,23 @@ class PhotoPage extends Template
</a>';
}
public function setTag(Tag $tag)
{
$this->tag = $tag;
}
private function photoNav()
{
if ($this->previous_photo_url)
if ($previousUrl = $this->photo->getUrlForPreviousInSet($this->tag))
echo '
<a href="', $this->previous_photo_url, '#photo_frame" id="previous_photo"><i class="bi bi-arrow-left"></i></a>';
<a href="', $previousUrl, '#photo_frame" id="previous_photo"><i class="bi bi-arrow-left"></i></a>';
else
echo '
<span id="previous_photo"><i class="bi bi-arrow-left"></i></span>';
if ($this->next_photo_url)
if ($nextUrl = $this->photo->getUrlForNextInSet($this->tag))
echo '
<a href="', $this->next_photo_url, '#photo_frame" id="next_photo"><i class="bi bi-arrow-right"></i></a>';
<a href="', $nextUrl, '#photo_frame" id="next_photo"><i class="bi bi-arrow-right"></i></a>';
else
echo '
<span id="next_photo"><i class="bi bi-arrow-right"></i></span>';
@ -106,52 +103,19 @@ class PhotoPage extends Template
private function photoMeta()
{
echo '
<div id="photo_exif_box" class="content-box clearfix">
<h3>EXIF</h3>
<dl class="photo_meta">';
<ul class="list-group photo_meta">';
if (!empty($this->exif->created_timestamp))
foreach ($this->metaData as $header => $body)
{
echo '
<dt>Date Taken</dt>
<dd>', date("j M Y, H:i:s", $this->exif->created_timestamp), '</dd>';
<li class="list-group-item">
<h4>', $header, '</h4>
', $body, '
</li>';
}
echo '
<dt>Uploaded by</dt>
<dd>', $this->photo->getAuthor()->getfullName(), '</dd>';
if (!empty($this->exif->camera))
echo '
<dt>Camera Model</dt>
<dd>', $this->exif->camera, '</dd>';
if (!empty($this->exif->shutter_speed))
echo '
<dt>Shutter Speed</dt>
<dd>', $this->exif->shutterSpeedFraction(), '</dd>';
if (!empty($this->exif->aperture))
echo '
<dt>Aperture</dt>
<dd>f/', number_format($this->exif->aperture, 1), '</dd>';
if (!empty($this->exif->focal_length))
echo '
<dt>Focal Length</dt>
<dd>', $this->exif->focal_length, ' mm</dd>';
if (!empty($this->exif->iso))
echo '
<dt>ISO Speed</dt>
<dd>', $this->exif->iso, '</dd>';
if (!empty($this->exif->software))
echo '
<dt>Software</dt>
<dd>', $this->exif->software, '</dd>';
echo '
</dl>
</div>';
</ul>';
}
private function taggedPeople()
@ -246,9 +210,9 @@ class PhotoPage extends Template
</script>';
}
public function setExif(EXIF $exif)
public function setMetaData(array $metaData)
{
$this->exif = $exif;
$this->metaData = $metaData;
}
public function userActions()
@ -257,13 +221,13 @@ class PhotoPage extends Template
return;
echo '
<div id="user_actions_box" class="content-box">
<h3>Actions</h3>
<a class="btn btn-primary" href="', $this->photo->getEditUrl(), '">Edit photo</a>
<div class="float-end">
<a class="btn btn-primary" href="', $this->photo->getEditUrl(), '">
<i class="bi bi-pencil"></i> Edit</a>
<a class="btn btn-danger" href="', $this->photo->getDeleteUrl(), '&',
Session::getSessionTokenKey(), '=', Session::getSessionToken(),
'" onclick="return confirm(\'Are you sure you want to delete this photo?\');"',
'">Delete photo</a>
'"><i class="bi bi-pencil"></i> Delete</a></a>
</div>';
}
}