Skip to content

feat(web): Memory - #2759

Merged
alextran1502 merged 30 commits into
mainfrom
feat/on-this-day
Jun 15, 2023
Merged

alextran1502 merged 30 commits into
mainfrom
feat/on-this-day

Conversation

@alextran1502

@alextran1502 alextran1502 commented Jun 14, 2023 •

Copy link
Copy Markdown
Member

This PR builds the foundation for the memory feature.

The first iteration only includes "x year ago"

TODO

  • Auto play

@vercel

vercel Bot commented Jun 14, 2023 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
immich ⬜️ Ignored (Inspect) Jun 15, 2023 1:25am

const luxonDate = DateTime.fromISO(new Date().toISOString(), { zone: timezone });
const today = new Date(luxonDate.year, luxonDate.month - 1, luxonDate.day);

const years = Array.from({ length: 30 }, (_, i) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 30?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cause I am 30 years old 😁

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha

const luxonDate = DateTime.fromISO(new Date().toISOString(), { zone: timezone });
const today = new Date(luxonDate.year, luxonDate.month - 1, luxonDate.day);

const years = Array.from({ length: 30 }, (_, i) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rather than a static number like 30, there should be a config which sets an upper limit?

Also, might it be more efficient to query the database for all distinct years? Would therefore be a single query followed by however many more are required, or just one query if you want to go crazy, instead of 30 always.

Something like:

SELECT DATE_PART('year', date_creation::date) AS year, count(*)
FROM assets
WHERE EXTRACT(MONTH FROM fileCreatedAt) = 2 AND EXTRACT(MONTH FROM fileCreatedAt) = 15;
GROUP BY year;

I haven't tested it, but theoretically it would produce something like:

const result = {
    2023: [{ fileCreatedAt: '2023-02-15', ... }],
    2000: [{ fileCreatedAt: '2000-02-15', ... }, { fileCreatedAt: '2000-02-15', ... }],
};

export class MemoryLaneResponseDto {
title!: string;

assets!: AssetResponseDto[];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is Dto? Data Transfer Object? What's the significance?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use DTO for openapi to generate the strong type for request and response

Comment on lines +73 to +76
return true;
}

return false;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the condition checks against showNextMemory, it may be simpler just to return that value.

Suggested change
return true;
}
return false;
return showNextMemory;

if (showPreviousMemory) {
resetAutoPlay();

currentIndex -= 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
currentIndex -= 1;
currentIndex--;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is Svelte reactivity, the rule of thumb is that the props need to be on the left hand side to trigger state changes

Read more here

https://svelte.dev/tutorial/updating-arrays-and-objects

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw I changed the example code to ++ and it seems to work okay.

image

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that indeed works, I tried to follow the convention of updating the left-hand side across the web app for consistency. However, it does make the code cleaner for this component. Thank you for the feedback

Comment thread web/src/lib/components/memory-page/memory-viewer.svelte Outdated
autoPlayInterval = setInterval(() => {
if (!canPlayNext) return;

window.requestAnimationFrame(() => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of an animation frame here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it is optimized for animation on screen

You can search around the internet for more information. I used this technique from implementing the virtual viewport

You can read the "Minimize changes" section in the article below

https://medium.com/google-design/google-photos-45b714dfbed1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a nice article, and even talks a bit about low resolution thumbnails which is relevant to some other work going on in #2649.

Though I still don't quite get the actual use of animation frame here. An animation frame is being request to increment an integer? I would imagine that won't do much if anything at all, and instead more logic would need to be moved into the animation frame. I could be mistaken though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The biggest thing it will do is not update the progress bar when the page is in the background.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it's still not great as suddenly all the animation frames are run all at once when the page is moved to the foreground again.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behaviour also becomes really strange if the animation frame doesn't run in reasonable time, all those animation frames will run all at once as mentioned before and I'm not sure how svelte would deal with that. Would it quickly do all steps from 0-100? Seems like it needs some thinking.

@uhthomas uhthomas Jun 15, 2023 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming the intended behaviour is for the animation to pause when the page is moved to the foreground, this may make more sense:

Details ```ts function draw() { setTimeout(() => requestAnimationFrame(() => {}), autoPlaySpeed / 100); } draw(); ```

It could be better to use requestAnimationFrame exclusively. It would be very efficient.

let previousTransition;
function draw(now) {
  previousTransition ??= now;

  const elapsed = previousTransition - now;
  const progress = elapsed / autoPlaySpeed * 100;

  if (progress >= 100) {
    autoPlayProgress = 0;
    autoPlayTransition();
    previousTransition = now;
  } else {
    autoPlayProgress = progress;
  }
 
  if (autoPlay) {
    requestAnimationFrame(draw);
  }
}
requestAnimationFrame(draw);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be worth using cancelAnimationFrame somewhere too to prevent two animation threads from running at the same time if one were to enable/disable auto-play in quick succession.

Comment thread web/src/lib/components/album-page/album-viewer.svelte
Comment thread mobile/openapi/test/asset_api_test.dart
Comment thread mobile/openapi/test/memory_lane_response_dto_test.dart
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants