98 lines
2.4 KiB
Dart
98 lines
2.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../layout/adaptive_card_grid.dart';
|
|
import '../theme/app_theme.dart';
|
|
|
|
|
|
class AppSkeleton extends StatefulWidget {
|
|
final double? width;
|
|
final double? height;
|
|
final double radius;
|
|
|
|
const AppSkeleton({super.key, this.width, this.height, this.radius = 8});
|
|
|
|
@override
|
|
State<AppSkeleton> createState() => _AppSkeletonState();
|
|
}
|
|
|
|
class _AppSkeletonState extends State<AppSkeleton>
|
|
with SingleTickerProviderStateMixin {
|
|
late final AnimationController _c = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(milliseconds: 1100),
|
|
)..repeat(reverse: true);
|
|
|
|
@override
|
|
void dispose() {
|
|
_c.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final base = Theme.of(context).colorScheme.onSurface;
|
|
return AnimatedBuilder(
|
|
animation: _c,
|
|
builder: (context, _) {
|
|
final alpha = 0.04 + 0.05 * _c.value;
|
|
return Container(
|
|
width: widget.width,
|
|
height: widget.height,
|
|
decoration: BoxDecoration(
|
|
color: base.withValues(alpha: alpha),
|
|
borderRadius: BorderRadius.circular(widget.radius),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
class SkeletonGrid extends StatelessWidget {
|
|
final int itemCount;
|
|
final double itemHeight;
|
|
final double minCardWidth;
|
|
final EdgeInsetsGeometry padding;
|
|
|
|
const SkeletonGrid({
|
|
super.key,
|
|
this.itemCount = 6,
|
|
this.itemHeight = 84,
|
|
this.minCardWidth = kRichCardMinWidth,
|
|
this.padding = const EdgeInsets.symmetric(horizontal: 24),
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final tokens = context.appTokens;
|
|
return Padding(
|
|
padding: padding,
|
|
child: LayoutBuilder(
|
|
builder: (_, constraints) {
|
|
final columns = cardColumnsFor(
|
|
constraints.maxWidth,
|
|
minCardWidth: minCardWidth,
|
|
);
|
|
final width =
|
|
(constraints.maxWidth - kCardGap * (columns - 1)) / columns;
|
|
return Wrap(
|
|
spacing: kCardGap,
|
|
runSpacing: kCardGap,
|
|
children: [
|
|
for (var i = 0; i < itemCount; i++)
|
|
SizedBox(
|
|
width: width,
|
|
child: AppSkeleton(
|
|
height: itemHeight,
|
|
radius: tokens.radiusCard,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|