Group months in album

pull/162/head
Varun Patil 2022-11-03 15:39:48 -07:00
parent 6feffe70ea
commit 80a76a5a48
6 changed files with 120 additions and 30 deletions

View File

@ -133,6 +133,21 @@ class ApiBase extends Controller
return $folder; return $folder;
} }
protected function isRecursive()
{
return null === $this->request->getParam('folder');
}
protected function isArchive()
{
return null !== $this->request->getParam('archive');
}
protected function isMonthView()
{
return null !== $this->request->getParam('monthView');
}
protected function getShareToken() protected function getShareToken()
{ {
return $this->request->getParam('folder_share'); return $this->request->getParam('folder_share');

View File

@ -49,25 +49,26 @@ class DaysController extends ApiBase
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_NOT_FOUND); return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_NOT_FOUND);
} }
// Params
$recursive = null === $this->request->getParam('folder');
$archive = null !== $this->request->getParam('archive');
// Run actual query // Run actual query
try { try {
$list = $this->timelineQuery->getDays( $list = $this->timelineQuery->getDays(
$folder, $folder,
$uid, $uid,
$recursive, $this->isRecursive(),
$archive, $this->isArchive(),
$this->getTransformations(true), $this->getTransformations(true),
); );
if ($this->isMonthView()) {
// Group days together into months
$list = $this->timelineQuery->daysToMonths($list);
} else {
// Preload some day responses // Preload some day responses
$this->preloadDays($list, $uid, $folder, $recursive, $archive); $this->preloadDays($list, $uid, $folder);
}
// Add subfolder info if querying non-recursively // Add subfolder info if querying non-recursively
if (!$recursive) { if (!$this->isRecursive()) {
array_unshift($list, $this->getSubfoldersEntry($folder)); array_unshift($list, $this->getSubfoldersEntry($folder));
} }
@ -88,18 +89,18 @@ class DaysController extends ApiBase
$uid = $this->getUid(); $uid = $this->getUid();
// Check for wildcard // Check for wildcard
$day_ids = []; $dayIds = [];
if ('*' === $id) { if ('*' === $id) {
$day_ids = null; $dayIds = null;
} else { } else {
// Split at commas and convert all parts to int // Split at commas and convert all parts to int
$day_ids = array_map(function ($part) { $dayIds = array_map(function ($part) {
return (int) $part; return (int) $part;
}, explode(',', $id)); }, explode(',', $id));
} }
// Check if $day_ids is empty // Check if $dayIds is empty
if (null !== $day_ids && 0 === \count($day_ids)) { if (null !== $dayIds && 0 === \count($dayIds)) {
return new JSONResponse([], Http::STATUS_OK); return new JSONResponse([], Http::STATUS_OK);
} }
@ -112,21 +113,29 @@ class DaysController extends ApiBase
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_NOT_FOUND); return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_NOT_FOUND);
} }
// Params // Convert to actual dayIds if month view
$recursive = null === $this->request->getParam('folder'); if ($this->isMonthView()) {
$archive = null !== $this->request->getParam('archive'); $dayIds = $this->timelineQuery->monthIdToDayIds($dayIds[0]);
}
// Run actual query // Run actual query
try { try {
$list = $this->timelineQuery->getDay( $list = $this->timelineQuery->getDay(
$folder, $folder,
$uid, $uid,
$day_ids, $dayIds,
$recursive, $this->isRecursive(),
$archive, $this->isArchive(),
$this->getTransformations(false), $this->getTransformations(false),
); );
// Force month id for dayId for month view
if ($this->isMonthView()) {
foreach ($list as &$photo) {
$photo['dayid'] = (int) $dayIds[0];
}
}
return new JSONResponse($list, Http::STATUS_OK); return new JSONResponse($list, Http::STATUS_OK);
} catch (\Exception $e) { } catch (\Exception $e) {
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR); return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
@ -255,10 +264,8 @@ class DaysController extends ApiBase
* @param array $days the days array * @param array $days the days array
* @param string $uid User ID or blank for public shares * @param string $uid User ID or blank for public shares
* @param null|Folder $folder the folder to search in * @param null|Folder $folder the folder to search in
* @param bool $recursive search in subfolders
* @param bool $archive search in archive folder only
*/ */
private function preloadDays(array &$days, string $uid, &$folder, bool $recursive, bool $archive) private function preloadDays(array &$days, string $uid, &$folder)
{ {
$transforms = $this->getTransformations(false); $transforms = $this->getTransformations(false);
$preloaded = 0; $preloaded = 0;
@ -283,8 +290,8 @@ class DaysController extends ApiBase
$folder, $folder,
$uid, $uid,
$preloadDayIds, $preloadDayIds,
$recursive, $this->isRecursive(),
$archive, $this->isArchive(),
$transforms, $transforms,
); );

View File

@ -78,6 +78,44 @@ trait TimelineQueryAlbums
return $albums; return $albums;
} }
/**
* Convert days response to months response.
* The dayId is used to group the days into months.
*/
public function daysToMonths(array &$days)
{
$months = [];
foreach ($days as &$day) {
$dayId = $day['dayid'];
$time = $dayId * 86400;
$monthid = strtotime(date('Ym', $time).'01') / 86400;
if (empty($months) || $months[\count($months) - 1]['dayid'] !== $monthid) {
$months[] = [
'dayid' => $monthid,
'count' => 0,
];
}
$months[\count($months) - 1]['count'] += $day['count'];
}
return $months;
}
/** Convert list of month IDs to list of dayIds */
public function monthIdToDayIds(int $monthId)
{
$dayIds = [];
$firstDay = (int) $monthId;
$lastDay = strtotime(date('Ymt', $firstDay * 86400)) / 86400;
for ($i = $firstDay; $i <= $lastDay; ++$i) {
$dayIds[] = (string) $i;
}
return $dayIds;
}
/** /**
* Get album if allowed. Also check if album is shared with user. * Get album if allowed. Also check if album is shared with user.
* *

View File

@ -78,7 +78,7 @@ trait TimelineQueryDays
* *
* @param null|Folder $folder The folder to get the day from * @param null|Folder $folder The folder to get the day from
* @param string $uid The user id * @param string $uid The user id
* @param int[] $dayid The day id * @param int[] $day_ids The day ids to fetch
* @param bool $recursive If the query should be recursive * @param bool $recursive If the query should be recursive
* @param bool $archive If the query should include only the archive folder * @param bool $archive If the query should include only the archive folder
* @param array $queryTransforms The query transformations to apply * @param array $queryTransforms The query transformations to apply

View File

@ -256,6 +256,10 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
return window.innerWidth <= 600; return window.innerWidth <= 600;
} }
isMonthView() {
return this.$route.name === "albums";
}
allowBreakout() { allowBreakout() {
return this.isMobileLayout() && !this.config_squareThumbs; return this.isMobileLayout() && !this.config_squareThumbs;
} }
@ -534,6 +538,11 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
query.set("folder_share", this.$route.params.token); query.set("folder_share", this.$route.params.token);
} }
// Month view
if (this.isMonthView()) {
query.set("monthView", "1");
}
// Create query string and append to URL // Create query string and append to URL
const queryStr = query.toString(); const queryStr = query.toString();
if (queryStr) { if (queryStr) {
@ -582,7 +591,12 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
// The reason this function is separate from processDays is // The reason this function is separate from processDays is
// because this call is terribly slow even on desktop // because this call is terribly slow even on desktop
const dateTaken = utils.dayIdToDate(head.dayId); const dateTaken = utils.dayIdToDate(head.dayId);
const name = utils.getLongDateStr(dateTaken, true); let name: string;
if (this.isMonthView()) {
name = utils.getMonthDateStr(dateTaken);
} else {
name = utils.getLongDateStr(dateTaken, true);
}
// Cache and return // Cache and return
head.name = name; head.name = name;
@ -782,6 +796,13 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
// Aggregate fetch requests // Aggregate fetch requests
this.fetchDayQueue.push(dayId); this.fetchDayQueue.push(dayId);
// Only single queries allowed for month vie
if (this.isMonthView()) {
return this.fetchDayExpire();
}
// Defer for aggregation
if (!this.fetchDayTimer) { if (!this.fetchDayTimer) {
this.fetchDayTimer = window.setTimeout(() => { this.fetchDayTimer = window.setTimeout(() => {
this.fetchDayTimer = null; this.fetchDayTimer = null;

View File

@ -51,6 +51,15 @@ export function getLongDateStr(date: Date, skipYear = false, time = false) {
}); });
} }
/** Get month and year string */
export function getMonthDateStr(date: Date) {
return date.toLocaleDateString(getCanonicalLocale(), {
month: "long",
year: "numeric",
timeZone: "UTC",
});
}
/** Get text like "5 years ago" from a date */ /** Get text like "5 years ago" from a date */
export function getFromNowStr(date: Date) { export function getFromNowStr(date: Date) {
// Get fromNow in correct locale // Get fromNow in correct locale