update
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:prosappco/src/authentication/authentication_repository.dart';
|
||||
@@ -7,6 +8,8 @@ import 'package:prosappco/src/components/pop_appbar.dart';
|
||||
import 'package:prosappco/src/models/chat_model.dart';
|
||||
import 'package:prosappco/src/models/event_model.dart';
|
||||
import 'package:prosappco/src/models/user_model.dart';
|
||||
import 'package:prosappco/src/screens/professional.dart';
|
||||
import 'package:prosappco/src/screens/professional_info.dart';
|
||||
|
||||
class ChatScreen extends StatefulWidget {
|
||||
final String? eventoId;
|
||||
@@ -20,6 +23,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
final _textController = TextEditingController();
|
||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
||||
UserModel? user;
|
||||
Professional? professional;
|
||||
bool pro = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -31,8 +36,10 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
(UserModel s) => setState(() => user = s),
|
||||
);
|
||||
} else {
|
||||
Professional.getProfessional(event.professionalId)
|
||||
.then((value) => {professional = value});
|
||||
UserModel.getUser(event.professionalId).then(
|
||||
(UserModel s) => setState(() => user = s),
|
||||
(UserModel s) => setState(() => {user = s, pro = true}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -65,12 +72,27 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
color: const Color(0xFFD6F4FF),
|
||||
alignment: Alignment.topCenter,
|
||||
child: ListTile(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: ReferencePhoto(
|
||||
ref: user?.photo,
|
||||
size: 55,
|
||||
sizeCircle: 60,
|
||||
leading: GestureDetector(
|
||||
onTap: () {
|
||||
if (pro) {
|
||||
Navigator.of(context).push(
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return ProfessionalInfoScreen(
|
||||
professional: professional!,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: ReferencePhoto(
|
||||
ref: user?.photo,
|
||||
size: 55,
|
||||
sizeCircle: 60,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
@@ -119,6 +141,31 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
filled: true,
|
||||
fillColor: Colors.grey[200],
|
||||
),
|
||||
onFieldSubmitted: (value) {
|
||||
String muestra = _textController.text.trim();
|
||||
if (muestra.isNotEmpty) {
|
||||
final nuevoMensaje = MessageModel(
|
||||
user: uid!,
|
||||
content:
|
||||
_textController.text.trimLeft().trimRight(),
|
||||
timestamp: DateTime.now());
|
||||
|
||||
final nuevoMensajeMap = {
|
||||
'user': nuevoMensaje.user,
|
||||
'content': nuevoMensaje.content,
|
||||
'timestamp': nuevoMensaje.timestamp,
|
||||
};
|
||||
|
||||
FirebaseFirestore.instance
|
||||
.collection('chats')
|
||||
.doc(widget.eventoId)
|
||||
.update({
|
||||
'message': FieldValue.arrayUnion([nuevoMensajeMap])
|
||||
});
|
||||
|
||||
_textController.clear();
|
||||
} else {}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
|
||||
+146
-109
@@ -359,20 +359,24 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (widget.evento.status != 'pendiente') {
|
||||
await FirebaseFirestore.instance
|
||||
final chatDoc = FirebaseFirestore.instance
|
||||
.collection('chats')
|
||||
.doc(widget.evento.id)
|
||||
.set(
|
||||
{
|
||||
.doc(widget.evento.id);
|
||||
final chatSnapshot = await chatDoc.get();
|
||||
|
||||
if (!chatSnapshot.exists ||
|
||||
chatSnapshot.data()!['message'] == null) {
|
||||
await chatDoc.set(
|
||||
{
|
||||
'professional_id':
|
||||
widget.evento.professionalId,
|
||||
'user_id': widget.evento.userId,
|
||||
'message': [],
|
||||
},
|
||||
SetOptions(
|
||||
merge:
|
||||
true)).catchError((error) => print(
|
||||
'Error al crear el documento: $error'));
|
||||
SetOptions(merge: true),
|
||||
).catchError((error) => print(
|
||||
'Error al crear el documento: $error'));
|
||||
}
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
@@ -383,7 +387,35 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
}
|
||||
|
||||
// if (widget.evento.status != 'pendiente') {
|
||||
// await FirebaseFirestore.instance
|
||||
// .collection('chats')
|
||||
// .doc(widget.evento.id)
|
||||
// .set(
|
||||
// {
|
||||
// 'professional_id':
|
||||
// widget.evento.professionalId,
|
||||
// 'user_id': widget.evento.userId,
|
||||
// 'message': [],
|
||||
// },
|
||||
// SetOptions(
|
||||
// merge:
|
||||
// true)).catchError((error) => print(
|
||||
// 'Error al crear el documento: $error'));
|
||||
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// CupertinoPageRoute(
|
||||
// builder: (BuildContext context) {
|
||||
// return ChatScreen(
|
||||
// eventoId: widget.evento.id);
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
else {
|
||||
final snackBar = SnackBar(
|
||||
backgroundColor: Colors.blue,
|
||||
content: const Text(
|
||||
@@ -497,84 +529,86 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
),
|
||||
),
|
||||
widget.evento.status == 'aprobado'
|
||||
? eventDate.year == today.year &&
|
||||
eventDate.month == today.month &&
|
||||
eventDate.day == today.day
|
||||
? (DateTime.now()
|
||||
.difference(
|
||||
DateTime.parse(widget.evento.range1Hour1))
|
||||
.abs() <=
|
||||
const Duration(minutes: 30) &&
|
||||
ver == true)
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
FirebaseFirestore.instance
|
||||
.collection("services")
|
||||
.doc('${widget.evento.id}')
|
||||
.update({"status": "iniciado"}).then(
|
||||
(value) {
|
||||
setState(() {
|
||||
ver = false;
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: eventDate.year == today.year &&
|
||||
eventDate.month == today.month &&
|
||||
eventDate.day == today.day
|
||||
? (DateTime.now()
|
||||
.difference(DateTime.parse(
|
||||
widget.evento.range1Hour1))
|
||||
.abs() <=
|
||||
const Duration(minutes: 30) &&
|
||||
ver == true)
|
||||
? ElevatedButton(
|
||||
onPressed: () {
|
||||
FirebaseFirestore.instance
|
||||
.collection("services")
|
||||
.doc('${widget.evento.id}')
|
||||
.update({"status": "iniciado"}).then(
|
||||
(value) {
|
||||
setState(() {
|
||||
ver = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
child: const Text(
|
||||
'Iniciar servicio',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
child: const Text(
|
||||
'Iniciar servicio',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox()
|
||||
: const SizedBox(),
|
||||
),
|
||||
widget.evento.professionalId == uid
|
||||
? ElevatedButton(
|
||||
onPressed: () {
|
||||
FirebaseFirestore.instance
|
||||
.collection("services")
|
||||
.doc('${widget.evento.id}')
|
||||
.update({"status": "denegado"}).then(
|
||||
(value) {
|
||||
Navigator.pushReplacementNamed(
|
||||
context, '/solicitud');
|
||||
});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFFEC2B2B),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
child: const Text(
|
||||
'Cancelar servicio',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
FirebaseFirestore.instance
|
||||
.collection("services")
|
||||
.doc('${widget.evento.id}')
|
||||
.update({"status": "denegado"}).then(
|
||||
(value) {
|
||||
Navigator.pushReplacementNamed(
|
||||
context, '/solicitud');
|
||||
});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFFEC2B2B),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
child: const Text(
|
||||
'Cancelar servicio',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox()
|
||||
: const SizedBox()
|
||||
)
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
widget.evento.status == 'pendiente'
|
||||
? Padding(
|
||||
@@ -583,33 +617,36 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
FirebaseFirestore.instance
|
||||
.collection("services")
|
||||
.doc('${widget.evento.id}')
|
||||
.update({"status": "aprobado"}).then((value) {
|
||||
Navigator.pushReplacementNamed(
|
||||
context, '/solicitud');
|
||||
});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
child: const Text(
|
||||
'Aceptar',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: widget.evento.professionalId == uid
|
||||
? ElevatedButton(
|
||||
onPressed: () {
|
||||
FirebaseFirestore.instance
|
||||
.collection("services")
|
||||
.doc('${widget.evento.id}')
|
||||
.update({"status": "aprobado"}).then(
|
||||
(value) {
|
||||
Navigator.pushReplacementNamed(
|
||||
context, '/solicitud');
|
||||
});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
child: const Text(
|
||||
'Aceptar',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
|
||||
@@ -52,8 +52,13 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
stream: FirebaseFirestore.instance
|
||||
.collection('services')
|
||||
.where('user_id', isEqualTo: uid)
|
||||
.where('status',
|
||||
whereIn: ['aprobado', 'denegado', 'iniciado', 'terminado'])
|
||||
.where('status', whereIn: [
|
||||
'aprobado',
|
||||
'denegado',
|
||||
'iniciado',
|
||||
'terminado',
|
||||
'pendiente'
|
||||
])
|
||||
.snapshots()
|
||||
.asyncMap((snapshot) async {
|
||||
try {
|
||||
@@ -123,17 +128,23 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
color: Colors.blue,
|
||||
size: 40,
|
||||
)
|
||||
: event.status == 'terminado'
|
||||
: event.status == 'pendiente'
|
||||
? const Icon(
|
||||
Icons.rocket_launch,
|
||||
Icons.access_time_outlined,
|
||||
color: Colors.blue,
|
||||
size: 40,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.red,
|
||||
size: 40,
|
||||
),
|
||||
: event.status == 'terminado'
|
||||
? const Icon(
|
||||
Icons.rocket_launch,
|
||||
color: Colors.blue,
|
||||
size: 40,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.red,
|
||||
size: 40,
|
||||
),
|
||||
title: RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
|
||||
@@ -258,6 +258,9 @@ class _ProfessionalProfileWebScreenState
|
||||
.child(random);
|
||||
|
||||
final metaData = SettableMetadata(contentType: 'image/jpeg');
|
||||
// final metaDataImg = SettableMetadata(contentType: 'image/jpeg');
|
||||
// final metaDataPdf = SettableMetadata(contentType: 'application/pdf');
|
||||
// final metaDataWord = SettableMetadata(contentType: 'application/msword');
|
||||
|
||||
final UploadTask uploadTask = ref.putData(imageCedulaBytes!, metaData);
|
||||
|
||||
|
||||
@@ -445,10 +445,10 @@ class _ProfileProState extends State<ProfilePro> {
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10),
|
||||
child: Row(
|
||||
children: const [
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 30),
|
||||
@@ -482,11 +482,11 @@ class _ProfileProState extends State<ProfilePro> {
|
||||
: const EdgeInsets.only(bottom: 70),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 30),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 30),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
children: [
|
||||
Text('Lunes'),
|
||||
Text('Martes'),
|
||||
Text('Miércoles'),
|
||||
|
||||
@@ -258,7 +258,7 @@ class _ProfileWebScreenState extends State<ProfileWebScreen> {
|
||||
body: Center(
|
||||
child: SizedBox(
|
||||
width: 300,
|
||||
height: 550,
|
||||
height: 600,
|
||||
child: Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
@@ -412,7 +412,7 @@ class _ProfileWebScreenState extends State<ProfileWebScreen> {
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
margin: const EdgeInsets.only(top: 50),
|
||||
margin: const EdgeInsets.only(top: 30),
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:community_material_icon/community_material_icon.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_email_sender/flutter_email_sender.dart';
|
||||
import 'package:prosappco/src/components/pop_appbar.dart';
|
||||
@@ -14,6 +15,8 @@ class SupportScreen extends StatefulWidget {
|
||||
|
||||
class SsupportStateScreen extends State<SupportScreen> {
|
||||
SettingModel? settings;
|
||||
final String subject = 'Soporte Prosapp';
|
||||
final String body = '';
|
||||
|
||||
Future<void> _sendWhatsapp(String? number) async {
|
||||
final _whatsappUrl =
|
||||
@@ -26,8 +29,8 @@ class SsupportStateScreen extends State<SupportScreen> {
|
||||
|
||||
Future<void> _sendEmail(String recipients) async {
|
||||
final Email email = Email(
|
||||
body: '',
|
||||
subject: 'Soporte Prosapp',
|
||||
body: body,
|
||||
subject: subject,
|
||||
recipients: [recipients],
|
||||
isHTML: false,
|
||||
);
|
||||
@@ -35,6 +38,17 @@ class SsupportStateScreen extends State<SupportScreen> {
|
||||
await FlutterEmailSender.send(email);
|
||||
}
|
||||
|
||||
void _sendEmailWeb(String recipients) async {
|
||||
final email =
|
||||
'mailto:$recipients?subject=${Uri.encodeComponent(recipients)}&body=${Uri.encodeComponent(body)}';
|
||||
if (await canLaunch(email)) {
|
||||
await launch(email);
|
||||
} else {
|
||||
// No se pudo abrir el cliente de correo electrónico
|
||||
// Puedes mostrar un diálogo o realizar otra acción en este caso
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -98,7 +112,11 @@ class SsupportStateScreen extends State<SupportScreen> {
|
||||
const SizedBox(width: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
_sendEmail(settings?.email ?? '');
|
||||
if (kIsWeb) {
|
||||
_sendEmailWeb(settings?.email ?? '');
|
||||
} else {
|
||||
_sendEmail(settings?.email ?? '');
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
|
||||
@@ -6,6 +6,7 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import cloud_firestore
|
||||
import device_info_plus
|
||||
import file_selector_macos
|
||||
import firebase_auth
|
||||
import firebase_core
|
||||
@@ -17,6 +18,7 @@ import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
|
||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||
|
||||
@@ -129,6 +129,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.8"
|
||||
device_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: device_info_plus
|
||||
sha256: "2c35b6d1682b028e42d07b3aee4b98fa62996c10bc12cb651ec856a80d6a761b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.2"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
diacritic:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1037,6 +1053,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.3"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32_registry
|
||||
sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -66,6 +66,7 @@ dependencies:
|
||||
flutter_local_notifications: ^14.1.1
|
||||
http: ^0.13.5
|
||||
flutter_dialogs: ^3.0.0
|
||||
device_info_plus: ^9.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user