configuracion - sugerencias - soporte

This commit is contained in:
Felipe
2024-03-13 23:55:48 -05:00
parent cde7e72f1a
commit 66125235dd
23 changed files with 547 additions and 100 deletions
+2 -2
View File
@@ -138,7 +138,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
}
}
} catch (e) {
emit(const AuthStateFailure(message: "Error inesperado. PUTA 🥸"));
emit(const AuthStateFailure(message: "Error inesperado. 🥸"));
}
}
@@ -184,7 +184,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
// await _userRepository
} catch (e) {
emit(const AuthStateFailure(message: "Error inesperado. PUTA 🥸"));
emit(const AuthStateFailure(message: "Error inesperado. 🥸"));
}
}
+37 -1
View File
@@ -1,12 +1,28 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:prosappco/components/general_drawer_header.dart';
import 'package:prosappco/components/general_drawer_item.dart';
import 'package:prosappco/screens/configuration/configuration_screen.dart';
import 'package:prosappco/screens/configuration/configuration_support_screen.dart';
import 'package:prosappco/screens/web/web_view_screen.dart';
import 'package:url_launcher/url_launcher.dart';
class GeneralDrawer extends StatelessWidget {
const GeneralDrawer({super.key});
Future<void> _irSugerencias() async {
const url = 'https://admin.prosapp.co/sugerencias';
final Uri _url = Uri.parse(url);
if (await canLaunchUrl(_url)) {
await launchUrl(_url);
} else {
throw 'No se pudo abrir la URL $url';
}
}
@override
Widget build(BuildContext context) {
return Drawer(
@@ -49,13 +65,33 @@ class GeneralDrawer extends StatelessWidget {
label: 'Soporte',
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) =>
const ConfigurationSupportScreen(),
),
);
},
),
GeneralDrawerItem(
leading: Icons.campaign_outlined,
label: 'Sugerencias',
onTap: () {
Navigator.pop(context);
if (kIsWeb) {
_irSugerencias();
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Sugerencias',
link: 'https://admin.prosapp.co/sugerencias');
},
),
);
}
},
),
],
+9 -3
View File
@@ -2,24 +2,26 @@ import 'package:flutter/material.dart';
class GeneralDrawerItem extends StatelessWidget {
final String label;
final String? subtitle;
final IconData? leading;
final bool trailing;
final Color? color;
final VoidCallback onTap;
final VoidCallback? onTap;
const GeneralDrawerItem({
super.key,
required this.label,
this.subtitle,
this.leading,
this.trailing = false,
this.color,
required this.onTap,
this.onTap,
});
@override
Widget build(BuildContext context) {
return ListTile(
onTap: onTap,
onTap: onTap == null ? null : () => onTap!(),
leading: leading == null
? null
: Icon(
@@ -36,6 +38,10 @@ class GeneralDrawerItem extends StatelessWidget {
label,
style: TextStyle(fontSize: 15, color: color),
),
subtitle: subtitle == null
? null
: Text(subtitle ?? "", style: const TextStyle(color: Colors.black54)),
// dense: true,
);
}
}
+4
View File
@@ -9,6 +9,7 @@ import 'package:prosappco/blocs/sign_up_bloc/sign_up_bloc.dart';
import 'package:prosappco/blocs/sing_in_bloc/sign_in_bloc.dart';
import 'package:user_repository/user_repository.dart';
import 'package:city_repository/city_repository.dart';
import 'package:setting_repository/setting_repository.dart';
class AppDI {
void register() {
@@ -19,6 +20,9 @@ class AppDI {
injector.registerSingleton<CityRepository>(() => FirebaseCityRepository());
injector.registerSingleton<SettingRepository>(
() => FirebaseSettingRepository());
injector.registerSingleton<AuthenticationBloc>((() =>
AuthenticationBloc(myUserRepository: injector.get<UserRepository>())));
-10
View File
@@ -1,10 +0,0 @@
import 'package:flutter/material.dart';
class AboutScreen extends StatelessWidget {
const AboutScreen({super.key});
@override
Widget build(BuildContext context) {
return Placeholder();
}
}
@@ -0,0 +1,103 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:injector/injector.dart';
import 'package:prosappco/components/general_drawer_item.dart';
import 'package:prosappco/screens/web/web_view_screen.dart';
import 'package:setting_repository/setting_repository.dart';
import 'package:url_launcher/url_launcher.dart';
class ConfigurationAboutScreen extends StatefulWidget {
const ConfigurationAboutScreen({super.key});
@override
State<ConfigurationAboutScreen> createState() =>
_ConfigurationAboutScreenState();
}
class _ConfigurationAboutScreenState extends State<ConfigurationAboutScreen> {
final settingRepository = Injector.appInstance.get<SettingRepository>();
SettingEntity? settings;
@override
void initState() {
super.initState();
_loadSettings();
}
void _loadSettings() {
settingRepository.getSettings().then(
(value) => setState(() {
settings = value;
}),
);
}
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url, forceSafariVC: false, forceWebView: false);
} else {
throw 'No se pudo abrir el enlace $url';
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Acerca de la aplicación'),
),
body: ListView(
children: [
GeneralDrawerItem(
label: 'Políticas de privacidad',
onTap: () {
if (kIsWeb) {
_launchURL(settings?.politicasPrivacidad ?? '');
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Políticas de privacidad',
link: settings?.politicasPrivacidad ?? '',
);
},
),
);
}
},
trailing: true,
),
GeneralDrawerItem(
label: 'Términos y condiciones',
onTap: () {
if (kIsWeb) {
_launchURL(settings?.terminosCondiciones ?? '');
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Términos y condiciones',
link: settings?.terminosCondiciones ?? '',
);
},
),
);
}
},
trailing: true,
),
GeneralDrawerItem(
label: 'Versión de la aplicación',
subtitle: settings?.version,
),
],
),
);
}
}
@@ -127,11 +127,13 @@
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injector/injector.dart';
import 'package:prosappco/blocs/setting_bloc/setting_bloc.dart';
import 'package:prosappco/components/general_drawer_item.dart';
import 'package:prosappco/screens/configuration/configuration_about_screen.dart';
class ConfigurationScreen extends StatelessWidget {
const ConfigurationScreen({super.key});
@@ -156,7 +158,16 @@ class ConfigurationScreen extends StatelessWidget {
children: [
GeneralDrawerItem(
label: 'Acerca de la aplicación',
onTap: () {},
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ConfigurationAboutScreen();
},
),
);
},
trailing: true,
),
GeneralDrawerItem(
@@ -0,0 +1,212 @@
import 'package:community_material_icon/community_material_icon.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:injector/injector.dart';
import 'package:setting_repository/setting_repository.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
class ConfigurationSupportScreen extends StatefulWidget {
const ConfigurationSupportScreen({super.key});
@override
State<ConfigurationSupportScreen> createState() =>
_ConfigurationSupportScreenState();
}
class _ConfigurationSupportScreenState
extends State<ConfigurationSupportScreen> {
final settingRepository = Injector.appInstance.get<SettingRepository>();
SettingEntity? settings;
final String subject = 'Soporte Prosapp';
final String body = '';
@override
void initState() {
super.initState();
_loadSettings();
}
void _loadSettings() {
settingRepository.getSettings().then(
(value) => setState(() {
settings = value;
}),
);
}
Future<void> _sendWhatsapp(String? number) async {
final _whatsappUrl =
'https://api.whatsapp.com/send?phone=$number&text=Hola%21+soy+usuario+de+Prosapp+y+quisiera+conocer+mas+sobre+esta+app+%F0%9F%98%81';
if (!await launch(_whatsappUrl)) {
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Error al enviar el mensaje de WhatsApp'),
));
}
}
Future<void> _sendEmail(String recipients) async {
final Email email = Email(
body: body,
subject: subject,
recipients: [recipients],
isHTML: false,
);
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 {
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Error al enviar el correo'),
));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Soporte'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 30, left: 35, right: 35),
child: Text(
'${settings?.tituloSoporte}',
style: const TextStyle(fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 35),
child: Text(settings?.parrafoSoporte ?? 'Cargando...'),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Material(
color: Colors.blue, // Color de fondo azul
shape: const CircleBorder(), // Forma circular
child: InkWell(
borderRadius: BorderRadius.circular(
30), // Radio del área de interacción
onTap: () {
_sendWhatsapp(settings?.numeroSoporte);
},
child: const Padding(
padding: EdgeInsets.all(15),
child: Icon(
CommunityMaterialIcons.whatsapp,
color: Colors.white,
size: 30,
),
),
),
),
const SizedBox(width: 20),
Material(
color: Colors.blue,
shape: const CircleBorder(),
child: InkWell(
borderRadius: BorderRadius.circular(30),
onTap: () {
if (kIsWeb) {
_sendEmailWeb(settings?.emailSoporte ?? '');
} else {
_sendEmail(settings?.emailSoporte ?? '');
}
},
child: const Padding(
padding: EdgeInsets.all(15),
child: Icon(
Icons.email_outlined,
color: Colors.white,
size: 30,
),
),
),
),
// ElevatedButton(
// onPressed: () {
// // _sendWhatsapp(settings?.numeroSoporte);
// },
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
// backgroundColor: const Color(0xFF2BA4EC),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(50),
// side: const BorderSide(
// color: Color(0xFF2BA4EC),
// width: 2,
// ),
// ),
// ),
// child: const Padding(
// padding: EdgeInsets.symmetric(vertical: 18, horizontal: 0),
// child: Icon(
// CommunityMaterialIcons.whatsapp,
// size: 30,
// color: Colors.white,
// ),
// ),
// ),
// const SizedBox(width: 20),
// ElevatedButton(
// onPressed: () {
// if (kIsWeb) {
// // _sendEmailWeb(settings?.emailSoporte ?? '');
// } else {
// // _sendEmail(settings?.emailSoporte ?? '');
// }
// },
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
// backgroundColor: const Color(0xFF2BA4EC),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(50),
// side: const BorderSide(
// color: Color(0xFF2BA4EC),
// width: 2,
// ),
// ),
// ),
// child: const Padding(
// padding: EdgeInsets.symmetric(vertical: 18, horizontal: 0),
// child: Icon(
// Icons.email_outlined,
// size: 30,
// color: Colors.white,
// ),
// ),
// ),
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 50),
child: Column(
children: [
const Text(
'Horario de atención:',
style: TextStyle(fontWeight: FontWeight.w600),
),
const SizedBox(height: 20),
Text('${settings?.diasSoporte}'),
const SizedBox(height: 5),
Text('${settings?.horasSoporte}'),
],
),
),
],
),
);
}
}
@@ -48,6 +48,11 @@ class _WebViewScreenState extends State<WebViewScreen> {
..loadRequest(Uri.parse(widget.link));
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -3,6 +3,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:prosappco/screens/web/web_view_screen.dart';
import 'package:prosappco/src/authentication/authentication_repository.dart';
import 'package:prosappco/src/components/photo_view.dart';
import 'package:prosappco/src/models/user_model.dart';
-40
View File
@@ -89,30 +89,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
firebase_auth:
dependency: "direct main"
description:
name: firebase_auth
sha256: "17b841e1b000c3441b8ffceca88f468e078d0443db9643e77541bdfb7a3fd16b"
url: "https://pub.dev"
source: hosted
version: "4.17.8"
firebase_auth_platform_interface:
dependency: transitive
description:
name: firebase_auth_platform_interface
sha256: f294ceef40409a36c819a14280ca864fe487b44033e5276443377c66cb448310
url: "https://pub.dev"
source: hosted
version: "7.1.8"
firebase_auth_web:
dependency: transitive
description:
name: firebase_auth_web
sha256: "1f231da900fe7ff9f2974f8adcbdb3363c410c24725978afa5dc33e1e7e62e06"
url: "https://pub.dev"
source: hosted
version: "5.9.8"
firebase_core:
dependency: "direct main"
description:
@@ -160,14 +136,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
js:
dependency: transitive
description:
@@ -277,14 +245,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.1"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
vector_math:
dependency: transitive
description:
-1
View File
@@ -13,7 +13,6 @@ dependencies:
equatable: ^2.0.5
# Firebase
firebase_auth: ^4.17.4
cloud_firestore: ^4.15.4
firebase_core: ^2.25.4
@@ -0,0 +1,6 @@
library setting_repository;
export 'src/models/models.dart';
export 'src/entities/entities.dart';
export 'src/repositories/setting_repo.dart';
export 'src/repositories/firebase_setting_repository.dart';
@@ -0,0 +1 @@
export '/src/entities/setting_entity.dart';
@@ -0,0 +1,107 @@
import 'package:equatable/equatable.dart';
class SettingEntity extends Equatable {
final bool? tarifas;
final bool? domicilios;
final bool? google;
final String? version;
final String? horaNotificacion;
final String? tituloSoporte;
final String? parrafoSoporte;
final String? numeroSoporte;
final String? emailSoporte;
final String? diasSoporte;
final String? horasSoporte;
final String? politicasPrivacidad;
final String? politicasPrivacidadTitle;
final String? politicasPrivacidadBody;
final String? terminosCondiciones;
final String? terminosCondicionesTitle;
final String? terminosCondicionesBody;
const SettingEntity({
required this.tarifas,
required this.domicilios,
required this.google,
required this.version,
required this.horaNotificacion,
required this.tituloSoporte,
required this.parrafoSoporte,
required this.numeroSoporte,
required this.emailSoporte,
required this.diasSoporte,
required this.horasSoporte,
required this.politicasPrivacidad,
required this.politicasPrivacidadTitle,
required this.politicasPrivacidadBody,
required this.terminosCondiciones,
required this.terminosCondicionesTitle,
required this.terminosCondicionesBody,
});
static SettingEntity fromDocument(Map<String, dynamic> doc) {
return SettingEntity(
tarifas: doc['tarifas'] as bool?,
domicilios: doc['domicilios'] as bool?,
google: doc['google'] as bool?,
version: doc['version'] as String?,
horaNotificacion: doc['hora_notificacion'] as String?,
tituloSoporte: doc['titulo_soporte'] as String?,
parrafoSoporte: doc['parrafo_soporte'] as String?,
numeroSoporte: doc['numero_soporte'] as String?,
emailSoporte: doc['email_soporte'] as String?,
diasSoporte: doc['dias_soporte'] as String?,
horasSoporte: doc['horas_soporte'] as String?,
politicasPrivacidad: doc['politicas_privacidad'] as String?,
politicasPrivacidadTitle: doc['politicas_privacidad_title'] as String?,
politicasPrivacidadBody: doc['politicas_privacidad_body'] as String?,
terminosCondiciones: doc['terminos_condiciones'] as String?,
terminosCondicionesTitle: doc['terminos_condiciones_title'] as String?,
terminosCondicionesBody: doc['terminos_condiciones_body'] as String?,
);
}
@override
List<Object?> get props => [
tarifas,
domicilios,
google,
version,
horaNotificacion,
tituloSoporte,
parrafoSoporte,
numeroSoporte,
emailSoporte,
diasSoporte,
horasSoporte,
politicasPrivacidad,
politicasPrivacidadTitle,
politicasPrivacidadBody,
terminosCondiciones,
terminosCondicionesTitle,
terminosCondicionesBody,
];
@override
String toString() {
return '''SettingEntity {
tarifas: $tarifas
domicilios: $domicilios
google: $google
version: $version
horaNotificacion: $horaNotificacion
tituloSoporte: $tituloSoporte
parrafoSoporte: $parrafoSoporte
numeroSoporte: $numeroSoporte
emailSoporte: $emailSoporte
diasSoporte: $diasSoporte
horasSoporte: $horasSoporte
politicasPrivacidad: $politicasPrivacidad
politicasPrivacidadTitle: $politicasPrivacidadTitle
politicasPrivacidadBody: $politicasPrivacidadBody
terminosCondiciones: $terminosCondiciones
terminosCondicionesTitle: $terminosCondicionesTitle
terminosCondicionesBody: $terminosCondicionesBody
}''';
}
}
@@ -0,0 +1,19 @@
import 'package:equatable/equatable.dart';
class SettingUi extends Equatable {
final String cityName;
final String coordsOfCity;
final String stateOfCity;
final String countryOfCity;
const SettingUi({
required this.cityName,
required this.coordsOfCity,
required this.stateOfCity,
required this.countryOfCity,
});
@override
List<Object?> get props =>
[cityName, coordsOfCity, stateOfCity, countryOfCity];
}
@@ -0,0 +1,14 @@
import 'package:setting_repository/src/entities/entities.dart';
import 'package:setting_repository/src/repositories/setting_repo.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class FirebaseSettingRepository implements SettingRepository {
final settingsCollection = FirebaseFirestore.instance.collection('settings');
@override
Future<SettingEntity> getSettings() async {
final DocumentSnapshot doc = await settingsCollection.doc('global').get();
return SettingEntity.fromDocument(doc.data() as Map<String, dynamic>);
}
}
@@ -0,0 +1,5 @@
import 'package:setting_repository/src/entities/entities.dart';
abstract class SettingRepository {
Future<SettingEntity> getSettings();
}
-40
View File
@@ -89,30 +89,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
firebase_auth:
dependency: "direct main"
description:
name: firebase_auth
sha256: "17b841e1b000c3441b8ffceca88f468e078d0443db9643e77541bdfb7a3fd16b"
url: "https://pub.dev"
source: hosted
version: "4.17.8"
firebase_auth_platform_interface:
dependency: transitive
description:
name: firebase_auth_platform_interface
sha256: f294ceef40409a36c819a14280ca864fe487b44033e5276443377c66cb448310
url: "https://pub.dev"
source: hosted
version: "7.1.8"
firebase_auth_web:
dependency: transitive
description:
name: firebase_auth_web
sha256: "1f231da900fe7ff9f2974f8adcbdb3363c410c24725978afa5dc33e1e7e62e06"
url: "https://pub.dev"
source: hosted
version: "5.9.8"
firebase_core:
dependency: "direct main"
description:
@@ -160,14 +136,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
js:
dependency: transitive
description:
@@ -277,14 +245,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.1"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
vector_math:
dependency: transitive
description:
+1 -2
View File
@@ -1,5 +1,5 @@
name: setting_repository
description: Dart package which manages the cities.
description: Dart package which manages the settings.
publish_to: "none"
version: 1.0.11+11
@@ -13,7 +13,6 @@ dependencies:
equatable: ^2.0.5
# Firebase
firebase_auth: ^4.17.4
cloud_firestore: ^4.15.4
firebase_core: ^2.25.4
+7
View File
@@ -1004,6 +1004,13 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
setting_repository:
dependency: "direct main"
description:
path: "packages/setting_repository"
relative: true
source: path
version: "1.0.11+11"
shared_preferences:
dependency: "direct main"
description:
+2
View File
@@ -56,6 +56,8 @@ dependencies:
path: packages/user_repository
city_repository:
path: packages/city_repository
setting_repository:
path: packages/setting_repository
webview_flutter: ^4.4.1
dev_dependencies: