Aidra Connect 10.0.2+16
Aidra Connect Mobile Application
Loading...
Searching...
No Matches
dashboard_card.dart
Go to the documentation of this file.
1import 'dart:ui';
2import 'package:flutter/material.dart';
3import 'package:flutter_screenutil/flutter_screenutil.dart';
4import 'package:go_router/go_router.dart';
5import 'dart:math' as math;
6
7import '../../../domain/entities/dashboard_item_entity.dart';
8
9class DashboardCard extends StatefulWidget {
11 final double? size;
13 super.key,
14 required this.item,
15 this.size,
16 });
17 @override
18 State<DashboardCard> createState() => _DashboardCardState();
19}
20
21class _DashboardCardState extends State<DashboardCard>
22 with SingleTickerProviderStateMixin {
23 late AnimationController _controller;
24 late Animation<double> _scaleAnimation;
25 bool _isPressed = false;
26
27 @override
28 void initState() {
29 super.initState();
30 _controller = AnimationController(
31 duration: const Duration(milliseconds: 150),
32 vsync: this,
33 );
34 _scaleAnimation = Tween<double>(begin: 1.0, end: 0.95).animate(
35 CurvedAnimation(
36 parent: _controller,
37 curve: Curves.easeInOut,
38 ),
39 );
40 }
41
42 @override
43 void dispose() {
44 _controller.dispose();
45 super.dispose();
46 }
47
48 void _handleTapDown(TapDownDetails details) {
49 setState(() => _isPressed = true);
50 _controller.forward();
51 }
52
53 void _handleTapUp(TapUpDetails details) {
54 setState(() => _isPressed = false);
55 _controller.reverse();
56 if (widget.item.path != null) context.push(widget.item.path!);
57 }
58
60 setState(() => _isPressed = false);
61 _controller.reverse();
62 }
63
64 @override
65 Widget build(BuildContext context) {
66 final size = widget.size ?? 170.sp;
67 final gap = 19.0;
68 final containerSize = size - (gap * 2);
69
70 return AnimatedBuilder(
71 animation: _scaleAnimation,
72 builder: (context, child) => Transform.scale(
73 scale: _scaleAnimation.value,
74 child: child,
75 ),
76 child: GestureDetector(
77 onTapDown: _handleTapDown,
78 onTapUp: _handleTapUp,
79 onTapCancel: _handleTapCancel,
80 child: SizedBox(
81 height: size,
82 width: size,
83 child: Stack(
84 alignment: Alignment.center,
85 children: [
86 CustomPaint(
87 size: Size(size, size),
88 painter: CircularProgressPainter(
89 progress: 0.75,
90 progressColor: Theme.of(context).colorScheme.primary,
91 strokeWidth: 1.0,
92 ),
93 ),
94 Container(
95 height: containerSize,
96 width: containerSize,
97 decoration: BoxDecoration(
98 shape: BoxShape.circle,
99 ),
100 child: Stack(
101 children: [
102 ClipRRect(
103 borderRadius: BorderRadius.circular(800),
104 child: BackdropFilter(
105 filter: ImageFilter.blur(
106 sigmaX: 20,
107 sigmaY: 20,
108 ),
109 child: Center(
110 child: Padding(
111 padding: EdgeInsets.all(20.sp),
112 child: Column(
113 crossAxisAlignment: CrossAxisAlignment.center,
114 mainAxisSize: MainAxisSize.min,
115 children: [
116 Container(
117 padding: EdgeInsets.all(12.sp),
118 decoration: BoxDecoration(
119 color: Theme.of(context)
120 .colorScheme
121 .primary
122 .withOpacity(0.11),
123 borderRadius: BorderRadius.circular(16),
124 ),
125 child: Icon(
126 widget.item.icon,
127 color:
128 Theme.of(context).colorScheme.primary,
129 size: 23,
130 ),
131 ),
132 SizedBox(height: 9.sp),
133 Text(
134 widget.item.title,
135 textAlign: TextAlign.center,
136 style: Theme.of(context)
137 .textTheme
138 .bodySmall
139 ?.copyWith(
140 fontSize: 10.sp,
141 color: Theme.of(context).hintColor,
142 ),
143 maxLines: 2,
144 ),
145 ],
146 ),
147 ),
148 ),
149 ),
150 ),
151 ],
152 ),
153 ),
154 // Pressed state overlay
155 if (_isPressed)
156 Container(
157 height: containerSize,
158 width: containerSize,
159 decoration: BoxDecoration(
160 color: widget.item.color.withOpacity(0.11),
161 shape: BoxShape.circle,
162 ),
163 ),
164 ],
165 ),
166 ),
167 ),
168 );
169 }
170}
171
173 final double progress;
174 final Color progressColor;
175 final double strokeWidth;
176
178 required this.progress,
179 required this.progressColor,
180 this.strokeWidth = 2.0,
181 });
182
183 @override
184 void paint(Canvas canvas, Size size) {
185 final center = Offset(size.width / 2, size.height / 2);
186 final radius = size.width / 2;
187
188 final progressPaint = Paint()
190 ..style = PaintingStyle.stroke
192 ..strokeCap = StrokeCap.round;
193
194 canvas.drawArc(
195 Rect.fromCircle(center: center, radius: radius),
196 -math.pi / 2,
197 2 * math.pi * progress,
198 false,
199 progressPaint,
200 );
201 }
202
203 @override
204 bool shouldRepaint(CustomPainter oldDelegate) => true;
205}
final double progress
final Color progressColor
override void paint(Canvas canvas, Size size)
CircularProgressPainter({ required this.progress, required this.progressColor, this.strokeWidth=2.0, })
override bool shouldRepaint(CustomPainter oldDelegate)
final double strokeWidth
const DashboardCard({ super.key, required this.item, this.size, })
final double size
override State< DashboardCard > createState()
final DashboardItem item
late Animation< double > _scaleAnimation
override void dispose()
final Widget child
final EdgeInsets padding
override void initState()
void _handleTapUp(TapUpDetails details)
void _handleTapDown(TapDownDetails details)
void _handleTapCancel()
bool _isPressed
final Color progressColor
final Color color
Definition failures.dart:1
override Widget build(BuildContext context)
class ArcPainter extends CustomPainter color
final double progress