mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 10:37:11 -04:00 
			
		
		
		
	* chore(mobile): small visual fix and update * update * update * remove design placeholder
		
			
				
	
	
		
			121 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'package:flutter/material.dart';
 | |
| import 'package:flutter_hooks/flutter_hooks.dart';
 | |
| import 'package:immich_mobile/widgets/common/immich_logo.dart';
 | |
| 
 | |
| class ImmichLoadingIndicator extends HookWidget {
 | |
|   final double? borderRadius;
 | |
| 
 | |
|   const ImmichLoadingIndicator({
 | |
|     super.key,
 | |
|     this.borderRadius,
 | |
|   });
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     final logoAnimationController = useAnimationController(
 | |
|       duration: const Duration(seconds: 6),
 | |
|     )
 | |
|       ..reverse()
 | |
|       ..repeat();
 | |
| 
 | |
|     final borderAnimationController = useAnimationController(
 | |
|       duration: const Duration(seconds: 6),
 | |
|     )..repeat();
 | |
| 
 | |
|     return Container(
 | |
|       height: 80,
 | |
|       width: 80,
 | |
|       decoration: BoxDecoration(
 | |
|         color: Colors.transparent,
 | |
|         borderRadius: BorderRadius.circular(borderRadius ?? 50),
 | |
|         backgroundBlendMode: BlendMode.luminosity,
 | |
|       ),
 | |
|       child: AnimatedBuilder(
 | |
|         animation: borderAnimationController,
 | |
|         builder: (context, child) {
 | |
|           return CustomPaint(
 | |
|             painter: GradientBorderPainter(
 | |
|               animation: borderAnimationController.value,
 | |
|               strokeWidth: 3,
 | |
|             ),
 | |
|             child: child,
 | |
|           );
 | |
|         },
 | |
|         child: Padding(
 | |
|           padding: const EdgeInsets.all(15),
 | |
|           child: RotationTransition(
 | |
|             turns: logoAnimationController,
 | |
|             child: const ImmichLogo(
 | |
|               heroTag: 'logo',
 | |
|             ),
 | |
|           ),
 | |
|         ),
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| }
 | |
| 
 | |
| class GradientBorderPainter extends CustomPainter {
 | |
|   final double animation;
 | |
|   final double strokeWidth;
 | |
|   final double opacity = 0.7;
 | |
|   final colors = [
 | |
|     const Color(0xFFFA2921),
 | |
|     const Color(0xFFED79B5),
 | |
|     const Color(0xFFFFB400),
 | |
|     const Color(0xFF1E83F7),
 | |
|     const Color(0xFF18C249),
 | |
|   ];
 | |
| 
 | |
|   GradientBorderPainter({
 | |
|     required this.animation,
 | |
|     required this.strokeWidth,
 | |
|   });
 | |
| 
 | |
|   @override
 | |
|   void paint(Canvas canvas, Size size) {
 | |
|     final center = Offset(size.width / 2, size.height / 2);
 | |
|     final radius = min(size.width, size.height) / 2 - strokeWidth / 2;
 | |
| 
 | |
|     // Create a sweep gradient that covers the entire circle
 | |
|     final Rect rect = Rect.fromCircle(center: center, radius: radius);
 | |
| 
 | |
|     // Create a paint with the gradient
 | |
|     final paint = Paint()
 | |
|       ..style = PaintingStyle.stroke
 | |
|       ..strokeWidth = strokeWidth;
 | |
| 
 | |
|     // Create a gradient that smoothly transitions between colors
 | |
|     final shader = SweepGradient(
 | |
|       // Use a fixed starting point and let matrix transformation handle rotation
 | |
|       startAngle: 0,
 | |
|       endAngle: 2 * 3.14159,
 | |
|       colors: [
 | |
|         // Repeat colors to ensure smooth transitions
 | |
|         ...colors.map((c) => c.withValues(alpha: opacity)),
 | |
|         colors.first.withValues(alpha: opacity),
 | |
|       ],
 | |
|       // Add evenly distributed stops
 | |
|       stops: List.generate(
 | |
|         colors.length + 1,
 | |
|         (index) => index / colors.length,
 | |
|       ),
 | |
|       tileMode: TileMode.clamp,
 | |
|       // Use transformations to rotate the gradient
 | |
|       transform: GradientRotation(-animation * 2 * 3.14159),
 | |
|     ).createShader(rect);
 | |
| 
 | |
|     paint.shader = shader;
 | |
| 
 | |
|     // Draw the circular border
 | |
|     canvas.drawCircle(center, radius, paint);
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   bool shouldRepaint(GradientBorderPainter oldDelegate) {
 | |
|     return animation != oldDelegate.animation;
 | |
|   }
 | |
| 
 | |
|   double min(double a, double b) => a < b ? a : b;
 | |
| }
 |