usability fixes
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:qpay/auth_state.dart';
|
||||
import 'package:qpay/models/responsive_policy.dart';
|
||||
import 'package:qpay/screens/receipt/receipt_controller.dart';
|
||||
import 'package:qpay/screens/transaction_controller.dart';
|
||||
@@ -251,6 +253,142 @@ class _HistoryScreenState extends State<HistoryScreen>
|
||||
);
|
||||
}
|
||||
|
||||
/// Shows the report download bottom sheet with start/end date pickers.
|
||||
void _showReportSheet() {
|
||||
DateTime selectedStart = DateTime.now().subtract(const Duration(days: 7));
|
||||
DateTime selectedEnd = DateTime.now();
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
builder: (ctx) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setSheetState) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 20,
|
||||
right: 20,
|
||||
top: 20,
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom + 20,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Download Report',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildDateField(
|
||||
label: 'Start Date',
|
||||
date: selectedStart,
|
||||
onTap: () async {
|
||||
final picked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: selectedStart,
|
||||
firstDate: DateTime(2020),
|
||||
lastDate: selectedEnd,
|
||||
);
|
||||
if (picked != null) {
|
||||
setSheetState(() => selectedStart = picked);
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildDateField(
|
||||
label: 'End Date',
|
||||
date: selectedEnd,
|
||||
onTap: () async {
|
||||
final picked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: selectedEnd,
|
||||
firstDate: selectedStart,
|
||||
lastDate: DateTime.now(),
|
||||
);
|
||||
if (picked != null) {
|
||||
setSheetState(() => selectedEnd = picked);
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton.icon(
|
||||
icon: controller.model.isActing
|
||||
? const SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: const Icon(Icons.download),
|
||||
label: Text(
|
||||
controller.model.isActing
|
||||
? 'Downloading…'
|
||||
: 'Download Report',
|
||||
),
|
||||
onPressed: controller.model.isActing
|
||||
? null
|
||||
: () {
|
||||
Navigator.of(ctx).pop();
|
||||
final workspaceId =
|
||||
prefs.getString("workspaceId") ?? '';
|
||||
controller.downloadReport(
|
||||
workspaceId: workspaceId,
|
||||
startDate: selectedStart,
|
||||
endDate: selectedEnd,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Builds a tappable date field for the report sheet.
|
||||
Widget _buildDateField({
|
||||
required String label,
|
||||
required DateTime date,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
final df = DateFormat('dd MMM yyyy');
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'$label: ${df.format(date)}',
|
||||
style: const TextStyle(fontSize: 15),
|
||||
),
|
||||
),
|
||||
Icon(Icons.calendar_today, size: 20, color: Colors.grey.shade600),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
@@ -396,6 +534,15 @@ class _HistoryScreenState extends State<HistoryScreen>
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// Report download — only visible to logged-in users.
|
||||
if (authState.isLoggedIn)
|
||||
_buildIconButton(
|
||||
icon: Icons.description_outlined,
|
||||
tooltip: 'Download report',
|
||||
isActive: false,
|
||||
onPressed: _showReportSheet,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_buildIconButton(
|
||||
icon: Icons.add,
|
||||
tooltip: 'New payment',
|
||||
@@ -679,4 +826,4 @@ class _HistoryScreenState extends State<HistoryScreen>
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user