mirror of
https://github.com/timokz/flutter-vienna-hackathon-25.git
synced 2025-11-08 23:44:19 +01:00
224 lines
5.9 KiB
Dart
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),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|