Compare commits
127 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
bf32a2baf2 | 1 year ago |
|
|
cbffe18384 | 1 year ago |
|
|
e1a97cc5a7 | 1 year ago |
|
|
d581bbd3ab | 1 year ago |
|
|
933c15188f | 1 year ago |
|
|
ba62c5782f | 1 year ago |
|
|
f459cb0610 | 1 year ago |
|
|
a36a702117 | 1 year ago |
|
|
e829e4b316 | 1 year ago |
|
|
f5ed622dd8 | 1 year ago |
|
|
a4be87fee0 | 1 year ago |
|
|
4218973a53 | 1 year ago |
|
|
ed4b565d62 | 1 year ago |
|
|
a71e17baed | 1 year ago |
|
|
b666876927 | 1 year ago |
|
|
8a2f2fbdb6 | 1 year ago |
|
|
f9584c14cc | 1 year ago |
|
|
0b63e00a14 | 1 year ago |
|
|
d2a2fd1f8e | 1 year ago |
|
|
957407a7ab | 1 year ago |
|
|
79a3737c03 | 1 year ago |
|
|
015f1483a5 | 1 year ago |
|
|
062cd4db2f | 1 year ago |
|
|
10f4803781 | 1 year ago |
|
|
275b64fb3b | 1 year ago |
|
|
fddfabe2b2 | 1 year ago |
|
|
28d96b3427 | 1 year ago |
|
|
d82d2e37f1 | 1 year ago |
|
|
bbf4a549e5 | 1 year ago |
|
|
6af484ebc9 | 1 year ago |
|
|
3fe34a6c0f | 1 year ago |
|
|
39d1b75fb2 | 1 year ago |
|
|
b6e1a6e95c | 1 year ago |
|
|
e2a1ee7f58 | 1 year ago |
|
|
4370f36ab2 | 1 year ago |
|
|
df25461575 | 1 year ago |
|
|
b3966b83ce | 1 year ago |
|
|
1d8a19472c | 1 year ago |
|
|
5654434fe2 | 1 year ago |
|
|
45443cf8c3 | 1 year ago |
|
|
1a7705bdac | 1 year ago |
|
|
e671565d04 | 1 year ago |
|
|
5f8422d68c | 1 year ago |
|
|
56673db6bc | 1 year ago |
|
|
0a8b1c2281 | 1 year ago |
|
|
77b8be6f20 | 1 year ago |
|
|
eec6420064 | 1 year ago |
|
|
5f3c12fcb0 | 1 year ago |
|
|
b00624c406 | 1 year ago |
|
|
9bfb4cb6a3 | 1 year ago |
|
|
b6e75da894 | 1 year ago |
|
|
ad8e0501f1 | 2 years ago |
|
|
55028d60c5 | 2 years ago |
|
|
44a7f0ab72 | 2 years ago |
|
|
7f9d9dba71 | 2 years ago |
|
|
fcc4f0ada0 | 2 years ago |
|
|
6235fd2a09 | 2 years ago |
|
|
f769b440e9 | 2 years ago |
|
|
2ac8099825 | 2 years ago |
|
|
bc71201dfd | 2 years ago |
|
|
7c8211b85c | 2 years ago |
|
|
931d5acb6f | 2 years ago |
|
|
6f527b7e8f | 2 years ago |
|
|
91ea03c834 | 2 years ago |
|
|
2f9c07c6d8 | 2 years ago |
|
|
360048c3bf | 2 years ago |
|
|
b2a597bac7 | 2 years ago |
|
|
eeec5aeb85 | 2 years ago |
|
|
d962424650 | 2 years ago |
|
|
87546dfec9 | 2 years ago |
|
|
6ed7e2fa3d | 2 years ago |
|
|
ea9c8ae346 | 2 years ago |
|
|
82a5af9170 | 2 years ago |
|
|
fdf432f30d | 2 years ago |
|
|
3ffbc85b46 | 2 years ago |
|
|
71030bf0fa | 2 years ago |
|
|
0b953bbe7d | 2 years ago |
|
|
e2de476581 | 2 years ago |
|
|
27fb9a2eab | 2 years ago |
|
|
42eca4c26f | 2 years ago |
|
|
67c7c485d9 | 2 years ago |
|
|
fb7dbe95cf | 2 years ago |
|
|
b5ce0a4b09 | 2 years ago |
|
|
4adc6bb5c2 | 2 years ago |
|
|
cd3699a510 | 2 years ago |
|
|
a8a7a87108 | 2 years ago |
|
|
08f6c55a10 | 2 years ago |
|
|
e79ad123fd | 2 years ago |
|
|
2b640c5624 | 2 years ago |
|
|
c7953189e3 | 2 years ago |
|
|
f510711768 | 2 years ago |
|
|
8fbd859005 | 2 years ago |
|
|
37ce6494dd | 2 years ago |
|
|
657d3bbd6a | 2 years ago |
|
|
711be7f5da | 2 years ago |
|
|
39d2add60f | 2 years ago |
|
|
13100cafce | 2 years ago |
|
|
a47cae92f2 | 2 years ago |
|
|
54fd8736c7 | 2 years ago |
|
|
9638deea3d | 2 years ago |
|
|
937a1db5d9 | 2 years ago |
|
|
2dd1952b20 | 2 years ago |
|
|
120dc86309 | 2 years ago |
|
|
7163c6c1ba | 2 years ago |
|
|
5bc5ca8954 | 2 years ago |
|
|
1c78b0e134 | 2 years ago |
|
|
fa35392611 | 2 years ago |
|
|
045ccc6f70 | 3 years ago |
|
|
ce9aab8db7 | 3 years ago |
|
|
e6c6c127f0 | 3 years ago |
|
|
533952e14e | 3 years ago |
|
|
436befd111 | 3 years ago |
|
|
83287f3b37 | 3 years ago |
|
|
f0130d189a | 3 years ago |
|
|
ab723b4b97 | 3 years ago |
|
|
8bc13dff34 | 3 years ago |
|
|
9499c902a8 | 3 years ago |
|
|
694567653a | 3 years ago |
|
|
e39c697ed0 | 3 years ago |
|
|
86c9419484 | 3 years ago |
|
|
0c9d4dfa7d | 3 years ago |
|
|
274e407fa9 | 3 years ago |
|
|
3f0178e1cd | 3 years ago |
|
|
4ccbf361fe | 3 years ago |
|
|
3390112aa3 | 3 years ago |
|
|
50baaacb74 | 3 years ago |
|
|
237911d711 | 3 years ago |
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "294636898500",
|
||||||
|
"project_id": "mowater-2c81a",
|
||||||
|
"storage_bucket": "mowater-2c81a.appspot.com"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:294636898500:android:f2f4ae08e5641216b0e191",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.cloud.solutions.mowater.ksa.customer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyD1WNNGrbBiCNvCrI31d3DV5AOgToq-Lus"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:294636898500:android:e93b7e5d1cc15ae6b0e191",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.cloud.solutions.mowater.ksa.provider"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyD1WNNGrbBiCNvCrI31d3DV5AOgToq-Lus"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.example.car_customer_app
|
package com.cloud.solutions.mowater.ksa.customer
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@ -1,3 +1,3 @@
|
|||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx4608m
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
|||||||
@ -1,11 +1,26 @@
|
|||||||
include ':app'
|
pluginManagement {
|
||||||
|
def flutterSdkPath = {
|
||||||
|
def properties = new Properties()
|
||||||
|
file("local.properties").withInputStream { properties.load(it) }
|
||||||
|
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||||
|
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||||
|
return flutterSdkPath
|
||||||
|
}()
|
||||||
|
|
||||||
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||||
def properties = new Properties()
|
|
||||||
|
|
||||||
assert localPropertiesFile.exists()
|
repositories {
|
||||||
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
plugins {
|
||||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
id "com.android.application" version '8.7.0' apply false
|
||||||
|
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
include ":app"
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>API_KEY</key>
|
||||||
|
<string>AIzaSyAQoUIOm-5FtUqUngK0zvkkF2fafRxsm_I</string>
|
||||||
|
<key>GCM_SENDER_ID</key>
|
||||||
|
<string>294636898500</string>
|
||||||
|
<key>PLIST_VERSION</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>BUNDLE_ID</key>
|
||||||
|
<string>com.cloud.solutions.mowater.ksa.customer.ios</string>
|
||||||
|
<key>PROJECT_ID</key>
|
||||||
|
<string>mowater-2c81a</string>
|
||||||
|
<key>STORAGE_BUCKET</key>
|
||||||
|
<string>mowater-2c81a.appspot.com</string>
|
||||||
|
<key>IS_ADS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_ANALYTICS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_APPINVITE_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_GCM_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_SIGNIN_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>GOOGLE_APP_ID</key>
|
||||||
|
<string>1:294636898500:ios:b47422d0ef4ca385b0e191</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import 'package:mc_common_app/config/dependencies.dart';
|
|
||||||
|
import 'package:mc_common_app/config/dependency_injection.dart';
|
||||||
|
|
||||||
class CustomerDependencies {
|
class CustomerDependencies {
|
||||||
static void addDependencies() {
|
static void addDependencies() {
|
||||||
AppDependencies.addDependencies();
|
AppDependencies.addDependencies();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,37 @@
|
|||||||
import 'package:car_customer_app/views/appointments/appointment_detail_view.dart';
|
import 'package:car_customer_app/views/branches/branch_detail_view.dart';
|
||||||
import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart';
|
import 'package:car_customer_app/views/branches/favourite_list_view.dart';
|
||||||
import 'package:car_customer_app/views/appointments/pick_items_view.dart';
|
import 'package:car_customer_app/views/branches/provider_profile_view.dart';
|
||||||
import 'package:car_customer_app/views/dashboard/dashboard_page.dart';
|
import 'package:mc_common_app/utils/enums.dart';
|
||||||
|
import 'package:mc_common_app/views/appointments/appointment_detail_view.dart';
|
||||||
|
import 'package:mc_common_app/views/appointments/book_appointment_schedules_view.dart';
|
||||||
|
import 'package:mc_common_app/views/appointments/book_appointment_services_view.dart';
|
||||||
|
import 'package:mc_common_app/views/appointments/book_appointments_item_view.dart';
|
||||||
|
import 'package:mc_common_app/views/appointments/review_appointment_view.dart';
|
||||||
|
import 'package:car_customer_app/views/dashboard/dashboard_view.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:mc_common_app/config/routes.dart';
|
import 'package:mc_common_app/config/routes.dart';
|
||||||
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
|
|
||||||
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
||||||
import 'package:mc_common_app/views/advertisement/ads_detail_view.dart';
|
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
|
||||||
import 'package:mc_common_app/views/advertisement/create_ad_view.dart';
|
import 'package:mc_common_app/views/branches/branches_filter_view.dart';
|
||||||
import 'package:mc_common_app/views/payments/payment_methods_view.dart';
|
import 'package:mc_common_app/views/appointments/appointments_filter_view.dart';
|
||||||
|
|
||||||
class CustomerAppRoutes {
|
class CustomerAppRoutes {
|
||||||
static final Map<String, WidgetBuilder> routes = {
|
static final Map<String, WidgetBuilder> routes = {
|
||||||
AppRoutes.dashboard: (context) => DashboardPage(),
|
AppRoutes.dashboard: (context) => DashboardView(dashboardRouteEnum: (ModalRoute.of(context)!.settings.arguments ?? DashboardRouteEnum.none) as DashboardRouteEnum),
|
||||||
AppRoutes.bookProviderAppView: (context) => BookProviderAppView(),
|
|
||||||
AppRoutes.appointmentDetailView: (context) => AppointmentDetailView(appointmentListModel: ModalRoute.of(context)!.settings.arguments as AppointmentListModel),
|
AppRoutes.appointmentDetailView: (context) => AppointmentDetailView(appointmentListModel: ModalRoute.of(context)!.settings.arguments as AppointmentListModel),
|
||||||
AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel),
|
|
||||||
AppRoutes.createAdView: (context) => CreateAdView(),
|
|
||||||
AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(),
|
AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(),
|
||||||
AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(),
|
AppRoutes.bookAppointmenSchedulesView: (context) => BookAppointmentSchedulesView(
|
||||||
|
screenArgumentsForAppointmentDetailPage: ModalRoute.of(context)!.settings.arguments as ScreenArgumentsForAppointmentDetailPage,
|
||||||
|
),
|
||||||
|
AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(),
|
||||||
|
AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(),
|
||||||
|
AppRoutes.branchDetailView: (context) => BranchDetailView(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel),
|
||||||
|
AppRoutes.branchSearchFilterPage: (context) => BranchesFilterView(),
|
||||||
|
AppRoutes.appoinmentSearchFilterPage: (context) => AppointmentsFilterView(),
|
||||||
|
AppRoutes.providerProfileView: (context) => ProviderProfileView(providerId: ModalRoute.of(context)!.settings.arguments as int),
|
||||||
|
AppRoutes.favoriteListView: (context) => FavoriteListView(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//314187
|
||||||
@ -1,102 +0,0 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
|
||||||
import 'package:mc_common_app/models/provider_category_model.dart';
|
|
||||||
import 'package:mc_common_app/models/provider_service_model.dart';
|
|
||||||
import 'package:mc_common_app/models/widgets_models.dart';
|
|
||||||
import 'package:mc_common_app/repositories/common_repo.dart';
|
|
||||||
import 'package:mc_common_app/services/common_services.dart';
|
|
||||||
|
|
||||||
class AppointmentsVM extends ChangeNotifier {
|
|
||||||
final CommonRepo commonRepo;
|
|
||||||
final CommonAppServices commonServices;
|
|
||||||
|
|
||||||
AppointmentsVM({required this.commonServices, required this.commonRepo});
|
|
||||||
|
|
||||||
bool isFetchingLists = false;
|
|
||||||
|
|
||||||
List<AppointmentListModel> myAppointments = [];
|
|
||||||
List<FilterListModel> appointmentsFilterOptions = [];
|
|
||||||
|
|
||||||
bool isFetchingServices = false;
|
|
||||||
|
|
||||||
List<ProviderCategoryModel> providerCategories = [];
|
|
||||||
|
|
||||||
bool isHomeTapped = false;
|
|
||||||
|
|
||||||
void updateIsHomeTapped(bool value) {
|
|
||||||
isHomeTapped = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
String pickedHomeLocation = "";
|
|
||||||
|
|
||||||
void updatePickedHomeLocation(String value) {
|
|
||||||
pickedHomeLocation = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectionModel providerCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
|
||||||
|
|
||||||
void updateProviderCategoryId(SelectionModel id) async {
|
|
||||||
providerCategoryId = id;
|
|
||||||
await getProviderServices(id.selectedId);
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ProviderServiceModel> providerServices = [];
|
|
||||||
|
|
||||||
SelectionModel providerServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
|
||||||
|
|
||||||
void updateProviderServiceId(SelectionModel id) async {
|
|
||||||
providerServiceId = id;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void getProviderCategories() async {
|
|
||||||
notifyListeners();
|
|
||||||
providerCategories = await commonRepo.getProviderServiceCategories();
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
getProviderServices(int categoryId) async {
|
|
||||||
providerServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
|
||||||
isHomeTapped = false;
|
|
||||||
pickedHomeLocation = "";
|
|
||||||
if (categoryId != -1) {
|
|
||||||
isFetchingServices = true;
|
|
||||||
notifyListeners();
|
|
||||||
providerServices = await commonRepo.getProviderServices(categoryId: categoryId);
|
|
||||||
isFetchingServices = false;
|
|
||||||
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
populateAppointmentsFilterList() {
|
|
||||||
appointmentsFilterOptions.clear();
|
|
||||||
appointmentsFilterOptions = [
|
|
||||||
FilterListModel(title: "All Appointments", isSelected: true, id: -1),
|
|
||||||
FilterListModel(title: "Booked", isSelected: false, id: 1),
|
|
||||||
FilterListModel(title: "Confirmed", isSelected: false, id: 2),
|
|
||||||
FilterListModel(title: "Arrived", isSelected: false, id: 3),
|
|
||||||
FilterListModel(title: "Cancelled", isSelected: false, id: 4),
|
|
||||||
];
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
applyFilterOnAppointmentsVM({required int index}) {
|
|
||||||
if (appointmentsFilterOptions.isEmpty) return;
|
|
||||||
for (var value in appointmentsFilterOptions) {
|
|
||||||
value.isSelected = false;
|
|
||||||
}
|
|
||||||
appointmentsFilterOptions[index].isSelected = true;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> getMyAppointments() async {
|
|
||||||
isFetchingLists = true;
|
|
||||||
myAppointments = await commonRepo.getMyAppointments();
|
|
||||||
isFetchingLists = false;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
import 'dart:io';
|
|
||||||
import 'package:mc_common_app/classes/app_state.dart';
|
|
||||||
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
|
||||||
import 'package:mc_common_app/models/user/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/utils/utils.dart';
|
|
||||||
import 'package:mc_common_app/view_models/base_view_model.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
|
|
||||||
class DashboardVM extends BaseVM {
|
|
||||||
final CommonAppServices commonServices;
|
|
||||||
final UserRepo userRepo;
|
|
||||||
|
|
||||||
DashboardVM({required this.commonServices, required this.userRepo});
|
|
||||||
|
|
||||||
String pickedImage = "";
|
|
||||||
|
|
||||||
int selectedNavbarBarIndex = 2;
|
|
||||||
|
|
||||||
void onNavbarTapped(int index) {
|
|
||||||
selectedNavbarBarIndex = index;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pickImageFromPhone(BuildContext context, int sourceFlag) async {
|
|
||||||
final File? pickedImageFile = await commonServices.pickImageFromPhone(sourceFlag);
|
|
||||||
if (pickedImageFile == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int sizeInBytes = pickedImageFile.lengthSync();
|
|
||||||
if (sizeInBytes > 1000) {
|
|
||||||
Utils.showToast(LocaleKeys.fileLarger.tr());
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
String image64 = Utils.convertFileToBase64(pickedImageFile);
|
|
||||||
|
|
||||||
Utils.showLoading(context);
|
|
||||||
ImageResponse response = await userRepo.updateUserImage(image64);
|
|
||||||
Utils.hideLoading(context);
|
|
||||||
Navigator.pop(context);
|
|
||||||
if (response.messageStatus == 1) {
|
|
||||||
Utils.showToast(LocaleKeys.imageUploaded.tr());
|
|
||||||
AppState().getUser.data!.userInfo!.userImageUrl = response.data;
|
|
||||||
} else {
|
|
||||||
Utils.showToast(response.message ?? "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ImageResponse> updateUserImage(String image) async {
|
|
||||||
return await userRepo.updateUserImage(image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:mc_common_app/models/widgets_models.dart';
|
|
||||||
import 'package:mc_common_app/repositories/common_repo.dart';
|
|
||||||
import 'package:mc_common_app/services/common_services.dart';
|
|
||||||
|
|
||||||
class ProvidersVM extends ChangeNotifier {
|
|
||||||
final CommonRepo commonRepo;
|
|
||||||
final CommonAppServices commonServices;
|
|
||||||
|
|
||||||
ProvidersVM({required this.commonServices, required this.commonRepo});
|
|
||||||
|
|
||||||
List<FilterListModel> providersFilterOptions = [];
|
|
||||||
|
|
||||||
populateProvidersFilterList() {
|
|
||||||
providersFilterOptions.clear();
|
|
||||||
providersFilterOptions = [
|
|
||||||
FilterListModel(title: "All Providers", isSelected: true, id: -1),
|
|
||||||
FilterListModel(title: "Maintenance", isSelected: false, id: 0),
|
|
||||||
FilterListModel(title: "Oil Service", isSelected: false, id: 1),
|
|
||||||
FilterListModel(title: "Accessories", isSelected: false, id: 2),
|
|
||||||
FilterListModel(title: "Tire Service", isSelected: false, id: 3),
|
|
||||||
FilterListModel(title: "Dent and Paint", isSelected: false, id: 4),
|
|
||||||
];
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
applyFilterOnProviders({required int index}) {
|
|
||||||
if (providersFilterOptions.isEmpty) return;
|
|
||||||
for (var value in providersFilterOptions) {
|
|
||||||
value.isSelected = false;
|
|
||||||
}
|
|
||||||
providersFilterOptions[index].isSelected = true;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:mc_common_app/classes/consts.dart';
|
|
||||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
|
||||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
|
||||||
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
|
||||||
import 'package:mc_common_app/theme/colors.dart';
|
|
||||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
|
||||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
|
||||||
import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.dart';
|
|
||||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
|
||||||
|
|
||||||
class AppointmentDetailView extends StatelessWidget {
|
|
||||||
AppointmentListModel appointmentListModel;
|
|
||||||
|
|
||||||
AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key);
|
|
||||||
|
|
||||||
final List<String> servicesList = [
|
|
||||||
"Mechanic",
|
|
||||||
"Electrician",
|
|
||||||
" Car Denting",
|
|
||||||
"Oil Change",
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: CustomAppBar(
|
|
||||||
title: "Appointment",
|
|
||||||
profileImageUrl: MyAssets.bnCar,
|
|
||||||
isRemoveBackButton: false,
|
|
||||||
isDrawerEnabled: false,
|
|
||||||
),
|
|
||||||
body: Container(
|
|
||||||
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
appointmentListModel.providerName!.toText(fontSize: 18, isBold: true),
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
MyAssets.miniClockDark.buildSvg(
|
|
||||||
height: 10,
|
|
||||||
width: 10,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
10.width,
|
|
||||||
"${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
13.height,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
MyAssets.maintenanceIcon.buildSvg(
|
|
||||||
height: 10,
|
|
||||||
width: 10,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
10.width,
|
|
||||||
"Maintenance".toText(fontSize: 18, isBold: true),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
children: servicesList
|
|
||||||
.map((e) => e
|
|
||||||
.toText(
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
fontSize: 13,
|
|
||||||
isBold: true,
|
|
||||||
color: MyColors.lightTextColor,
|
|
||||||
)
|
|
||||||
.paddingOnly(bottom: 5))
|
|
||||||
.toList(),
|
|
||||||
).paddingOnly(left: 15),
|
|
||||||
15.height,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
CardButtonWithIcon(
|
|
||||||
title: "Reschedule Appointment",
|
|
||||||
onCardTapped: () {},
|
|
||||||
icon: MyAssets.scheduleAppointmentIcon.buildSvg(),
|
|
||||||
),
|
|
||||||
10.width,
|
|
||||||
CardButtonWithIcon(
|
|
||||||
title: "Pay for Appointment",
|
|
||||||
onCardTapped: () {},
|
|
||||||
icon: MyAssets.creditCardIcon.buildSvg(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
15.height,
|
|
||||||
],
|
|
||||||
).toWhiteContainer(width: double.infinity, allPading: 12),
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ShowFillButton(
|
|
||||||
maxHeight: 55,
|
|
||||||
title: "Cancel",
|
|
||||||
onPressed: () {},
|
|
||||||
backgroundColor: MyColors.redColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (appointmentListModel.appointmentStatusID == 1) ...[
|
|
||||||
12.width,
|
|
||||||
Expanded(
|
|
||||||
child: ShowFillButton(
|
|
||||||
maxHeight: 55,
|
|
||||||
title: "Confirm",
|
|
||||||
onPressed: () {},
|
|
||||||
backgroundColor: MyColors.greenColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,325 +0,0 @@
|
|||||||
import 'package:car_customer_app/view_models/appointments_view_model.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:mc_common_app/classes/consts.dart';
|
|
||||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
|
||||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
|
||||||
import 'package:mc_common_app/models/widgets_models.dart';
|
|
||||||
import 'package:mc_common_app/theme/colors.dart';
|
|
||||||
import 'package:mc_common_app/views/advertisement/custom_add_button.dart';
|
|
||||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
|
||||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
|
||||||
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
|
|
||||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
|
||||||
import 'package:mc_common_app/widgets/txt_field.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class BookAppointmentServicesView extends StatelessWidget {
|
|
||||||
const BookAppointmentServicesView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
void openTheAddServiceBottomSheet(BuildContext context) {
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
isScrollControlled: true,
|
|
||||||
enableDrag: true,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
AppointmentsVM appointmentsVM = context.watch<AppointmentsVM>();
|
|
||||||
return SizedBox(
|
|
||||||
height: MediaQuery.of(context).size.height * 0.85,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
margin: const EdgeInsets.all(8),
|
|
||||||
height: 8,
|
|
||||||
width: 60,
|
|
||||||
decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))),
|
|
||||||
),
|
|
||||||
12.height,
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
"Select Category".toText(fontSize: 24, isBold: true),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
30.height,
|
|
||||||
Expanded(
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
List<DropValue> serviceCategories = [];
|
|
||||||
for (var element in appointmentsVM.providerCategories) {
|
|
||||||
if (!element.isSelected!) {
|
|
||||||
serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.categoryName ?? "", ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DropdownField(
|
|
||||||
(DropValue value) => appointmentsVM.updateProviderCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
|
|
||||||
list: serviceCategories,
|
|
||||||
hint: "Select Category",
|
|
||||||
dropdownValue: appointmentsVM.providerCategoryId.selectedId != -1
|
|
||||||
? DropValue(appointmentsVM.providerCategoryId.selectedId, appointmentsVM.providerCategoryId.selectedOption, "")
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (appointmentsVM.isFetchingServices) ...[
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [const CircularProgressIndicator().paddingAll(10)],
|
|
||||||
),
|
|
||||||
] else if (appointmentsVM.providerServices.isNotEmpty) ...[
|
|
||||||
8.height,
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
List<DropValue> serviceCategories = [];
|
|
||||||
for (var element in appointmentsVM.providerServices) {
|
|
||||||
if (!element.isSelected!) {
|
|
||||||
serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.id.toString(), ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DropdownField(
|
|
||||||
(DropValue value) => appointmentsVM.updateProviderServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
|
|
||||||
list: serviceCategories,
|
|
||||||
hint: "Select Services",
|
|
||||||
dropdownValue: appointmentsVM.providerServiceId.selectedId != -1
|
|
||||||
? DropValue(appointmentsVM.providerServiceId.selectedId, appointmentsVM.providerServiceId.selectedOption, "")
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
if (appointmentsVM.providerServiceId.selectedId != -1 && !appointmentsVM.isFetchingServices) ...[
|
|
||||||
16.height,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
"Select Service Location".toText(
|
|
||||||
fontSize: 16,
|
|
||||||
isBold: true,
|
|
||||||
color: MyColors.black,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
8.height,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ShowFillButton(
|
|
||||||
isFilled: appointmentsVM.isHomeTapped,
|
|
||||||
maxHeight: 48,
|
|
||||||
title: "Home",
|
|
||||||
txtColor: appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor,
|
|
||||||
onPressed: () => appointmentsVM.updateIsHomeTapped(true),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
12.width,
|
|
||||||
Expanded(
|
|
||||||
child: ShowFillButton(
|
|
||||||
isFilled: !appointmentsVM.isHomeTapped,
|
|
||||||
txtColor: !appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor,
|
|
||||||
maxHeight: 48,
|
|
||||||
title: "Workshop",
|
|
||||||
onPressed: () => appointmentsVM.updateIsHomeTapped(false),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (appointmentsVM.isHomeTapped) ...[
|
|
||||||
8.height,
|
|
||||||
TxtField(
|
|
||||||
hint: 'Pick Home Location',
|
|
||||||
value: appointmentsVM.pickedHomeLocation,
|
|
||||||
isNeedClickAll: true,
|
|
||||||
postfixData: Icons.location_on,
|
|
||||||
postFixDataColor: MyColors.darkTextColor,
|
|
||||||
onTap: () {
|
|
||||||
//TODO: open the place picked to pick the location and save it in provider.
|
|
||||||
appointmentsVM.updatePickedHomeLocation("PM58+F97, Al Olaya, Riyadh 12333");
|
|
||||||
},
|
|
||||||
),
|
|
||||||
14.height,
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.warning,
|
|
||||||
color: MyColors.adPendingStatusColor,
|
|
||||||
size: 19,
|
|
||||||
).paddingOnly(bottom: 2),
|
|
||||||
3.width,
|
|
||||||
"Some services are not available on home location.".toText(
|
|
||||||
color: MyColors.adPendingStatusColor,
|
|
||||||
fontSize: 12,
|
|
||||||
isItalic: true,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
if (appointmentsVM.isHomeTapped && !appointmentsVM.isFetchingServices) ...[
|
|
||||||
const Divider(thickness: 1, height: 1),
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
// TODO: This Price will be decided according to the service selected
|
|
||||||
150.toString().toText(fontSize: 30, isBold: true),
|
|
||||||
"SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
"These charges are additional to the actual service charges. For heavy items the charges may vary.".toText(fontSize: 12, color: MyColors.lightTextColor),
|
|
||||||
22.height,
|
|
||||||
],
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: ShowFillButton(
|
|
||||||
maxHeight: 55,
|
|
||||||
title: "Next",
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
).paddingOnly(bottom: 20)
|
|
||||||
],
|
|
||||||
)).horPaddingMain();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: CustomAppBar(
|
|
||||||
title: "Book Appointment",
|
|
||||||
isRemoveBackButton: false,
|
|
||||||
isDrawerEnabled: false,
|
|
||||||
actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)],
|
|
||||||
onBackButtonTapped: () => Navigator.pop(context),
|
|
||||||
),
|
|
||||||
body: Consumer(
|
|
||||||
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
21.height,
|
|
||||||
CustomAddButton(
|
|
||||||
onTap: () => {openTheAddServiceBottomSheet(context)},
|
|
||||||
text: "Add Services",
|
|
||||||
icon: Container(
|
|
||||||
height: 24,
|
|
||||||
width: 24,
|
|
||||||
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
|
|
||||||
child: const Icon(Icons.add, color: MyColors.white),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 20.height,
|
|
||||||
// ListView.builder(
|
|
||||||
// physics: const NeverScrollableScrollPhysics(),
|
|
||||||
// shrinkWrap: true,
|
|
||||||
// itemCount: adVM.specialServiceCards.length,
|
|
||||||
// itemBuilder: (BuildContext context, int index) {
|
|
||||||
// SpecialServiceCard specialServicesCard = adVM.specialServiceCards[index];
|
|
||||||
// return Column(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Column(
|
|
||||||
// children: [
|
|
||||||
// Row(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
// children: [
|
|
||||||
// Expanded(
|
|
||||||
// child: specialServicesCard.serviceSelectedId!.selectedOption.toText(fontSize: 16, isBold: true),
|
|
||||||
// ),
|
|
||||||
// Align(
|
|
||||||
// alignment: Alignment.topRight,
|
|
||||||
// child: MyAssets.closeWithOrangeBg.buildSvg(
|
|
||||||
// fit: BoxFit.fill,
|
|
||||||
// height: 30,
|
|
||||||
// width: 30,
|
|
||||||
// ),
|
|
||||||
// ).onPress(() => adVM.removeSpecialServiceCard(index))
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// Builder(builder: (context) {
|
|
||||||
// return Column(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// if (specialServicesCard.serviceSelectedId!.selectedId != 1 && specialServicesCard.serviceSelectedId!.selectedId != 3) ...[
|
|
||||||
// // Row(
|
|
||||||
// // crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// // children: [
|
|
||||||
// // "Duration: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
|
||||||
// // (specialServicesCard.duration ?? "").toText(fontSize: 12, isBold: true).expand(),
|
|
||||||
// // ],
|
|
||||||
// // ),
|
|
||||||
// 8.height,
|
|
||||||
// Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// "Description: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
|
||||||
// (specialServicesCard.description ?? "").toText(fontSize: 12, isBold: true).expand(),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// if (specialServicesCard.serviceSelectedId!.selectedId == 1 || specialServicesCard.serviceSelectedId!.selectedId == 3) ...[
|
|
||||||
// Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// const Icon(
|
|
||||||
// weight: 2,
|
|
||||||
// Icons.location_on_outlined,
|
|
||||||
// color: MyColors.primaryColor,
|
|
||||||
// size: 17,
|
|
||||||
// ),
|
|
||||||
// "${specialServicesCard.duration} km".toText(fontSize: 10, color: MyColors.primaryColor),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// 8.height,
|
|
||||||
// Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// "Branch Address: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
|
||||||
// (specialServicesCard.address ?? "").toText(fontSize: 12, isBold: true).expand(),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// "Appointment Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
|
||||||
// "${specialServicesCard.serviceDate} - ${specialServicesCard.serviceTime}".toText(fontSize: 12, isBold: true).expand(),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// 6.height,
|
|
||||||
// Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
// children: [
|
|
||||||
// (specialServicesCard.serviceSelectedId!.itemPrice).toText(fontSize: 20, isBold: true),
|
|
||||||
// 2.width,
|
|
||||||
// "SAR".toText(color: MyColors.lightTextColor, fontSize: 14),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// }),
|
|
||||||
// 3.height,
|
|
||||||
// const Divider(thickness: 1.5)
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// 10.height,
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).horPaddingMain());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,168 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:mc_common_app/classes/consts.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';
|
|
||||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
|
||||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
|
||||||
import 'package:mc_common_app/widgets/common_widgets/provider_details_card.dart';
|
|
||||||
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
|
|
||||||
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
|
|
||||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
|
||||||
|
|
||||||
class BookProviderAppView extends StatefulWidget {
|
|
||||||
const BookProviderAppView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<BookProviderAppView> createState() => _BookProviderAppViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _BookProviderAppViewState extends State<BookProviderAppView> {
|
|
||||||
bool isReview = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: CustomAppBar(
|
|
||||||
title: "Appointment",
|
|
||||||
profileImageUrl: MyAssets.bnCar,
|
|
||||||
isRemoveBackButton: false,
|
|
||||||
isDrawerEnabled: false,
|
|
||||||
),
|
|
||||||
body: Container(
|
|
||||||
color: MyColors.backgroundColor,
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
ProviderDetailsCard(
|
|
||||||
onCardTapped: () {},
|
|
||||||
providerImageUrl: MyAssets.bnCar,
|
|
||||||
providerLocation: "3km",
|
|
||||||
providerName: "Al Ahmed Maintenance",
|
|
||||||
providerRatings: "4.9",
|
|
||||||
),
|
|
||||||
12.height,
|
|
||||||
isReview ? ReviewAppointmentSection() : ServicesSelectionSection(),
|
|
||||||
10.height,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
10.height,
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
|
|
||||||
child: ShowFillButton(
|
|
||||||
title: "Book Appointment",
|
|
||||||
maxWidth: double.infinity,
|
|
||||||
onPressed: () {
|
|
||||||
isReview = !isReview;
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ServicesSelectionSection extends StatelessWidget {
|
|
||||||
const ServicesSelectionSection({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
List<DropValue> dropList = [
|
|
||||||
DropValue(0, "Maintenance", ""),
|
|
||||||
DropValue(1, "Car Wash", ""),
|
|
||||||
DropValue(2, "Monthly Checkup", ""),
|
|
||||||
DropValue(3, "Friendly Visit", ""),
|
|
||||||
DropValue(4, "Muftaa", ""),
|
|
||||||
];
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
"Select services you want".toText(fontSize: 18, isBold: true),
|
|
||||||
8.height,
|
|
||||||
DropdownField(
|
|
||||||
(DropValue value) {},
|
|
||||||
list: dropList,
|
|
||||||
hint: "Select service type",
|
|
||||||
),
|
|
||||||
8.height,
|
|
||||||
DropdownField(
|
|
||||||
(DropValue value) {},
|
|
||||||
list: dropList,
|
|
||||||
hint: "Select service type",
|
|
||||||
),
|
|
||||||
8.height,
|
|
||||||
DropdownField(
|
|
||||||
(DropValue value) {},
|
|
||||||
list: dropList,
|
|
||||||
hint: "Select service type",
|
|
||||||
),
|
|
||||||
22.height,
|
|
||||||
"Select date and time".toText(fontSize: 18, isBold: true),
|
|
||||||
8.height,
|
|
||||||
DropdownField(
|
|
||||||
(DropValue value) {},
|
|
||||||
list: dropList,
|
|
||||||
hint: "Select service type",
|
|
||||||
),
|
|
||||||
22.height,
|
|
||||||
"Available slots".toText(fontSize: 15, isBold: true),
|
|
||||||
8.height,
|
|
||||||
BuildTimeSlots(onPressed: (index) {}, timeSlots: []),
|
|
||||||
22.height,
|
|
||||||
"Total Amount".toText(fontSize: 18, isBold: true),
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
"3000".toText(fontSize: 20, isBold: true),
|
|
||||||
"SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
10.height,
|
|
||||||
],
|
|
||||||
).toWhiteContainer(width: double.infinity, allPading: 12),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ReviewAppointmentSection extends StatelessWidget {
|
|
||||||
const ReviewAppointmentSection({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
"Review Appointment".toText(fontSize: 18, isBold: true),
|
|
||||||
15.height,
|
|
||||||
"Services".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
|
||||||
"Car Engine Check".toText(fontSize: 18, isBold: true),
|
|
||||||
13.height,
|
|
||||||
"Date and Time".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
|
||||||
"2 Feb, 2023 at 09:00am".toText(fontSize: 18, isBold: true),
|
|
||||||
13.height,
|
|
||||||
"Total Amount".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
"3000".toText(fontSize: 20, isBold: true),
|
|
||||||
"SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
100.height,
|
|
||||||
],
|
|
||||||
).toWhiteContainer(width: double.infinity, allPading: 12),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,199 +0,0 @@
|
|||||||
import 'package:carousel_slider/carousel_slider.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:mc_common_app/classes/consts.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';
|
|
||||||
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
|
||||||
import 'package:mc_common_app/theme/colors.dart';
|
|
||||||
import 'package:mc_common_app/utils/navigator.dart';
|
|
||||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
|
||||||
|
|
||||||
class CustomerAppointmentSliderWidget extends StatelessWidget {
|
|
||||||
final List<AppointmentListModel> myUpComingAppointments;
|
|
||||||
|
|
||||||
const CustomerAppointmentSliderWidget({Key? key, required this.myUpComingAppointments}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (myUpComingAppointments.isEmpty) {
|
|
||||||
return InkWell(
|
|
||||||
child: Container(
|
|
||||||
height: 86,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
height: 24,
|
|
||||||
width: 24,
|
|
||||||
decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
|
|
||||||
child: Icon(
|
|
||||||
Icons.add,
|
|
||||||
color: MyColors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
"Add New Appointment".toText(
|
|
||||||
fontSize: 15,
|
|
||||||
isBold: true,
|
|
||||||
color: MyColors.lightTextColor,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
).toWhiteContainer(width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 21, vertical: 10));
|
|
||||||
}
|
|
||||||
return CarouselSlider.builder(
|
|
||||||
options: CarouselOptions(
|
|
||||||
height: 140,
|
|
||||||
viewportFraction: 1.0,
|
|
||||||
enlargeCenterPage: false,
|
|
||||||
enableInfiniteScroll: false,
|
|
||||||
),
|
|
||||||
itemCount: myUpComingAppointments.length,
|
|
||||||
itemBuilder: (BuildContext context, int itemIndex, int pageViewIndex) => BuildAppointmentContainerForCustomer(
|
|
||||||
isForHome: true,
|
|
||||||
appointmentListModel: myUpComingAppointments[itemIndex],
|
|
||||||
onTapped: () => navigateWithName(context, AppRoutes.appointmentDetailView, arguments: myUpComingAppointments[itemIndex]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BuildAppointmentContainerForCustomer extends StatelessWidget {
|
|
||||||
final bool? isForHome;
|
|
||||||
final AppointmentListModel? appointmentListModel;
|
|
||||||
final Function() onTapped;
|
|
||||||
|
|
||||||
const BuildAppointmentContainerForCustomer({Key? key, this.isForHome = false, required this.onTapped, required this.appointmentListModel}) : super(key: key);
|
|
||||||
|
|
||||||
Widget showServices(String title, String icon, {bool isMoreText = false}) {
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
if (icon != "") ...[
|
|
||||||
SvgPicture.asset(icon),
|
|
||||||
8.width,
|
|
||||||
],
|
|
||||||
Flexible(
|
|
||||||
child: title.toText(
|
|
||||||
fontSize: 12,
|
|
||||||
isBold: true,
|
|
||||||
color: isMoreText ? MyColors.primaryColor : MyColors.black,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) {
|
|
||||||
if (appointmentListModel.serviceAppointmentItems == null || appointmentListModel.serviceAppointmentItems!.isEmpty) {
|
|
||||||
return [SizedBox()];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appointmentListModel.serviceAppointmentItems!.length == 1) {
|
|
||||||
return [
|
|
||||||
showServices(
|
|
||||||
appointmentListModel.serviceAppointmentItems![0].serviceItemName!,
|
|
||||||
MyAssets.modificationsIcon,
|
|
||||||
)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> servicesList = List.generate(
|
|
||||||
2,
|
|
||||||
(index) => showServices(
|
|
||||||
appointmentListModel.serviceAppointmentItems![index].serviceItemName!,
|
|
||||||
MyAssets.modificationsIcon,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (appointmentListModel.serviceAppointmentItems!.length > 1) {
|
|
||||||
servicesList.add(
|
|
||||||
showServices(
|
|
||||||
"+ ${appointmentListModel.serviceAppointmentItems!.length - 1} More",
|
|
||||||
"",
|
|
||||||
isMoreText: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return servicesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
isForHome != null && isForHome!
|
|
||||||
? Image.asset(
|
|
||||||
MyAssets.bnCar,
|
|
||||||
width: 56,
|
|
||||||
height: 56,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
).toCircle(borderRadius: 100)
|
|
||||||
: Image.asset(
|
|
||||||
MyAssets.bnCar,
|
|
||||||
width: 80,
|
|
||||||
height: 85,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
8.width,
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
(appointmentListModel!.providerName ?? "").toText(color: MyColors.black, isBold: true, fontSize: 16),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
MyAssets.miniClock.buildSvg(height: 12),
|
|
||||||
2.width,
|
|
||||||
"${appointmentListModel!.duration ?? ""} ${appointmentListModel!.appointmentDate!.toFormattedDateWithoutTime()}".toText(
|
|
||||||
color: MyColors.lightTextColor,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
9.height,
|
|
||||||
isForHome != null && isForHome!
|
|
||||||
? Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
"Appointment Details".toText(
|
|
||||||
color: MyColors.primaryColor,
|
|
||||||
isUnderLine: true,
|
|
||||||
isBold: true,
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
const Icon(Icons.arrow_forward),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
children: buildServicesFromAppointment(appointmentListModel: appointmentListModel!),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Icon(
|
|
||||||
Icons.arrow_forward,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).onPress(onTapped).toWhiteContainer(width: double.infinity, allPading: 12),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,267 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:car_customer_app/views/branches/components/branch_reviews_widget.dart';
|
||||||
|
import 'package:car_customer_app/views/branches/components/items_list_sheet.dart';
|
||||||
|
import 'package:mc_common_app/utils/utils.dart';
|
||||||
|
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mc_common_app/classes/consts.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';
|
||||||
|
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
|
||||||
|
import 'package:mc_common_app/theme/colors.dart';
|
||||||
|
import 'package:mc_common_app/utils/navigator.dart';
|
||||||
|
import 'package:mc_common_app/views/advertisement/components/ads_images_corousel_widget.dart';
|
||||||
|
import 'package:mc_common_app/widgets/bottom_sheet.dart';
|
||||||
|
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class BranchDetailView extends StatefulWidget {
|
||||||
|
final BranchDetailModel branchDetailModel;
|
||||||
|
|
||||||
|
BranchDetailView({required this.branchDetailModel});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BranchDetailView> createState() => _BranchDetailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BranchDetailViewState extends State<BranchDetailView> {
|
||||||
|
late AppointmentsVM appointmentsVM;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
appointmentsVM = context.read<AppointmentsVM>();
|
||||||
|
super.initState();
|
||||||
|
if (widget.branchDetailModel.branchServices!.length > 0) widget.branchDetailModel.branchServices?.first.isExpandedOrSelected = true;
|
||||||
|
getBranchReviews();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getBranchReviews() async {
|
||||||
|
scheduleMicrotask(() async {
|
||||||
|
await appointmentsVM.getReviewsByBranchId(serviceProviderBranchID: widget.branchDetailModel.id!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
appointmentsVM.resetCurrentBranchRatings();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: CustomAppBar(
|
||||||
|
title: LocaleKeys.branchDetail.tr(),
|
||||||
|
actions: [
|
||||||
|
// Padding(
|
||||||
|
// padding: EdgeInsets.only(top: 8, bottom: 8, right: 21),
|
||||||
|
// child: const Icon(Icons.messenger_outline_rounded, color: Colors.black, size: 18).toContainer(
|
||||||
|
// borderRadius: 100,
|
||||||
|
// borderColor: MyColors.lightGreyEFColor,
|
||||||
|
// isEnabledBorder: true,
|
||||||
|
// ),
|
||||||
|
// ).onPress(() {})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.all(21),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ImagesCorouselWidget(imagesList: widget.branchDetailModel.branchImages ?? []),
|
||||||
|
12.height,
|
||||||
|
"${widget.branchDetailModel.branchName} | ${widget.branchDetailModel.serviceProviderName}".toString().toText(
|
||||||
|
fontSize: 16,
|
||||||
|
isBold: true,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
(LocaleKeys.location.tr() + ":").toText(color: MyColors.lightTextColor, fontSize: 12),
|
||||||
|
4.width,
|
||||||
|
(widget.branchDetailModel.distanceKm.toString() + " km").toText(fontSize: 12, isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
(LocaleKeys.time.tr() + ":").toText(color: MyColors.lightTextColor, fontSize: 12),
|
||||||
|
4.width,
|
||||||
|
Flexible(
|
||||||
|
child: "${widget.branchDetailModel.openTime} - ${widget.branchDetailModel.closeTime}".toText(fontSize: 12, isBold: true),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
2.height,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
if ((widget.branchDetailModel.latitude != null && widget.branchDetailModel.latitude!.isNotEmpty) && (widget.branchDetailModel.longitude != null && widget.branchDetailModel.longitude!.isNotEmpty)) ...[
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.openMapLocation.tr().toText(
|
||||||
|
fontSize: 12,
|
||||||
|
isBold: true,
|
||||||
|
color: MyColors.primaryColor,
|
||||||
|
isUnderLine: true,
|
||||||
|
),
|
||||||
|
4.width,
|
||||||
|
Image.asset(
|
||||||
|
MyAssets.icRightUpPng,
|
||||||
|
height: 6,
|
||||||
|
width: 6,
|
||||||
|
color: MyColors.primaryColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(EdgeInsets.symmetric(vertical: 6, horizontal: 2)).onPress(() async {
|
||||||
|
double latitude, longitude = 0.0;
|
||||||
|
|
||||||
|
latitude = double.parse(widget.branchDetailModel.latitude!);
|
||||||
|
longitude = double.parse(widget.branchDetailModel.longitude!);
|
||||||
|
await Utils.openLocationInMaps(latitude: latitude, longitude: longitude);
|
||||||
|
}),
|
||||||
|
] else ...[
|
||||||
|
SizedBox(),
|
||||||
|
],
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.providerProfile.tr().toText(
|
||||||
|
fontSize: 12,
|
||||||
|
isBold: true,
|
||||||
|
color: MyColors.primaryColor,
|
||||||
|
isUnderLine: true,
|
||||||
|
),
|
||||||
|
2.width,
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward,
|
||||||
|
size: 12,
|
||||||
|
color: MyColors.primaryColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(EdgeInsets.symmetric(vertical: 6, horizontal: 2)).onPress(() => navigateWithName(context, AppRoutes.providerProfileView, arguments: widget.branchDetailModel.serviceProviderId)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
20.height,
|
||||||
|
LocaleKeys.servicesOffer.tr().toText(
|
||||||
|
fontSize: 16,
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
isBold: true,
|
||||||
|
),
|
||||||
|
if (widget.branchDetailModel.branchServices!.length == 0)
|
||||||
|
LocaleKeys.noServicesAvailable.tr().toText(
|
||||||
|
fontSize: 12,
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
isBold: true,
|
||||||
|
),
|
||||||
|
buildServicesList(),
|
||||||
|
],
|
||||||
|
).toWhiteContainer(width: double.infinity, allPading: 12),
|
||||||
|
10.height,
|
||||||
|
BranchReviewsWidget(branchRateAvg: widget.branchDetailModel.branchRateAvg ?? 0.0),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ShowFillButton(
|
||||||
|
maxHeight: 55,
|
||||||
|
isDisabled: widget.branchDetailModel.branchServices!.length == 0,
|
||||||
|
title: LocaleKeys.bookAppointment.tr(),
|
||||||
|
margin: EdgeInsets.all(12),
|
||||||
|
maxWidth: double.infinity,
|
||||||
|
onPressed: () {
|
||||||
|
if (widget.branchDetailModel.branchServices!.length == 0) {
|
||||||
|
Utils.showToast(LocaleKeys.noServicesAvailable.tr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
navigateWithName(context, AppRoutes.bookAppointmenServicesView);
|
||||||
|
context.read<AppointmentsVM>().updateSelectedBranch(widget.branchDetailModel);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildServicesList() {
|
||||||
|
return ListView.separated(
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return ExpansionTile(
|
||||||
|
tilePadding: EdgeInsets.zero,
|
||||||
|
title: (widget.branchDetailModel.branchServices![index].serviceDescription ?? "").toText(fontSize: 16),
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
showItem(LocaleKeys.allowingHomeService.tr() + " :", (widget.branchDetailModel.branchServices![index].isAllowAppointment ?? false) ? LocaleKeys.yes.tr() : LocaleKeys.no.tr(), valueColor: Colors.green),
|
||||||
|
if ((widget.branchDetailModel.branchServices![index].isAllowAppointment ?? false)) ...[
|
||||||
|
showItem(LocaleKeys.homeServiceRange.tr() + " :", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "KM"),
|
||||||
|
showItem(LocaleKeys.chargesPerKM.tr() + " :", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + LocaleKeys.sar.tr()),
|
||||||
|
],
|
||||||
|
8.height,
|
||||||
|
((widget.branchDetailModel.branchServices![index].itemsCount != null && widget.branchDetailModel.branchServices![index].itemsCount! > 0)
|
||||||
|
? widget.branchDetailModel.branchServices![index].itemsCount.toString() + " items"
|
||||||
|
: "No" + " items")
|
||||||
|
.toText(
|
||||||
|
fontSize: 12,
|
||||||
|
isBold: true,
|
||||||
|
color: MyColors.primaryColor,
|
||||||
|
isUnderLine: true,
|
||||||
|
),
|
||||||
|
20.height,
|
||||||
|
],
|
||||||
|
).onPress(() {
|
||||||
|
if (widget.branchDetailModel.branchServices![index].itemsCount != null && widget.branchDetailModel.branchServices![index].itemsCount! > 0) {
|
||||||
|
showMyBottomSheet(context, child: ItemsListSheet(widget.branchDetailModel.branchServices![index].serviceProviderServiceId ?? 0));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
onExpansionChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
widget.branchDetailModel.branchServices![index].isExpandedOrSelected = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
collapsedBackgroundColor: Colors.transparent,
|
||||||
|
initiallyExpanded: widget.branchDetailModel.branchServices![index].isExpandedOrSelected,
|
||||||
|
trailing: widget.branchDetailModel.branchServices![index].isExpandedOrSelected ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) {
|
||||||
|
return Divider(
|
||||||
|
height: 1,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: widget.branchDetailModel.branchServices!.length,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget showItem(String item, String value, {Color valueColor = Colors.black}) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
item.toText(fontSize: 12, color: MyColors.lightTextColor),
|
||||||
|
4.width,
|
||||||
|
value.toText(fontSize: 12, color: valueColor),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,108 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
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:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mc_common_app/models/provider_branches_models/branch_review_model.dart';
|
||||||
|
import 'package:mc_common_app/theme/colors.dart';
|
||||||
|
import 'package:mc_common_app/utils/enums.dart';
|
||||||
|
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class BranchReviewsWidget extends StatelessWidget {
|
||||||
|
final double branchRateAvg;
|
||||||
|
|
||||||
|
const BranchReviewsWidget({super.key, required this.branchRateAvg});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.review.tr().toText(fontSize: 18, isBold: true, letterSpacing: 0.1),
|
||||||
|
if (branchRateAvg != 0.0) ...[
|
||||||
|
"$branchRateAvg".toString().toText(fontSize: 18, isBold: true, letterSpacing: 0.1),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
10.height,
|
||||||
|
if (appointmentsVM.state == ViewState.busy) ...[
|
||||||
|
Center(child: CircularProgressIndicator())
|
||||||
|
] else if (appointmentsVM.currentBranchReviews.isEmpty) ...[
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.noReviewsBranch.tr().toText(fontSize: 14, color: MyColors.lightTextColor),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
] else ...[
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: List.generate(
|
||||||
|
5,
|
||||||
|
(index) => MyAssets.icStar.buildSvg(
|
||||||
|
color: (index <= branchRateAvg - 1) ? MyColors.lightPrimaryColor : MyColors.lightGreyDDColor,
|
||||||
|
height: 50,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
10.height,
|
||||||
|
ListView.separated(
|
||||||
|
separatorBuilder: (context, index) => Divider(height: 1),
|
||||||
|
itemCount: !appointmentsVM.isReadMoreEnabled ? 3 : appointmentsVM.currentBranchReviews.length,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
BranchRatingModel rating = appointmentsVM.currentBranchReviews[index];
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
10.height,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
("${rating.title} - ${rating.ratNo}.0").toText(fontSize: 14, isBold: true),
|
||||||
|
MyAssets.icStar.buildSvg(color: MyColors.darkPrimaryColor, height: 13).paddingOnly(left: 5, bottom: 2),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
3.height,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 9,
|
||||||
|
child: "${rating.review}".toText(fontSize: 12, color: MyColors.lightTextColor),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: "-${rating.customerName ?? "Unknown"}".toText(fontSize: 2, color: MyColors.lightTextColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
10.height,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (appointmentsVM.isReadMoreEnabled) ...[
|
||||||
|
LocaleKeys.readLess.tr().toText(fontSize: 13, color: MyColors.darkPrimaryColor, isUnderLine: true).onPress(() {
|
||||||
|
appointmentsVM.updateIsReadMoreEnabled(false);
|
||||||
|
}),
|
||||||
|
] else ...[
|
||||||
|
LocaleKeys.readMoreReviews.tr().toText(fontSize: 13, color: MyColors.darkPrimaryColor, isUnderLine: true).onPress(() {
|
||||||
|
appointmentsVM.updateIsReadMoreEnabled(true);
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
).toWhiteContainer(
|
||||||
|
width: double.infinity,
|
||||||
|
allPading: 12,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.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';
|
||||||
|
import 'package:mc_common_app/models/services_models/item_model.dart';
|
||||||
|
import 'package:mc_common_app/theme/colors.dart';
|
||||||
|
import 'package:mc_common_app/utils/date_helper.dart';
|
||||||
|
import 'package:mc_common_app/utils/enums.dart';
|
||||||
|
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||||
|
import 'package:mc_common_app/widgets/empty_widget.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ItemsListSheet extends StatefulWidget {
|
||||||
|
final int serviceProviderServiceId;
|
||||||
|
|
||||||
|
ItemsListSheet(this.serviceProviderServiceId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ItemsListSheet> createState() => _ItemsListSheetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ItemsListSheetState extends State<ItemsListSheet> {
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
scheduleMicrotask(() {
|
||||||
|
context.read<AppointmentsVM>().getServiceItems(serviceId: widget.serviceProviderServiceId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: MediaQuery.of(context).size.height / 1.2,
|
||||||
|
child: Consumer<AppointmentsVM>(
|
||||||
|
builder: (context, appointmentsVM, _) {
|
||||||
|
if (appointmentsVM.state == ViewState.busy) {
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
return appointmentsVM.serviceItemsFromApi.isEmpty
|
||||||
|
? EmptyWidget(text: LocaleKeys.noItemsToShow.tr(), isWrappedColumn: false)
|
||||||
|
: ListView.separated(
|
||||||
|
itemCount: appointmentsVM.serviceItemsFromApi.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
ItemData serviceItemModel = appointmentsVM.serviceItemsFromApi[index];
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
serviceItemModel.name.toString().toText(fontSize: 16, isBold: true),
|
||||||
|
serviceItemModel.description.toString().toText(fontSize: 12, color: MyColors.lightTextColor),
|
||||||
|
8.height,
|
||||||
|
if (serviceItemModel.manufactureDate != null && serviceItemModel.manufactureDate!.isNotEmpty) ...[
|
||||||
|
showItem(LocaleKeys.manufacturedOn.tr() + ":", (DateHelper.formatAsDayMonthYear(DateHelper.parseStringToDate(serviceItemModel.manufactureDate!))),
|
||||||
|
valueColor: MyColors.darkTextColor),
|
||||||
|
],
|
||||||
|
showItem(LocaleKeys.availableforAppointment.tr() + ":", (serviceItemModel.isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green),
|
||||||
|
showItem(LocaleKeys.allowingWorkshopService.tr() + ":", (serviceItemModel.isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green),
|
||||||
|
showItem(LocaleKeys.allowingHomeService.tr() + ":", (serviceItemModel.isAppointmentCustomerLoc ?? false) ? "Yes" : "No", valueColor: Colors.green),
|
||||||
|
12.height,
|
||||||
|
LocaleKeys.serviceAmount.tr().toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
serviceItemModel.price!.toText(fontSize: 22, isBold: true),
|
||||||
|
2.width,
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 4),
|
||||||
|
child: LocaleKeys.sar.tr().toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Padding(
|
||||||
|
// padding: const EdgeInsets.all(4.0),
|
||||||
|
// child: SvgPicture.asset(
|
||||||
|
// MyAssets.icEdit,
|
||||||
|
// width: 16,
|
||||||
|
// height: 16,
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).toWhiteContainer(width: double.infinity, allPading: 12);
|
||||||
|
},
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return 12.height;
|
||||||
|
},
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget showItem(String item, String value, {Color valueColor = Colors.black}) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
item.toText(fontSize: 12, color: MyColors.lightTextColor),
|
||||||
|
4.width,
|
||||||
|
value.toText(fontSize: 12, color: valueColor, isBold: true),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
|
||||||
|
import 'package:mc_common_app/utils/date_helper.dart';
|
||||||
|
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mc_common_app/classes/consts.dart';
|
||||||
|
import 'package:mc_common_app/config/routes.dart';
|
||||||
|
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mc_common_app/theme/colors.dart';
|
||||||
|
import 'package:mc_common_app/utils/enums.dart';
|
||||||
|
import 'package:mc_common_app/utils/navigator.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/provider_details_card.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class FavoriteListView extends StatefulWidget {
|
||||||
|
const FavoriteListView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FavoriteListView> createState() => _FavoriteListViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FavoriteListViewState extends State<FavoriteListView> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
scheduleMicrotask(() async => context.read<AppointmentsVM>().getMyFavoriteProviders());
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer(
|
||||||
|
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: CustomAppBar(
|
||||||
|
title: LocaleKeys.favoriteList.tr(),
|
||||||
|
isRemoveBackButton: false,
|
||||||
|
),
|
||||||
|
body: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
await context.read<AppointmentsVM>().getMyFavoriteProviders();
|
||||||
|
},
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: appointmentsVM.state == ViewState.busy
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: appointmentsVM.myFavProvidersList.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: (LocaleKeys.noProvidersInFav.tr()).toText(
|
||||||
|
fontSize: 16,
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: ListView.separated(
|
||||||
|
itemCount: appointmentsVM.myFavProvidersList.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
ProviderProfileModel providerProfileModel = appointmentsVM.myFavProvidersList[index];
|
||||||
|
return ProviderDetailCard(
|
||||||
|
isFromFavoriteList: true,
|
||||||
|
onCardTapped: () => navigateWithName(context, AppRoutes.providerProfileView, arguments: providerProfileModel.providerID),
|
||||||
|
providerImageUrl: providerProfileModel.profileImage ?? "",
|
||||||
|
title: providerProfileModel.name ?? "",
|
||||||
|
description: providerProfileModel.companyDescription ?? "",
|
||||||
|
startedSince: DateHelper.formatAsDayMonthYear(DateHelper.parseStringToDate(DateHelper.formatDateT(providerProfileModel.memberSince ?? ""))),
|
||||||
|
branches: providerProfileModel.serviceProviderBranch ?? [],
|
||||||
|
totalBranches: (providerProfileModel.noOfBranches ?? 0).toString(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) => 12.height,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
),
|
||||||
|
).paddingOnly(left: 10, right: 10),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,161 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
|
||||||
|
import 'package:mc_common_app/utils/date_helper.dart';
|
||||||
|
import 'package:mc_common_app/utils/enums.dart';
|
||||||
|
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.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';
|
||||||
|
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mc_common_app/theme/colors.dart';
|
||||||
|
import 'package:mc_common_app/utils/navigator.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/branch_details_card.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ProviderProfileView extends StatefulWidget {
|
||||||
|
final int providerId;
|
||||||
|
|
||||||
|
ProviderProfileView({required this.providerId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ProviderProfileView> createState() => _ProviderProfileViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ProviderProfileViewState extends State<ProviderProfileView> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
scheduleMicrotask(() async => context.read<AppointmentsVM>().getProviderProfileWithBranchesAndServices(widget.providerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer(
|
||||||
|
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||||
|
if (appointmentsVM.state == ViewState.busy || appointmentsVM.providerProfileModel == null) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: MyColors.white,
|
||||||
|
appBar: CustomAppBar(
|
||||||
|
title: LocaleKeys.providerDetails.tr(),
|
||||||
|
),
|
||||||
|
body: Center(child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: CustomAppBar(
|
||||||
|
title: LocaleKeys.providerDetails.tr(),
|
||||||
|
actions: [
|
||||||
|
Icon(
|
||||||
|
appointmentsVM.providerProfileModel!.isFavorite! ? Icons.favorite : Icons.favorite_border,
|
||||||
|
color: appointmentsVM.providerProfileModel!.isFavorite! ? MyColors.darkPrimaryColor : MyColors.black,
|
||||||
|
).horPaddingMain().onPress(
|
||||||
|
() async {
|
||||||
|
if (appointmentsVM.providerProfileModel!.isFavorite!) {
|
||||||
|
bool status = await appointmentsVM.removeProviderFromFavorite(serviceProviderID: appointmentsVM.providerProfileModel!.id!, context: context);
|
||||||
|
if (status) {
|
||||||
|
appointmentsVM.providerProfileModel!.isFavorite = false;
|
||||||
|
appointmentsVM.getMyFavoriteProviders();
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bool status = await appointmentsVM.addProviderToFavorite(serviceProviderID: appointmentsVM.providerProfileModel!.id!, context: context);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
appointmentsVM.providerProfileModel!.isFavorite = true;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 21),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Center(child: appointmentsVM.providerProfileModel!.profileImage.buildNetworkImage(height: 250, width: double.infinity, fit: BoxFit.cover)),
|
||||||
|
12.height,
|
||||||
|
if (appointmentsVM.providerProfileModel!.memberSince!.isNotEmpty) ...[
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
("${LocaleKeys.companyName.tr()}:").toText(color: MyColors.lightTextColor, fontSize: 12),
|
||||||
|
4.width,
|
||||||
|
(appointmentsVM.providerProfileModel!.companyName ?? appointmentsVM.providerProfileModel!.name).toString().toText(
|
||||||
|
fontSize: 16,
|
||||||
|
isBold: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
if (appointmentsVM.providerProfileModel!.memberSince!.isNotEmpty) ...[
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
("${LocaleKeys.memberSince.tr()}:").toText(color: MyColors.lightTextColor, fontSize: 12),
|
||||||
|
4.width,
|
||||||
|
"${DateHelper.formatAsMonthYear(
|
||||||
|
DateHelper.parseStringToDate(
|
||||||
|
DateHelper.formatDateT(
|
||||||
|
appointmentsVM.providerProfileModel!.memberSince ?? "",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)}"
|
||||||
|
.toText(fontSize: 12, isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
4.height,
|
||||||
|
appointmentsVM.providerProfileModel!.companyDescription!.toText(color: MyColors.lightTextColor, fontSize: 12),
|
||||||
|
],
|
||||||
|
).toWhiteContainer(width: double.infinity, allPading: 12),
|
||||||
|
12.height,
|
||||||
|
appointmentsVM.providerProfileModel!.serviceProviderBranch == null
|
||||||
|
? Center(
|
||||||
|
child: (LocaleKeys.noBranchFound.tr()).toText(
|
||||||
|
fontSize: 16,
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: appointmentsVM.providerProfileModel!.serviceProviderBranch!.isEmpty
|
||||||
|
? Center(child: Text(LocaleKeys.no_branch.tr()))
|
||||||
|
: ListView.separated(
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
BranchDetailModel branchModel = appointmentsVM.providerProfileModel!.serviceProviderBranch![index];
|
||||||
|
return BranchDetailCard(
|
||||||
|
onCardTapped: () {
|
||||||
|
navigateWithName(context, AppRoutes.branchDetailView, arguments: branchModel);
|
||||||
|
},
|
||||||
|
providerImageUrl: (branchModel.branchImages != null && branchModel.branchImages!.isNotEmpty) ? (branchModel.branchImages!.first.imageUrl ?? "") : "",
|
||||||
|
title: branchModel.branchName ?? "",
|
||||||
|
providerLocation: branchModel.distanceKm.toString() + " KM",
|
||||||
|
providerName: branchModel.serviceProviderName ?? "",
|
||||||
|
providerRatings: (branchModel.branchRateAvg ?? 0.0),
|
||||||
|
services: branchModel.branchServices,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) {
|
||||||
|
return 12.height;
|
||||||
|
},
|
||||||
|
itemCount: appointmentsVM.providerProfileModel!.serviceProviderBranch!.length,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,104 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:car_customer_app/view_models/appointments_view_model.dart';
|
|
||||||
import 'package:car_customer_app/view_models/dashboard_view_model.dart';
|
|
||||||
import 'package:car_customer_app/view_models/providers_view_model.dart';
|
|
||||||
import 'package:car_customer_app/views/dashboard/fragments/ads_fragment.dart';
|
|
||||||
import 'package:car_customer_app/views/dashboard/fragments/appointments_fragment.dart';
|
|
||||||
import 'package:car_customer_app/views/dashboard/fragments/home_fragment.dart';
|
|
||||||
import 'package:car_customer_app/views/dashboard/fragments/providers_fragment.dart';
|
|
||||||
import 'package:car_customer_app/views/dashboard/fragments/settings_fragment.dart';
|
|
||||||
import 'package:car_customer_app/views/dashboard/widgets/bottom_nav_bar.dart';
|
|
||||||
import 'package:car_customer_app/views/dashboard/widgets/drawer_widget.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:mc_common_app/classes/consts.dart';
|
|
||||||
import 'package:mc_common_app/view_models/ad_view_model.dart';
|
|
||||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
|
||||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class DashboardPage extends StatefulWidget {
|
|
||||||
const DashboardPage({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<DashboardPage> createState() => _DashboardPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DashboardPageState extends State<DashboardPage> {
|
|
||||||
// late DashboardVM dashboardVM;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
// dashboardVM = Provider.of<DashboardVM>(context, listen: false);
|
|
||||||
fetchUsername();
|
|
||||||
scheduleMicrotask(() {
|
|
||||||
context.read<AppointmentsVM>().populateAppointmentsFilterList();
|
|
||||||
context.read<ProvidersVM>().populateProvidersFilterList();
|
|
||||||
context.read<AdVM>().populateAdsFilterList();
|
|
||||||
_onRefresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onRefresh() async {
|
|
||||||
AdVM adVm = Provider.of<AdVM>(context, listen: false);
|
|
||||||
AppointmentsVM appointmentsVM = Provider.of<AppointmentsVM>(context, listen: false);
|
|
||||||
if (appointmentsVM.myAppointments.isEmpty) {
|
|
||||||
await appointmentsVM.getMyAppointments();
|
|
||||||
}
|
|
||||||
if (adVm.myAds.isEmpty) {
|
|
||||||
await adVm.getMyAds();
|
|
||||||
}
|
|
||||||
if (adVm.exploreAds.isEmpty) {
|
|
||||||
await adVm.getExploreAds();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchUsername() async {}
|
|
||||||
|
|
||||||
List<Widget> fragments = [
|
|
||||||
const ProvidersFragment(),
|
|
||||||
const AppointmentsFragment(),
|
|
||||||
const HomeFragment(),
|
|
||||||
AdsFragment(),
|
|
||||||
const SettingsFragment(),
|
|
||||||
];
|
|
||||||
|
|
||||||
String getPageTitle(int index) {
|
|
||||||
if (index == 0) {
|
|
||||||
return "Providers";
|
|
||||||
}
|
|
||||||
if (index == 1) {
|
|
||||||
return "Appointments";
|
|
||||||
}
|
|
||||||
if (index == 2) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if (index == 3) {
|
|
||||||
return "Ads";
|
|
||||||
}
|
|
||||||
if (index == 4) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
bool isHomePage = context.watch<DashboardVM>().selectedNavbarBarIndex == 2;
|
|
||||||
return Scaffold(
|
|
||||||
appBar: CustomAppBar(
|
|
||||||
backgroundColor: null,
|
|
||||||
leadingWidth: 100,
|
|
||||||
title: getPageTitle(context.watch<DashboardVM>().selectedNavbarBarIndex),
|
|
||||||
profileImageUrl: MyAssets.bnCar,
|
|
||||||
isRemoveBackButton: true,
|
|
||||||
isDrawerEnabled: isHomePage ? true : false,
|
|
||||||
actions: [(isHomePage ? MyAssets.notificationsBellIcon : MyAssets.searchIcon).buildSvg().paddingOnly(right: 21)],
|
|
||||||
),
|
|
||||||
drawer: CustomDrawer(dashboardVM: context.watch<DashboardVM>()),
|
|
||||||
bottomNavigationBar: CustomBottomNavbar(),
|
|
||||||
body: fragments[context.watch<DashboardVM>().selectedNavbarBarIndex],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:car_customer_app/views/dashboard/fragments/appointments_fragment.dart';
|
||||||
|
import 'package:car_customer_app/views/dashboard/fragments/home_fragment.dart';
|
||||||
|
import 'package:car_customer_app/views/dashboard/widgets/bottom_nav_bar.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mc_common_app/classes/app_state.dart';
|
||||||
|
import 'package:mc_common_app/config/routes.dart';
|
||||||
|
import 'package:mc_common_app/utils/enums.dart';
|
||||||
|
import 'package:mc_common_app/utils/navigator.dart';
|
||||||
|
import 'package:mc_common_app/utils/utils.dart';
|
||||||
|
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
|
||||||
|
import 'package:mc_common_app/views/common_fragments/ads_fragment.dart';
|
||||||
|
import 'package:mc_common_app/views/common_fragments/requests_fragment.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'fragments/branches_fragment.dart';
|
||||||
|
|
||||||
|
class DashboardView extends StatefulWidget {
|
||||||
|
final DashboardRouteEnum dashboardRouteEnum;
|
||||||
|
|
||||||
|
const DashboardView({Key? key, required this.dashboardRouteEnum}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DashboardView> createState() => _DashboardViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DashboardViewState extends State<DashboardView> {
|
||||||
|
late DashboardVmCustomer dashboardVM;
|
||||||
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
dashboardVM = context.read<DashboardVmCustomer>();
|
||||||
|
scheduleMicrotask(() async => await dashboardVM.onRefresh(context, dashboardRouteEnum: widget.dashboardRouteEnum));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Widget> fragments = [
|
||||||
|
const BranchesFragment(),
|
||||||
|
const AppointmentsFragment(),
|
||||||
|
const HomeFragment(),
|
||||||
|
const AdsFragment(),
|
||||||
|
const MyRequestsFragment(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// return GestureDetector(
|
||||||
|
// behavior: HitTestBehavior.translucent,
|
||||||
|
// onTap: () {
|
||||||
|
// if (AppState().getIsViewOnly) {
|
||||||
|
// Utils.showToast("message");
|
||||||
|
// } else {
|
||||||
|
// print("========NN========");
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// child: child,
|
||||||
|
// )
|
||||||
|
return PopScope(
|
||||||
|
canPop: false,
|
||||||
|
child: Scaffold(
|
||||||
|
key: _scaffoldKey,
|
||||||
|
bottomNavigationBar: CustomBottomNavbar(),
|
||||||
|
body: fragments[context.watch<DashboardVmCustomer>().selectedNavbarBarIndex],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// return PopScope(
|
||||||
|
// canPop: false,
|
||||||
|
// child: Scaffold(
|
||||||
|
// key: _scaffoldKey,
|
||||||
|
// bottomNavigationBar: CustomBottomNavbar(),
|
||||||
|
// body: fragments[context.watch<DashboardVmCustomer>().selectedNavbarBarIndex],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,118 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:mc_common_app/classes/app_state.dart';
|
|
||||||
import 'package:mc_common_app/config/routes.dart';
|
|
||||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
|
||||||
import 'package:mc_common_app/theme/colors.dart';
|
|
||||||
import 'package:mc_common_app/utils/navigator.dart';
|
|
||||||
import 'package:mc_common_app/view_models/ad_view_model.dart';
|
|
||||||
import 'package:mc_common_app/views/advertisement/ads_list.dart';
|
|
||||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
|
||||||
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
|
|
||||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class AdsFragment extends StatelessWidget {
|
|
||||||
AdsFragment({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
Future<void> onRefreshAds(BuildContext context) async {
|
|
||||||
AdVM adVM = context.read<AdVM>();
|
|
||||||
await adVM.getExploreAds();
|
|
||||||
await adVM.getMyAds();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: Container(
|
|
||||||
color: MyColors.backgroundColor,
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
16.height,
|
|
||||||
Consumer(
|
|
||||||
builder: (BuildContext context, AdVM adVM, Widget? child) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ShowFillButton(
|
|
||||||
isFilled: adVM.isExploreAdsTapped,
|
|
||||||
maxHeight: 55,
|
|
||||||
title: "Explore Ads",
|
|
||||||
txtColor: adVM.isExploreAdsTapped ? MyColors.white : MyColors.darkTextColor,
|
|
||||||
onPressed: () {
|
|
||||||
print("ads: ${AppState().getUser.data!.accessToken}");
|
|
||||||
adVM.updateIsExploreAds(true);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
12.width,
|
|
||||||
Expanded(
|
|
||||||
child: ShowFillButton(
|
|
||||||
isFilled: !adVM.isExploreAdsTapped,
|
|
||||||
txtColor: !adVM.isExploreAdsTapped ? MyColors.white : MyColors.darkTextColor,
|
|
||||||
maxHeight: 55,
|
|
||||||
title: "My Ads",
|
|
||||||
onPressed: () {
|
|
||||||
adVM.updateIsExploreAds(false);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).horPaddingMain(),
|
|
||||||
if (adVM.isExploreAdsTapped && adVM.exploreAds.isNotEmpty) ...[
|
|
||||||
16.height,
|
|
||||||
FiltersList(filterList: adVM.exploreAdsFilterOptions, onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnExploreAds(index: index), needLeftPadding: false)
|
|
||||||
.paddingOnly(left: 21),
|
|
||||||
],
|
|
||||||
if (!adVM.isExploreAdsTapped && adVM.myAds.isNotEmpty) ...[
|
|
||||||
16.height,
|
|
||||||
FiltersList(
|
|
||||||
filterList: adVM.myAdsFilterOptions,
|
|
||||||
onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnMyAds(index: index, selectedFilterId: selectedFilterId),
|
|
||||||
needLeftPadding: false)
|
|
||||||
.paddingOnly(left: 21),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
16.height,
|
|
||||||
Expanded(
|
|
||||||
child: RefreshIndicator(
|
|
||||||
onRefresh: () => onRefreshAds(context),
|
|
||||||
child: Consumer(
|
|
||||||
builder: (BuildContext context, AdVM adVM, Widget? child) {
|
|
||||||
return BuildAdsList(
|
|
||||||
isAdsFragment: true,
|
|
||||||
shouldShowAdStatus: !adVM.isExploreAdsTapped,
|
|
||||||
adsList: adVM.isExploreAdsTapped && adVM.exploreAdsFilteredList.isNotEmpty
|
|
||||||
? adVM.exploreAdsFilteredList
|
|
||||||
: !adVM.isExploreAdsTapped && adVM.myAdsFilteredList.isNotEmpty
|
|
||||||
? adVM.myAdsFilteredList
|
|
||||||
: [],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: () {
|
|
||||||
context.read<AdVM>().getVehicleTypes();
|
|
||||||
|
|
||||||
navigateWithName(context, AppRoutes.createAdView);
|
|
||||||
},
|
|
||||||
backgroundColor: MyColors.darkPrimaryColor,
|
|
||||||
child: Icon(
|
|
||||||
Icons.add,
|
|
||||||
color: MyColors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,56 +1,141 @@
|
|||||||
import 'package:car_customer_app/view_models/appointments_view_model.dart';
|
import 'package:mc_common_app/classes/app_state.dart';
|
||||||
import 'package:car_customer_app/views/appointments/widgets/customer_appointment_slider_widget.dart';
|
import 'package:mc_common_app/classes/consts.dart';
|
||||||
|
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||||
|
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
|
||||||
|
import 'package:mc_common_app/views/appointments/widgets/common_appointment_slider_widget.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mc_common_app/config/routes.dart';
|
import 'package:mc_common_app/config/routes.dart';
|
||||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
||||||
import 'package:mc_common_app/theme/colors.dart';
|
import 'package:mc_common_app/theme/colors.dart';
|
||||||
|
import 'package:mc_common_app/utils/enums.dart';
|
||||||
import 'package:mc_common_app/utils/navigator.dart';
|
import 'package:mc_common_app/utils/navigator.dart';
|
||||||
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
|
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/filters_list.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
class AppointmentsFragment extends StatelessWidget {
|
class AppointmentsFragment extends StatelessWidget {
|
||||||
const AppointmentsFragment({Key? key}) : super(key: key);
|
const AppointmentsFragment({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Consumer(
|
||||||
color: MyColors.backgroundColor,
|
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: CustomAppBar(
|
||||||
|
title: LocaleKeys.appointments.tr(),
|
||||||
|
isRemoveBackButton: true,
|
||||||
|
actions: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: appointmentsVM.appointmentFiltersCounter > 0 ? 20 : 0, right: 21),
|
||||||
|
child: Badge(
|
||||||
|
isLabelVisible: appointmentsVM.appointmentFiltersCounter > 0,
|
||||||
|
largeSize: 15,
|
||||||
|
smallSize: 20,
|
||||||
|
backgroundColor: MyColors.darkPrimaryColor,
|
||||||
|
label: Text('${appointmentsVM.appointmentFiltersCounter}'),
|
||||||
|
child: MyAssets.searchIcon.buildSvg(),
|
||||||
|
),
|
||||||
|
).onPress(() {
|
||||||
|
navigateWithName(context, AppRoutes.appoinmentSearchFilterPage);
|
||||||
|
})
|
||||||
|
],
|
||||||
|
).toViewOnly(context, onTap: () {
|
||||||
|
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
|
||||||
|
}),
|
||||||
|
body: SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
child: Consumer(
|
child: Column(
|
||||||
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
children: [
|
||||||
16.height,
|
16.height,
|
||||||
FiltersList(
|
FiltersList(
|
||||||
filterList: appointmentsVM.appointmentsFilterOptions,
|
filterList: appointmentsVM.appointmentsFilterOptions,
|
||||||
onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnAppointmentsVM(index: index),
|
onFilterTapped: (index, selectedFilterId) {
|
||||||
|
appointmentsVM.applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum());
|
||||||
|
},
|
||||||
),
|
),
|
||||||
16.height,
|
16.height,
|
||||||
Expanded(
|
Expanded(
|
||||||
child: appointmentsVM.myAppointments.isEmpty
|
child: RefreshIndicator(
|
||||||
? Column(
|
onRefresh: () async {
|
||||||
|
int index = appointmentsVM.appointmentsFilterOptions.indexWhere((element) => element.isSelected);
|
||||||
|
if (index != -1) {
|
||||||
|
AppointmentStatusEnum appointmentStatusEnum = appointmentsVM.appointmentsFilterOptions[index].id.toAppointmentStatusEnum();
|
||||||
|
appointmentsVM.applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: appointmentStatusEnum);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: appointmentsVM.state == ViewState.busy
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: appointmentsVM.myFilteredAppointmentsForCustomers.isEmpty
|
||||||
|
? AppState().getIsViewOnly
|
||||||
|
? LocaleKeys.loginToViewAppointments.tr().toText(fontSize: 16, color: MyColors.lightTextColor)
|
||||||
|
: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
"No Appointments to show.".toText(fontSize: 16, color: MyColors.lightTextColor),
|
LocaleKeys.noAppointmentstoShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor),
|
||||||
|
if (appointmentsVM.appointmentFiltersCounter > 0) ...[
|
||||||
|
8.height,
|
||||||
|
InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
appointmentsVM.clearAppointmentFilters();
|
||||||
|
await appointmentsVM.applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
|
||||||
|
},
|
||||||
|
child: LocaleKeys.clearFilters.tr().toText(
|
||||||
|
fontSize: 14,
|
||||||
|
isBold: true,
|
||||||
|
color: MyColors.darkPrimaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: ListView.builder(
|
: ListView.separated(
|
||||||
|
separatorBuilder: (context, index) => 12.height,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: appointmentsVM.myAppointments.length,
|
itemCount: appointmentsVM.myFilteredAppointmentsForCustomers.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
return BuildAppointmentContainerForCustomer(
|
return AppointmentFragmentTileWidget(
|
||||||
onTapped: () => navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentsVM.myAppointments[index]),
|
onTapped: () {
|
||||||
appointmentListModel: appointmentsVM.myAppointments[index],
|
AppointmentListModel appointmentModel = appointmentsVM.myFilteredAppointmentsForCustomers[index];
|
||||||
);
|
appointmentModel.appointmentServicesList!.forEach((service) {
|
||||||
|
double totalServicePrice = 0.0;
|
||||||
|
service.serviceItems!.forEach((item) {
|
||||||
|
totalServicePrice = totalServicePrice + (double.parse("${item.price ?? 0.0}"));
|
||||||
|
});
|
||||||
|
service.currentTotalServicePrice = totalServicePrice;
|
||||||
|
});
|
||||||
|
navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentModel);
|
||||||
|
},
|
||||||
|
appointmentListModel: appointmentsVM.myFilteredAppointmentsForCustomers[index],
|
||||||
|
).margin(left: 21, right: 21).toViewOnly(context, onTap: () {
|
||||||
|
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
),
|
||||||
|
),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: () async {
|
||||||
|
context.read<DashboardVmCustomer>().onNavbarTapped(0);
|
||||||
},
|
},
|
||||||
|
backgroundColor: MyColors.darkPrimaryColor,
|
||||||
|
child: Icon(
|
||||||
|
Icons.add,
|
||||||
|
color: MyColors.white,
|
||||||
),
|
),
|
||||||
|
).toViewOnly(context, onTap: () {
|
||||||
|
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,108 @@
|
|||||||
|
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mc_common_app/classes/consts.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';
|
||||||
|
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
|
||||||
|
import 'package:mc_common_app/theme/colors.dart';
|
||||||
|
import 'package:mc_common_app/utils/enums.dart';
|
||||||
|
import 'package:mc_common_app/utils/navigator.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/branch_details_card.dart';
|
||||||
|
import 'package:mc_common_app/widgets/common_widgets/filters_list.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class BranchesFragment extends StatelessWidget {
|
||||||
|
const BranchesFragment({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer(
|
||||||
|
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: CustomAppBar(
|
||||||
|
title: LocaleKeys.branches.tr(),
|
||||||
|
isRemoveBackButton: true,
|
||||||
|
actions: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: appointmentsVM.branchFiltersCounter > 0 ? 20 : 0, right: 21),
|
||||||
|
child: Badge(
|
||||||
|
largeSize: 15,
|
||||||
|
smallSize: 20,
|
||||||
|
isLabelVisible: appointmentsVM.branchFiltersCounter > 0,
|
||||||
|
backgroundColor: MyColors.darkPrimaryColor,
|
||||||
|
label: Text('${appointmentsVM.branchFiltersCounter}'),
|
||||||
|
child: MyAssets.searchIcon.buildSvg(),
|
||||||
|
),
|
||||||
|
).onPress(() {
|
||||||
|
navigateWithName(context, AppRoutes.branchSearchFilterPage);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).toViewOnly(context, onTap: () {
|
||||||
|
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
|
||||||
|
}),
|
||||||
|
body: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (appointmentsVM.branchesCategoriesFilterOptions.isNotEmpty) ...[
|
||||||
|
16.height,
|
||||||
|
FiltersList(
|
||||||
|
filterList: appointmentsVM.branchesCategoriesFilterOptions,
|
||||||
|
onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnBranches(index: index),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
16.height,
|
||||||
|
Expanded(
|
||||||
|
child: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
context.read<AppointmentsVM>().getAllNearBranches(isNeedToRebuild: true, isFromRefresh: true);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: appointmentsVM.state == ViewState.busy
|
||||||
|
? const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
)
|
||||||
|
: appointmentsVM.nearbyBranches.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: LocaleKeys.no_branch.tr().toText(
|
||||||
|
fontSize: 16,
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: ListView.separated(
|
||||||
|
itemCount: appointmentsVM.nearbyBranches.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
BranchDetailModel branchDetailModel = appointmentsVM.nearbyBranches[index];
|
||||||
|
return BranchDetailCard(
|
||||||
|
onCardTapped: () => navigateWithName(context, AppRoutes.branchDetailView, arguments: branchDetailModel),
|
||||||
|
providerImageUrl: branchDetailModel.branchProfileImage ?? "",
|
||||||
|
title: branchDetailModel.branchName ?? "",
|
||||||
|
providerLocation: branchDetailModel.distanceKm.toString() + " KM",
|
||||||
|
providerName: branchDetailModel.serviceProviderName ?? "",
|
||||||
|
providerRatings: branchDetailModel.branchRateAvg ?? 0.0,
|
||||||
|
services: branchDetailModel.branchServices,
|
||||||
|
).toViewOnly(context, onTap: () {
|
||||||
|
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) => 12.height,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
),
|
||||||
|
).paddingOnly(left: 10, right: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,60 +1,60 @@
|
|||||||
import 'package:car_customer_app/view_models/appointments_view_model.dart';
|
// import 'package:car_customer_app/view_models/appointments_view_model.dart';
|
||||||
import 'package:car_customer_app/view_models/providers_view_model.dart';
|
// import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/material.dart';
|
// import 'package:mc_common_app/classes/consts.dart';
|
||||||
import 'package:mc_common_app/classes/consts.dart';
|
// import 'package:mc_common_app/config/routes.dart';
|
||||||
import 'package:mc_common_app/config/routes.dart';
|
// import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
// import 'package:mc_common_app/theme/colors.dart';
|
||||||
import 'package:mc_common_app/theme/colors.dart';
|
// import 'package:mc_common_app/utils/navigator.dart';
|
||||||
import 'package:mc_common_app/utils/navigator.dart';
|
// import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
|
||||||
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
|
// import 'package:mc_common_app/widgets/common_widgets/provider_details_card.dart';
|
||||||
import 'package:mc_common_app/widgets/common_widgets/provider_details_card.dart';
|
// import 'package:provider/provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
//
|
||||||
|
// class ProvidersFragment extends StatelessWidget {
|
||||||
class ProvidersFragment extends StatelessWidget {
|
// const ProvidersFragment({Key? key}) : super(key: key);
|
||||||
const ProvidersFragment({Key? key}) : super(key: key);
|
//
|
||||||
|
// @override
|
||||||
@override
|
// Widget build(BuildContext context) {
|
||||||
Widget build(BuildContext context) {
|
// return Container(
|
||||||
return Container(
|
// color: MyColors.backgroundColor,
|
||||||
color: MyColors.backgroundColor,
|
// width: double.infinity,
|
||||||
width: double.infinity,
|
// height: double.infinity,
|
||||||
height: double.infinity,
|
// child: Consumer(
|
||||||
child: Consumer(
|
// builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||||
builder: (BuildContext context, ProvidersVM providersVM, Widget? child) {
|
// return Column(
|
||||||
return Column(
|
// children: [
|
||||||
children: [
|
// 16.height,
|
||||||
16.height,
|
// FiltersList(
|
||||||
FiltersList(
|
// filterList: appointmentsVM.providersFilterOptions,
|
||||||
filterList: providersVM.providersFilterOptions,
|
// onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnProviders(index: index),
|
||||||
onFilterTapped: (index, selectedFilterId) => providersVM.applyFilterOnProviders(index: index),
|
// ),
|
||||||
),
|
// 16.height,
|
||||||
16.height,
|
// Expanded(
|
||||||
Expanded(
|
// child: Container(
|
||||||
child: Container(
|
// child: ListView.builder(
|
||||||
child: ListView.builder(
|
// shrinkWrap: true,
|
||||||
shrinkWrap: true,
|
// itemCount: 30,
|
||||||
itemCount: 30,
|
// itemBuilder: (BuildContext context, int index) {
|
||||||
itemBuilder: (BuildContext context, int index) {
|
// return ProviderDetailsCard(
|
||||||
return ProviderDetailsCard(
|
// onCardTapped: () {
|
||||||
onCardTapped: () {
|
// if (context.read<AppointmentsVM>().branchCategories.isEmpty) {
|
||||||
if (context.read<AppointmentsVM>().providerCategories.isEmpty) {
|
// context.read<AppointmentsVM>().getBranchCategories();
|
||||||
context.read<AppointmentsVM>().getProviderCategories();
|
// }
|
||||||
}
|
// navigateWithName(context, AppRoutes.bookAppointmenServicesView);
|
||||||
navigateWithName(context, AppRoutes.bookAppointmenServicesView);
|
// },
|
||||||
},
|
// providerImageUrl: MyAssets.bnCar,
|
||||||
providerImageUrl: MyAssets.bnCar,
|
// title: "",
|
||||||
providerLocation: " 3km",
|
// providerLocation: " 3km",
|
||||||
providerName: "Al Ahmed Maintenance",
|
// providerName: "Al Ahmed Maintenance",
|
||||||
providerRatings: "4.9",
|
// providerRatings: "4.9",
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SettingsFragment extends StatelessWidget {
|
|
||||||
const SettingsFragment({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.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';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
|
||||||
|
class AdWidget extends StatelessWidget {
|
||||||
|
final int count;
|
||||||
|
|
||||||
|
const AdWidget({Key? key, required this.count}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: count,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 15),
|
||||||
|
child: buildAdContainer(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildAdContainer() {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
"assets/images/bn_car.jpeg",
|
||||||
|
width: 80,
|
||||||
|
height: 80,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
12.width,
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Toyota Crolla".toText(fontSize: 16, isBold: true),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
"Model:".toText(
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
2.width,
|
||||||
|
"2019".toText(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
"Mileage:".toText(
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
2.width,
|
||||||
|
"73,000 km".toText(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Riyadh".toText(
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
"9 Hours Ago".toText(
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
"30,000".toText(fontSize: 16, isBold: true),
|
||||||
|
2.width,
|
||||||
|
"SAR:".toText(
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Icon(Icons.arrow_forward)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).toWhiteContainer(width: double.infinity, allPading: 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.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';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
|
||||||
|
class AppointmentSliderWidget extends StatelessWidget {
|
||||||
|
const AppointmentSliderWidget({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Olaya Brach".toText(
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
isBold: true,
|
||||||
|
),
|
||||||
|
"Abdullah Alhbas".toText(
|
||||||
|
isBold: true,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
"Appt. On:".toText(
|
||||||
|
color: MyColors.lightTextColor,
|
||||||
|
),
|
||||||
|
2.width,
|
||||||
|
"19-Mar-2023 11:48 AM".toText(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"1+ Requests".toText(fontSize: 10).toContainer(
|
||||||
|
borderRadius: 15,
|
||||||
|
backgroundColor: MyColors.lightGreyEAColor,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 6,
|
||||||
|
horizontal: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
showServices("Maintenance"),
|
||||||
|
2.height,
|
||||||
|
showServices("Accessories and Modification"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.arrow_forward,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).toWhiteContainer(width: double.infinity, allPading: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget showServices(String title) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
Icons.ac_unit,
|
||||||
|
color: MyColors.primaryColor,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
8.width,
|
||||||
|
title.toText(
|
||||||
|
fontSize: 14,
|
||||||
|
isBold: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mc_common_app/classes/consts.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';
|
||||||
|
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
|
||||||
|
import 'package:mc_common_app/utils/navigator.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
|
||||||
|
class MyRecentBranchesWidget extends StatelessWidget {
|
||||||
|
final List<BranchDetailModel> nearbyBranches;
|
||||||
|
|
||||||
|
const MyRecentBranchesWidget({Key? key, required this.nearbyBranches}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 140,
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: nearbyBranches.length,
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
BranchDetailModel branchDetailModel = nearbyBranches[index];
|
||||||
|
return SizedBox(
|
||||||
|
width: 90,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
branchDetailModel.branchProfileImage.buildNetworkImage(height: 73, width: 73, fit: BoxFit.cover).toCircle(borderRadius: 100),
|
||||||
|
9.height,
|
||||||
|
Flexible(
|
||||||
|
child: branchDetailModel.branchName!.toText(fontSize: 14, textAlign: TextAlign.center, letterSpacing: -0.84, height: 18 / 14),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).onPress(() => navigateWithName(
|
||||||
|
context,
|
||||||
|
AppRoutes.branchDetailView,
|
||||||
|
arguments: branchDetailModel,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mc_common_app/models/general_models/widgets_models.dart';
|
||||||
|
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||||
|
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
|
||||||
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class MyServicesCategoriesWidget extends StatelessWidget {
|
||||||
|
final List<FilterListModel> homeCategories;
|
||||||
|
|
||||||
|
const MyServicesCategoriesWidget({Key? key, required this.homeCategories}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 140,
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: homeCategories.length,
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
FilterListModel category = homeCategories[index];
|
||||||
|
if (category.id == 0) {
|
||||||
|
return SizedBox();
|
||||||
|
}
|
||||||
|
return SizedBox(
|
||||||
|
width: 90,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
category.iconUrl.buildNetworkImage(height: 73, width: 73, fit: BoxFit.cover).toCircle(borderRadius: 100),
|
||||||
|
9.height,
|
||||||
|
Flexible(
|
||||||
|
child: category.title.toText(
|
||||||
|
fontSize: 14,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
letterSpacing: -0.84,
|
||||||
|
height: 18 / 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).onPress(() {
|
||||||
|
final appointmentVM = context.read<AppointmentsVM>();
|
||||||
|
final dashboardCustomerVM = context.read<DashboardVmCustomer>();
|
||||||
|
context.read<DashboardVmCustomer>().onNavbarTapped(0);
|
||||||
|
dashboardCustomerVM.onNavbarTapped(0);
|
||||||
|
appointmentVM.applyFilterOnBranches(index: index);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mc_common_app/theme/colors.dart';
|
||||||
|
|
||||||
|
class ViewAllWidget extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String subTitle;
|
||||||
|
|
||||||
|
const ViewAllWidget({Key? key, required this.title, required this.subTitle}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.only(bottom: 10),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: title.toText(isBold: true, fontSize: 18)),
|
||||||
|
subTitle.toText(
|
||||||
|
fontSize: 11,
|
||||||
|
isBold: true,
|
||||||
|
color: MyColors.primaryColor,
|
||||||
|
textDecoration: TextDecoration.underline,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue