mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 18:47:09 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			131 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'package:auto_route/auto_route.dart';
 | |
| import 'package:easy_localization/easy_localization.dart';
 | |
| import 'package:flutter/material.dart';
 | |
| import 'package:hooks_riverpod/hooks_riverpod.dart';
 | |
| import 'package:immich_mobile/extensions/build_context_extensions.dart';
 | |
| import 'package:immich_mobile/providers/infrastructure/people.provider.dart';
 | |
| import 'package:immich_mobile/routing/router.dart';
 | |
| import 'package:immich_mobile/services/api.service.dart';
 | |
| import 'package:immich_mobile/utils/image_url_builder.dart';
 | |
| import 'package:immich_mobile/utils/people.utils.dart';
 | |
| import 'package:immich_mobile/widgets/common/search_field.dart';
 | |
| 
 | |
| @RoutePage()
 | |
| class DriftPeopleCollectionPage extends ConsumerStatefulWidget {
 | |
|   const DriftPeopleCollectionPage({super.key});
 | |
| 
 | |
|   @override
 | |
|   ConsumerState<DriftPeopleCollectionPage> createState() => _DriftPeopleCollectionPageState();
 | |
| }
 | |
| 
 | |
| class _DriftPeopleCollectionPageState extends ConsumerState<DriftPeopleCollectionPage> {
 | |
|   final FocusNode _formFocus = FocusNode();
 | |
|   String? _search;
 | |
| 
 | |
|   @override
 | |
|   void dispose() {
 | |
|     _formFocus.dispose();
 | |
|     super.dispose();
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     final people = ref.watch(driftGetAllPeopleProvider);
 | |
|     final headers = ApiService.getRequestHeaders();
 | |
| 
 | |
|     return LayoutBuilder(
 | |
|       builder: (context, constraints) {
 | |
|         final isTablet = constraints.maxWidth > 600;
 | |
|         final isPortrait = context.orientation == Orientation.portrait;
 | |
| 
 | |
|         return Scaffold(
 | |
|           appBar: AppBar(
 | |
|             automaticallyImplyLeading: _search == null,
 | |
|             title: _search != null
 | |
|                 ? SearchField(
 | |
|                     focusNode: _formFocus,
 | |
|                     onTapOutside: (_) => _formFocus.unfocus(),
 | |
|                     onChanged: (value) => setState(() => _search = value),
 | |
|                     filled: true,
 | |
|                     hintText: 'filter_people'.tr(),
 | |
|                     autofocus: true,
 | |
|                   )
 | |
|                 : Text('people'.tr()),
 | |
|             actions: [
 | |
|               IconButton(
 | |
|                 icon: Icon(_search != null ? Icons.close : Icons.search),
 | |
|                 onPressed: () {
 | |
|                   setState(() => _search = _search == null ? '' : null);
 | |
|                 },
 | |
|               ),
 | |
|             ],
 | |
|           ),
 | |
|           body: SafeArea(
 | |
|             child: people.when(
 | |
|               data: (people) {
 | |
|                 if (_search != null) {
 | |
|                   people = people.where((person) {
 | |
|                     return person.name.toLowerCase().contains(_search!.toLowerCase());
 | |
|                   }).toList();
 | |
|                 }
 | |
|                 return GridView.builder(
 | |
|                   gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
 | |
|                     crossAxisCount: isTablet ? 6 : 3,
 | |
|                     childAspectRatio: 0.85,
 | |
|                     mainAxisSpacing: isPortrait && isTablet ? 36 : 0,
 | |
|                   ),
 | |
|                   padding: const EdgeInsets.symmetric(vertical: 32),
 | |
|                   itemCount: people.length,
 | |
|                   itemBuilder: (context, index) {
 | |
|                     final person = people[index];
 | |
| 
 | |
|                     return Column(
 | |
|                       children: [
 | |
|                         GestureDetector(
 | |
|                           onTap: () {
 | |
|                             context.pushRoute(DriftPersonRoute(person: person));
 | |
|                           },
 | |
|                           child: Material(
 | |
|                             shape: const CircleBorder(side: BorderSide.none),
 | |
|                             elevation: 3,
 | |
|                             child: CircleAvatar(
 | |
|                               maxRadius: isTablet ? 100 / 2 : 96 / 2,
 | |
|                               backgroundImage: NetworkImage(getFaceThumbnailUrl(person.id), headers: headers),
 | |
|                             ),
 | |
|                           ),
 | |
|                         ),
 | |
|                         const SizedBox(height: 12),
 | |
|                         GestureDetector(
 | |
|                           onTap: () => showNameEditModal(context, person),
 | |
|                           child: person.name.isEmpty
 | |
|                               ? Text(
 | |
|                                   'add_a_name'.tr(),
 | |
|                                   style: context.textTheme.titleSmall?.copyWith(
 | |
|                                     fontWeight: FontWeight.w500,
 | |
|                                     color: context.colorScheme.primary,
 | |
|                                   ),
 | |
|                                 )
 | |
|                               : Padding(
 | |
|                                   padding: const EdgeInsets.symmetric(horizontal: 16.0),
 | |
|                                   child: Text(
 | |
|                                     person.name,
 | |
|                                     overflow: TextOverflow.ellipsis,
 | |
|                                     style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500),
 | |
|                                   ),
 | |
|                                 ),
 | |
|                         ),
 | |
|                       ],
 | |
|                     );
 | |
|                   },
 | |
|                 );
 | |
|               },
 | |
|               error: (error, stack) => const Text("error"),
 | |
|               loading: () => const Center(child: CircularProgressIndicator()),
 | |
|             ),
 | |
|           ),
 | |
|         );
 | |
|       },
 | |
|     );
 | |
|   }
 | |
| }
 |