notificaciones al pedir servicio y al enviar mensaje de chat

This commit is contained in:
Felipe
2024-04-25 11:15:33 -05:00
parent 76be1f1f1a
commit e1049f7281
15 changed files with 411 additions and 304 deletions
+2
View File
@@ -16,6 +16,8 @@
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyCW_og6qQ8W8G-5_BxIS4sBnl8cLkjL95s"/>
<activity
android:showWhenLocked="true"
android:turnScreenOn="true"
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.
+6 -1
View File
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injector/injector.dart';
import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart';
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
import 'package:prosappco/blocs/notification_bloc/notification_bloc.dart';
import 'package:prosappco/blocs/professional_bloc/professional_bloc.dart';
import 'package:prosappco/blocs/professional_profile_bloc/professional_profile_bloc.dart';
import 'package:prosappco/blocs/profile_bloc/profile_bloc.dart';
@@ -29,7 +30,11 @@ class MainApp extends StatelessWidget {
create: (context) => Injector.appInstance.get<ProfessionalBloc>(),
),
BlocProvider<ProfessionalProfileBloc>(
create: (context) => Injector.appInstance.get<ProfessionalProfileBloc>(),
create: (context) =>
Injector.appInstance.get<ProfessionalProfileBloc>(),
),
BlocProvider<NotificationBloc>(
create: (context) => Injector.appInstance.get<NotificationBloc>(),
)
],
child: BlocBuilder<MyUserBloc, MyUserState>(
@@ -0,0 +1,115 @@
import 'dart:developer';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:prosappco/firebase_options.dart';
import 'package:prosappco/local_notifications/local_notifications.dart';
import 'package:user_repository/user_repository.dart';
part 'notification_event.dart';
part 'notification_state.dart';
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
}
class NotificationBloc extends Bloc<NotificationEvent, NotificationState> {
FirebaseMessaging messaging = FirebaseMessaging.instance;
final Future<void> Function() requestLocalNotificationPermission;
final void Function({
required int id,
String? title,
String? body,
String? data,
}) showLocalNotification;
NotificationBloc(
{required this.requestLocalNotificationPermission,
required this.showLocalNotification})
: super(const NotificationState()) {
on<NotificationStatusChanged>(_notificationStatusChanged);
_initialStatusCheck();
_onForegroundMessage();
}
static Future<void> initializeFCM() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
void _notificationStatusChanged(
NotificationStatusChanged event, Emitter<NotificationState> emit) {
emit(state.copyWith(status: event.status));
_getFCMToken();
}
void _initialStatusCheck() async {
final settings = await messaging.getNotificationSettings();
add(NotificationStatusChanged(settings.authorizationStatus));
_getFCMToken();
}
Future<void> _saveFCMTokenToFirestore(String token) async {
try {
CollectionReference users = FirebaseFirestore.instance.collection('users');
await users.doc(FirebaseAuth.instance.currentUser!.uid).update({
'token': token,
});
} catch (e) {
print('tokenFCM Error saving FCM token to Firestore: $e');
}
}
void _getFCMToken() async {
if (state.status != AuthorizationStatus.authorized) return;
final fcmToken = await messaging.getToken();
log('tokenFCM ${fcmToken.toString()}');
if (fcmToken == null) return;
_saveFCMTokenToFirestore(fcmToken);
}
void _handleRemoteMessage(RemoteMessage message) {
if (message.notification == null) return;
showLocalNotification(
id: 1,
title: message.notification!.title,
body: message.notification!.body,
);
}
void _onForegroundMessage() {
FirebaseMessaging.onMessage.listen(_handleRemoteMessage);
}
void requestPermission() async {
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
// Solicitar permiso a las local notificaciones
await requestLocalNotificationPermission();
add(NotificationStatusChanged(settings.authorizationStatus));
}
}
@@ -0,0 +1,14 @@
part of 'notification_bloc.dart';
abstract class NotificationEvent extends Equatable {
const NotificationEvent();
@override
List<Object> get props => [];
}
class NotificationStatusChanged extends NotificationEvent {
final AuthorizationStatus status;
const NotificationStatusChanged(this.status);
}
@@ -0,0 +1,21 @@
part of 'notification_bloc.dart';
class NotificationState extends Equatable {
final AuthorizationStatus status;
const NotificationState({
this.status = AuthorizationStatus.notDetermined,
});
NotificationState copyWith({
AuthorizationStatus? status,
}) =>
NotificationState(
status: status ?? this.status,
);
@override
List<Object> get props => [status];
}
class NotificationInitial extends NotificationState {}
+8
View File
@@ -7,6 +7,7 @@ import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart';
import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart';
import 'package:prosappco/blocs/chat_bloc/chat_bloc.dart';
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
import 'package:prosappco/blocs/notification_bloc/notification_bloc.dart';
import 'package:prosappco/blocs/professional_bloc/professional_bloc.dart';
import 'package:prosappco/blocs/professional_list_bloc/professional_list_bloc.dart';
import 'package:prosappco/blocs/professional_profile_bloc/professional_profile_bloc.dart';
@@ -16,6 +17,7 @@ import 'package:prosappco/blocs/service_bloc/service_bloc.dart';
import 'package:prosappco/blocs/setting_bloc/setting_bloc.dart';
import 'package:prosappco/blocs/sign_up_bloc/sign_up_bloc.dart';
import 'package:prosappco/blocs/sing_in_bloc/sign_in_bloc.dart';
import 'package:prosappco/local_notifications/local_notifications.dart';
import 'package:score_repository/score_repository.dart';
import 'package:service_repository/service_repository.dart';
import 'package:user_repository/user_repository.dart';
@@ -56,6 +58,12 @@ class AppDI {
professionalRepository: injector.get(),
userRepository: injector.get<UserRepository>()),
);
injector.registerSingleton(
() => NotificationBloc(
requestLocalNotificationPermission: LocalNotifications.requestPermissionLocalNotifications,
showLocalNotification: LocalNotifications.showLocalNotification,
),
);
injector.registerDependency<SignInBloc>(
() => SignInBloc(userRepository: injector.get<UserRepository>()));
@@ -0,0 +1,92 @@
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class LocalNotifications {
static Future<void> requestPermissionLocalNotifications() async {
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestPermission();
}
static Future<void> initializeLocalNotifications() async {
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
const initializationSettingsAndroid =
AndroidInitializationSettings('app_icon');
const initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
);
}
static void showLocalNotification({
required int id,
String? title,
String? body,
String? data,
}) {
const androidDetails = AndroidNotificationDetails(
'channel_id',
'channel_name',
importance: Importance.max,
priority: Priority.high,
playSound: true,
sound: RawResourceAndroidNotificationSound('notification'),
);
const notificationDetails = NotificationDetails(
android: androidDetails,
);
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
flutterLocalNotificationsPlugin.show(
id,
title,
body,
notificationDetails,
payload: data,
);
}
static Future<void> sendPushNotification(
String token, String title, String body) async {
try {
http.Response response = await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization':
'key=AAAAORdR-xU:APA91bF_wblg86jHAC-uexrXPHavYRlk5wge1Gf46m56V4J2D2L37Cp_hf46JZUzpvsWPSpqc5ewHelKI9LTifUG_s2mciMI6e5VLKo7E1R8btbNo7iaM9do2ctoyHKUm1atlZBdKaN2',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
'body': body,
'title': title,
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done',
},
'to': token,
},
),
);
response;
} catch (e) {
rethrow;
}
}
}
+49 -168
View File
@@ -1,181 +1,62 @@
// import 'package:flutter/material.dart';
// import 'package:flutter/services.dart';
// import 'package:get/get.dart';
// import 'package:intl/date_symbol_data_local.dart';
// import 'package:prosappco/src/authentication/authentication_repository.dart';
// import 'package:prosappco/src/presentation/screens/service_web.dart';
// import 'package:prosappco/src/providers/user_provider.dart';
// import 'package:prosappco/src/presentation/screens/calendar.dart';
// import 'package:prosappco/src/presentation/screens/city.dart';
// import 'package:prosappco/src/presentation/screens/login/login.dart';
// import 'package:firebase_core/firebase_core.dart';
// import 'package:prosappco/src/presentation/screens/login/login_email.dart';
// import 'package:prosappco/src/presentation/screens/my_services.dart';
// import 'package:prosappco/src/presentation/screens/my_services_pro.dart';
// import 'package:prosappco/src/presentation/screens/new_number.dart';
// import 'package:prosappco/src/presentation/screens/new_password.dart';
// import 'package:prosappco/src/presentation/screens/profession.dart';
// import 'package:prosappco/src/presentation/screens/professional_profile.dart';
// import 'package:prosappco/src/presentation/screens/professional_revision.dart';
// import 'package:prosappco/src/presentation/screens/profile/profile.dart';
// import 'package:prosappco/src/presentation/screens/profile/profile_pro.dart';
// import 'package:prosappco/src/presentation/screens/register/register.dart';
// import 'package:prosappco/src/presentation/screens/request_sent.dart';
// import 'package:prosappco/src/presentation/screens/reset_password/reset_password.dart';
// import 'package:prosappco/src/presentation/screens/map/service.dart';
// import 'package:prosappco/src/presentation/screens/solicitudes.dart';
// import 'package:prosappco/src/services/local_notifications.dart';
// import 'firebase_options.dart';
// import 'package:firebase_messaging/firebase_messaging.dart';
// import 'package:flutter/foundation.dart' show kIsWeb;
// import 'package:provider/provider.dart';
// import 'package:flutter_localizations/flutter_localizations.dart';
// Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// await Firebase.initializeApp();
// print('Handling a backdround message: ${message.messageId}');
// }
// void main() async {
// WidgetsFlutterBinding.ensureInitialized();
// await Firebase.initializeApp(
// options: DefaultFirebaseOptions.currentPlatform,
// ).then((value) => Get.put(AuthenticationRepository()));
// // Evitar la solicitud de permiso en la versión web
// if (!kIsWeb) {
// FirebaseMessaging messaging = FirebaseMessaging.instance;
// await messaging.requestPermission(
// alert: true,
// announcement: false,
// badge: true,
// carPlay: false,
// criticalAlert: false,
// provisional: false,
// sound: true,
// );
// FirebaseMessaging.onBackgroundMessage(
// (_firebaseMessagingBackgroundHandler));
// FirebaseMessaging.onMessage.listen((RemoteMessage message) {});
// }
// await initNotifications();
// await initializeDateFormatting('es_MX', null);
// SystemChrome.setPreferredOrientations([
// DeviceOrientation.portraitUp,
// DeviceOrientation.portraitDown,
// ]);
// runApp(const MyApp());
// }
// class MyApp extends StatelessWidget {
// const MyApp({super.key});
// @override
// Widget build(BuildContext context) {
// return MultiProvider(
// providers: [
// ChangeNotifierProvider(
// create: (_) => UserProvider(),
// ),
// ],
// child: GetMaterialApp(
// theme: ThemeData(fontFamily: 'Poppins'),
// debugShowCheckedModeBanner: false,
// localizationsDelegates: const [
// GlobalMaterialLocalizations.delegate,
// GlobalWidgetsLocalizations.delegate,
// GlobalCupertinoLocalizations.delegate,
// ],
// supportedLocales: const [
// Locale('es', 'US'),
// ],
// title: 'ProsApp',
// initialRoute: '/',
// routes: {
// '/': (context) => const LoginScreen(),
// '/splash': (context) => const SplashScreen(),
// '/login': (context) => const LoginEmailScreen(),
// '/profile': (context) => const ProfileScreen(),
// '/register': (context) => const RegisterScreen(),
// '/city': (context) => const CityScreen(),
// '/profession': (context) => const ProfessionScreen(),
// '/newNumber': (context) => const NewNumberScreen(),
// '/profesionalRevision': (context) =>
// const ProfessionalRevisionScreen(),
// '/profesionalProfile': (context) => const ProfessionalProfileScreen(),
// '/solicitudEnviada': (context) => const RequestSentScreen(),
// '/nuevaPassword': (context) => NewPasswordScreen(),
// '/servicio': (context) => const ServiceScreen(),
// '/servicioWeb': (context) => const ServiceWebScreen(),
// '/profilePro': (context) => const ProfileProScreen(),
// '/calendar': (context) => const CalendarScreen(),
// '/solicitud': (context) => SolicitudScreen(),
// '/misserviciospro': (context) => MyServicesProScreen(),
// '/misservicios': (context) => MyServicesScreen(),
// '/resetpassword': (context) => const ResetPasswordScreen(),
// },
// onGenerateRoute: (settings) {
// throw Exception('Ruta desconocida: ${settings.name}');
// },
// ),
// );
// }
// }
// class SplashScreen extends StatefulWidget {
// const SplashScreen({super.key});
// @override
// State<SplashScreen> createState() => _SplashScreenState();
// }
// class _SplashScreenState extends State<SplashScreen> {
// @override
// void initState() {
// super.initState();
// if (kIsWeb) {
// // Espera 3 segundos y luego redirige a LoginScreen
// Future.delayed(const Duration(seconds: 3), () {
// Navigator.pushReplacement(
// context,
// MaterialPageRoute(builder: (context) => const LoginScreen()),
// );
// });
// }
// }
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// backgroundColor: Colors.blue,
// body: Center(
// child: kIsWeb ? Image.asset('/images/splash.png') : const LoginScreen(),
// ),
// );
// }
// }
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injector/injector.dart';
import 'package:prosappco/app_view.dart';
import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart';
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
import 'package:prosappco/blocs/notification_bloc/notification_bloc.dart';
import 'package:prosappco/blocs/professional_bloc/professional_bloc.dart';
import 'package:prosappco/blocs/professional_profile_bloc/professional_profile_bloc.dart';
import 'package:prosappco/blocs/profile_bloc/profile_bloc.dart';
import 'package:prosappco/dependency/app_di.dart';
import 'app.dart';
import 'package:prosappco/local_notifications/local_notifications.dart';
import 'simple_bloc_observer.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
// await Firebase.initializeApp();
await NotificationBloc.initializeFCM();
await LocalNotifications.initializeLocalNotifications();
Bloc.observer = SimpleBlocObserver();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
AppDI().register();
runApp(const MainApp());
runApp(
MultiBlocProvider(
providers: [
BlocProvider<AuthenticationBloc>(
create: (context) => Injector.appInstance.get<AuthenticationBloc>(),
),
BlocProvider<MyUserBloc>(
create: (context) => Injector.appInstance.get<MyUserBloc>(),
),
BlocProvider<ProfileBloc>(
create: (context) => Injector.appInstance.get<ProfileBloc>(),
),
BlocProvider<ProfessionalBloc>(
create: (context) => Injector.appInstance.get<ProfessionalBloc>(),
),
BlocProvider<ProfessionalProfileBloc>(
create: (context) =>
Injector.appInstance.get<ProfessionalProfileBloc>(),
),
BlocProvider<NotificationBloc>(
create: (context) => Injector.appInstance.get<NotificationBloc>(),
)
],
child: BlocBuilder<MyUserBloc, MyUserState>(
builder: (context, state) {
return const SafeArea(child: MyAppView());
},
),
),
);
// runApp(const MainApp());
}
+42 -118
View File
@@ -8,6 +8,7 @@ import 'package:injector/injector.dart';
import 'package:intl/intl.dart';
import 'package:prosappco/blocs/chat_bloc/chat_bloc.dart';
import 'package:prosappco/components/general_reputation.dart';
import 'package:prosappco/local_notifications/local_notifications.dart';
import 'package:service_repository/service_repository.dart';
import 'package:user_repository/user_repository.dart';
@@ -26,6 +27,7 @@ class _ChatScreenState extends State<ChatScreen> {
final FocusNode _messageFocusNode = FocusNode();
List<dynamic>? _userInfo;
DateTime? _lastNotificationTime;
@override
void initState() {
@@ -177,126 +179,8 @@ class _ChatScreenState extends State<ChatScreen> {
),
);
} else {
// Indicador de carga opcional si se desea mostrar mientras se carga la información por primera vez.
return const Center(child: CircularProgressIndicator());
}
// if (snapshot.connectionState == ConnectionState.waiting) {
// return const Center(child: CircularProgressIndicator());
// } else {
// if (snapshot.hasError) {
// return Center(
// child: Text('Error inesperado: ${snapshot.error}'),
// );
// } else {
// final userInfo = snapshot.data![0] as MyUser;
// return Container(
// padding: const EdgeInsets.symmetric(vertical: 8),
// color: const Color(0xFFD6F4FF),
// alignment: Alignment.topCenter,
// child: ListTile(
// leading: Container(
// width: 60,
// height: 60,
// decoration: BoxDecoration(
// color: Colors.grey.shade300,
// shape: BoxShape.circle,
// image: userInfo.picture == null
// ? null
// : DecorationImage(
// image: NetworkImage(
// userInfo.picture ?? ''),
// fit: BoxFit.contain,
// ),
// ),
// child: userInfo.picture == null
// ? Icon(
// CupertinoIcons.person,
// color: Colors.grey.shade400,
// size: 40,
// )
// : null,
// ),
// title: Text(
// userInfo.name ?? '',
// overflow: TextOverflow.ellipsis,
// style: const TextStyle(
// fontSize: 15,
// fontWeight: FontWeight.w600,
// ),
// ),
// subtitle: widget.service.userId ==
// FirebaseAuth.instance.currentUser!.uid
// ? GeneralReputation(
// userId: widget.service.professionalId,
// builder: (context, reputation) {
// final average = reputation.averagePro;
// final total = reputation.totalPro;
// return Row(
// children: [
// RatingBar.builder(
// initialRating:
// calculoRating(average),
// minRating: 1,
// direction: Axis.horizontal,
// allowHalfRating: true,
// itemCount: 5,
// itemSize: 25,
// maxRating: 5,
// itemBuilder: (context, _) =>
// const Icon(
// Icons.star,
// color: Color(0xFF2BA4EC),
// ),
// onRatingUpdate: (rating) {},
// ignoreGestures: true,
// ),
// const SizedBox(width: 5),
// Text(
// '${average.toStringAsFixed(1)} (${total.toString()})',
// ),
// ],
// );
// })
// : GeneralReputation(
// userId: widget.service.userId,
// builder: (context, reputation) {
// final average = reputation.average;
// final total = reputation.total;
// return Row(
// children: [
// RatingBar.builder(
// initialRating:
// calculoRating(average),
// minRating: 1,
// direction: Axis.horizontal,
// allowHalfRating: true,
// itemCount: 5,
// itemSize: 25,
// maxRating: 5,
// itemBuilder: (context, _) =>
// const Icon(
// Icons.star,
// color: Color(0xFF2BA4EC),
// ),
// onRatingUpdate: (rating) {},
// ignoreGestures: true,
// ),
// const SizedBox(width: 5),
// Text(
// '${average.toStringAsFixed(1)} (${total.toString()})',
// ),
// ],
// );
// },
// ),
// ),
// );
// }
// }
},
),
Expanded(
@@ -353,6 +237,26 @@ class _ChatScreenState extends State<ChatScreen> {
serviceId: widget.service.id!,
message: message,
));
if (_userInfo != null) {
final userInfo = _userInfo![0] as MyUser;
if (userInfo.token == null) return;
if (_lastNotificationTime == null ||
DateTime.now().difference(
_lastNotificationTime!) >
const Duration(minutes: 5)) {
LocalNotifications.sendPushNotification(
userInfo.token!,
'Nuevo mensaje',
'Tienes un nuevo mensaje de ${userInfo.name}',
);
_lastNotificationTime = DateTime.now();
}
}
_messageController.clear();
_messageFocusNode.requestFocus();
},
@@ -375,6 +279,26 @@ class _ChatScreenState extends State<ChatScreen> {
serviceId: widget.service.id!,
message: message,
));
if (_userInfo != null) {
final userInfo = _userInfo![0] as MyUser;
if (userInfo.token == null) return;
if (_lastNotificationTime == null ||
DateTime.now().difference(
_lastNotificationTime!) >
const Duration(minutes: 5)) {
LocalNotifications.sendPushNotification(
userInfo.token!,
'Nuevo mensaje',
'Tienes un nuevo mensaje de ${userInfo.name}',
);
_lastNotificationTime = DateTime.now();
}
}
_messageController.clear();
_messageFocusNode.requestFocus();
},
+12 -9
View File
@@ -180,7 +180,7 @@ class UserCalendarScreenState extends State<UserCalendarScreen> {
schedule.range2Hour2!,
);
return rangesItemList(ranges, _services);
return rangesItemList(ranges, _services, today);
}
List<TimeOfDay> ranges1 = TimeOfDayUtils.genRanges(
@@ -193,26 +193,29 @@ class UserCalendarScreenState extends State<UserCalendarScreen> {
);
return [
...rangesItemList(ranges1, _services),
...rangesItemList(ranges2, _services),
...rangesItemList(ranges1, _services, today),
...rangesItemList(ranges2, _services, today),
];
}
bool _isHora1Ocupada(TimeOfDay hora1, List<ServiceEntity>? events) {
bool _isHora1Ocupada(
TimeOfDay hora1, List<ServiceEntity>? events, DateTime selectedDay) {
if (events != null) {
for (ServiceEntity event in events) {
if (hora1 == event.range1Hour1) {
return true;
if (selectedDay.toString() == event.day) {
if (hora1 == event.range1Hour1) {
return true;
}
}
}
}
return false;
}
List<Widget> rangesItemList(
List<TimeOfDay> ranges, List<ServiceEntity>? events) {
List<Widget> rangesItemList(List<TimeOfDay> ranges,
List<ServiceEntity>? events, DateTime selectedDay) {
return ranges.map((time) {
if (_isHora1Ocupada(time, events)) {
if (_isHora1Ocupada(time, events, selectedDay)) {
return Card(
elevation: 4,
margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
+23 -5
View File
@@ -13,9 +13,11 @@ import 'package:injector/injector.dart';
import 'package:intl/intl.dart';
import 'package:professional_repository/professional_repository.dart';
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
import 'package:prosappco/blocs/notification_bloc/notification_bloc.dart';
import 'package:prosappco/blocs/professional_list_bloc/professional_list_bloc.dart';
import 'package:prosappco/blocs/service_bloc/service_bloc.dart';
import 'package:prosappco/constansts.dart';
import 'package:prosappco/local_notifications/local_notifications.dart';
import 'package:prosappco/screens/lists/professional_list_screen.dart';
import 'package:prosappco/screens/user/user_service_screen.dart';
import 'package:prosappco/utils/time_of_day_extension.dart';
@@ -86,6 +88,10 @@ class _UserMapScreenState extends State<UserMapScreen> {
}
}
// void requestNotificationPermission() async {
// context.read<NotificationBloc>().requestPermission();
// }
void _loadSettings() {
settingRepository.getSettings().then(
(value) => setState(() {
@@ -172,10 +178,13 @@ class _UserMapScreenState extends State<UserMapScreen> {
elevation: 3,
minimumSize: const Size(50, 50),
),
child: const Icon(
child: Icon(
Icons.menu,
color: Colors.black,
size: 35,
size: context.select(
(NotificationBloc bloc) =>
bloc.state.status.index > 0 ? 35 : 35,
),
),
onPressed: () {
Scaffold.of(context).openDrawer();
@@ -318,6 +327,9 @@ class _UserMapScreenState extends State<UserMapScreen> {
decoration: const InputDecoration(
prefixIcon: Icon(Icons.assignment_ind_rounded),
suffixIcon: Icon(Icons.arrow_drop_down),
// hintText: context.select(
// (NotificationBloc bloc) => '${bloc.state.status}',
// ),
hintText: 'Selecciona un profesional',
),
),
@@ -386,7 +398,7 @@ class _UserMapScreenState extends State<UserMapScreen> {
onPressed: isLoading
? null
: () {
// tODO: Crear servicio
if (profesionalSeleccionado == null) return;
if (serviceLocationPreference ==
ServiceLocationPreferences.office) {
if (settings?.tarifas == true) {
@@ -487,7 +499,14 @@ class _UserMapScreenState extends State<UserMapScreen> {
// TODO: error inesperado
}
// clear inputs
if (profesionalSeleccionado!.myUser.token != null) {
LocalNotifications.sendPushNotification(
profesionalSeleccionado!.myUser.token!,
'Nuevo servicio',
'Tienes una nueva solicitud de servicio pendiente',
);
}
fechaSeleccionada = null;
horaSeleccionada = null;
profesionalSeleccionado = null;
@@ -538,7 +557,6 @@ class _UserMapScreenState extends State<UserMapScreen> {
borderRadius: BorderRadius.circular(10),
),
),
//x
child: const Icon(
CupertinoIcons.xmark,
color: Colors.white,
@@ -12,6 +12,7 @@ class MyUserEntity extends Equatable {
final String? birthday;
final String? gender;
final ProState proState;
final String? token;
const MyUserEntity({
required this.id,
@@ -24,6 +25,7 @@ class MyUserEntity extends Equatable {
required this.birthday,
required this.gender,
required this.proState,
required this.token,
});
Map<String, Object?> toDocument() {
@@ -38,6 +40,7 @@ class MyUserEntity extends Equatable {
'birthday': birthday,
'gender': gender,
'professional_state': enumToInt(proState),
'token': token
};
}
@@ -53,12 +56,24 @@ class MyUserEntity extends Equatable {
birthday: doc['birthday'] as String?,
gender: doc['gender'] as String?,
proState: intToEnum(doc['professional_state'] as int),
token: doc['token'] as String?,
);
}
@override
List<Object?> get props =>
[id, email, phone, name, nickname, city, picture, birthday, gender];
List<Object?> get props => [
id,
email,
phone,
name,
nickname,
city,
picture,
birthday,
gender,
proState,
token
];
@override
String toString() {
@@ -72,7 +87,8 @@ class MyUserEntity extends Equatable {
picture: $picture
birthday: $birthday
gender: $gender,
proState: ${proState.name}
proState: ${proState.name},
token: $token
}''';
}
}
@@ -12,6 +12,7 @@ class MyUser extends Equatable {
final String? birthday;
final String? gender;
final ProState proState;
final String? token;
const MyUser({
required this.id,
@@ -24,6 +25,7 @@ class MyUser extends Equatable {
this.birthday,
this.gender,
required this.proState,
this.token,
});
get drawerLabel => email != null && email!.isNotEmpty
@@ -44,6 +46,7 @@ class MyUser extends Equatable {
birthday: '',
gender: '',
proState: ProState.inactive,
token: '',
);
/// Modify MyUser parameters
@@ -58,6 +61,7 @@ class MyUser extends Equatable {
String? birthday,
String? gender,
ProState? proState,
String? token,
}) {
return MyUser(
id: id ?? this.id,
@@ -70,6 +74,7 @@ class MyUser extends Equatable {
birthday: birthday ?? this.birthday,
gender: gender ?? this.gender,
proState: proState ?? this.proState,
token: token ?? this.token,
);
}
@@ -91,6 +96,7 @@ class MyUser extends Equatable {
birthday: birthday,
gender: gender,
proState: proState,
token: token,
);
}
@@ -106,6 +112,7 @@ class MyUser extends Equatable {
birthday: entity.birthday,
gender: entity.gender,
proState: entity.proState,
token: entity.token,
);
}
@@ -121,5 +128,6 @@ class MyUser extends Equatable {
birthday,
gender,
proState,
token,
];
}