175 lines
7.1 KiB
Dart
175 lines
7.1 KiB
Dart
|
|
// lib/screens/learn_more_screen.dart
|
||
|
|
|
||
|
|
import 'package:flutter/material.dart';
|
||
|
|
import '../features/events/models/event_models.dart';
|
||
|
|
import '../features/events/services/events_service.dart';
|
||
|
|
import 'booking_screen.dart';
|
||
|
|
|
||
|
|
class LearnMoreScreen extends StatefulWidget {
|
||
|
|
final int eventId;
|
||
|
|
const LearnMoreScreen({Key? key, required this.eventId}) : super(key: key);
|
||
|
|
|
||
|
|
@override
|
||
|
|
State<LearnMoreScreen> createState() => _LearnMoreScreenState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _LearnMoreScreenState extends State<LearnMoreScreen> {
|
||
|
|
final EventsService _service = EventsService();
|
||
|
|
|
||
|
|
bool _loading = true;
|
||
|
|
EventModel? _event;
|
||
|
|
String? _error;
|
||
|
|
|
||
|
|
@override
|
||
|
|
void initState() {
|
||
|
|
super.initState();
|
||
|
|
_loadEvent();
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> _loadEvent() async {
|
||
|
|
setState(() {
|
||
|
|
_loading = true;
|
||
|
|
_error = null;
|
||
|
|
});
|
||
|
|
|
||
|
|
try {
|
||
|
|
final ev = await _service.getEventDetails(widget.eventId);
|
||
|
|
if (!mounted) return;
|
||
|
|
setState(() => _event = ev);
|
||
|
|
} catch (e) {
|
||
|
|
if (!mounted) return;
|
||
|
|
setState(() => _error = e.toString());
|
||
|
|
} finally {
|
||
|
|
if (mounted) setState(() => _loading = false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Widget _buildImageCarousel() {
|
||
|
|
final imgs = _event?.images ?? [];
|
||
|
|
final thumb = _event?.thumbImg;
|
||
|
|
final list = <String>[];
|
||
|
|
|
||
|
|
if (thumb != null && thumb.isNotEmpty) list.add(thumb);
|
||
|
|
for (final i in imgs) {
|
||
|
|
if (i.image.isNotEmpty && !list.contains(i.image)) list.add(i.image);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (list.isEmpty) {
|
||
|
|
return Container(
|
||
|
|
height: 220,
|
||
|
|
color: Colors.grey.shade200,
|
||
|
|
child: const Center(child: Icon(Icons.event, size: 80, color: Colors.grey)),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return SizedBox(
|
||
|
|
height: 220,
|
||
|
|
child: PageView.builder(
|
||
|
|
itemCount: list.length,
|
||
|
|
itemBuilder: (context, i) => Image.network(list[i], fit: BoxFit.cover, width: double.infinity),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
final theme = Theme.of(context);
|
||
|
|
|
||
|
|
return Scaffold(
|
||
|
|
appBar: AppBar(
|
||
|
|
title: const Text('Event Details'),
|
||
|
|
),
|
||
|
|
body: _loading
|
||
|
|
? const Center(child: CircularProgressIndicator())
|
||
|
|
: _error != null
|
||
|
|
? Center(child: Text('Error: $_error'))
|
||
|
|
: _event == null
|
||
|
|
? const Center(child: Text('Event not found'))
|
||
|
|
: SingleChildScrollView(
|
||
|
|
child: DefaultTextStyle.merge(
|
||
|
|
// force child Text widgets to use theme-aware foreground color (works in light/dark)
|
||
|
|
style: TextStyle(color: theme.colorScheme.onSurface, height: 1.45),
|
||
|
|
child: Column(
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
|
|
children: [
|
||
|
|
_buildImageCarousel(),
|
||
|
|
Padding(
|
||
|
|
padding: const EdgeInsets.all(16.0),
|
||
|
|
child: Column(
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
|
children: [
|
||
|
|
// Title — use theme typography
|
||
|
|
Text(
|
||
|
|
_event!.title ?? _event!.name ?? '',
|
||
|
|
style: theme.textTheme.headlineSmall?.copyWith(fontSize: 22, fontWeight: FontWeight.bold),
|
||
|
|
),
|
||
|
|
const SizedBox(height: 8),
|
||
|
|
|
||
|
|
// Meta row (date, location) — icons will use theme icon color
|
||
|
|
Row(
|
||
|
|
children: [
|
||
|
|
Icon(Icons.calendar_today, size: 16, color: theme.iconTheme.color),
|
||
|
|
const SizedBox(width: 6),
|
||
|
|
Text(
|
||
|
|
'${_event!.startDate}${_event!.startTime != null ? ' • ${_event!.startTime}' : ''}',
|
||
|
|
style: theme.textTheme.bodyMedium,
|
||
|
|
),
|
||
|
|
const SizedBox(width: 12),
|
||
|
|
Icon(Icons.location_on, size: 16, color: theme.iconTheme.color),
|
||
|
|
const SizedBox(width: 6),
|
||
|
|
Flexible(child: Text(_event!.place ?? _event!.venueName ?? '', style: theme.textTheme.bodyMedium)),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
const SizedBox(height: 12),
|
||
|
|
|
||
|
|
// Description — themed body text (no hardcoded black)
|
||
|
|
Text(
|
||
|
|
_event!.description ?? '',
|
||
|
|
style: theme.textTheme.bodyMedium,
|
||
|
|
),
|
||
|
|
const SizedBox(height: 16),
|
||
|
|
|
||
|
|
// Important section (if present)
|
||
|
|
if ((_event!.importantInformation ?? '').isNotEmpty) ...[
|
||
|
|
Text('Important', style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
|
||
|
|
const SizedBox(height: 6),
|
||
|
|
Text(_event!.importantInformation!, style: theme.textTheme.bodyMedium),
|
||
|
|
const SizedBox(height: 12),
|
||
|
|
],
|
||
|
|
|
||
|
|
// Book button
|
||
|
|
Row(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
||
|
|
children: [
|
||
|
|
ElevatedButton(
|
||
|
|
onPressed: () {
|
||
|
|
Navigator.push(
|
||
|
|
context,
|
||
|
|
MaterialPageRoute(
|
||
|
|
builder: (_) => BookingScreen(
|
||
|
|
onBook: () {
|
||
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Booked (demo)')));
|
||
|
|
},
|
||
|
|
image: _event!.thumbImg ?? '',
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
},
|
||
|
|
child: const Padding(
|
||
|
|
padding: EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||
|
|
child: Text('Book Tickets'),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|