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

View File

@ -78,6 +78,44 @@ trait TimelineQueryAlbums
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.
*

View File

@ -78,7 +78,7 @@ trait TimelineQueryDays
*
* @param null|Folder $folder The folder to get the day from
* @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 $archive If the query should include only the archive folder
* @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;
}
isMonthView() {
return this.$route.name === "albums";
}
allowBreakout() {
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);
}
// Month view
if (this.isMonthView()) {
query.set("monthView", "1");
}
// Create query string and append to URL
const queryStr = query.toString();
if (queryStr) {
@ -582,7 +591,12 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
// The reason this function is separate from processDays is
// because this call is terribly slow even on desktop
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
head.name = name;
@ -782,6 +796,13 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
// Aggregate fetch requests
this.fetchDayQueue.push(dayId);
// Only single queries allowed for month vie
if (this.isMonthView()) {
return this.fetchDayExpire();
}
// Defer for aggregation
if (!this.fetchDayTimer) {
this.fetchDayTimer = window.setTimeout(() => {
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 */
export function getFromNowStr(date: Date) {
// Get fromNow in correct locale