Files
CityCards_Partner_Flutter/lib/redemption/view/ticket_redemption_screen.dart
2025-10-29 18:55:48 +05:30

306 lines
14 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../bloc/redemption_bloc.dart';
import '../bloc/redemption_event.dart';
import '../bloc/redemption_state.dart';
import '../viewmodel/redemption_view_model.dart';
import 'manual_entry_screen.dart';
class TicketRedemptionScreen extends StatelessWidget {
const TicketRedemptionScreen({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => RedemptionBloc()..add(LoadRecentRedemptions()),
child: Builder(
builder: (context) {
final vm = RedemptionViewModel(context.read<RedemptionBloc>());
return BlocBuilder<RedemptionBloc, RedemptionState>(
builder: (context, state) {
return Scaffold(
backgroundColor: Colors.white,
// appBar: AppBar(
// backgroundColor: Colors.white,
// elevation: 0,
// leading: IconButton(
// icon: const Icon(Icons.arrow_back, color: Colors.black),
// onPressed: () => Navigator.pop(context),
// ),
// title: const Text(
// "Ticket Redemption",
// style: TextStyle(
// color: Colors.black,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeaderSection(context),
const SizedBox(height: 68),
const Text(
"Recent Redemptions",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
Expanded(
child: ListView.builder(
itemCount: state.recentRedemptions.length,
itemBuilder: (context, i) {
final item = state.recentRedemptions[i];
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: Container(
height: 111,
decoration: BoxDecoration(
color: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
/// 🧾 Left Content (Title + Subtitle Row)
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
/// Title
Text(
item['title'],
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
const SizedBox(height: 6),
/// Subtitle Row (Date + Status)
Row(
children: [
Image.asset(
"assets/ticket/lets-icons_date-fill.png",
scale: 4,
),
const SizedBox(width: 8),
const Text(
"Today, 2:53 PM",
style: TextStyle(
fontSize: 13,
color: Colors.black87,
),
),
const SizedBox(width: 8),
Icon(
Icons.circle,
size: 10,
color: item['status'] ? Colors.green : Colors.red,
),
],
),
],
),
),
/// 🎟️ Trailing Ticket Image Section
Container(
height: 74,
width: 92,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(20),
),
color: Colors.white,
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(17)),
child: Stack(
fit: StackFit.expand,
children: [
/// Background image
Image.asset(
"assets/ticket/dubai.jpg",
fit: BoxFit.cover,
),
/// Decorative vertical cutouts (aligned to right)
Align(
alignment: const FractionalOffset(0.7, 0.5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 6,
width: 10,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
),
color: Color(0xffF5F5F5),
),
),
Container(
height: 12,
width: 8,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Color(0xffF5F5F5),
),
),
Container(
height: 12,
width: 8,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Color(0xffF5F5F5),
),
),
Container(
height: 6,
width: 8,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
),
color: Color(0xffF5F5F5),
),
),
],
),
),
],
),
),
),
],
),
),
);
},
),
),
const SizedBox(height: 12),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xffF95F62),
foregroundColor: Colors.white,
minimumSize: const Size.fromHeight(50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () {},
child: const Text(
"Scan New Ticket",
style: TextStyle(fontWeight: FontWeight.w600),
),
),
const SizedBox(height: 8),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.redAccent),
minimumSize: const Size.fromHeight(50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => BlocProvider(
create: (_) => RedemptionBloc(),
child: const ManualEntryScreen(),
),
),
);
},
child: const Text(
"Manual Ticket Entry",
style: TextStyle(
color: Colors.redAccent,
fontWeight: FontWeight.w600,
),
),
),
const SizedBox(height: 5),
],
),
),
),
);
},
);
},
),
);
}
Widget _buildHeaderSection(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 2.0, vertical: 14.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Container(
width: 44,
height: 44,
decoration: const BoxDecoration(
color: Color(0xFFF95F62),
shape: BoxShape.circle,
),
child: const Icon(Icons.arrow_back, color: Colors.white),
),
),
Text(
'Ticket Redemption',
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 28,
),
),
SizedBox(
width: 40,
)
],
),
),
SizedBox(height: 8),
Align(
alignment: Alignment.center,
child: Text(
'Redeem your passes at partner locations',
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
height: 1.4,
),
),
),
],
);
}
}