mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-30 18:35:00 -04:00 
			
		
		
		
	* refactor: autoroutex pushroute * refactor: autoroutex popRoute * refactor: autoroutex navigate and replace * chore: add doc comments for extension methods * refactor: Add LoggerMixin and refactor Album activities to use mixin * refactor: Activity page * chore: activity user from user constructor * fix: update current asset after build method * refactor: tests with similar structure as lib * chore: remove avoid-declaring-call-method rule from dcm analysis * test: fix proper expect order * test: activity_statistics_provider_test * test: activity_provider_test * test: use proper matchers * test: activity_text_field_test & dismissible_activity_test added * test: add http mock to return transparent image * test: download isar core libs during test * test: add widget tags to widget test cases * test: activity_tile_test * build: currentAlbumProvider to generator * movie add / remove like to activity input tile * test: activities_page_test.dart * chore: better error logs * chore: dismissibleactivity as statelesswidget --------- Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
		
			
				
	
	
		
			189 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'package:auto_route/auto_route.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/shared/models/store.dart';
 | |
| import 'package:immich_mobile/shared/ui/app_bar_dialog/app_bar_dialog.dart';
 | |
| import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
 | |
| 
 | |
| import 'package:immich_mobile/routing/router.dart';
 | |
| import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
 | |
| import 'package:immich_mobile/shared/models/server_info/server_info.model.dart';
 | |
| import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
 | |
| import 'package:immich_mobile/shared/providers/server_info.provider.dart';
 | |
| 
 | |
| class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
 | |
|   @override
 | |
|   Size get preferredSize => const Size.fromHeight(kToolbarHeight);
 | |
|   final Widget? action;
 | |
| 
 | |
