added notifications

master_new_changes
Faiz Hashmi 2 years ago
parent 5e8a8412d3
commit fc2b400845

@ -567,16 +567,8 @@
"logOut": "تسجيل الخروج",
"customer": "العميل",
"amountVAR": "كمية",
"accept": "قبول",
"requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل."
"requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.",
"acceptOfferConfirmation": "هل تريد قبول هذا العرض؟",
"acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض."
}

@ -567,5 +567,7 @@
"customer": "Customer",
"accept": "Accept",
"amountVAR": "Amount",
"requestAlreadyInProgress": "This request is already in progress."
"requestAlreadyInProgress": "This request is already in progress.",
"acceptOfferConfirmation": "Do you want to accept this offer?",
"acceptOfferConfirmationMessage": "This offer will be accepted and you will pay the requested amount to the buyer in given time or else this offer will be cancelled."
}

@ -17,6 +17,14 @@ class AppState {
bool? get getIsLogged => isLogged;
String? _deviceToken;
String? get getDeviceToken => _deviceToken;
set setDeviceToken(String value) {
_deviceToken = value;
}
AppType currentAppType = AppType.provider;
UserType userType = UserType.customer;

@ -1,3 +1,4 @@
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/generated/codegen_loader.g.dart';
@ -172,6 +173,7 @@ class GlobalConsts {
static String demandAmountError = "Amount Cannot be Empty";
static String reservationCancelError = "Cancellation Reason Cannot be Empty";
static String descriptionError = "Description Cannot be Empty";
static String acceptingThisOffer = "I am accepting this offer.";
static String vehicleVinError = "Vehicle VIN Cannot be Empty";
static String vehicleTitleError = "Vehicle Title Cannot be Empty";
static String warrantyError = "Warranty Duration Cannot be Empty";
@ -294,3 +296,18 @@ class MyFonts {
static const poppinsFont = "packages/mc_common_app/Poppins";
static const gessTwoFont = "packages/mc_common_app/GessTwo";
}
class SignalrConsts {
// Requests
static String receiveMessageRequestOffer = "ReceiveMessageRequestOffer";
static String sendMessageRequestOffer = "SendMessageRequestOffer";
// Ads
static String sendMessageAds = "SendMessageAds";
static String receiveMessageAds = "ReceiveMessageAds";
// General
static String sendMessageGeneral = "SendMessageGeneral";
static String receiveMessageGeneral = "ReceiveMessageGeneral";
}

@ -1,6 +1,8 @@
// import 'package:firebase_crashlytics/firebase_crashlytics.dart';
// import 'package:flutter/material.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:injector/injector.dart';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
@ -12,6 +14,7 @@ import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/services/firebase_service.dart';
import 'package:mc_common_app/services/payments_service.dart';
import '../repositories/request_repo.dart';
@ -25,6 +28,10 @@ class AppDependencies {
injector.registerSingleton<ApiClient>(() => ApiClientImp());
injector.registerSingleton<CommonAppServices>(() => CommonServicesImp());
injector.registerSingleton<PaymentService>(() => PaymentServiceImp());
injector.registerSingleton<FirebaseMessagingService>(() => FirebaseMessagingServiceImp(
firebaseMessaging: FirebaseMessaging.instance,
flutterLocalNotifications: FlutterLocalNotificationsPlugin(),
));
//repos
injector.registerSingleton<UserRepo>(() => UserRepoImp());
@ -35,5 +42,7 @@ class AppDependencies {
injector.registerSingleton<AppointmentRepo>(() => AppointmentRepoImp());
injector.registerSingleton<ChatRepo>(() => ChatRepoImp());
injector.registerSingleton<BranchRepo>(() => BranchRepoImp());
//
}
}

@ -1,3 +1,4 @@
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
@ -50,11 +51,9 @@ class AppRoutes {
static const String changeEmailPage = "/changeEmailPage";
static const String editAccountPage = "/editAccoundPage";
static const String dashboard = "/dashboard";
static const String bookProviderAppView = "/bookProviderAppView";
// Appoinments
static const String appointmentDetailView = "/appointmentDetailView";
static const String bookAppointmenServicesView = "/bookAppointmenServicesView";
@ -146,7 +145,7 @@ class AppRoutes {
};
}
class ChatViewArguments {
class ChatViewArgumentsForRequest {
final int? requestId;
final ChatTypeEnum chatTypeEnum;
final String senderId;
@ -155,7 +154,7 @@ class ChatViewArguments {
final int requestIndex;
final RequestModel? requestModel;
ChatViewArguments({
ChatViewArgumentsForRequest({
required this.chatTypeEnum,
this.requestId,
required this.senderId,
@ -166,6 +165,24 @@ class ChatViewArguments {
});
}
class ChatViewArgumentsForAd {
final AdDetailsModel? adDetailsModel;
ChatViewArgumentsForAd({required this.adDetailsModel});
}
class ChatViewArguments {
final ChatViewArgumentsForAd? chatViewArgumentsForAd;
final ChatViewArgumentsForRequest? chatViewArgumentsForRequest;
final ChatTypeEnum chatTypeEnum;
ChatViewArguments({
this.chatViewArgumentsForAd,
this.chatViewArgumentsForRequest,
required this.chatTypeEnum,
});
}
class OfferListPageArguments {
final List<ServiceProvidersOffers> serviceProviderOffers;
final int? requestId;

File diff suppressed because it is too large Load Diff

@ -545,8 +545,10 @@ abstract class LocaleKeys {
static const defineLicenses = 'defineLicenses';
static const logOut = 'logOut';
static const customer = 'customer';
static const accept = 'accept';
static const amountVAR = 'amountVAR';
static const accept = 'accept';
static const requestAlreadyInProgress = 'requestAlreadyInProgress';
static const acceptOfferConfirmation = 'acceptOfferConfirmation';
static const acceptOfferConfirmationMessage = 'acceptOfferConfirmationMessage';
}

@ -10,94 +10,54 @@ import 'package:provider/single_child_widget.dart';
import 'package:sizer/sizer.dart';
//testing push
final navigatorKey = GlobalKey<NavigatorState>();
Logger logger = Logger(
// printer: PrettyPrinter(lineLength: 0, methodCount: 0,),
);
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
}
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
// AppState().setPostParamsInitConfig();
HttpOverrides.global = MyHttpOverrides();
runApp(
EasyLocalization(
supportedLocales: const <Locale>[
Locale('en', 'US'),
Locale('ar', 'SA'),
],
path: 'resources',
// assetLoader: const CodegenLoader(),
child: MultiProvider(
providers: const <SingleChildWidget>[
// ChangeNotifierProvider<LoginProviderModel>(
// create: (_) => LoginProviderModel(),
// ),
],
child: const MyApp(),
),
),
);
}
// todo terminal command to genertate translation files
// flutter pub run easy_localization:generate --source-dir ./assets/langs
// todo terminal command to genertate translation keys
// flutter pub run easy_localization:generate --source-dir ./assets/langs -f keys -o locale_keys.g.dart
// command to generate languages data from json
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
return Sizer(
builder: (
BuildContext context,
Orientation orientation,
DeviceType deviceType,
) {
List<LocalizationsDelegate<dynamic>> delegates = context.localizationDelegates;
// AppState().setPostParamsModel(
// PostParamsModel(
// languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2,
// ),
// );
return MaterialApp(
// key: navigatorKey,
navigatorKey: navigatorKey,
theme: AppTheme.getTheme(
isArabic: EasyLocalization.of(context)?.locale.languageCode == "ar",
),
debugShowCheckedModeBanner: false,
localizationsDelegates: delegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
);
},
);
});
}
}
// class MyApp extends StatelessWidget {
// MyApp({super.key}) {
// AppDependencies.addDependencies();
// AppState = Injector.appInstance.get<AppState>();
// // AppState.setPostParamsInitConfig();
//
// class MyHttpOverrides extends HttpOverrides {
// @override
// HttpClient createHttpClient(SecurityContext? context) {
// return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
// }
// }
//
// Future<void> main() async {
// WidgetsFlutterBinding.ensureInitialized();
//
// await EasyLocalization.ensureInitialized();
// // AppState().setPostParamsInitConfig();
// HttpOverrides.global = MyHttpOverrides();
//
// runApp(
// EasyLocalization(
// supportedLocales: const <Locale>[
// Locale('en', 'US'),
// Locale('ar', 'SA'),
// ],
// path: 'resources',
// // assetLoader: const CodegenLoader(),
// child: MultiProvider(
// providers: const <SingleChildWidget>[
// // ChangeNotifierProvider<LoginProviderModel>(
// // create: (_) => LoginProviderModel(),
// // ),
// ],
// child: const MyApp(),
// ),
// ),
// );
// }
//
// // todo terminal command to genertate translation files
// // flutter pub run easy_localization:generate --source-dir ./assets/langs
// // todo terminal command to genertate translation keys
// // flutter pub run easy_localization:generate --source-dir ./assets/langs -f keys -o locale_keys.g.dart
// // command to generate languages data from json
//
// class MyApp extends StatelessWidget {
// const MyApp({super.key});
//
// @override
// Widget build(BuildContext context) {
@ -108,7 +68,6 @@ class MyApp extends StatelessWidget {
// Orientation orientation,
// DeviceType deviceType,
// ) {
// SizeConfig().init(constraints, orientation);
// List<LocalizationsDelegate<dynamic>> delegates = context.localizationDelegates;
// // AppState().setPostParamsModel(
// // PostParamsModel(
@ -117,19 +76,58 @@ class MyApp extends StatelessWidget {
// // );
// return MaterialApp(
// // key: navigatorKey,
// navigatorKey: navigatorKey,
// theme: AppTheme.getTheme(
// EasyLocalization.of(context)?.locale.languageCode == "ar",
// isArabic: EasyLocalization.of(context)?.locale.languageCode == "ar",
// ),
// debugShowCheckedModeBanner: false,
// localizationsDelegates: delegates,
// supportedLocales: context.supportedLocales,
// locale: context.locale,
// initialRoute: AppRoutes.initialPage,
// routes: AppRoutes.routes,
// );
// },
// );
// });
// }
// }
//
// // class MyApp extends StatelessWidget {
// // MyApp({super.key}) {
// // AppDependencies.addDependencies();
// // AppState = Injector.appInstance.get<AppState>();
// // // AppState.setPostParamsInitConfig();
// // }
// //
// // @override
// // Widget build(BuildContext context) {
// // return LayoutBuilder(builder: (context, constraints) {
// // return Sizer(
// // builder: (
// // BuildContext context,
// // Orientation orientation,
// // DeviceType deviceType,
// // ) {
// // SizeConfig().init(constraints, orientation);
// // List<LocalizationsDelegate<dynamic>> delegates = context.localizationDelegates;
// // // AppState().setPostParamsModel(
// // // PostParamsModel(
// // // languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2,
// // // ),
// // // );
// // return MaterialApp(
// // // key: navigatorKey,
// // navigatorKey: navigatorKey,
// // theme: AppTheme.getTheme(
// // EasyLocalization.of(context)?.locale.languageCode == "ar",
// // ),
// // debugShowCheckedModeBanner: false,
// // localizationsDelegates: delegates,
// // supportedLocales: context.supportedLocales,
// // locale: context.locale,
// // initialRoute: AppRoutes.initialPage,
// // routes: AppRoutes.routes,
// // );
// // },
// // );
// // });
// // }
// // }

@ -2,6 +2,7 @@ import 'dart:math';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/special_service_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/utils/enums.dart';
class AdDetailsModel {
@ -44,46 +45,49 @@ class AdDetailsModel {
String? phoneNo;
String? whatsAppNo;
CreatedByRoleEnum? createdByRoleEnum;
AdDetailsModel(
{this.id,
this.startdate,
this.enddate,
this.vehicle,
this.specialservice,
// this.reserved,
this.statusID,
this.statuslabel,
this.adsDurationPrice,
this.adsDurationDiscount,
this.adsDurationDiscountPrice,
this.comment,
this.active,
this.isPaid,
this.isSubscription,
this.isVerified,
this.netPrice,
this.specialServiceTotalPrice,
this.taxPrice,
this.totalPrice,
this.userID,
this.vehiclePostingID,
this.qrCodePath,
this.isCustomerAcknowledged,
this.createdByRole,
this.totalViews,
this.createdOn,
this.priceExcludingDiscount,
this.reservePrice,
this.isMCHandled,
this.adPostStatus,
this.adReserveStatus,
this.isMyAd,
this.isReservedByMe,
this.phoneNo,
this.whatsAppNo,
this.createdByRoleEnum,
this.modifiedOn});
List<ChatMessageModel>? adMessages;
AdDetailsModel({
this.id,
this.startdate,
this.enddate,
this.vehicle,
this.specialservice,
// this.reserved,
this.statusID,
this.statuslabel,
this.adsDurationPrice,
this.adsDurationDiscount,
this.adsDurationDiscountPrice,
this.comment,
this.active,
this.isPaid,
this.isSubscription,
this.isVerified,
this.netPrice,
this.specialServiceTotalPrice,
this.taxPrice,
this.totalPrice,
this.userID,
this.vehiclePostingID,
this.qrCodePath,
this.isCustomerAcknowledged,
this.createdByRole,
this.totalViews,
this.createdOn,
this.priceExcludingDiscount,
this.reservePrice,
this.isMCHandled,
this.adPostStatus,
this.adReserveStatus,
this.isMyAd,
this.isReservedByMe,
this.phoneNo,
this.whatsAppNo,
this.createdByRoleEnum,
this.modifiedOn,
this.adMessages,
});
int getRandomValue({required int min, required int max}) {
Random random = Random();
@ -157,7 +161,7 @@ class Vehicle {
ModelYear? modelyear;
Condition? sellertype;
Condition? transmission;
Duration? duration;
AdsDuration? duration;
List<AdImage>? image;
List<DamageReport>? damagereport;
String? vehicleDescription;
@ -211,7 +215,7 @@ class Vehicle {
modelyear = json['modelyear'] != null ? ModelYear.fromJson(json['modelyear']) : null;
sellertype = json['sellertype'] != null ? Condition.fromJson(json['sellertype']) : null;
transmission = json['transmission'] != null ? Condition.fromJson(json['transmission']) : null;
duration = json['duration'] != null ? Duration.fromJson(json['duration']) : null;
duration = json['duration'] != null ? AdsDuration.fromJson(json['duration']) : null;
if (json['image'] != null) {
image = <AdImage>[];
json['image'].forEach((v) {
@ -326,16 +330,16 @@ class ModelYear {
}
}
class Duration {
class AdsDuration {
int? id;
String? label;
int? days;
double? price;
ModelYear? country;
Duration({this.id, this.label, this.days, this.price, this.country});
AdsDuration({this.id, this.label, this.days, this.price, this.country});
Duration.fromJson(Map<String, dynamic> json) {
AdsDuration.fromJson(Map<String, dynamic> json) {
id = json['id'];
label = json['label'];
days = json['days'];

@ -1,5 +1,6 @@
import 'dart:developer';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
class ProviderOffersModel {
@ -66,7 +67,7 @@ class ServiceProvidersOffers {
ServiceProvidersOffers.fromJson(Map<String, dynamic> json) {
providerId = json['providerID'];
providerUserId = json['providerUserId'] ?? "c680271c-b2a7-4ecf-7e95-08db545aec1b"; //TODO Remove this when parameter is added in backend
providerUserId = json['providerUserID'];
name = json['name'];
mobileNo = json['mobileNo'];
email = json['email'];
@ -74,4 +75,9 @@ class ServiceProvidersOffers {
offerCount = json['offerCount'];
chatMessages = [];
}
@override
String toString() {
return 'ServiceProvidersOffers{providerUserId: $providerUserId, providerId: $providerId, name: $name, mobileNo: $mobileNo, email: $email, companyName: $companyName, offerCount: $offerCount, chatMessages: $chatMessages}';
}
}

@ -4,7 +4,7 @@ import 'dart:developer';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';

@ -3,7 +3,7 @@ import 'dart:developer';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/appointments_models/schedule_model.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';

@ -3,7 +3,7 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';

@ -4,7 +4,7 @@ import 'package:http/io_client.dart';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';

@ -1,7 +1,7 @@
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/advertisment_models/ss_car_check_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/services_models/item_model.dart';

@ -1,7 +1,7 @@
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart';

@ -1,7 +1,7 @@
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
@ -18,7 +18,7 @@ abstract class RequestRepo {
Future<List<RequestModel>> getRequests(Map<String, dynamic> postParams);
Future<GenericRespModel> updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId});
Future<GenericRespModel> updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments});
}
class RequestRepoImp implements RequestRepo {
@ -93,10 +93,11 @@ class RequestRepoImp implements RequestRepo {
}
@override
Future<GenericRespModel> updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId}) async {
Future<GenericRespModel> updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments}) async {
var queryParameters = {
"requestOfferId": requestOfferId.toString(),
"offerStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum().toString(),
"comments": comments,
};
GenericRespModel genericRespModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),

@ -4,7 +4,7 @@ import 'package:mc_common_app/models/provider_branches_models/profile/services.d
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
abstract class ScheduleRepo {
Future<Services> getAllServices(String branchId);

@ -1,7 +1,7 @@
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';

@ -6,7 +6,7 @@ import 'package:http/http.dart';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/user_models/basic_otp.dart';
import 'package:mc_common_app/models/user_models/change_email.dart';

@ -0,0 +1,103 @@
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/main.dart';
import 'package:permission_handler/permission_handler.dart';
abstract class FirebaseMessagingService {
Future<String> getFirebaseToken();
Future<void> initializeNotifications();
}
class FirebaseMessagingServiceImp implements FirebaseMessagingService {
final FlutterLocalNotificationsPlugin flutterLocalNotifications;
final FirebaseMessaging firebaseMessaging;
FirebaseMessagingServiceImp({required this.firebaseMessaging, required this.flutterLocalNotifications});
@override
Future<String> getFirebaseToken() async => await firebaseMessaging.getToken() ?? "";
Future<void> requestPermissions() async {
if (Platform.isIOS) {
await flutterLocalNotifications.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()?.requestPermissions(alert: true, badge: true, sound: true);
} else if (Platform.isAndroid) {
AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotifications.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
bool? granted = await androidImplementation?.requestNotificationsPermission();
if (granted == false) {
await Permission.notification.request();
}
}
}
@override
Future<void> initializeNotifications() async {
await requestPermissions();
AppState().setDeviceToken = await getFirebaseToken();
await Permission.notification.isDenied.then((bool value) {
if (value) {
Permission.notification.request();
}
});
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('ic_launcher');
final DarwinInitializationSettings initializationSettingsDarwin = DarwinInitializationSettings(onDidReceiveLocalNotification: _onDidReceiveLocalNotification);
final InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsDarwin);
await flutterLocalNotifications.initialize(initializationSettings, onDidReceiveNotificationResponse: (notificationResponse) {});
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) _handleNotification(initialMessage);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.notification != null) _handleNotification(message);
});
FirebaseMessaging.onMessageOpenedApp.listen(_handleNotification);
FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
FirebaseMessaging.instance.onTokenRefresh.listen((String token) async {
AppState().setDeviceToken = token;
});
}
void _onDidReceiveLocalNotification(int id, String? title, String? body, String? payload) async {
logger.i(body);
}
void _handleNotification(RemoteMessage message) async {
logger.i(message.notification!.title);
logger.i(message.notification!.body);
displayNotification(title: message.notification!.title ?? '', body: message.notification!.body ?? '');
}
Future<void> displayNotification({required String title, required String body}) async {
const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
"0",
'mowater',
channelDescription: 'mowater_notifications',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker',
);
const DarwinNotificationDetails iOSPlatformChannelSpecifics = DarwinNotificationDetails(threadIdentifier: 'thread_id');
const NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails, iOS: iOSPlatformChannelSpecifics);
await flutterLocalNotifications.show(0, title, body, notificationDetails, payload: 'item x');
}
}
@pragma('vm:entry-point')
Future<dynamic> backgroundMessageHandler(RemoteMessage message) async {
await Firebase.initializeApp();
}

@ -3,7 +3,7 @@ import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
@ -1808,6 +1808,13 @@ class AdVM extends BaseVM {
int ifSpecialServiceAlreadyThere(int id) {
return specialServiceCards.indexWhere((element) => element.serviceSelectedId!.selectedId == id);
}
void onMessagesButtonPressed({required BuildContext context, required AdDetailsModel adDetailsModel}) {
ChatViewArgumentsForAd chatViewArgumentsForAd = ChatViewArgumentsForAd(adDetailsModel: adDetailsModel);
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.ads, chatViewArgumentsForAd: chatViewArgumentsForAd);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
}
}
// Edit Work End Amir

@ -8,6 +8,7 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
@ -46,6 +47,23 @@ class ChatVM extends ChangeNotifier {
notifyListeners();
}
bool isUserOnChatScreen = false;
final ScrollController scrollController = ScrollController();
void scrollChatDown() {
if (!isUserOnChatScreen) {
return;
}
logger.i(scrollController.position.maxScrollExtent);
scrollController.animateTo(
scrollController.position.maxScrollExtent + 200, // for the text field
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
List<OfferRequestCommentModel> offerRejectModelList = [
OfferRequestCommentModel(
index: 0,
@ -69,10 +87,17 @@ class ChatVM extends ChangeNotifier {
),
];
OfferRequestCommentModel selectedOfferRequestCommentModel = OfferRequestCommentModel(
index: 3,
isSelected: true,
title: LocaleKeys.otherVar.tr(),
);
void updateSelectionInOfferRejectModelList(int index) {
for (var value in offerRejectModelList) {
value.isSelected = false;
}
selectedOfferRequestCommentModel = offerRejectModelList[index];
offerRejectModelList[index].isSelected = true;
notifyListeners();
}
@ -89,6 +114,9 @@ class ChatVM extends ChangeNotifier {
//REJECTING OFFER
bool isRejectOfferButtonValidated() {
if (selectedOfferRequestCommentModel.index != offerRejectModelList.length - 1) {
return true;
}
bool isValidated = true;
if (rejectOfferDescription.isEmpty) {
rejectOfferDescriptionError = GlobalConsts.descriptionError;
@ -102,35 +130,32 @@ class ChatVM extends ChangeNotifier {
return isValidated;
}
Future<void> onNewMessageReceived({required List<ChatMessageModel> messages, required BuildContext context, bool isMyOwnOffer = false}) async {
Future<void> onNewMessageReceived({required List<ChatMessageModel> messages, bool isMyOwnOffer = false, required RequestsVM requestsVM}) async {
if (AppState().currentAppType == AppType.customer) {
for (var msg in messages) {
int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID); // TODO : NEED TO BE CHECKED
int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID);
if (providerIndex != -1) {
serviceProviderOffersList[providerIndex].chatMessages!.add(msg);
scrollChatDown();
}
}
//providerUserId
} else {
for (var msg in messages) {
logger.i(msg);
// Where we need to call this function for saving a message in chat we will use receiverUserID and in those cases where received ID is null , it means it is a signal R call
int providerIndex = -1;
if (isMyOwnOffer) {
providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere(
(element) => element.customerUserID == msg.receiverUserID,
);
providerIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == msg.receiverUserID && element.id == msg.requestID));
} else {
providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere(
(element) => element.customerUserID == msg.senderUserID,
);
providerIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == msg.senderUserID && element.id == msg.requestID));
}
log("providerIndex: $providerIndex");
if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: msg, index: providerIndex);
requestsVM.addChatMessagesInRequestsModel(msg: msg, index: providerIndex);
scrollChatDown();
}
}
}
notifyListeners();
}
@ -139,16 +164,28 @@ class ChatVM extends ChangeNotifier {
try {
hubConnection = await chatRepo.getHubConnection();
await hubConnection!.start();
hubConnection!.on("ReceiveMessageRequestOffer", (List<Object?>? arguments) {
hubConnection!.on(SignalrConsts.receiveMessageRequestOffer, (List<Object?>? arguments) {
if (arguments == null || arguments.isEmpty) return;
List<ChatMessageModel> chat = [];
for (var message in arguments) {
final chatMessage = ChatMessageModel.fromJson(message as Map<String, dynamic>);
chat.add(chatMessage);
}
onNewMessageReceived(messages: chat, context: context);
logger.i("I received ping : ${arguments.toString()}");
onNewMessageReceived(messages: chat, requestsVM: context.read<RequestsVM>());
logger.i(arguments);
Utils.showToast(arguments.toString());
});
hubConnection!.onclose((exception) {
logger.i("onClose: ${exception.toString()}");
buildHubConnection(context);
});
hubConnection!.onreconnecting((exception) => () {
logger.i("onReconnecting: ${exception.toString()}");
});
hubConnection!.onreconnected((connectionId) => () {
logger.i("onReconnected: ${connectionId.toString()}");
});
} catch (e) {
logger.i("Error: ${e.toString()}");
}
@ -157,7 +194,7 @@ class ChatVM extends ChangeNotifier {
}
}
Future<bool> onSendMessageForRequestOffer({
Future<bool> onOfferSendForRequest({
required String receiverId,
required ChatMessageTypeEnum chatMessageType,
required String message,
@ -166,12 +203,13 @@ class ChatVM extends ChangeNotifier {
required BuildContext context,
}) async {
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
logger.i("Hub Not Connected!!");
await buildHubConnection(context);
}
if (hubConnection!.state == HubConnectionState.connected) {
final providerId = AppState().getUser.data!.userInfo!.providerId;
hubConnection!.invoke(
"SendMessageRequestOffer",
SignalrConsts.sendMessageRequestOffer,
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
@ -196,12 +234,14 @@ class ChatVM extends ChangeNotifier {
}
logger.i(<String, dynamic>{
"ID": "", //here should be req offer ID
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"RequestID": requestId,
"ReqOfferID": 0,
"ReqOffer": <String, dynamic>{
"ID": "",
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": AppState().getUser.data!.userInfo!.providerId,
@ -212,7 +252,7 @@ class ChatVM extends ChangeNotifier {
return true;
}
Future<bool> onTextMessageSend({
Future<bool> onTextMessageSendForRequest({
required String receiverId,
required ChatMessageTypeEnum chatMessageType,
required String message,
@ -223,6 +263,8 @@ class ChatVM extends ChangeNotifier {
if (message.isEmpty) return false;
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
logger.i("Hub Not Connected!!");
await buildHubConnection(context);
}
if (hubConnection!.state == HubConnectionState.connected) {
@ -236,10 +278,11 @@ class ChatVM extends ChangeNotifier {
"ChatText": message,
"RequestID": requestId,
"ReqOfferID": latestOfferId,
// "ReqOffer": {}
}));
hubConnection!.invoke(
"SendMessageRequestOffer",
SignalrConsts.sendMessageRequestOffer,
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
@ -248,6 +291,7 @@ class ChatVM extends ChangeNotifier {
"ChatText": message,
"RequestID": requestId,
"ReqOfferID": latestOfferId,
// "ReqOffer": {}
}
],
).catchError((e) {
@ -273,7 +317,8 @@ class ChatVM extends ChangeNotifier {
serviceProviderOffersList[providerIndex].chatMessages!.add(chatMessageModel);
}
} else {
int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => element.customerUserID == receiverId);
int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => (element.customerUserID == receiverId && element.id == requestId));
log("providerIndex2:$providerIndex");
if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex);
}
@ -340,7 +385,7 @@ class ChatVM extends ChangeNotifier {
int providerId = AppState().getUser.data!.userInfo!.providerId!;
Utils.showLoading(context);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId);
context.read<RequestsVM>().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex);
context.read<RequestsVM>().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex, context: context);
Utils.hideLoading(context);
} catch (e) {
logger.i(e.toString());
@ -349,11 +394,10 @@ class ChatVM extends ChangeNotifier {
}
}
Future<int> onActionOfferTapped({required BuildContext context, required RequestOfferStatusEnum requestOfferStatusEnum, required int reqOfferId}) async {
Future<int> onActionOfferTapped({required BuildContext context, required RequestOfferStatusEnum requestOfferStatusEnum, required int reqOfferId, required String comments}) async {
try {
Utils.showLoading(context);
GenericRespModel genericRespModel = await requestRepo.updateOfferRequestStatus(requestOfferStatusEnum: requestOfferStatusEnum, requestOfferId: reqOfferId);
Utils.hideLoading(context);
GenericRespModel genericRespModel = await requestRepo.updateOfferRequestStatus(requestOfferStatusEnum: requestOfferStatusEnum, requestOfferId: reqOfferId, comments: comments);
Utils.showToast(genericRespModel.message.toString());
return genericRespModel.messageStatus == 1 ? reqOfferId : -1;
} catch (e) {
logger.i(e.toString());
@ -362,4 +406,131 @@ class ChatVM extends ChangeNotifier {
return -1;
}
}
Future<bool> onSendMessageForActionOnRequestOffer({
required String receiverId,
required ChatMessageTypeEnum chatMessageType,
required String comments,
required int requestId,
required int serviceProviderID,
required int requestOfferID,
required String offerPrice,
required RequestOfferStatusEnum requestOfferStatusEnum,
required BuildContext context,
}) async {
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
logger.i("Hub Not Connected!!");
await buildHubConnection(context);
}
if (hubConnection!.state == HubConnectionState.connected) {
hubConnection!.invoke(
SignalrConsts.sendMessageRequestOffer,
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": comments,
"RequestID": requestId,
"ReqOfferID": requestOfferID,
"ReqOffer": <String, dynamic>{
"ID": requestOfferID,
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": serviceProviderID,
"OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(),
"Comment": comments,
},
}
],
).catchError((e) {
logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}");
Utils.showToast(e.toString());
return false;
});
}
logger.i(<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": comments,
"RequestID": requestId,
"ReqOfferID": 0,
"ReqOffer": <String, dynamic>{
"ID": requestOfferID,
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": serviceProviderID,
"OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(),
"Comment": comments,
},
});
return true;
}
// =================== Ads ======================
Future<bool> onTextMessageSendForAds({
required String receiverId,
required ChatMessageTypeEnum chatMessageType,
required String message,
required AdDetailsModel adDetailsModel,
required BuildContext context,
}) async {
if (message.isEmpty) return false;
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
logger.i("Hub Not Connected!!");
await buildHubConnection(context);
}
if (hubConnection!.state == HubConnectionState.connected) {
final userId = AppState().getUser.data!.userInfo!.userId.toString();
final name = AppState().getUser.data!.userInfo!.firstName.toString();
hubConnection!.invoke(
SignalrConsts.sendMessageAds,
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"SenderUserID": userId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"AdsID": adDetailsModel.id,
}
],
).catchError((e) {
logger.i("error in invoking SendMessage: ${e.toString()}");
Utils.showToast(e.toString());
return false;
});
ChatMessageModel chatMessageModel = ChatMessageModel(
messageType: chatMessageType.getIdFromChatMessageTypeEnum(),
chatText: message,
isMyMessage: true,
requestID: 0,
senderName: name,
senderUserID: userId,
chatMessageTypeEnum: ChatMessageTypeEnum.freeText,
receiverUserID: receiverId,
);
if (AppState().currentAppType == AppType.customer) {
} else {
}
return true;
}
return false;
}
}

@ -1,13 +1,23 @@
import 'dart:io';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/models/user_models/image_response.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/services/firebase_service.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:provider/provider.dart';
class DashboardVmCustomer extends BaseVM {
final CommonAppServices commonServices;
@ -19,7 +29,8 @@ class DashboardVmCustomer extends BaseVM {
int selectedNavbarBarIndex = 2;
void onNavbarTapped(int index) {
void onNavbarTapped(int index) async {
print(AppState().getDeviceToken);
selectedNavbarBarIndex = index;
notifyListeners();
}
@ -49,6 +60,56 @@ class DashboardVmCustomer extends BaseVM {
}
}
onInitState(BuildContext context) async {
Future.wait<dynamic>([
context.read<RequestsVM>().populateRequestsFilterList(),
context.read<AppointmentsVM>().populateAppointmentsFilterList(),
context.read<AppointmentsVM>().populateBranchesFilterList(),
context.read<AdVM>().populateAdsFilterList(),
]);
}
Future<void> onRefresh(BuildContext context) async {
AdVM adVM = Provider.of<AdVM>(context, listen: false);
AppointmentsVM appointmentsVM = Provider.of<AppointmentsVM>(context, listen: false);
RequestsVM requestsVM = Provider.of<RequestsVM>(context, listen: false);
ChatVM chatVM = Provider.of<ChatVM>(context, listen: false);
if (appointmentsVM.myAppointments.isEmpty) {
await appointmentsVM.getMyAppointments();
}
if (appointmentsVM.nearbyBranches.isEmpty) {
await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches!
}
if (adVM.myAds.isEmpty) {
await adVM.getMyAds();
}
if (adVM.exploreAds.isEmpty) {
await adVM.getExploreAds();
}
if (requestsVM.myRequests.isEmpty) {
await requestsVM.getRequests(appType: AppType.customer);
}
if (adVM.vehicleTypes.isEmpty) {
await adVM.getVehicleTypes();
}
if (adVM.vehicleAdsDurations.isEmpty) {
await adVM.getVehicleAdsDuration();
}
await chatVM.buildHubConnection(context);
adVM.updateVehicleAdDurationId(
SelectionModel(
selectedId: adVM.vehicleAdsDurations.first.id ?? 0,
selectedOption: "${adVM.vehicleAdsDurations.first.days} Days",
itemPrice: adVM.vehicleAdsDurations.first.price!.toInt().toString(),
),
);
}
Future<ImageResponse> updateUserImage(String image) async {
return await userRepo.updateUserImage(image);
}

@ -83,13 +83,22 @@ class RequestsVM extends BaseVM {
}
addChatMessagesInRequestsModel({required ChatMessageModel msg, required int index}) {
log("msg: $msg");
log("index: $index");
myFilteredRequests[index].chatMessages.add(msg);
notifyListeners();
}
overwriteChatMessagesInRequestsModel({required List<ChatMessageModel> messages, required int index}) {
overwriteChatMessagesInRequestsModel({required List<ChatMessageModel> messages, required int index, required BuildContext context}) {
myFilteredRequests[index].chatMessages.clear();
myFilteredRequests[index].chatMessages = messages;
if (myFilteredRequests[index].chatMessages.isNotEmpty) {
for (var message in myFilteredRequests[index].chatMessages) {
if (message.chatMessageTypeEnum == ChatMessageTypeEnum.offer) {
context.read<ChatVM>().updateLatestOfferId(message.reqOfferID ?? 0);
}
}
}
notifyListeners();
}
@ -100,7 +109,6 @@ class RequestsVM extends BaseVM {
}
requestsTypeFilterOptions[requestsTypeEnum.getIdFromRequestTypeStatusEnum() - 1].isSelected = true; // -1 to match with the index
myFilteredRequests = myRequests.where((element) => element.requestType == requestsTypeEnum.getIdFromRequestTypeStatusEnum()).toList();
notifyListeners();
}
@ -420,7 +428,7 @@ class RequestsVM extends BaseVM {
}) async {
if (isSendOfferValidated()) {
final chatVM = context.read<ChatVM>();
bool status = await chatVM.onSendMessageForRequestOffer(
bool status = await chatVM.onOfferSendForRequest(
receiverId: receiverId,
chatMessageType: ChatMessageTypeEnum.offer,
message: message,
@ -432,7 +440,7 @@ class RequestsVM extends BaseVM {
if (status) {
final senderName = AppState().getUser.data!.userInfo!.firstName;
final senderId = AppState().getUser.data!.userInfo!.userId;
// resetSendOfferBottomSheet();
resetSendOfferBottomSheet();
Navigator.pop(context);
ChatMessageModel chatMessageModel = ChatMessageModel(
isMyMessage: true,
@ -452,9 +460,10 @@ class RequestsVM extends BaseVM {
comment: message,
offerStatusText: "",
));
context.read<ChatVM>().onNewMessageReceived(messages: [chatMessageModel], context: context, isMyOwnOffer: true);
context.read<ChatVM>().onNewMessageReceived(messages: [chatMessageModel], requestsVM: this, isMyOwnOffer: true);
if (!isFromChatScreen) {
ChatViewArguments chatViewArguments = ChatViewArguments(
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer,
requestId: requestModel.id,
receiverId: requestModel.customerID,
@ -462,6 +471,8 @@ class RequestsVM extends BaseVM {
requestIndex: requestIndex,
providerIndex: -1,
);
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.requestOffer, chatViewArgumentsForRequest: chatViewArgumentsForRequest);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
}
}

@ -42,8 +42,11 @@ class AdsDetailView extends StatefulWidget {
}
class _AdsDetailViewState extends State<AdsDetailView> {
late AdVM adVM;
@override
void initState() {
adVM = context.read<AdVM>();
scheduleMicrotask(() {
onAdDetailsLoaded();
});
@ -53,12 +56,11 @@ class _AdsDetailViewState extends State<AdsDetailView> {
Future<void> onAdDetailsLoaded() async {
context.read<PaymentVM>().updateCurrentAdId(id: widget.adDetails.id!);
if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus == AdPostStatus.reserved)) {
await context.read<AdVM>().getAdBankingAccountInfo(adId: widget.adDetails.id!);
await adVM.getAdBankingAccountInfo(adId: widget.adDetails.id!);
}
}
void deleteAdBottomSheet(BuildContext context) {
AdVM adVM = context.read<AdVM>();
return actionConfirmationBottomSheet(
context: context,
title: LocaleKeys.deleteAdConfirmation.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
@ -99,17 +101,14 @@ class _AdsDetailViewState extends State<AdsDetailView> {
isRemoveBackButton: false,
isDrawerEnabled: false,
actions: [
((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved)
((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) && (widget.adDetails.adPostStatus != AdPostStatus.active)
? IconButton(
icon: const Icon(Icons.delete_outline, color: MyColors.redColor),
onPressed: () {
return deleteAdBottomSheet(context);
},
)
: IconButton(
icon: const Icon(Icons.chat_outlined, color: Colors.black),
onPressed: () {},
))
: IconButton(icon: const Icon(Icons.chat_outlined, color: Colors.black), onPressed: () => adVM.onMessagesButtonPressed(context: context, adDetailsModel: widget.adDetails)))
.toContainer(
margin: const EdgeInsets.fromLTRB(0, 8, 21, 8),
paddingAll: 0,
@ -154,7 +153,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
children: [
Row(
children: [
(LocaleKeys.model.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
("${LocaleKeys.model.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${widget.adDetails.vehicle!.modelyear!.label}".toText(
fontSize: 14,
isBold: true,
@ -169,7 +168,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
children: [
Row(
children: [
(LocaleKeys.mileage.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
("${LocaleKeys.mileage.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${widget.adDetails.vehicle!.mileage!.mileageEnd}Km".toText(
fontSize: 14,
isBold: true,
@ -183,7 +182,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
),
Row(
children: [
(LocaleKeys.transmission.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
("${LocaleKeys.transmission.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${widget.adDetails.vehicle!.transmission!.label}".toText(
fontSize: 14,
isBold: true,
@ -191,14 +190,14 @@ class _AdsDetailViewState extends State<AdsDetailView> {
],
),
8.height,
(LocaleKeys.description.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
("${LocaleKeys.description.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${widget.adDetails.vehicle!.vehicleDescription}".toText(
fontSize: 14,
isBold: true,
),
if (widget.adDetails.isMyAd ?? false) ...[
8.height,
(LocaleKeys.demand.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
("${LocaleKeys.demand.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
@ -238,7 +237,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
// ),
Row(
children: [
(LocaleKeys.bankName.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
("${LocaleKeys.bankName.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
(adVM.adsBankDetailsModel!.bankName ?? "").toText(
fontSize: 14,
isBold: true,
@ -247,7 +246,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
),
Row(
children: [
(LocaleKeys.iban.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
("${LocaleKeys.iban.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
(adVM.adsBankDetailsModel!.iban ?? "").toText(
fontSize: 14,
isBold: true,
@ -278,10 +277,10 @@ class _AdsDetailViewState extends State<AdsDetailView> {
],
).onPress(() async {
Utils.showLoading(context);
await context.read<AdVM>().getVehicleTypes();
await context.read<AdVM>().getVehicleBrandsByVehicleTypeId(vehicleIdForEditAd: widget.adDetails.vehicle!.vehicleType ?? -1);
await adVM.getVehicleTypes();
await adVM.getVehicleBrandsByVehicleTypeId(vehicleIdForEditAd: widget.adDetails.vehicle!.vehicleType ?? -1);
Utils.hideLoading(context);
context.read<AdVM>().onEditUpdateAdPressed(context, widget.adDetails);
adVM.onEditUpdateAdPressed(context, widget.adDetails);
}),
],
).paddingOnly(bottom: 5),
@ -842,7 +841,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
maxHeight: 55,
title: (LocaleKeys.book.tr() + " ${photoSpecialServiceModel.name}"),
title: ("${LocaleKeys.book.tr()} ${photoSpecialServiceModel.name}"),
txtColor: MyColors.darkPrimaryColor,
onPressed: () {
onBookPhotographyServiceClicked(context, adDetailsModel: adDetailsModel);

@ -1,5 +1,4 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
@ -10,7 +9,9 @@ import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
@ -22,13 +23,48 @@ import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart' as lcl;
class ChatView extends StatelessWidget {
class ChatView extends StatefulWidget {
final ChatViewArguments chatViewArguments;
const ChatView({super.key, required this.chatViewArguments});
@override
State<ChatView> createState() => _ChatViewState();
}
class _ChatViewState extends State<ChatView> {
late ChatVM chatVM;
late ChatTypeEnum chatTypeEnum;
ChatViewArgumentsForRequest? chatViewArgumentsForRequest;
ChatViewArgumentsForAd? chatViewArgumentsForAd;
@override
void initState() {
chatTypeEnum = widget.chatViewArguments.chatTypeEnum;
if (chatTypeEnum == ChatTypeEnum.ads) {
chatViewArgumentsForAd = widget.chatViewArguments.chatViewArgumentsForAd;
} else if (chatTypeEnum == ChatTypeEnum.requestOffer) {
chatViewArgumentsForRequest = widget.chatViewArguments.chatViewArgumentsForRequest;
}
chatVM = context.read<ChatVM>();
chatVM.isUserOnChatScreen = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (chatVM.scrollController.hasClients) {
chatVM.scrollChatDown();
}
});
super.initState();
}
@override
void dispose() {
chatVM.isUserOnChatScreen = false;
super.dispose();
}
Future buildSendOfferBottomSheet(BuildContext context) {
RequestModel requestDetail = chatViewArguments.requestModel!;
RequestModel requestDetail = chatViewArgumentsForRequest!.requestModel!;
return showModalBottomSheet(
context: context,
isScrollControlled: true,
@ -51,6 +87,7 @@ class ChatView extends StatelessWidget {
errorValue: requestsVM.offerPriceError,
keyboardType: TextInputType.number,
hint: LocaleKeys.enterAmount.tr(),
numbersOnly: true,
onChanged: (v) => requestsVM.updateOfferPrice(v),
),
12.height,
@ -75,7 +112,7 @@ class ChatView extends StatelessWidget {
requestId: requestDetail.id,
offerPrice: requestsVM.offerPrice,
requestModel: requestDetail,
requestIndex: chatViewArguments.requestIndex,
requestIndex: chatViewArgumentsForRequest!.requestIndex,
isFromChatScreen: true,
);
},
@ -90,20 +127,44 @@ class ChatView extends StatelessWidget {
);
}
Future<bool> onTextMessageSend() async {
bool status = false;
if (chatTypeEnum == ChatTypeEnum.requestOffer) {
status = await chatVM.onTextMessageSendForRequest(
context: context,
receiverId: chatViewArgumentsForRequest!.receiverId,
message: chatVM.chatMessageText,
requestId: chatViewArgumentsForRequest!.requestId ?? 0,
offerPrice: "0.0",
chatMessageType: ChatMessageTypeEnum.freeText,
);
} else if (chatTypeEnum == ChatTypeEnum.ads) {
} else {}
return status;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.chat.tr()),
body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) {
final chatMessages = AppState().currentAppType == AppType.customer
? chatVM.serviceProviderOffersList[chatViewArguments.providerIndex].chatMessages
: requestVM.myFilteredRequests[chatViewArguments.requestIndex].chatMessages;
return chatMessages == null
? Center(child: LocaleKeys.noRequestsShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: Column(
children: [
Expanded(
child: ListView.separated(
List<ChatMessageModel> chatMessages = [];
if (chatTypeEnum == ChatTypeEnum.ads) {
chatMessages = chatViewArgumentsForAd!.adDetailsModel!.adMessages ?? [];
} else if (chatTypeEnum == ChatTypeEnum.requestOffer) {
if (AppState().currentAppType == AppType.customer) {
chatMessages = chatVM.serviceProviderOffersList[chatViewArgumentsForRequest!.providerIndex].chatMessages ?? [];
} else {
chatMessages = requestVM.myFilteredRequests[chatViewArgumentsForRequest!.requestIndex].chatMessages;
}
}
return Column(
children: [
Expanded(
child: chatMessages.isEmpty
? Center(child: LocaleKeys.noRequestsShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
controller: chatVM.scrollController,
itemCount: chatMessages.length,
separatorBuilder: (BuildContext context, int index) => 20.height,
itemBuilder: (BuildContext context, int index) {
@ -111,73 +172,73 @@ class ChatView extends StatelessWidget {
return ChatMessageCustomWidget(chatMessageModel: chatMessageModel);
},
).horPaddingMain(),
),
10.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (requestVM.currentSelectedRequest!.requestStatus == RequestStatus.inProgress) ...[
Center(
child: LocaleKeys.requestAlreadyInProgress.tr().toText(
textAlign: TextAlign.center,
color: MyColors.lightTextColor,
fontSize: 14,
),
).paddingAll(15)
] else ...[
if (AppState().currentAppType == AppType.provider) ...[
Expanded(
flex: 1,
child: const Icon(
Icons.local_offer_rounded,
color: MyColors.darkPrimaryColor,
size: 30,
).onPress(
() async {
buildSendOfferBottomSheet(context);
},
),
),
],
Expanded(
flex: 8,
child: TxtField(
value: chatVM.chatMessageText,
hint: LocaleKeys.typeMessageHere.tr(),
keyboardType: TextInputType.text,
isNeedBorder: false,
onChanged: (v) => chatVM.updateChatMessageText(v),
),
),
10.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (chatTypeEnum == ChatTypeEnum.requestOffer && requestVM.currentSelectedRequest!.requestStatus == RequestStatus.inProgress) ...[
Center(
child: LocaleKeys.requestAlreadyInProgress.tr().toText(
textAlign: TextAlign.center,
color: MyColors.lightTextColor,
fontSize: 14,
),
Expanded(
flex: 1,
child: const Icon(
Icons.send_rounded,
color: MyColors.darkPrimaryColor,
size: 30,
).onPress(
() async {
log("chatViewArguments.requestId:${chatViewArguments.requestId}");
final status = await chatVM.onTextMessageSend(
context: context,
receiverId: chatViewArguments.receiverId,
message: chatVM.chatMessageText,
requestId: chatViewArguments.requestId ?? 0,
offerPrice: "0.0",
chatMessageType: ChatMessageTypeEnum.freeText,
);
).paddingAll(15)
] else ...[
if (AppState().currentAppType == AppType.provider && chatTypeEnum == ChatTypeEnum.requestOffer) ...[
Expanded(
flex: 1,
child: const Icon(
Icons.local_offer_rounded,
color: MyColors.darkPrimaryColor,
size: 30,
).onPress(
() async {
buildSendOfferBottomSheet(context);
},
),
),
],
Expanded(
flex: 8,
child: TxtField(
value: chatVM.chatMessageText,
hint: LocaleKeys.typeMessageHere.tr(),
keyboardType: TextInputType.text,
isNeedBorder: false,
onChanged: (v) => chatVM.updateChatMessageText(v),
),
),
Expanded(
flex: 1,
child: const Icon(
Icons.send_rounded,
color: MyColors.darkPrimaryColor,
size: 30,
).onPress(
() async {
final status = await chatVM.onTextMessageSendForRequest(
context: context,
receiverId: chatViewArgumentsForRequest!.receiverId,
message: chatVM.chatMessageText,
requestId: chatViewArgumentsForRequest!.requestId ?? 0,
offerPrice: "0.0",
chatMessageType: ChatMessageTypeEnum.freeText,
);
if (status) {
chatVM.clearChatMessageText();
}
},
),
),
],
],
).toContainer(isShadowEnabled: true),
if (status) {
chatVM.scrollChatDown();
chatVM.clearChatMessageText();
}
},
),
),
],
);
],
).toContainer(isShadowEnabled: true),
],
);
}),
// body:
);
@ -194,7 +255,7 @@ class ChatMessageCustomWidget extends StatefulWidget {
}
class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Future buildRejectOfferBottomSheet() {
Future buildRejectOfferBottomSheet({required ChatMessageModel chatMessageModel}) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
@ -228,21 +289,55 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
);
},
),
12.height,
TxtField(
maxLines: 5,
value: chatVM.rejectOfferDescription,
errorValue: chatVM.rejectOfferDescriptionError,
keyboardType: TextInputType.text,
hint: LocaleKeys.description.tr(),
onChanged: (v) => chatVM.updateRejectOfferDescription(v),
),
if (chatVM.selectedOfferRequestCommentModel.index == chatVM.offerRejectModelList.length - 1) ...[
// comparing if the "other" is selected
12.height,
TxtField(
maxLines: 5,
value: chatVM.rejectOfferDescription,
errorValue: chatVM.rejectOfferDescriptionError,
keyboardType: TextInputType.text,
hint: LocaleKeys.description.tr(),
onChanged: (v) => chatVM.updateRejectOfferDescription(v),
),
],
],
),
25.height,
ShowFillButton(
title: LocaleKeys.submit.tr(),
onPressed: () {},
onPressed: () async {
String comments = "";
if (chatVM.selectedOfferRequestCommentModel.index == chatVM.offerRejectModelList.length - 1) //Other
{
comments = chatVM.rejectOfferDescription;
} else {
comments = chatVM.selectedOfferRequestCommentModel.title ?? "";
}
if (!chatVM.isRejectOfferButtonValidated()) {
return;
}
Navigator.pop(context);
bool status = await context.read<ChatVM>().onSendMessageForActionOnRequestOffer(
receiverId: chatMessageModel.receiverUserID ?? "",
chatMessageType: ChatMessageTypeEnum.offer,
comments: comments,
requestId: chatMessageModel.reqOffer!.requestID ?? -1,
serviceProviderID: chatMessageModel.serviceProviderID ?? 0,
requestOfferID: chatMessageModel.reqOffer!.id ?? -1,
offerPrice: chatMessageModel.reqOffer!.price.toString(),
requestOfferStatusEnum: RequestOfferStatusEnum.rejected,
context: context,
);
if (status) {
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.rejected;
setState(() {});
// Navigator.pop(context);
Utils.showToast("Offer Rejected");
// navigateReplaceWithName(context, AppRoutes.dashboard);
}
},
maxWidth: double.infinity,
),
19.height,
@ -254,6 +349,65 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
);
}
void offerAcceptConfirmationBottomSheet({required ChatMessageModel chatMessageModel}) {
return actionConfirmationBottomSheet(
context: context,
title: LocaleKeys.acceptOfferConfirmation.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: LocaleKeys.acceptOfferConfirmationMessage.tr(),
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.yes.tr(),
fontSize: 15,
onPressed: () async {
log("ServiceProviderID: ${chatMessageModel.toString()}");
Navigator.pop(context);
// int status = await context.read<ChatVM>().onActionOfferTapped(
// context: context,
// requestOfferStatusEnum: RequestOfferStatusEnum.accepted,
// reqOfferId: chatMessageModel.reqOfferID ?? -1,
// comments: GlobalConsts.acceptingThisOffer,
// );
bool status = await context.read<ChatVM>().onSendMessageForActionOnRequestOffer(
receiverId: chatMessageModel.receiverUserID ?? "",
chatMessageType: ChatMessageTypeEnum.offer,
comments: GlobalConsts.acceptingThisOffer,
requestId: chatMessageModel.reqOffer!.requestID ?? -1,
serviceProviderID: chatMessageModel.serviceProviderID ?? 0,
requestOfferID: chatMessageModel.reqOffer!.id ?? -1,
offerPrice: chatMessageModel.reqOffer!.price.toString(),
requestOfferStatusEnum: RequestOfferStatusEnum.accepted,
context: context,
);
if (status) {
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted;
setState(() {});
// Navigator.pop(context);
Utils.showToast("Offer Accepted");
// navigateReplaceWithName(context, AppRoutes.dashboard);
}
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: LocaleKeys.no.tr(),
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
Widget buildOfferDetailsInChatMessage({required ChatMessageModel chatMessageModel, required BuildContext context}) {
final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer;
@ -281,19 +435,8 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
fontSize: 9,
borderColor: MyColors.greenColor,
isFilled: false,
onPressed: () async {
int status = await context.read<ChatVM>().onActionOfferTapped(
context: context,
requestOfferStatusEnum: RequestOfferStatusEnum.accepted,
reqOfferId: chatMessageModel.reqOfferID ?? -1,
);
if (status != -1) {
if (chatMessageModel.reqOfferID == status) {
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted;
setState(() {});
}
}
onPressed: () {
offerAcceptConfirmationBottomSheet(chatMessageModel: chatMessageModel);
},
backgroundColor: MyColors.white,
txtColor: MyColors.greenColor,
@ -310,7 +453,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
txtColor: MyColors.redColor,
fontSize: 9,
onPressed: () async {
buildRejectOfferBottomSheet();
buildRejectOfferBottomSheet(chatMessageModel: chatMessageModel);
},
),
)

@ -88,7 +88,7 @@ class OfferListPage extends StatelessWidget {
),
],
).onPress(() async {
ChatViewArguments chatViewArguments = ChatViewArguments(
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer,
receiverId: "${offersModel.providerUserId}",
senderId: AppState().getUser.data!.userInfo!.userId.toString(),
@ -97,6 +97,8 @@ class OfferListPage extends StatelessWidget {
requestIndex: -1, // This will be only send in case of provider
);
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.requestOffer, chatViewArgumentsForRequest: chatViewArgumentsForRequest);
final chatVM = context.read<ChatVM>();
await chatVM

@ -124,7 +124,6 @@ class RequestItem extends StatelessWidget {
navigateWithName(context, AppRoutes.requestsDetailPage, arguments: requestDetailPageArguments);
} else {
ChatVM chatVM = context.read<ChatVM>();
await chatVM.getOffersFromProvidersByRequest(requestId: request.id, context: context);
OfferListPageArguments offerListPageArguments = OfferListPageArguments(serviceProviderOffers: chatVM.serviceProviderOffersList, requestId: request.id);
navigateWithName(context, AppRoutes.offersListPage, arguments: offerListPageArguments);

@ -5,7 +5,7 @@ import 'package:flutter/cupertino.dart';
import 'package:local_auth/local_auth.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
@ -33,7 +33,6 @@ class _LoginMethodSelectionPageState extends State<LoginMethodSelectionPage> {
Widget build(BuildContext context) {
UserVM userVM = context.read<UserVM>();
AppState appState = injector.get<AppState>();
print("current: ${appState.currentAppType}");
return Scaffold(
appBar: CustomAppBar(isRemoveBackButton: true, title: LocaleKeys.log_in.tr()),
body: Container(

@ -49,10 +49,10 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
userVM = Provider.of(context, listen: false);
context.read<UserVM>().getAvailBio();
if (AppState().currentAppType == AppType.provider) {
// phoneNum = "966530896018";
// password = "Amir@1234";
phoneNum = "966569755630";
password = "Amir12345@";
phoneNum = "966530896018";
password = "Amir@1234";
// phoneNum = "966569755630";
// password = "Amir12345@";
}
getCountryList();

@ -1,4 +1,4 @@
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -33,6 +34,7 @@ class TxtField extends StatelessWidget {
bool isBackgroundEnabled = false;
Widget? postfixWidget;
Widget? preFixWidget;
bool numbersOnly;
TxtField({
Key? key,
@ -61,6 +63,7 @@ class TxtField extends StatelessWidget {
this.postfixWidget,
this.preFixWidget,
this.onPostFixPressed,
this.numbersOnly = false,
}) : super(key: key);
@override
@ -97,6 +100,7 @@ class TxtField extends StatelessWidget {
obscureText: isPasswordEnabled ?? false,
onChanged: onChanged,
onSubmitted: onSubmitted,
inputFormatters: numbersOnly ? <TextInputFormatter>[FilteringTextInputFormatter.allow(RegExp('[0-9]'))] : [],
decoration: InputDecoration(
labelText: lable,
alignLabelWithHint: true,

@ -41,16 +41,24 @@ dependencies:
signalr_core: ^1.1.1
logging: ^1.2.0
percent_indicator: ^4.2.3
change_app_package_name: ^1.3.0
# Firebase Packages
firebase_messaging: ^15.0.4
firebase_core: ^3.3.0
flutter_local_notifications: ^17.2.1+2
# google
google_maps_flutter: ^2.1.1
geolocator: any
# geocoding: ^2.1.0
# geocoding: ^2.1.0
geocoding: ^3.0.0
# Auth
# Auth
local_auth: ^2.2.0
huawei_fido: ^6.3.0+305

Loading…
Cancel
Save