4/9/1
This commit is contained in:
@@ -196,6 +196,7 @@ class FirebaseMessagesController extends GetxController {
|
||||
Get.to(() => RateDriverFromPassenger(), arguments: {
|
||||
'driverId': driverList[0].toString(),
|
||||
'rideId': driverList[1].toString(),
|
||||
'price': driverList[3].toString()
|
||||
});
|
||||
}
|
||||
} else if (message.notification!.title! == 'Call Income') {
|
||||
@@ -347,6 +348,7 @@ class FirebaseMessagesController extends GetxController {
|
||||
Get.to(() => RateDriverFromPassenger(), arguments: {
|
||||
'driverId': driverList[0].toString(),
|
||||
'rideId': driverList[1].toString(),
|
||||
'price': driverList[3].toString()
|
||||
});
|
||||
},
|
||||
kolor: AppColor.greenColor,
|
||||
@@ -357,6 +359,7 @@ class FirebaseMessagesController extends GetxController {
|
||||
Get.to(() => RateDriverFromPassenger(), arguments: {
|
||||
'driverId': driverList[0].toString(),
|
||||
'rideId': driverList[1].toString(),
|
||||
'price': driverList[3].toString()
|
||||
});
|
||||
},
|
||||
kolor: AppColor.redColor,
|
||||
|
||||
@@ -1,101 +1,159 @@
|
||||
import 'dart:io';
|
||||
|
||||
// import 'dart:io';
|
||||
//
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_sound/flutter_sound.dart';
|
||||
// import 'package:get/get.dart';
|
||||
// import 'package:permission_handler/permission_handler.dart';
|
||||
//
|
||||
// import '../home/map_passenger_controller.dart';
|
||||
//
|
||||
// class AudioController extends GetxController {
|
||||
// final recorder = FlutterSoundRecorder();
|
||||
// bool isRecording = false;
|
||||
//
|
||||
// @override
|
||||
// void onInit() {
|
||||
// super.onInit();
|
||||
// initRecorder();
|
||||
// }
|
||||
//
|
||||
// Future<void> initRecorder() async {
|
||||
// final status = await Permission.microphone.request();
|
||||
// if (status != PermissionStatus.granted) {
|
||||
// if (status.isPermanentlyDenied) {
|
||||
// // Handle permission permanently denied
|
||||
// showPermissionDeniedDialog();
|
||||
// } else if (status.isDenied) {
|
||||
// // Handle permission denied
|
||||
// showPermissionDeniedSnackbar();
|
||||
// } else if (status.isRestricted) {
|
||||
// // Handle permission restricted
|
||||
// showPermissionDeniedSnackbar();
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// await recorder.openRecorder();
|
||||
// recorder.setSubscriptionDuration(const Duration(minutes: 50));
|
||||
// }
|
||||
//
|
||||
// Future<void> startRecording() async {
|
||||
// if (!recorder.isStopped) {
|
||||
// await recorder.startRecorder();
|
||||
// }
|
||||
// isRecording = true;
|
||||
// update();
|
||||
// }
|
||||
//
|
||||
// Future<void> stopRecording() async {
|
||||
// final filePath = await recorder.stopRecorder();
|
||||
// final audioFile = File(filePath!);
|
||||
// print('Recorded file path: $audioFile');
|
||||
// // Now you can send this file to the server
|
||||
// isRecording = false;
|
||||
// update();
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// void onClose() {
|
||||
// recorder.stopRecorder();
|
||||
// super.onClose();
|
||||
// }
|
||||
//
|
||||
// void showPermissionDeniedDialog() {
|
||||
// showDialog(
|
||||
// context: Get.context!,
|
||||
// builder: (context) => AlertDialog(
|
||||
// title: const Text('Microphone Permission'),
|
||||
// content:
|
||||
// const Text('Microphone permission is required to record audio.'),
|
||||
// actions: [
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// openAppSettings();
|
||||
// },
|
||||
// child: const Text('Open Settings'),
|
||||
// ),
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// child: const Text('Cancel'),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// void showPermissionDeniedSnackbar() {
|
||||
// Get.snackbar(
|
||||
// 'Microphone Permission',
|
||||
// 'Microphone permission is required to record audio.',
|
||||
// snackPosition: SnackPosition.BOTTOM,
|
||||
// duration: const Duration(seconds: 5),
|
||||
// mainButton: TextButton(
|
||||
// onPressed: () {
|
||||
// openAppSettings();
|
||||
// },
|
||||
// child: const Text(
|
||||
// 'Open Settings',
|
||||
// style: TextStyle(color: Colors.white),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_sound/flutter_sound.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter_sound/flutter_sound.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
import '../home/map_passenger_controller.dart';
|
||||
|
||||
class AudioController extends GetxController {
|
||||
final recorder = FlutterSoundRecorder();
|
||||
final flutterSoundHelper = FlutterSoundHelper();
|
||||
|
||||
bool isRecording = false;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
initRecorder();
|
||||
}
|
||||
Future<void> startRecording() async {
|
||||
if (!await flutterSoundHelper.hasPermissions()) {
|
||||
await flutterSoundHelper.requestPermissions();
|
||||
}
|
||||
|
||||
Future<void> initRecorder() async {
|
||||
final status = await Permission.microphone.request();
|
||||
if (status != PermissionStatus.granted) {
|
||||
if (status.isPermanentlyDenied) {
|
||||
// Handle permission permanently denied
|
||||
showPermissionDeniedDialog();
|
||||
} else {
|
||||
// Handle permission denied
|
||||
showPermissionDeniedSnackbar();
|
||||
}
|
||||
if (!await flutterSoundHelper.hasPermissions()) {
|
||||
return;
|
||||
}
|
||||
await recorder.openRecorder();
|
||||
recorder.setSubscriptionDuration(const Duration(minutes: 50));
|
||||
}
|
||||
|
||||
Future<void> startRecording() async {
|
||||
final controller = Get.find<MapPassengerController>();
|
||||
final filePath = 'audio_${controller.rideId}.wav'; // Specify the file name
|
||||
await recorder.startRecorder(toFile: filePath);
|
||||
await flutterSoundHelper.startRecorder();
|
||||
isRecording = true;
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> stopRecording() async {
|
||||
final filePath = await recorder.stopRecorder();
|
||||
final audioFile = File(filePath!);
|
||||
print('Recorded file path: $audioFile');
|
||||
// Now you can send this file to the server
|
||||
if (!isRecording) {
|
||||
return;
|
||||
}
|
||||
|
||||
await flutterSoundHelper.stopRecorder();
|
||||
isRecording = false;
|
||||
update();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
recorder.stopRecorder();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void showPermissionDeniedDialog() {
|
||||
showDialog(
|
||||
context: Get.context!,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('Microphone Permission'),
|
||||
content: Text('Microphone permission is required to record audio.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
openAppSettings();
|
||||
},
|
||||
child: Text('Open Settings'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text('Cancel'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void showPermissionDeniedSnackbar() {
|
||||
Get.snackbar(
|
||||
'Microphone Permission',
|
||||
'Microphone permission is required to record audio.',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
duration: Duration(seconds: 5),
|
||||
mainButton: TextButton(
|
||||
onPressed: () {
|
||||
openAppSettings();
|
||||
},
|
||||
child: Text(
|
||||
'Open Settings',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FlutterSoundHelper {
|
||||
final flutterSound = FlutterSoundRecorder();
|
||||
|
||||
Future<bool> hasPermissions() async {
|
||||
return await Permission.microphone.isGranted;
|
||||
}
|
||||
|
||||
Future<void> requestPermissions() async {
|
||||
await Permission.microphone.request();
|
||||
}
|
||||
|
||||
Future<void> startRecorder() async {
|
||||
await flutterSound.openRecorder();
|
||||
await flutterSound.startRecorder(toFile: 'audio.wav');
|
||||
}
|
||||
|
||||
Future<void> stopRecorder() async {
|
||||
await flutterSound.stopRecorder();
|
||||
await flutterSound.closeRecorder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,9 +425,11 @@ class MapDriverController extends GetxController {
|
||||
isRideFinished = true;
|
||||
isRideStarted = false;
|
||||
isPriceWindow = false;
|
||||
totalCost = carType == 'Comfort' || carType == 'Mashwari'
|
||||
? price.toStringAsFixed(1)
|
||||
: totalPassenger;
|
||||
totalCost = carType != 'Comfort' || carType != 'Mashwari'
|
||||
? totalPassenger
|
||||
: price < double.parse(totalPassenger)
|
||||
? totalPassenger
|
||||
: price.toStringAsFixed(1);
|
||||
paymentAmount = totalCost;
|
||||
box.write(BoxName.statusDriverLocation, 'off');
|
||||
// changeRideToBeginToPassenger();
|
||||
@@ -466,7 +468,7 @@ class MapDriverController extends GetxController {
|
||||
100; // for eygpt /100
|
||||
var res = await CRUD().post(link: AppLink.addDriversWalletPoints, payload: {
|
||||
'paymentID': 'rideId$rideId',
|
||||
'amount': (pointsSubstraction).toString(),
|
||||
'amount': (pointsSubstraction).toStringAsFixed(0),
|
||||
'paymentMethod': paymentMethod,
|
||||
'driverID': box.read(BoxName.driverID).toString(),
|
||||
});
|
||||
@@ -474,68 +476,18 @@ class MapDriverController extends GetxController {
|
||||
Future.delayed(const Duration(milliseconds: 300));
|
||||
FirebaseMessagesController().sendNotificationToPassengerToken(
|
||||
'Driver Finish Trip',
|
||||
'you will pay to Driver'.tr +
|
||||
' ${carType == 'Comfort' || carType == 'Mashwari' ? price.toStringAsFixed(2) : totalPassenger} \$'
|
||||
.tr,
|
||||
'${'you will pay to Driver'.tr} $paymentAmount \$',
|
||||
tokenPassenger,
|
||||
[
|
||||
box.read(BoxName.driverID),
|
||||
rideId,
|
||||
box.read(BoxName.tokenDriver),
|
||||
carType == 'Comfort' || carType == 'Mashwari'
|
||||
? price.toStringAsFixed(2)
|
||||
: totalPassenger
|
||||
// carType == 'Comfort' || carType == 'Mashwari'
|
||||
// ? price.toStringAsFixed(2)
|
||||
// : totalPassenger
|
||||
paymentAmount.toString()
|
||||
],
|
||||
);
|
||||
// } else {
|
||||
// Get.defaultDialog(
|
||||
// title: 'You don\'t arrive destenation yet .'.tr,
|
||||
// middleText: '',
|
||||
// confirm: MyElevatedButton(
|
||||
// title: 'Ok'.tr,
|
||||
// onPressed: () {
|
||||
// Get.back();
|
||||
// }));
|
||||
// }
|
||||
// } else {
|
||||
// totalCost = price.toStringAsFixed(2);
|
||||
// paymentAmount = totalCost;
|
||||
// box.write(BoxName.statusDriverLocation, 'off');
|
||||
// // changeRideToBeginToPassenger();
|
||||
// await CRUD().post(link: AppLink.updateRides, payload: {
|
||||
// 'id': rideId,
|
||||
// 'rideTimeFinish': DateTime.now().toString(),
|
||||
// 'status': 'Finished'
|
||||
// });
|
||||
// print('walletChecked is $walletChecked');
|
||||
// if (walletChecked == 'true') {
|
||||
// await CRUD().post(link: AppLink.addPassengersWallet, payload: {
|
||||
// 'passenger_id': passengerId,
|
||||
// 'balance': ((-1) * double.parse(paymentAmount)).toString()
|
||||
// });
|
||||
// }
|
||||
// print('passengerWalletBurc bef ${double.parse(passengerWalletBurc)}');
|
||||
// if (double.parse(passengerWalletBurc) < 0) {
|
||||
// await CRUD().post(link: AppLink.addPassengersWallet, payload: {
|
||||
// 'passenger_id': passengerId,
|
||||
// 'balance': ((-1) * double.parse(passengerWalletBurc)).toString()
|
||||
// });
|
||||
// print('passengerWalletBurc aft ${double.parse(passengerWalletBurc)}');
|
||||
// }
|
||||
// Future.delayed(const Duration(milliseconds: 300));
|
||||
// FirebaseMessagesController().sendNotificationToPassengerToken(
|
||||
// 'Driver Finish Trip',
|
||||
// 'you will pay to Driver'.tr + ' $totalCost \$'.tr,
|
||||
// tokenPassenger,
|
||||
// [
|
||||
// box.read(BoxName.driverID),
|
||||
// rideId,
|
||||
// box.read(BoxName.tokenDriver),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
|
||||
// add wallet from passenger from driver
|
||||
Get.to(() => RatePassenger(), arguments: {
|
||||
'passengerId': passengerId,
|
||||
'rideId': rideId,
|
||||
|
||||
@@ -477,7 +477,9 @@ class MyTranslation extends Translations {
|
||||
'Trip has Steps': "الرحلة تتكون من خطوات",
|
||||
'Distance from Passenger to destination is ':
|
||||
"المسافة من الراكب إلى الوجهة هي ",
|
||||
'Cost Of Trip IS ': "تكلفة الرحلة هي ",
|
||||
'price is': 'التكلفة',
|
||||
'distance is'
|
||||
'Cost Of Trip IS ': "تكلفة الرحلة هي ",
|
||||
"We noticed the speed is exceeding 100 km/h. Please slow down for your safety. If you feel unsafe, you can share your trip details with a contact or call the police using the red SOS button.":
|
||||
"لقد لاحظنا أن السرعة تتجاوز ١٠٠ كم/ساعة. يرجى التباطؤ من أجل سلامتك. إذا كنت تشعر بعدم الأمان، يمكنك مشاركة تفاصيل رحلتك مع جهة اتصال أو الاتصال بالشرطة باستخدام زر SOS الأحمر.",
|
||||
'Warning: Speeding detected!': "تحذير: تم رصد السرعة الزائدة!",
|
||||
|
||||
@@ -17,7 +17,7 @@ import 'package:SEFER/views/widgets/elevated_btn.dart';
|
||||
class RateController extends GetxController {
|
||||
double selectedRateItemId = -1;
|
||||
TextEditingController comment = TextEditingController();
|
||||
String? rideId, passengerId, driverId;
|
||||
String? rideId, passengerId, driverId, price;
|
||||
late GlobalKey<FormState> formKey;
|
||||
@override
|
||||
void onInit() {
|
||||
@@ -25,6 +25,7 @@ class RateController extends GetxController {
|
||||
passengerId = Get.arguments['passengerId'];
|
||||
rideId = Get.arguments['rideId'];
|
||||
driverId = Get.arguments['driverId'];
|
||||
price = Get.arguments['price'];
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:SEFER/constant/box_name.dart';
|
||||
import 'package:SEFER/controller/home/map_passenger_controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -5,6 +7,7 @@ import 'package:get/get.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/style.dart';
|
||||
import '../../controller/rate/rate_conroller.dart';
|
||||
import '../../main.dart';
|
||||
import '../widgets/elevated_btn.dart';
|
||||
import '../widgets/my_scafold.dart';
|
||||
|
||||
@@ -21,9 +24,69 @@ class RateDriverFromPassenger extends StatelessWidget {
|
||||
left: Get.width * .1,
|
||||
right: Get.width * .1,
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Container(
|
||||
height: Get.height * .25,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'${'Total price to '.tr}${Get.find<MapPassengerController>().firstName}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 2,
|
||||
color: AppColor.redColor,
|
||||
)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Text(
|
||||
(double.parse(controller.price
|
||||
.toString()) *
|
||||
.12 +
|
||||
double.parse(
|
||||
controller.price.toString()))
|
||||
.toStringAsFixed(2),
|
||||
style: AppStyle.number.copyWith(
|
||||
color: AppColor.redColor,
|
||||
textBaseline:
|
||||
TextBaseline.ideographic,
|
||||
decoration:
|
||||
TextDecoration.lineThrough,
|
||||
decorationColor: AppColor.redColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 2,
|
||||
color: AppColor.greenColor,
|
||||
)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Text(
|
||||
controller.price.toString(),
|
||||
style: AppStyle.number,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
Center(
|
||||
child: RatingBar.builder(
|
||||
initialRating: 0,
|
||||
|
||||
@@ -21,8 +21,8 @@ GetBuilder<MapDriverController> driverEndRideBar() {
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration,
|
||||
height: mapDriverController.remainingTimeTimerRideBegin < 60
|
||||
? mapDriverController.driverEndPage = 180
|
||||
: 150,
|
||||
? mapDriverController.driverEndPage = 190
|
||||
: 170,
|
||||
width: 240,
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -70,7 +70,7 @@ GetBuilder<MapDriverController> driverEndRideBar() {
|
||||
Text(mapDriverController.price.toStringAsFixed(2)),
|
||||
],
|
||||
),
|
||||
(mapDriverController.carType == 'Free Ride' ||
|
||||
(mapDriverController.carType == 'Mashwari' ||
|
||||
mapDriverController.carType == 'Comfort') &&
|
||||
mapDriverController.remainingTimeTimerRideBegin > 60
|
||||
? Row(
|
||||
|
||||
@@ -200,7 +200,7 @@ class OrderRequestPage extends StatelessWidget {
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
height: Get.height * .15,
|
||||
height: Get.height * .2,
|
||||
width: Get.width * .9,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Column(
|
||||
@@ -284,7 +284,10 @@ class OrderRequestPage extends StatelessWidget {
|
||||
style: AppStyle.title,
|
||||
children: [
|
||||
TextSpan(
|
||||
text: (mpg * double.parse(myList[5]))
|
||||
text: ((Get.find<HomeCaptainController>()
|
||||
.fuelPrice /
|
||||
12) *
|
||||
double.parse(myList[5]))
|
||||
.toStringAsFixed(2),
|
||||
style: AppStyle.headTitle2),
|
||||
],
|
||||
|
||||
@@ -81,11 +81,11 @@ class OrderSpeedRequest extends StatelessWidget {
|
||||
endIcon = value;
|
||||
});
|
||||
// }
|
||||
double mpg = 0;
|
||||
calculateConsumptionFuel() {
|
||||
mpg = Get.find<HomeCaptainController>().fuelPrice /
|
||||
12; //todo in register car add mpg in box
|
||||
}
|
||||
// double mpg = 0;
|
||||
// calculateConsumptionFuel() {
|
||||
// mpg = Get.find<HomeCaptainController>().fuelPrice /
|
||||
// 12; //todo in register car add mpg in box
|
||||
// }
|
||||
|
||||
return MyScafolld(
|
||||
title: 'Order Details'.tr,
|
||||
@@ -199,7 +199,7 @@ class OrderSpeedRequest extends StatelessWidget {
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
height: Get.height * .15,
|
||||
height: Get.height * .2,
|
||||
width: Get.width * .9,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Column(
|
||||
@@ -292,8 +292,11 @@ class OrderSpeedRequest extends StatelessWidget {
|
||||
style: AppStyle.title,
|
||||
children: [
|
||||
TextSpan(
|
||||
text: (mpg * double.parse(myList[5]))
|
||||
.toStringAsFixed(2),
|
||||
text:
|
||||
((Get.find<HomeCaptainController>().fuelPrice /
|
||||
12) *
|
||||
double.parse(myList[5]))
|
||||
.toStringAsFixed(2),
|
||||
style: AppStyle.headTitle2),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -33,8 +33,8 @@ List<CarType> carTypes = [
|
||||
carDetail: 'Delivery service'.tr,
|
||||
image: 'assets/images/moto.png'),
|
||||
CarType(
|
||||
carType: 'Free Ride',
|
||||
carDetail: 'free ride without end point'.tr,
|
||||
carType: 'Mashwari',
|
||||
carDetail: 'Mashwari without end point'.tr,
|
||||
image: 'assets/images/freeRide.png'),
|
||||
];
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ class RideBeginPassenger extends StatelessWidget {
|
||||
),
|
||||
audioController.isRecording == false
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
audioController.startRecording();
|
||||
onPressed: () async {
|
||||
await audioController.startRecording();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.play_circle_fill_outlined,
|
||||
@@ -95,8 +95,8 @@ class RideBeginPassenger extends StatelessWidget {
|
||||
' Add Note', // Optional tooltip for clarity
|
||||
)
|
||||
: IconButton(
|
||||
onPressed: () {
|
||||
audioController.stopRecording();
|
||||
onPressed: () async {
|
||||
await audioController.stopRecording();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.stop_circle,
|
||||
|
||||
Reference in New Issue
Block a user