mirror of
https://github.com/timokz/flutter-vienna-hackathon-25.git
synced 2025-11-08 21:24:20 +01:00
116 lines
3 KiB
Dart
116 lines
3 KiB
Dart
import 'dart:math' as math;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:wien_talks_client/wien_talks_client.dart';
|
|
import 'package:wien_talks_flutter/widgets/card_contenty.dart';
|
|
import 'package:wien_talks_flutter/widgets/ubahn_tape.dart';
|
|
|
|
typedef StaticMapUrlBuilder = String Function(
|
|
double lat,
|
|
double lon, {
|
|
int w,
|
|
int h,
|
|
int zoom,
|
|
});
|
|
|
|
class FlamboyantQuoteCard extends StatelessWidget {
|
|
const FlamboyantQuoteCard({
|
|
super.key,
|
|
required this.quote,
|
|
required this.meta,
|
|
required this.onVoteUp,
|
|
required this.onVoteDown,
|
|
this.staticMapUrlBuilder,
|
|
this.onTap,
|
|
});
|
|
|
|
final Quote quote;
|
|
final String meta;
|
|
final VoidCallback onVoteUp;
|
|
final VoidCallback onVoteDown;
|
|
final StaticMapUrlBuilder? staticMapUrlBuilder;
|
|
final VoidCallback? onTap;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final seed = (quote.id ?? quote.text.hashCode) & 0x7fffffff;
|
|
final rng = math.Random(seed);
|
|
|
|
final variant = rng.nextInt(3);
|
|
final tiltDeg = [-2.2, -1.4, -0.6, 0, 0.6, 1.2, 2.0][rng.nextInt(7)];
|
|
final tiltRad = tiltDeg * math.pi / 180.0;
|
|
final accents = [
|
|
const Color(0xFFE53935),
|
|
const Color(0xFF3949AB),
|
|
const Color(0xFF00897B),
|
|
];
|
|
final accent = accents[seed % accents.length];
|
|
|
|
final t = Theme.of(context);
|
|
final metaStyle = t.textTheme.bodySmall?.copyWith(
|
|
color: (t.textTheme.bodySmall?.color ?? t.colorScheme.onSurface)
|
|
.withValues(alpha: 0.70),
|
|
);
|
|
|
|
final borderRadius = BorderRadius.circular(14);
|
|
|
|
final cardContent = CardContenty(
|
|
quote: quote,
|
|
staticMapUrlBuilder: staticMapUrlBuilder,
|
|
meta: meta,
|
|
onVoteUp: onVoteUp,
|
|
onVoteDown: onVoteDown,
|
|
context: context,
|
|
variant: variant,
|
|
accent: accent,
|
|
metaStyle: metaStyle,
|
|
);
|
|
|
|
final tappableCard = Material(
|
|
type: MaterialType.transparency,
|
|
child: Ink(
|
|
decoration: BoxDecoration(
|
|
color: t.colorScheme.surface,
|
|
borderRadius: borderRadius,
|
|
boxShadow: const [
|
|
BoxShadow(
|
|
color: Color(0x14000000),
|
|
blurRadius: 12,
|
|
offset: Offset(0, 6),
|
|
),
|
|
],
|
|
border: Border.all(color: accent.withValues(alpha: 0.25), width: 1),
|
|
),
|
|
child: InkWell(
|
|
borderRadius: borderRadius,
|
|
onTap: onTap,
|
|
child: cardContent,
|
|
),
|
|
),
|
|
);
|
|
|
|
return Padding(
|
|
padding: const EdgeInsets.only(top: 6, bottom: 2),
|
|
child: Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
Transform.rotate(
|
|
angle: tiltRad,
|
|
transformHitTests: false,
|
|
child: tappableCard,
|
|
),
|
|
Positioned(
|
|
top: -8,
|
|
right: 16,
|
|
child: IgnorePointer(
|
|
child: UbahnTape(
|
|
lat: quote.lat,
|
|
lon: quote.long,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|