immich/mobile/lib/presentation/widgets/memory/memory_lane.widget.dart
Ben Beckford 351be95769
feat: memories view (#28675)
* wip web memories view

* paginate searchMemories

* improve memories ui

* feat(mobile): memories view

* improve memories web ui

* fix(web): avoid unnecessary memory refreshes

* refactor(web): move timline memory manager filter

* fix(web): memories infinitely loading on 0 results

* fix(web): memories resetting

* feat(web): animated memory previews

* feat(web): memory page dark styling

* chore(mobile): fix failing memory lane tests

* chore(mobile): remove old import

* chore(e2e): fix failing memory lane tests

* chore(server): revert searchMemories changes

* chore(server): lint

* chore(mobile): fix bad merge

* chore(e2e): fix memory ui tests

* chore(web): rename /memory to /memories

* chore(mobile): linting

* chore(web): linting

* fix(web): prevent duplicate memory page loading

* fix(web): lint

* fix(web): memories page improvements

* chore(mobile): lint

* fix(mobile): fix translations

* fix(mobile): build errors

* fix(web): prevent memories from infinitely loading

* chore(e2e)): fix failng memory viewer test

* chore(web): clean up types in memory manager

* chore(web): lint

* feat: update list and detail memory page layouts

* onlyFavorites through drift

* rename to get all

* mobile: use widgetWhen in memory list page

* remove redundant check

* fix: e2e

---------

Co-authored-by: Timon <mail@timonrieger.de>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2026-08-24 19:16:33 -05:00

87 lines
2.9 KiB
Dart

import 'dart:async';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/memory.model.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/pages/drift_memory.page.dart';
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
import 'package:immich_mobile/providers/infrastructure/memory.provider.dart';
import 'package:immich_mobile/routing/router.dart';
class DriftMemoryLane extends ConsumerWidget {
const DriftMemoryLane({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final memoryLaneProvider = ref.watch(driftMemoryLaneProvider);
final memories = memoryLaneProvider.value ?? const [];
if (memories.isEmpty) {
return const SizedBox.shrink();
}
return ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200),
child: CarouselView(
itemExtent: 145.0,
shrinkExtent: 1.0,
elevation: 2,
backgroundColor: Colors.black,
overlayColor: WidgetStateProperty.all(Colors.white.withValues(alpha: 0.1)),
onTap: (index) {
ref.read(hapticFeedbackProvider.notifier).heavyImpact();
if (memories[index].assets.isNotEmpty) {
DriftMemoryPage.setMemory(ref, memories[index]);
}
unawaited(context.pushRoute(DriftMemoryRoute(memories: memories, memoryIndex: index)));
},
children: memories
.map((memory) => DriftMemoryCard(key: Key(memory.id), memory: memory))
.toList(growable: false),
),
);
}
}
class DriftMemoryCard extends StatelessWidget {
const DriftMemoryCard({super.key, required this.memory});
final DriftMemory memory;
@override
Widget build(BuildContext context) {
final yearsAgo = DateTime.now().year - memory.data.year;
final title = context.t.years_ago(years: yearsAgo);
return Center(
child: Stack(
children: [
ColorFiltered(
colorFilter: ColorFilter.mode(Colors.black.withValues(alpha: 0.2), BlendMode.darken),
child: SizedBox(
width: 205,
height: 200,
child: Thumbnail.remote(
remoteId: memory.assets[0].id,
thumbhash: memory.assets[0].thumbHash ?? "",
fit: BoxFit.cover,
),
),
),
Positioned(
bottom: 16,
left: 16,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 114),
child: Text(
title,
style: const TextStyle(fontWeight: FontWeight.w600, color: Colors.white, fontSize: 15),
),
),
),
],
),
);
}
}