This commit is contained in:
2026-06-28 16:27:59 +03:00
parent 3adac05cdf
commit 65ea30339d
3 changed files with 85 additions and 108 deletions
+1 -1
View File
@@ -168,7 +168,7 @@ class AppStrings {
} }
String get colorPrimary => _ru ? 'Основной' : 'Primary'; String get colorPrimary => _ru ? 'Основной' : 'Primary';
String get colorSecondary => _ru ? 'Второй' : 'Secondary'; String get colorSecondary => _ru ? 'Второй' : 'Second';
String get colorSecond => _ru ? 'Второй' : 'Second'; String get colorSecond => _ru ? 'Второй' : 'Second';
String get colorSolid => _ru ? 'Однотон' : 'Solid'; String get colorSolid => _ru ? 'Однотон' : 'Solid';
String get gradientLinear => _ru ? 'Линейный' : 'Linear'; String get gradientLinear => _ru ? 'Линейный' : 'Linear';
@@ -38,6 +38,7 @@ class BalanceCard extends ConsumerStatefulWidget {
final String? accountName; final String? accountName;
final CardColors? accountColors; final CardColors? accountColors;
final double? cardHeight; final double? cardHeight;
final Widget? resizeHandle;
const BalanceCard({ const BalanceCard({
super.key, super.key,
@@ -50,6 +51,7 @@ class BalanceCard extends ConsumerStatefulWidget {
this.accountName, this.accountName,
this.accountColors, this.accountColors,
this.cardHeight, this.cardHeight,
this.resizeHandle,
}); });
@override @override
@@ -132,24 +134,27 @@ class BalanceCardState extends ConsumerState<BalanceCard>
..setEntry(3, 2, 0.001) ..setEntry(3, 2, 0.001)
..rotateX(_tiltX * 0.42) ..rotateX(_tiltX * 0.42)
..rotateY(_tiltY * 0.42), ..rotateY(_tiltY * 0.42),
child: Container( child: Stack(
width: double.infinity, clipBehavior: Clip.none,
height: widget.cardHeight ?? kBalanceCardHeight, children: [
decoration: BoxDecoration( Container(
borderRadius: BorderRadius.circular(20), width: double.infinity,
gradient: buildCardGradient(primary, secondary, gradientType), height: widget.cardHeight ?? kBalanceCardHeight,
boxShadow: [ decoration: BoxDecoration(
BoxShadow( borderRadius: BorderRadius.circular(20),
color: Colors.black.withOpacity(0.4), gradient: buildCardGradient(primary, secondary, gradientType),
blurRadius: 20, boxShadow: [
offset: const Offset(0, 8), BoxShadow(
color: Colors.black.withOpacity(0.4),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
), ),
], child: ClipRRect(
), borderRadius: BorderRadius.circular(20),
child: ClipRRect( child: Stack(
borderRadius: BorderRadius.circular(20), children: [
child: Stack(
children: [
if (widget.accountName != null) if (widget.accountName != null)
Positioned( Positioned(
top: 20, top: 20,
@@ -336,6 +341,14 @@ class BalanceCardState extends ConsumerState<BalanceCard>
], ],
), ),
), ),
),
if (widget.resizeHandle != null)
Positioned(
right: 0,
bottom: 0,
child: widget.resizeHandle!,
),
],
), ),
); );
}, },
@@ -90,20 +90,15 @@ class _FullScreenBlurOverlayState extends State<FullScreenBlurOverlay> {
? dash.tempDarkGradientType ? dash.tempDarkGradientType
: dash.tempLightGradientType, : dash.tempLightGradientType,
cardHeight: cardHeight, cardHeight: cardHeight,
), resizeHandle: _CornerResizeHandle(
), cardHeight: cardHeight,
Positioned( onHeightChanged: (newHeight) {
left: 8, ref.read(cardHeightProvider.notifier).set(newHeight);
right: 8, if (ref.read(hapticEnabledProvider)) {
bottom: 0, HapticService.selection();
child: _HeightResizeHandle( }
cardHeight: cardHeight, },
onHeightChanged: (newHeight) { ),
ref.read(cardHeightProvider.notifier).set(newHeight);
if (ref.read(hapticEnabledProvider)) {
HapticService.light();
}
},
), ),
), ),
], ],
@@ -813,28 +808,26 @@ class PanelTab extends StatelessWidget {
} }
} }
class _HeightResizeHandle extends StatefulWidget { class _CornerResizeHandle extends StatefulWidget {
final double cardHeight; final double cardHeight;
final ValueChanged<double> onHeightChanged; final ValueChanged<double> onHeightChanged;
const _HeightResizeHandle({ const _CornerResizeHandle({
required this.cardHeight, required this.cardHeight,
required this.onHeightChanged, required this.onHeightChanged,
}); });
@override @override
State<_HeightResizeHandle> createState() => _HeightResizeHandleState(); State<_CornerResizeHandle> createState() => _CornerResizeHandleState();
} }
class _HeightResizeHandleState extends State<_HeightResizeHandle> { class _CornerResizeHandleState extends State<_CornerResizeHandle> {
bool _dragging = false; bool _dragging = false;
double _lastHeight = 0; double _lastHeight = 0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final canShrink = widget.cardHeight > CardHeightNotifier.minHeight;
final canGrow = widget.cardHeight < CardHeightNotifier.maxHeight;
return GestureDetector( return GestureDetector(
onVerticalDragStart: (_) { onVerticalDragStart: (_) {
@@ -851,95 +844,66 @@ class _HeightResizeHandleState extends State<_HeightResizeHandle> {
onVerticalDragEnd: (_) => setState(() => _dragging = false), onVerticalDragEnd: (_) => setState(() => _dragging = false),
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: SizedBox( child: SizedBox(
height: 44, width: 48,
child: Stack( height: 48,
clipBehavior: Clip.none, child: CustomPaint(
alignment: Alignment.center, size: const Size(48, 48),
children: [ painter: _CornerDashedPainter(
Positioned( color: theme.colorScheme.onSurface.withOpacity(_dragging ? 0.8 : 0.5),
left: 0, radius: 20,
right: 0, ),
top: 0,
child: CustomPaint(
size: const Size(double.infinity, 0),
painter: _DashedLinePainter(
color: theme.colorScheme.onSurface.withOpacity(0.5),
),
),
),
Positioned(
top: 6,
child: Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: theme.colorScheme.surface,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.3),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (canGrow)
Icon(
Icons.keyboard_arrow_up_rounded,
size: 16,
color: theme.colorScheme.onSurface.withOpacity(_dragging ? 0.9 : 0.5),
)
else
const SizedBox(height: 6),
if (canShrink)
Icon(
Icons.keyboard_arrow_down_rounded,
size: 16,
color: theme.colorScheme.onSurface.withOpacity(_dragging ? 0.9 : 0.5),
)
else
const SizedBox(height: 6),
],
),
),
),
],
), ),
), ),
); );
} }
} }
class _DashedLinePainter extends CustomPainter { class _CornerDashedPainter extends CustomPainter {
final Color color; final Color color;
final double radius;
const _DashedLinePainter({required this.color}); const _CornerDashedPainter({
required this.color,
required this.radius,
});
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
final paint = Paint() final paint = Paint()
..color = color ..color = color
..strokeWidth = 2 ..strokeWidth = 2.5
..style = PaintingStyle.stroke ..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round; ..strokeCap = StrokeCap.round;
const dashWidth = 10.0; const dashLength = 6.0;
const dashSpace = 6.0; const dashSpace = 5.0;
double x = 0; const extraLine = 8.0;
while (x < size.width) {
canvas.drawLine( final cornerCenter = Offset(size.width - radius, size.height - radius);
Offset(x, 0),
Offset(x + dashWidth, 0), final path = Path()
paint, ..moveTo(cornerCenter.dx - extraLine, size.height)
); ..lineTo(cornerCenter.dx, size.height)
x += dashWidth + dashSpace; ..arcToPoint(
Offset(size.width, cornerCenter.dy),
radius: Radius.circular(radius),
clockwise: false,
)
..lineTo(size.width, cornerCenter.dy - extraLine);
final metrics = path.computeMetrics();
for (final metric in metrics) {
double distance = 0;
while (distance < metric.length) {
final end = (distance + dashLength).clamp(0.0, metric.length);
final extracted = metric.extractPath(distance, end);
canvas.drawPath(extracted, paint);
distance += dashLength + dashSpace;
}
} }
} }
@override @override
bool shouldRepaint(covariant _DashedLinePainter oldDelegate) => bool shouldRepaint(covariant _CornerDashedPainter oldDelegate) =>
color != oldDelegate.color; color != oldDelegate.color;
} }