|   const ImmichAppBar({super.key, this.action});
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context, WidgetRef ref) {
 | |
|     final BackUpState backupState = ref.watch(backupProvider);
 | |
|     final bool isEnableAutoBackup =
 | |
|         backupState.backgroundBackup || backupState.autoBackup;
 | |
|     final ServerInfo serverInfoState = ref.watch(serverInfoProvider);
 | |
|     final user = Store.tryGet(StoreKey.currentUser);
 | |
|     final isDarkTheme = context.isDarkTheme;
 | |
|     const widgetSize = 30.0;
 | |
| 
 | |
|     buildProfileIndicator() {
 | |
|       return InkWell(
 | |
|         onTap: () => showDialog(
 | |
|           context: context,
 | |
|           useRootNavigator: false,
 | |
|           builder: (ctx) => const ImmichAppBarDialog(),
 | |
|         ),
 | |
|         borderRadius: BorderRadius.circular(12),
 | |
|         child: Badge(
 | |
|           label: Container(
 | |
|             decoration: BoxDecoration(
 | |
|               color: Colors.black,
 | |
|               borderRadius: BorderRadius.circular(widgetSize / 2),
 | |
|             ),
 | |
|             child: const Icon(
 | |
|               Icons.info,
 | |
|               color: Color.fromARGB(255, 243, 188, 106),
 | |
|               size: widgetSize / 2,
 | |
|             ),
 | |
|           ),
 | |
|           backgroundColor: Colors.transparent,
 | |
|           alignment: Alignment.bottomRight,
 | |
|           isLabelVisible: serverInfoState.isVersionMismatch ||
 | |
|               ((user?.isAdmin ?? false) &&
 | |
|                   serverInfoState.isNewReleaseAvailable),
 | |
|           offset: const Offset(2, 2),
 | |
|           child: user == null
 | |
|               ? const Icon(
 | |
|                   Icons.face_outlined,
 | |
|                   size: widgetSize,
 | |
|                 )
 | |
|               : UserCircleAvatar(
 | |
|                   radius: 15,
 | |
|                   size: 27,
 | |
|                   user: user,
 | |
|                 ),
 | |
|         ),
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     getBackupBadgeIcon() {
 | |
|       final iconColor = isDarkTheme ? Colors.white : Colors.black;
 | |
| 
 | |
|       if (isEnableAutoBackup) {
 | |
|         if (backupState.backupProgress == BackUpProgressEnum.inProgress) {
 | |
|           return Container(
 | |
|             padding: const EdgeInsets.all(3.5),
 | |
|             child: CircularProgressIndicator(
 | |
|               strokeWidth: 2,
 | |
|               strokeCap: StrokeCap.round,
 | |
|               valueColor: AlwaysStoppedAnimation<Color>(iconColor),
 | |
|             ),
 | |
|           );
 | |
|         } else if (backupState.backupProgress !=
 | |
|                 BackUpProgressEnum.inBackground &&
 | |
|             backupState.backupProgress != BackUpProgressEnum.manualInProgress) {
 | |
|           return Icon(
 | |
|             Icons.check_outlined,
 | |
|             size: 9,
 | |
|             color: iconColor,
 | |
|           );
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (!isEnableAutoBackup) {
 | |
|         return Icon(
 | |
|           Icons.cloud_off_rounded,
 | |
|           size: 9,
 | |
|           color: iconColor,
 | |
|         );
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     buildBackupIndicator() {
 | |
|       final indicatorIcon = getBackupBadgeIcon();
 | |
|       final badgeBackground = isDarkTheme ? Colors.blueGrey[800] : Colors.white;
 | |
| 
 | |
|       return InkWell(
 | |
|         onTap: () => context.pushRoute(const BackupControllerRoute()),
 | |
|         borderRadius: BorderRadius.circular(12),
 | |
|         child: Badge(
 | |
|           label: Container(
 | |
|             width: widgetSize / 2,
 | |
|             height: widgetSize / 2,
 | |
|             decoration: BoxDecoration(
 | |
|               color: badgeBackground,
 | |
|               border: Border.all(
 | |
|                 color: isDarkTheme ? Colors.black : Colors.grey,
 | |
|               ),
 | |
|               borderRadius: BorderRadius.circular(widgetSize / 2),
 | |
|             ),
 | |
|             child: indicatorIcon,
 | |
|           ),
 | |
|           backgroundColor: Colors.transparent,
 | |
|           alignment: Alignment.bottomRight,
 | |
|           isLabelVisible: indicatorIcon != null,
 | |
|           offset: const Offset(2, 2),
 | |
|           child: Icon(
 | |
|             Icons.backup_rounded,
 | |
|             size: widgetSize,
 | |
|             color: context.primaryColor,
 | |
|           ),
 | |
|         ),
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     return AppBar(
 | |
|       backgroundColor: context.themeData.appBarTheme.backgroundColor,
 | |
|       shape: const RoundedRectangleBorder(
 | |
|         borderRadius: BorderRadius.all(
 | |
|           Radius.circular(5),
 | |
|         ),
 | |
|       ),
 | |
|       automaticallyImplyLeading: false,
 | |
|       centerTitle: false,
 | |
|       title: Builder(
 | |
|         builder: (BuildContext context) {
 | |
|           return Row(
 | |
|             children: [
 | |
|               Container(
 | |
|                 padding: const EdgeInsets.only(top: 3),
 | |
|                 width: 28,
 | |
|                 height: 28,
 | |
|                 child: Image.asset(
 | |
|                   'assets/immich-logo.png',
 | |
|                 ),
 | |
|               ),
 | |
|               Container(
 | |
|                 margin: const EdgeInsets.only(left: 10),
 | |
|                 child: const Text(
 | |
|                   'IMMICH',
 | |
|                   style: TextStyle(
 | |
|                     fontFamily: 'SnowburstOne',
 | |
|                     fontWeight: FontWeight.bold,
 | |
|                     fontSize: 24,
 | |
|                   ),
 | |
|                 ),
 | |
|               ),
 | |
|             ],
 | |
|           );
 | |
|         },
 | |
|       ),
 | |
|       actions: [
 | |
|         if (action != null)
 | |
|           Padding(padding: const EdgeInsets.only(right: 20), child: action!),
 | |
|         Padding(
 | |
|           padding: const EdgeInsets.only(right: 20),
 | |
|           child: buildBackupIndicator(),
 | |
|         ),
 | |
|         Padding(
 | |
|           padding: const EdgeInsets.only(right: 20),
 | |
|           child: buildProfileIndicator(),
 | |
|         ),
 | |
|       ],
 | |
|     );
 | |
|   }
 | |
| }
 |