import 'dart:io'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:open_file/open_file.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:qadirneyriz/config/config.dart'; import 'package:qadirneyriz/global/global_state/global_state.dart'; import 'package:qadirneyriz/screens/report/state.dart'; import 'package:qadirneyriz/setting/setting.dart'; import 'package:qadirneyriz/utils/enums/status.dart'; import 'package:qadirneyriz/utils/tools/tools.dart'; import 'package:qadirneyriz/widgets/ExpansionTileCustom.dart'; import 'package:qadirneyriz/widgets/custom_appbar.dart'; import 'package:qadirneyriz/widgets/custom_button.dart'; import 'package:qadirneyriz/widgets/error_widget.dart'; import 'package:qadirneyriz/widgets/loading_widget.dart'; import 'package:qadirneyriz/widgets/picker.dart'; import 'package:qadirneyriz/widgets/today_widget.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class ReportScreen extends StatefulWidget { const ReportScreen({super.key}); @override State createState() => _ReportScreenState(); } class _ReportScreenState extends State { @override Widget build(BuildContext context) { DateTime now = DateTime.now(); String dateMiladi = setting.userLocalDb.getUser().language == 'fa' ? Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now)) : DateFormat('yyyy-MM-dd').format(now); String dateJalali = Tools.convertToPersianDigits( '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'); // فرمت کردن تاریخ return CustomScrollView( slivers: [ const CustomAppbar(), SliverToBoxAdapter( child: TodayWidget( formattedDate: setting.userLocalDb.getUser().language == 'en' ? dateMiladi : dateJalali), ), SliverFillRemaining( child: FiltersItemInReport(), ) ], ); } } class FiltersItemInReport extends StatefulWidget { const FiltersItemInReport({ super.key, }); @override State createState() => _FiltersItemInReportState(); } class _FiltersItemInReportState extends State { ReportState? reportState; GlobalState? globalState; @override void initState() { reportState = Provider.of(context, listen: false); globalState = Provider.of(context, listen: false); Future.delayed(Duration.zero, () async { await globalState!.getAllFiltersItems(); }); super.initState(); } @override Widget build(BuildContext context) { List meetingStatuses = [ MeetingsStatus(id: 1, title: AppLocalizations.of(context)!.donemeetings), MeetingsStatus( id: 2, title: AppLocalizations.of(context)!.adjournedmeetings), MeetingsStatus( id: 3, title: AppLocalizations.of(context)!.canceldmeetings), MeetingsStatus( id: 4, title: AppLocalizations.of(context)!.meetingswaitingtobeheld), ]; return Consumer2( builder: (context, reportState, globalState, child) { switch (globalState.allFiltersStatus) { case Status.ready: return Column( children: [ Expanded( child: SingleChildScrollView( child: Column( children: [ Column( mainAxisSize: MainAxisSize.max, children: [ ExpansionTileCustom( title: AppLocalizations.of(context)!.date, widgets: [ Row( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ PickerCustom( showDate: reportState.fromDate.isNotEmpty ? reportState.fromDate : AppLocalizations.of(context)! .selectdate, // Show selected date or prompt onTap: () { showDialog( context: context, builder: (context) { return Dialog( child: Tools .shamsiDateCalendarWidget( context, (newDate) { String fromDateString = '${newDate.year}/${newDate.month}/${newDate.day}'; reportState.setFromDates( fromDateString); // Update the selected date }, ), ); }, ); }, ), Text( AppLocalizations.of(context)!.to, ), PickerCustom( showDate: reportState.toDate.isNotEmpty ? reportState.toDate : AppLocalizations.of(context)! .selectdate, // Show selected date or prompt onTap: () { showDialog( context: context, builder: (context) { return Dialog( child: Tools .shamsiDateCalendarWidget( context, (newDate) { String toDateString = '${newDate.year}/${newDate.month}/${newDate.day}'; reportState.setToDates( toDateString); // Update the selected date }, ), ); }, ); }, ), ], ) ], ), ExpansionTileCustom( title: AppLocalizations.of(context)!.location, widgets: [ ListView.builder( primary: false, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: globalState.locationsModel!.length, itemBuilder: (BuildContext context, int index) { final items = globalState.locationsModel![index]; return RadioListTile( toggleable: true, groupValue: reportState.selectedLocationId, value: items.id ?? -1, title: Text( items.address ?? '', maxLines: 1, style: TextStyle( fontWeight: FontWeight.w100, fontSize: 14), overflow: TextOverflow.ellipsis, ), activeColor: config.ui.secendGreen, onChanged: (int? newValue) { reportState .selectLocation(newValue ?? null); }, ); }, ), ], ), if (setting.userLocalDb.getUser().role != 1) ExpansionTileCustom( title: AppLocalizations.of(context)! .meetingmanager, widgets: [ ListView.builder( primary: false, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: globalState .meetingsManagerModel!.length, itemBuilder: (BuildContext context, int index) { final items = globalState .meetingsManagerModel![index]; return RadioListTile( toggleable: true, groupValue: reportState.selectedManagersId, value: items.id ?? -1, title: Text( items.name ?? '', style: TextStyle( fontWeight: FontWeight.w100, fontSize: 14), maxLines: 1, overflow: TextOverflow.ellipsis, ), activeColor: config.ui.secendGreen, onChanged: (int? newValue) { reportState .selectManager(newValue ?? null); }, ); }, ), ], ), ExpansionTileCustom( title: AppLocalizations.of(context)!.subject, widgets: [ ListView.builder( primary: false, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: globalState.subjectsModel!.length, itemBuilder: (BuildContext context, int index) { final items = globalState.subjectsModel![index]; return RadioListTile( toggleable: true, groupValue: reportState.selectedSubjectId, value: items.id ?? -1, title: Text( items.subject ?? '', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.w100, fontSize: 14), ), activeColor: config.ui.secendGreen, onChanged: (int? newValue) { reportState .selectSubject(newValue ?? null); }, ); }, ), ], ), Divider(), if (setting.userLocalDb.getUser().role != 1) SizedBox( height: 300, child: ListView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, primary: false, itemCount: meetingStatuses.length, itemBuilder: (BuildContext context, int index) { final items = meetingStatuses[index]; return RadioListTile( toggleable: true, groupValue: reportState.selectedStatusId, value: items.id, title: Text( items.title, maxLines: 1, style: TextStyle( fontWeight: FontWeight.w100, fontSize: 14), overflow: TextOverflow.ellipsis, ), activeColor: config.ui.secendGreen, onChanged: (int? newValue) { reportState.selectStatusMeeting( newValue ?? null); }, ); }, ), ), Padding( padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 50), child: downloadButton(reportState), ) ], ), ], ), ), ), ], ); case Status.loading: return const LoadingWidget(); case Status.error: return CustomErrorWidget( onPressed: () async { await globalState.getAllFiltersItems(refresh: true); }, ); default: return Container(); } }, ); } CustomButton downloadButton(ReportState state) { switch (state.statusDownload) { case Status.loading: return CustomButton( borderRadius: 15, hieght: 50, text: AppLocalizations.of(context)!.loading, width: double.infinity, ); default: return CustomButton( borderRadius: 15, hieght: 50, text: AppLocalizations.of(context)!.downloadreport, width: double.infinity, onPressed: () async { bool hasPermission = await hasStoragePermission(); if (!hasPermission) { Tools.showCustomSnackBar(context, text: 'Permission denied. Please allow storage access.', isError: true); return; } // Download the file await state.downloadReport( toDate: reportState!.toDate, fromDate: reportState!.fromDate, location: reportState!.selectedLocationId, subject: reportState!.selectedSubjectId, meetingManager: reportState!.selectedManagersId, status: reportState!.selectedStatusId); if (state.statusDownload == Status.ready) { await OpenFile.open(state.messageDownload); // print(status.message); } else { Tools.showCustomSnackBar( context, text: AppLocalizations.of(context)!.error, isError: true, ); } }, ); } } Future hasStoragePermission() async { if (Platform.isAndroid) { final status = await Permission.storage.status; if (status != PermissionStatus.granted) { final result = await Permission.manageExternalStorage.request(); if (result == PermissionStatus.granted) { return true; } } else { return true; } } else { return true; } return false; } } class LineButtomSheet extends StatelessWidget { const LineButtomSheet({ super.key, }); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.only(top: 8.0), width: 30.0, height: 3.0, decoration: BoxDecoration( color: Colors.grey.shade400, borderRadius: BorderRadius.circular(24.0), ), ); } } class MeetingsStatus { int id; String title; MeetingsStatus({ required this.id, required this.title, }); }