flutter-vienna-hackathon-25/wien_talks/wien_talks_flutter/lib/widgets/card_contenty.dart
2025-08-17 04:30:47 +02:00

224 lines
5.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:wien_talks_client/wien_talks_client.dart';
import 'package:wien_talks_flutter/widgets/flamboyant_quote_card.dart';
import 'package:wien_talks_flutter/widgets/map_preview_widget.dart';
class CardContenty extends StatelessWidget {
const CardContenty({
super.key,
required this.quote,
required this.staticMapUrlBuilder,
required this.meta,
required this.onVoteUp,
required this.onVoteDown,
required this.context,
required this.variant,
required this.accent,
required this.metaStyle,
});
final Quote quote;
final StaticMapUrlBuilder? staticMapUrlBuilder;
final String meta;
final VoidCallback onVoteUp;
final VoidCallback onVoteDown;
final BuildContext context;
final int variant;
final Color accent;
final TextStyle? metaStyle;
@override
Widget build(BuildContext context) {
final hasMap = (variant != 0);
final map = hasMap
? Padding(
padding: const EdgeInsets.only(bottom: 8),
child: MapPreview(
lat: quote.lat,
lon: quote.long,
accent: accent,
staticMapUrlBuilder: staticMapUrlBuilder,
),
)
: const SizedBox.shrink();
final textBlock = _ContentText(
quote: quote,
meta: meta,
metaStyle: metaStyle,
onVoteUp: onVoteUp,
onVoteDown: onVoteDown,
accent: accent);
stacked() => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [map, textBlock],
);
return switch (variant) {
1 when hasMap => stacked(),
2 when hasMap => LayoutBuilder(
builder: (context, c) {
final wide = c.maxWidth >= 420;
return wide
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 5,
child: Padding(
padding: const EdgeInsets.fromLTRB(12, 10, 8, 12),
child: MapPreview(
lat: quote.lat,
lon: quote.long,
accent: accent,
staticMapUrlBuilder: staticMapUrlBuilder,
aspect: 4 / 3,
),
),
),
Flexible(flex: 7, child: textBlock),
],
)
: stacked();
},
),
_ => textBlock,
};
}
}
class _ContentText extends StatelessWidget {
const _ContentText({
required this.quote,
required this.meta,
required this.metaStyle,
required this.onVoteUp,
required this.onVoteDown,
required this.accent,
});
final Quote quote;
final String meta;
final TextStyle? metaStyle;
final VoidCallback onVoteUp;
final VoidCallback onVoteDown;
final Color accent;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(12, 10, 12, 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
quote.text,
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Text(meta,
style: metaStyle, overflow: TextOverflow.ellipsis)),
const SizedBox(width: 8),
_VotePills(
up: quote.upvotes,
down: quote.downvotes,
onUp: onVoteUp,
onDown: onVoteDown,
accent: accent,
),
],
),
],
),
);
}
}
class _VotePills extends StatelessWidget {
const _VotePills({
required this.up,
required this.down,
required this.onUp,
required this.onDown,
required this.accent,
});
final int up;
final int down;
final VoidCallback onUp;
final VoidCallback onDown;
final Color accent;
@override
Widget build(BuildContext context) {
final t = Theme.of(context);
final bg = t.colorScheme.surfaceContainerHighest.withValues(alpha: 0.55);
final onBg = ThemeData.estimateBrightnessForColor(bg) == Brightness.dark
? Colors.white
: const Color(0xFF1A1A1A);
final pillStyle = t.textTheme.labelSmall?.copyWith(color: onBg);
return Row(
mainAxisSize: MainAxisSize.min,
children: [
_Pill(
icon: Icons.arrow_upward,
color: accent,
text: '$up',
onTap: onUp,
textStyle: pillStyle,
),
const SizedBox(width: 6),
_Pill(
icon: Icons.arrow_downward,
color: const Color(0xFFD32F2F),
text: '$down',
onTap: onDown,
textStyle: pillStyle,
),
],
);
}
}
class _Pill extends StatelessWidget {
const _Pill({
required this.icon,
required this.color,
required this.text,
required this.onTap,
required this.textStyle,
});
final IconData icon;
final Color color;
final String text;
final VoidCallback onTap;
final TextStyle? textStyle;
@override
Widget build(BuildContext context) {
return Material(
color: color.withValues(alpha: 0.12),
borderRadius: BorderRadius.circular(999),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(999),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
child: Row(
children: [
Icon(icon, size: 16, color: color),
const SizedBox(width: 6),
Text(text, style: textStyle),
],
),
),
),
);
}
}