Files
intaleq_driver/lib/views/home/profile/complaint_page.dart

279 lines
12 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sefer_driver/constant/style.dart';
import 'package:sefer_driver/controller/home/profile/complaint_controller.dart';
import 'package:sefer_driver/views/widgets/my_scafold.dart';
import 'package:sefer_driver/views/widgets/mycircular.dart';
import 'package:sefer_driver/views/widgets/mydialoug.dart';
import 'package:sefer_driver/views/widgets/elevated_btn.dart';
import '../../../constant/colors.dart';
import '../../../controller/functions/audio_recorder_controller.dart';
class ComplaintPage extends StatelessWidget {
ComplaintPage({super.key});
final ComplaintController complaintController =
Get.put(ComplaintController());
final AudioRecorderController audioRecorderController =
Get.put(AudioRecorderController());
@override
Widget build(BuildContext context) {
return MyScafolld(
title: 'Submit a Complaint'.tr,
isleading: true,
body: [
GetBuilder<ComplaintController>(
builder: (controller) {
if (controller.isLoading && controller.ridesList.isEmpty) {
return const MyCircularProgressIndicator();
}
return Stack(
children: [
Form(
key: controller.formKey,
child: ListView(
padding: const EdgeInsets.all(16.0),
children: [
// --- 1. Select Ride Section ---
_buildSectionCard(
title: '1. Select Ride'.tr,
child: controller.ridesList.isEmpty
? Text('No rides found to complain about.'.tr,
style: AppStyle.subtitle)
: DropdownButtonFormField<Map<String, dynamic>>(
value: controller.selectedRide,
dropdownColor: AppColor.surfaceColor,
items: controller.ridesList.map((ride) {
return DropdownMenuItem<Map<String, dynamic>>(
value: ride,
child: Text(
'${'Ride'.tr} #${ride['id']} (${ride['date']})',
style: AppStyle.subtitle,
),
);
}).toList(),
onChanged: (ride) {
if (ride != null) {
controller.selectRide(ride);
}
},
decoration: InputDecoration(
filled: true,
fillColor:
AppColor.secondaryColor.withOpacity(0.5),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
),
),
),
// --- 2. Describe Your Issue Section ---
_buildSectionCard(
title: '2. Describe Your Issue'.tr,
child: TextFormField(
controller: controller.complaintController,
decoration: InputDecoration(
hintText: 'Enter your complaint here...'.tr,
filled: true,
fillColor:
AppColor.secondaryColor.withOpacity(0.5),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.all(16),
),
maxLines: 6,
style: AppStyle.subtitle,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a description of the issue.'
.tr;
}
return null;
},
),
),
// --- 3. Attach Recorded Audio Section ---
if (controller.selectedRide != null)
_buildSectionCard(
title: '3. Attach Recorded Audio (Optional)'.tr,
child: FutureBuilder<List<String>>(
future: audioRecorderController.getRecordedFiles(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator());
}
final rideId =
controller.selectedRide!['id'].toString();
// Filter files to only show the audio file associated with the selected Ride ID
final matchingFiles = snapshot.data
?.where((path) =>
path.endsWith('_${rideId}.m4a'))
.toList() ??
[];
if (snapshot.hasError || matchingFiles.isEmpty) {
return Center(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0),
child: Text(
'No audio files found for this ride.'.tr,
style: AppStyle.subtitle),
),
);
}
return Column(
children: matchingFiles.map((audioFilePath) {
final audioFile = File(audioFilePath);
final isUploaded =
controller.audioLink.isNotEmpty &&
controller.attachedFileName ==
audioFilePath.split('/').last;
return ListTile(
leading: Icon(
isUploaded
? Icons.check_circle
: Icons.mic,
color: isUploaded
? AppColor.greenColor
: AppColor.redColor),
title: Text(audioFilePath.split('/').last,
style: AppStyle.subtitle,
overflow: TextOverflow.ellipsis),
subtitle: isUploaded
? Text('Uploaded'.tr,
style: const TextStyle(
color: AppColor.greenColor))
: null,
onTap: isUploaded
? null
: () {
MyDialogContent().getDialog(
'Confirm Attachment'.tr,
Text(
'Attach this audio file?'
.tr), () async {
await controller
.uploadAudioFile(audioFile);
});
},
);
}).toList(),
);
},
),
),
// --- 4. Review Details & Response Section ---
if (controller.selectedRide != null)
_buildSectionCard(
title: '4. Review Details & Response'.tr,
child: Column(
children: [
_buildDetailRow(
Icons.calendar_today_outlined,
'Date'.tr,
controller.selectedRide!['date'] ?? ''),
_buildDetailRow(
Icons.monetization_on_outlined,
'Price'.tr,
'${controller.selectedRide!['price'] ?? ''}'),
const Divider(height: 24),
ListTile(
leading: const Icon(
Icons.support_agent_outlined,
color: AppColor.primaryColor),
title: Text("Intaleq's Response".tr,
style: AppStyle.title),
subtitle: Text(
controller.driverReport?['body']
?.toString() ??
'Awaiting response...'.tr,
style:
AppStyle.subtitle.copyWith(height: 1.5),
),
),
],
),
),
// --- 5. Submit Button ---
const SizedBox(height: 24),
MyElevatedButton(
onPressed: () async {
await controller.submitComplaintToServer();
},
title: 'Submit Complaint'.tr,
),
const SizedBox(height: 24),
],
),
),
if (controller.isLoading)
Container(
color: Colors.black.withOpacity(0.5),
child: const MyCircularProgressIndicator(),
),
],
);
},
),
],
);
}
Widget _buildSectionCard({required String title, required Widget child}) {
return Card(
margin: const EdgeInsets.only(bottom: 20),
elevation: 4,
shadowColor: Colors.black.withOpacity(0.1),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: AppStyle.headTitle.copyWith(fontSize: 18)),
const SizedBox(height: 12),
child,
],
),
),
);
}
Widget _buildDetailRow(IconData icon, String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [
Icon(icon, color: AppColor.writeColor.withOpacity(0.6), size: 20),
const SizedBox(width: 12),
Text('${label.tr}:',
style: AppStyle.subtitle
.copyWith(color: AppColor.writeColor.withOpacity(0.7))),
const Spacer(),
Text(value,
style: AppStyle.title.copyWith(fontWeight: FontWeight.bold)),
],
),
);
}
}