Merge pull request 'Ad Module Completion' (#3) from faiz_development into master

Reviewed-on: http://34.17.52.79/Haroon6138/car_customer_app/pulls/3
mirza_development
Mirza Shafique 3 years ago
commit 1c78b0e134

@ -6,7 +6,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.1.0' classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip

@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>9.0</string> <string>11.0</string>
</dict> </dict>
</plist> </plist>

@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 46; objectVersion = 54;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@ -68,7 +68,6 @@
C74C73D850C4D4FC94940060 /* Pods-Runner.release.xcconfig */, C74C73D850C4D4FC94940060 /* Pods-Runner.release.xcconfig */,
3643750A79F4A25346F39B6F /* Pods-Runner.profile.xcconfig */, 3643750A79F4A25346F39B6F /* Pods-Runner.profile.xcconfig */,
); );
name = Pods;
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@ -140,6 +139,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
9A2045E27F192C87BCD2FA50 /* [CP] Embed Pods Frameworks */, 9A2045E27F192C87BCD2FA50 /* [CP] Embed Pods Frameworks */,
4CC2E88FCFA89EAD7EEA637B /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@ -156,7 +156,7 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1020; LastUpgradeCheck = 1300;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
@ -200,10 +200,12 @@
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
); );
name = "Thin Binary"; name = "Thin Binary";
outputPaths = ( outputPaths = (
@ -212,8 +214,26 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
4CC2E88FCFA89EAD7EEA637B /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
@ -340,7 +360,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -356,9 +376,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.carCustomerApp; PRODUCT_BUNDLE_IDENTIFIER = com.example.carCustomerApp;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -414,7 +439,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -463,11 +488,12 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
@ -480,9 +506,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.carCustomerApp; PRODUCT_BUNDLE_IDENTIFIER = com.example.carCustomerApp;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -499,9 +530,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.carCustomerApp; PRODUCT_BUNDLE_IDENTIFIER = com.example.carCustomerApp;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1020" LastUpgradeVersion = "1300"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSCameraUsageDescription</key>
<string>Used to access media images for car parts</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
@ -28,18 +30,22 @@
<string>Main</string> <string>Main</string>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
</array> </array>
<key>UISupportedInterfaceOrientations~ipad</key> <key>UISupportedInterfaceOrientations~ipad</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict> </dict>
</plist> </plist>

@ -1,10 +1,12 @@
import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:mc_common_app/config/dependencies.dart'; import 'package:mc_common_app/config/dependencies.dart';
class CustomerDependencies { class CustomerDependencies {
static void addDependencies() { static void addDependencies() {
AppDependencies.addDependencies(); AppDependencies.addDependencies();
injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp()); injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp());
injector.registerSingleton<ScheduleRepo>(() => ScheduleRepoImp());
} }
} }

@ -1,6 +1,8 @@
import 'package:car_customer_app/views/appointments/appointment_detail_view.dart'; import 'package:car_customer_app/views/appointments/appointment_detail_view.dart';
import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart'; import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart';
import 'package:car_customer_app/views/appointments/book_appointments_item_view.dart';
import 'package:car_customer_app/views/appointments/pick_items_view.dart'; import 'package:car_customer_app/views/appointments/pick_items_view.dart';
import 'package:car_customer_app/views/appointments/review_appointment_view.dart';
import 'package:car_customer_app/views/dashboard/dashboard_page.dart'; import 'package:car_customer_app/views/dashboard/dashboard_page.dart';
import 'package:car_customer_app/views/provider/branch_detail_page.dart'; import 'package:car_customer_app/views/provider/branch_detail_page.dart';
import 'package:car_customer_app/views/provider/provider_profile_page.dart'; import 'package:car_customer_app/views/provider/provider_profile_page.dart';
@ -8,21 +10,28 @@ 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/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/models/services/branch_model.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/views/advertisement/ads_detail_view.dart'; import 'package:mc_common_app/views/advertisement/ads_detail_view.dart';
import 'package:mc_common_app/views/advertisement/create_ad_view.dart'; import 'package:mc_common_app/views/advertisement/create_ad_view.dart';
import 'package:mc_common_app/views/advertisement/select_ad_type_view.dart';
import 'package:mc_common_app/views/payments/payment_methods_view.dart'; import 'package:mc_common_app/views/payments/payment_methods_view.dart';
import 'package:mc_common_app/views/advertisement/ads_search_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) => DashboardPage(),
AppRoutes.bookProviderAppView: (context) => BookProviderAppView(), 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.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel),
AppRoutes.createAdView: (context) => CreateAdView(), AppRoutes.createAdView: (context) => CreateAdView(),
AppRoutes.adsSearchFilterScreen: (context) => AdsSearchFilterView(),
AppRoutes.selectAdTypeView: (context) => SelectAdTypeView(isProvider: ModalRoute.of(context)!.settings.arguments as bool),
AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(),
AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(), AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(),
AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchModel: ModalRoute.of(context)!.settings.arguments as BranchModel), AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(),
AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypesEnum),
AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel),
AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int), AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int),
}; };
} }

@ -1,9 +1,9 @@
import 'package:car_customer_app/config/customer_dependencies.dart'; import 'package:car_customer_app/config/customer_dependencies.dart';
import 'package:car_customer_app/config/customer_routes.dart'; import 'package:car_customer_app/config/customer_routes.dart';
import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
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/dashboard_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:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
@ -27,6 +27,7 @@ import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart'; import 'package:provider/single_child_widget.dart';
import 'package:sizer/sizer.dart'; import 'package:sizer/sizer.dart';
//test commit
Future<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
CustomerDependencies.addDependencies(); CustomerDependencies.addDependencies();
@ -53,15 +54,10 @@ Future<void> main() async {
adsRepo: injector.get<AdsRepo>(), adsRepo: injector.get<AdsRepo>(),
), ),
), ),
ChangeNotifierProvider<ProvidersVM>(
create: (_) => ProvidersVM(
commonServices: injector.get<CommonAppServices>(),
commonRepo: injector.get<CommonRepo>(),
providerRepo: injector.get<ProviderRepo>(),
),
),
ChangeNotifierProvider<AppointmentsVM>( ChangeNotifierProvider<AppointmentsVM>(
create: (_) => AppointmentsVM( create: (_) => AppointmentsVM(
scheduleRepo: injector.get<ScheduleRepo>(),
providerRepo: injector.get<ProviderRepo>(),
commonServices: injector.get<CommonAppServices>(), commonServices: injector.get<CommonAppServices>(),
commonRepo: injector.get<CommonRepo>(), commonRepo: injector.get<CommonRepo>(),
), ),

@ -1,51 +1,55 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:mc_common_app/models/model/provider_model.dart';
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/services/near_branch_model.dart';
import 'package:http/http.dart' as http;
import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart'; import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:flutter/cupertino.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
import 'package:mc_common_app/models/services/item_model.dart';
abstract class ProviderRepo { abstract class ProviderRepo {
Future<NearBrancheModel> getAllNearBranchAndServices(); Future<List<BranchDetailModel>> getAllNearBranchAndServices();
Future<ItemModel> getServiceItems(int serviceId); Future<List<ItemData>> getServiceItems(int serviceId);
Future<ProviderModel> getBranchAndServices(int providerId); Future<ProviderProfileModel> getBranchAndServices(int providerId);
} }
class ProviderRepoImp implements ProviderRepo { class ProviderRepoImp implements ProviderRepo {
ApiClient apiClient = injector.get<ApiClient>();
AppState appState = injector.get<AppState>();
@override @override
Future<NearBrancheModel> getAllNearBranchAndServices() async { Future<List<BranchDetailModel>> getAllNearBranchAndServices() async {
// var postParams = {"serviceProviderID": AppState().getUser.data?.userInfo?.providerId.toString() ?? ""}; GenericRespModel adsGenericModel = await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.GetAllNearBranches, token: appState.getUser.data!.accessToken);
String t = AppState().getUser.data!.accessToken ?? ""; List<BranchDetailModel> nearBranches = List.generate(adsGenericModel.data.length, (index) => BranchDetailModel.fromJson(adsGenericModel.data[index]));
return await injector.get<ApiClient>().getJsonForObject((json) => NearBrancheModel.fromJson(json), ApiConsts.GetAllNearBranches, token: t); return nearBranches;
} }
@override @override
Future<ItemModel> getServiceItems(int serviceId) async { Future<List<ItemData>> getServiceItems(int serviceId) async {
var queryParameters = { var queryParameters = {
"ServiceProviderServiceID": serviceId.toString(), "ServiceProviderServiceID": serviceId.toString(),
}; };
String? token = AppState().getUser.data?.accessToken;
debugPrint(token); GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
return await injector (json) => GenericRespModel.fromJson(json),
.get<ApiClient>() ApiConsts.getServiceItems,
.getJsonForObject((json) => ItemModel.fromJson(json), ApiConsts.getServiceItems, queryParameters: queryParameters, token: AppState().getUser.data!.accessToken ?? ""); token: appState.getUser.data!.accessToken,
queryParameters: queryParameters,
);
List<ItemData> serviceItems = List.generate(adsGenericModel.data.length, (index) => ItemData.fromJson(adsGenericModel.data[index]));
return serviceItems;
} }
@override @override
Future<ProviderModel> getBranchAndServices(int providerId) async { Future<ProviderProfileModel> getBranchAndServices(int providerId) async {
var postParams = {"serviceProviderID": providerId.toString()}; var postParams = {"serviceProviderID": providerId.toString()};
String t = AppState().getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel =
return await injector.get<ApiClient>().getJsonForObject((json) => ProviderModel.fromJson(json), ApiConsts.BranchesAndServices, queryParameters: postParams, token: t); await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.BranchesAndServices, token: appState.getUser.data!.accessToken, queryParameters: postParams);
return ProviderProfileModel.fromJson(adsGenericModel.data);
} }
} }

@ -0,0 +1,88 @@
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/m_response.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/models/schedule_model.dart';
import 'package:mc_common_app/models/service_schedule_model.dart';
abstract class ScheduleRepo {
Future<Services> getAllServices(String branchId);
Future<MResponse> createSchedule(Map map);
Future<MResponse> addServicesInSchedule(Map map);
Future<MResponse> updateSchedule(Map map);
Future<List<ScheduleData>> getSchedules(String branchId);
Future<MResponse> updateServicesInSchedule(Map map);
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({required List<String> serviceItemIds});
}
class ScheduleRepoImp implements ScheduleRepo {
@override
Future<Services> getAllServices(String branchId) async {
Map<String, dynamic> map = {"ProviderBranchID": branchId};
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().getJsonForObject((json) => Services.fromJson(json), ApiConsts.getServicesOfBranch, token: t, queryParameters: map);
}
@override
Future<MResponse> createSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createSchedule, map, token: t);
}
@override
Future<MResponse> addServicesInSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createGroup, map, token: t);
}
@override
Future<List<ScheduleData>> getSchedules(String branchId) async {
Map<String, dynamic> map = {"ServiceProviderBranchID": branchId};
String t = AppState().getUser.data!.accessToken ?? "";
GenericRespModel adsGenericModel = await injector.get<ApiClient>().getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getSchedule,
token: t,
queryParameters: map,
);
return List.generate(adsGenericModel.data.length, (index) => ScheduleData.fromJson(adsGenericModel.data[index]));
}
@override
Future<MResponse> updateSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateSchedule, map, token: t);
}
@override
Future<MResponse> updateServicesInSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t);
}
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({required List<String> serviceItemIds}) async {
String t = AppState().getUser.data!.accessToken ?? "";
var dummyServiceIds = ["3", "2"];
var queryParameters = {"ServiceItemIDs": dummyServiceIds};
GenericRespModel adsGenericModel = await injector.get<ApiClient>().getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.GetServiceItemAppointmentScheduleSlots,
token: t,
queryParameters: queryParameters,
);
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleModel =
List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index]));
return serviceAppointmentScheduleModel;
}
}

@ -1,28 +1,78 @@
import 'package:flutter/cupertino.dart'; import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:mc_common_app/classes/consts.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/models/provider_category_model.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_service_model.dart'; import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
import 'package:mc_common_app/models/service_schedule_model.dart';
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/services/service_model.dart';
import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/common_services.dart'; import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
class AppointmentsVM extends ChangeNotifier { class AppointmentsVM extends BaseVM {
final CommonRepo commonRepo; final CommonRepo commonRepo;
final CommonAppServices commonServices; final CommonAppServices commonServices;
final ProviderRepo providerRepo;
final ScheduleRepo scheduleRepo;
AppointmentsVM({required this.commonServices, required this.commonRepo}); AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo});
bool isFetchingLists = false; bool isFetchingLists = false;
List<AppointmentListModel> myAppointments = []; List<AppointmentListModel> myAppointments = [];
List<FilterListModel> appointmentsFilterOptions = []; List<FilterListModel> appointmentsFilterOptions = [];
// List<ScheduleData> availableSchedules = [];
bool isFetchingServices = false; bool isFetchingServices = false;
List<ProviderCategoryModel> providerCategories = []; List<DropValue> branchCategories = [];
bool isHomeTapped = false; bool isHomeTapped = false;
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleList = [];
// Future<void> getSchedulesByBranchId() async {
// availableSchedules = await scheduleRepo.getSchedules(selectedBranchModel!.id!.toString());
// log("schedules: ${availableSchedules.toString()}");
// notifyListeners();
// }
List<DropValue> servicesInSchedule = [];
Future<void> mergeServiceIntoAvailableSchedules() async {
List<String> serviceItemIds = [];
serviceItems.forEach((serviceItem) {
if (serviceItem.isUpdateOrSelected!) {
serviceItemIds.add(serviceItem.id!.toString());
}
});
var scheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(serviceItemIds: serviceItemIds);
serviceAppointmentScheduleList.addAll(scheduleList);
servicesInSchedule.clear();
serviceAppointmentScheduleList.forEach((schedule) {
schedule.serviceItemList!.forEach((item) {
if (!ifItemAlreadyThere(item.serviceProviderServiceId!)) {
servicesInSchedule.add(DropValue(item.serviceProviderServiceId!, item.description!, ""));
}
});
});
notifyListeners();
}
bool ifItemAlreadyThere(int id) {
int index = servicesInSchedule.indexWhere((element) => element.id == id);
if (index == -1) {
return false;
}
return true;
}
void updateIsHomeTapped(bool value) { void updateIsHomeTapped(bool value) {
isHomeTapped = value; isHomeTapped = value;
notifyListeners(); notifyListeners();
@ -32,44 +82,38 @@ class AppointmentsVM extends ChangeNotifier {
void updatePickedHomeLocation(String value) { void updatePickedHomeLocation(String value) {
pickedHomeLocation = value; pickedHomeLocation = value;
pickHomeLocationError = "";
notifyListeners(); notifyListeners();
} }
SelectionModel providerCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateProviderCategoryId(SelectionModel id) async { void updateProviderCategoryId(SelectionModel id) {
providerCategoryId = id; branchSelectedCategoryId = id;
await getProviderServices(id.selectedId); getBranchServices(categoryId: branchSelectedCategoryId.selectedId);
notifyListeners(); notifyListeners();
} }
List<ProviderServiceModel> providerServices = []; List<FilterListModel> providersFilterOptions = [];
List<BranchDetailModel> nearbyBranches = [];
BranchDetailModel? selectedBranchModel;
SelectionModel providerServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); List<ServiceModel> branchServices = [];
ServiceModel? currentServiceSelection;
void updateProviderServiceId(SelectionModel id) async { void updateBranchServiceId(SelectionModel id) async {
providerServiceId = id; branchSelectedServiceId = id;
notifyListeners(); currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId);
}
void getProviderCategories() async {
notifyListeners();
providerCategories = await commonRepo.getProviderServiceCategories();
notifyListeners(); notifyListeners();
} }
getProviderServices(int categoryId) async { resetCategorySelectionBottomSheet() {
providerServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); selectedSubServicesCounter = 0;
branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
isHomeTapped = false; isHomeTapped = false;
pickedHomeLocation = ""; branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
if (categoryId != -1) { currentServiceSelection = null;
isFetchingServices = true;
notifyListeners();
providerServices = await commonRepo.getProviderServices(categoryId: categoryId);
isFetchingServices = false;
notifyListeners();
}
} }
populateAppointmentsFilterList() { populateAppointmentsFilterList() {
@ -99,4 +143,174 @@ class AppointmentsVM extends ChangeNotifier {
isFetchingLists = false; isFetchingLists = false;
notifyListeners(); notifyListeners();
} }
updateSelectedBranch(BranchDetailModel branchDetailModel) {
selectedBranchModel = branchDetailModel;
getBranchCategories();
notifyListeners();
}
List<ItemData> serviceItems = [];
List<ItemData> selectedServiceItems = [];
ProviderProfileModel? providerProfileModel;
int selectedSubServicesCounter = 0;
updateSelectedSubServicesCounter(int value) {
selectedSubServicesCounter = value;
notifyListeners();
}
onItemUpdateOrSelected(int index, bool selected, int itemId) {
serviceItems[index].isUpdateOrSelected = selected;
if (selected) {
selectedSubServicesCounter = selectedSubServicesCounter + 1;
updateSelectedSubServicesCounter(selectedSubServicesCounter);
selectSubServicesError = "";
currentServiceSelection!.serviceItems!.add(serviceItems[index]);
}
if (!selected) {
selectedSubServicesCounter = selectedSubServicesCounter - 1;
updateSelectedSubServicesCounter(selectedSubServicesCounter);
currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId);
}
notifyListeners();
}
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();
}
getAllNearBranches({bool isNeedToRebuild = false}) async {
//TODO: needs to lat,long into API
nearbyBranches.clear();
if (isNeedToRebuild) setState(ViewState.busy);
nearbyBranches = await providerRepo.getAllNearBranchAndServices();
setState(ViewState.idle);
}
Future<List<ItemData>> getServiceItems(int serviceId) async {
serviceItems.clear();
serviceItems = await providerRepo.getServiceItems(serviceId);
setState(ViewState.idle);
return serviceItems;
}
getBranchAndServices(int providerId) async {
providerProfileModel = null;
providerProfileModel = await providerRepo.getBranchAndServices(providerId);
setState(ViewState.idle);
}
String pickHomeLocationError = "";
String selectSubServicesError = "";
SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
bool isCategoryAlreadyPresent(int id) {
final contain = branchCategories.where((element) => element.id == id);
if (contain.isEmpty) {
return false;
}
return true;
}
void getBranchCategories() async {
for (var value in selectedBranchModel!.branchServices!) {
if (!isCategoryAlreadyPresent(value.categoryId!)) {
branchCategories.add(DropValue(value.categoryId!, value.categoryName!, ""));
}
}
notifyListeners();
}
getBranchServices({required int categoryId}) async {
branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
isHomeTapped = false;
pickedHomeLocation = "";
pickHomeLocationError = "";
if (categoryId != -1) {
isFetchingServices = true;
// notifyListeners();
branchServices = getFilteredBranchServices(categoryId: categoryId);
isFetchingServices = false;
notifyListeners();
}
}
List<ServiceModel> getFilteredBranchServices({required int categoryId}) {
List<ServiceModel> filteredServices = selectedBranchModel!.branchServices!.where((element) => element.categoryId == categoryId).toList();
return filteredServices;
}
void updatePickHomeLocationError(String value) {
pickHomeLocationError = value;
notifyListeners();
}
bool isServiceSelectionValidated() {
if (branchSelectedServiceId.selectedId == -1) {
return false;
}
if (isHomeTapped) {
if (pickedHomeLocation == "") {
updatePickHomeLocationError(GlobalConsts.homeLocationEmptyError);
return false;
}
}
return true;
}
bool onSubServicesNextPressed() {
for (var value in serviceItems) {
if (value.isUpdateOrSelected!) {
return true;
}
}
selectSubServicesError = "Please select at least one sub service";
notifyListeners();
return false;
}
// void mergeServiceInAvailableSchedule() {
// log("schedules: ${availableSchedules}");
// for (var schedule in availableSchedules) {
// for (var service in schedule.scheduleServices!) {
// if (branchSelectedServiceId.selectedId == service.serviceId) {
// log("ID matched: ${service.serviceId}");
// log("SelectedServices: ${schedule.selectedServices}");
//
//
// int isAlreadyThereIndex = schedule.selectedServices!.indexWhere((element) => element.serviceProviderServiceId == branchSelectedServiceId.selectedId);
// if (isAlreadyThereIndex != -1) {
// log("removing: ${service.serviceId}");
// schedule.selectedServices!.removeAt(isAlreadyThereIndex);
// }
// schedule.selectedServices!.add(currentServiceSelection!);
// notifyListeners();
// return;
// }
// }
// }
// notifyListeners();
// }
} }

@ -1,67 +0,0 @@
import 'package:mc_common_app/models/model/provider_model.dart';
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/services/near_branch_model.dart';
import 'package:car_customer_app/repositories/provider_repo.dart';
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';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
class ProvidersVM extends BaseVM {
final CommonRepo commonRepo;
final CommonAppServices commonServices;
final ProviderRepo providerRepo;
ProvidersVM({required this.commonServices, required this.commonRepo, required this.providerRepo});
List<FilterListModel> providersFilterOptions = [];
NearBrancheModel? branches;
ItemModel? serviceItems;
ProviderModel? providerModel;
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();
}
//Create new branch
getAllNearBranches({bool isNeedToRebuild = false}) async {
//TODO: needs to lat,long into API
branches = null;
if (isNeedToRebuild) setState(ViewState.busy);
branches = await providerRepo.getAllNearBranchAndServices();
setState(ViewState.idle);
}
Future<ItemModel?> getServiceItems(int serviceId) async {
serviceItems = null;
serviceItems = await providerRepo.getServiceItems(serviceId);
setState(ViewState.idle);
return serviceItems;
}
getBranchAndServices(int providerId) async {
providerModel = null;
providerModel = await providerRepo.getBranchAndServices(providerId);
setState(ViewState.idle);
}
}

@ -1,195 +1,133 @@
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/views/appointments/widgets/appointment_service_pick_bottom_sheet.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/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/service_schedule_model.dart';
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/models/widgets_models.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/views/advertisement/custom_add_button.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/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.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/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.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'; import 'package:provider/provider.dart';
class BookAppointmentServicesView extends StatelessWidget { class BookAppointmentServicesView extends StatelessWidget {
const BookAppointmentServicesView({Key? key}) : super(key: key); BookAppointmentServicesView({Key? key}) : super(key: key);
void openTheAddServiceBottomSheet(BuildContext context) { void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
enableDrag: true, enableDrag: true,
builder: (BuildContext context) { builder: (BuildContext context) {
AppointmentsVM appointmentsVM = context.watch<AppointmentsVM>(); return AppointmentServicePickBottomSheet();
return SizedBox( },
height: MediaQuery.of(context).size.height * 0.85, );
child: Column( }
children: [
Container( final _dummySlots = [
margin: const EdgeInsets.all(8), TimeSlotModel(isSelected: false, slotId: 1, slot: "11:00"),
height: 8, TimeSlotModel(isSelected: false, slotId: 2, slot: "12:00"),
width: 60, TimeSlotModel(isSelected: true, slotId: 3, slot: "13:00"),
decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))), TimeSlotModel(isSelected: false, slotId: 4, slot: "14:00"),
), TimeSlotModel(isSelected: false, slotId: 5, slot: "15:00"),
12.height, TimeSlotModel(isSelected: false, slotId: 6, slot: "16:00"),
Row( TimeSlotModel(isSelected: false, slotId: 7, slot: "17:00"),
mainAxisAlignment: MainAxisAlignment.start, TimeSlotModel(isSelected: false, slotId: 8, slot: "18:00"),
children: [ TimeSlotModel(isSelected: false, slotId: 9, slot: "19:00"),
"Select Category".toText(fontSize: 24, isBold: true), TimeSlotModel(isSelected: false, slotId: 10, slot: "20:00"),
], TimeSlotModel(isSelected: false, slotId: 11, slot: "21:00"),
), TimeSlotModel(isSelected: false, slotId: 12, slot: "22:00"),
30.height, TimeSlotModel(isSelected: false, slotId: 13, slot: "23:00"),
Expanded( TimeSlotModel(isSelected: false, slotId: 14, slot: "24:00"),
child: ListView( TimeSlotModel(isSelected: false, slotId: 15, slot: "25:00"),
children: [ TimeSlotModel(isSelected: false, slotId: 16, slot: "26:00"),
Builder( TimeSlotModel(isSelected: false, slotId: 17, slot: "27:00"),
builder: (context) { TimeSlotModel(isSelected: false, slotId: 18, slot: "28:00"),
List<DropValue> serviceCategories = []; TimeSlotModel(isSelected: false, slotId: 19, slot: "29:00"),
for (var element in appointmentsVM.providerCategories) { ];
if (!element.isSelected!) {
serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.categoryName ?? "", "")); void priceBreakDownClicked(BuildContext context) {
} showModalBottomSheet(
} context: context,
return DropdownField( isScrollControlled: true,
(DropValue value) => appointmentsVM.updateProviderCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), enableDrag: true,
list: serviceCategories, builder: (BuildContext context) {
hint: "Select Category", return InfoBottomSheet(
dropdownValue: appointmentsVM.providerCategoryId.selectedId != -1 title: "Charges Breakdown",
? DropValue(appointmentsVM.providerCategoryId.selectedId, appointmentsVM.providerCategoryId.selectedOption, "") description: Column(
: null, crossAxisAlignment: CrossAxisAlignment.start,
); children: [
}, "Services".toText(fontSize: 16, isBold: true),
Column(
children: List.generate(
5,
(index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Gear Kit".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"200 SAR".toText(fontSize: 12, isBold: true),
],
), ),
if (appointmentsVM.isFetchingServices) ...[ ),
Row( ),
mainAxisAlignment: MainAxisAlignment.center, Row(
children: [const CircularProgressIndicator().paddingAll(10)], mainAxisAlignment: MainAxisAlignment.end,
), children: [
] else if (appointmentsVM.providerServices.isNotEmpty) ...[ "1149 SAR".toText(fontSize: 16, isBold: true),
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,
),
],
),
]
],
], ],
), ),
), 20.height,
SizedBox( "Home Location".toText(fontSize: 16, isBold: true),
width: double.infinity, Row(
child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if (appointmentsVM.isHomeTapped && !appointmentsVM.isFetchingServices) ...[ "10km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
const Divider(thickness: 1, height: 1), "5 x 10".toText(fontSize: 12, isBold: true),
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) 8.height,
], Row(
)).horPaddingMain(); mainAxisAlignment: MainAxisAlignment.end,
}, children: [
); "50 SAR".toText(fontSize: 16, isBold: true),
],
),
30.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Total Amount ".toText(fontSize: 16, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"120".toText(fontSize: 29, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
],
)
],
),
30.height,
],
));
});
}
String getTotalPrice(List<ItemData> serviceItems) {
var totalPrice = 0.0;
serviceItems.forEach((element) {
totalPrice = totalPrice + double.parse(element.price ?? "0.0");
});
return totalPrice.toString();
} }
@override @override
@ -209,117 +147,166 @@ class BookAppointmentServicesView extends StatelessWidget {
children: [ children: [
21.height, 21.height,
CustomAddButton( CustomAddButton(
onTap: () => {openTheAddServiceBottomSheet(context)}, needsBorder: true,
bgColor: MyColors.white,
onTap: () => openTheAddServiceBottomSheet(context, appointmentsVM),
text: "Add Services", text: "Add Services",
icon: Container( icon: Container(
height: 24, height: 24,
width: 24, width: 24,
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: const Icon(Icons.add, color: MyColors.white), child: const Icon(Icons.add, color: MyColors.white),
), ),
), ).horPaddingMain(),
// 20.height, 10.height,
// ListView.builder( ListView.builder(
// physics: const NeverScrollableScrollPhysics(), shrinkWrap: true,
// shrinkWrap: true, itemCount: appointmentsVM.serviceAppointmentScheduleList.length,
// itemCount: adVM.specialServiceCards.length, itemBuilder: (BuildContext context, int scheduleIndex) {
// itemBuilder: (BuildContext context, int index) { ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
// SpecialServiceCard specialServicesCard = adVM.specialServiceCards[index]; return Column(
// return Column( children: [
// crossAxisAlignment: CrossAxisAlignment.start, Row(
// children: [ mainAxisAlignment: MainAxisAlignment.spaceBetween,
// Column( children: [
// children: [ Expanded(
// Row( child: "Schedule: ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true),
// mainAxisAlignment: MainAxisAlignment.spaceBetween, ),
// children: [ Align(
// Expanded( alignment: Alignment.topRight,
// child: specialServicesCard.serviceSelectedId!.selectedOption.toText(fontSize: 16, isBold: true), child: Icon(
// ), Icons.delete_outline,
// Align( size: 28,
// alignment: Alignment.topRight, ),
// child: MyAssets.closeWithOrangeBg.buildSvg( ).onPress(() {}),
// fit: BoxFit.fill, ],
// height: 30, ),
// width: 30, if (true) ...[
// ), 5.height,
// ).onPress(() => adVM.removeSpecialServiceCard(index)) Row(
// ], mainAxisAlignment: MainAxisAlignment.start,
// ), children: [
// Builder(builder: (context) { ("Available Dates").toText(fontSize: 14, isBold: true),
// return Column( ],
// crossAxisAlignment: CrossAxisAlignment.start, ),
// children: [ 5.height,
// if (specialServicesCard.serviceSelectedId!.selectedId != 1 && specialServicesCard.serviceSelectedId!.selectedId != 3) ...[ SizedBox(
// // Row( width: double.infinity,
// // crossAxisAlignment: CrossAxisAlignment.start, child: BuildTimeSlots(
// // children: [ timeSlots: scheduleData.availableDates!,
// // "Duration: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), onPressed: (index) => null,
// // (specialServicesCard.duration ?? "").toText(fontSize: 12, isBold: true).expand(), ),
// // ], ),
// // ), ],
// 8.height, if (scheduleData.selectedDate!.isNotEmpty) ...[
// Row( 5.height,
// crossAxisAlignment: CrossAxisAlignment.start, Row(
// children: [ mainAxisAlignment: MainAxisAlignment.start,
// "Description: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), children: [
// (specialServicesCard.description ?? "").toText(fontSize: 12, isBold: true).expand(), ("Available Slots").toText(fontSize: 14, isBold: true),
// ], ],
// ), ),
// ], 5.height,
// if (specialServicesCard.serviceSelectedId!.selectedId == 1 || specialServicesCard.serviceSelectedId!.selectedId == 3) ...[ SizedBox(
// Row( width: double.infinity,
// crossAxisAlignment: CrossAxisAlignment.start, child: BuildTimeSlots(
// children: [ timeSlots: _dummySlots,
// const Icon( onPressed: (index) => null,
// weight: 2, ),
// Icons.location_on_outlined, ),
// color: MyColors.primaryColor, ],
// size: 17, 20.height,
// ), Column(
// "${specialServicesCard.duration} km".toText(fontSize: 10, color: MyColors.primaryColor), crossAxisAlignment: CrossAxisAlignment.start,
// ], children: [
// ), ListView.separated(
// 8.height, physics: NeverScrollableScrollPhysics(),
// Row( shrinkWrap: true,
// crossAxisAlignment: CrossAxisAlignment.start, itemCount: appointmentsVM.servicesInSchedule.length,
// children: [ itemBuilder: (BuildContext context, int serviceIndex) {
// "Branch Address: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex];
// (specialServicesCard.address ?? "").toText(fontSize: 12, isBold: true).expand(), return Column(
// ], children: [
// ), Row(
// Row( children: [
// crossAxisAlignment: CrossAxisAlignment.start, Expanded(
// children: [ child: selectedService.value.toText(fontSize: 15, isBold: true),
// "Appointment Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), ),
// "${specialServicesCard.serviceDate} - ${specialServicesCard.serviceTime}".toText(fontSize: 12, isBold: true).expand(), ],
// ], ),
// ), if (true) ...[
// ], Row(
// 6.height, crossAxisAlignment: CrossAxisAlignment.start,
// Row( children: [
// crossAxisAlignment: CrossAxisAlignment.end, "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
// children: [ ("Home").toText(fontSize: 12, isBold: true).expand(),
// (specialServicesCard.serviceSelectedId!.itemPrice).toText(fontSize: 20, isBold: true), ],
// 2.width, ),
// "SAR".toText(color: MyColors.lightTextColor, fontSize: 14), 5.height,
// ], Column(
// ), children: List.generate(scheduleData.serviceItemList!.length, (itemIndex) {
// ], ItemData itemData = scheduleData.serviceItemList![itemIndex];
// ); return Row(
// }), crossAxisAlignment: CrossAxisAlignment.start,
// 3.height, children: [
// const Divider(thickness: 1.5) "${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true),
// ], ("${itemData.price}").toText(fontSize: 13, isBold: true).expand(),
// ), ],
// 10.height, );
// ], }),
// ); ),
// }, ],
// ), ],
);
},
separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2),
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
getTotalPrice(appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].serviceItemList ?? []).toText(fontSize: 32, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
Icon(
Icons.arrow_drop_down,
size: 30,
)
],
).onPress(() => priceBreakDownClicked(context)),
],
),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
).expand(),
Row(
children: [
Expanded(
child: ShowFillButton(
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
onPressed: () {},
backgroundColor: MyColors.greyButtonColor,
),
),
12.width,
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Review",
onPressed: () {
navigateWithName(context, AppRoutes.reviewAppointmentView);
},
backgroundColor: MyColors.darkPrimaryColor,
),
)
],
).paddingAll(21)
], ],
); );
}, },
).horPaddingMain()); ));
} }
} }

@ -0,0 +1,147 @@
import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:car_customer_app/views/appointments/widgets/service_item_with_price_checkbox.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/models/services/item_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.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 BookAppointmentsItemView extends StatelessWidget {
const BookAppointmentsItemView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Select Services",
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: [
Container(
height: 40,
width: double.infinity,
color: MyColors.darkTextColor,
alignment: Alignment.centerLeft,
child: "${appointmentsVM.selectedSubServicesCounter} Item(s) Selected".toText(fontSize: 16, color: MyColors.white).horPaddingMain(),
),
16.height,
Column(
children: [
"Few services are not available on home location. Change the location to workshop to full access the services".toText(fontSize: 12, isItalic: true, color: MyColors.lightTextColor),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Change location or service: ".toText(fontSize: 14, isBold: true),
"Edit".toText(fontSize: 14, isBold: true, isUnderLine: true, color: MyColors.adPendingStatusColor),
5.width,
MyAssets.icEdit.buildSvg(width: 17),
],
).onPress(() {}),
16.height,
Divider(),
],
).horPaddingMain(),
appointmentsVM.serviceItems.isEmpty
? Expanded(child: Center(child: "No Items to show.".toText(fontSize: 16, color: MyColors.lightTextColor)))
: ListView.separated(
separatorBuilder: (BuildContext context, int index) => Divider(),
itemCount: appointmentsVM.serviceItems.length,
itemBuilder: (BuildContext context, int index) {
ItemData itemData = appointmentsVM.serviceItems[index];
return ServiceItemWithPriceCheckBox(
description: "Some description about the sub-services",
title: itemData.name!,
isSelected: itemData.isUpdateOrSelected!,
onSelection: (bool value) {
appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!);
},
priceWidget: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// TODO: This Price will be decided according to the service selected
itemData.price!.split(".").first.toText(fontSize: 30, isBold: true),
" SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
],
),
);
},
).expand(),
Column(
children: [
Divider(
height: 1,
thickness: 0.7,
),
8.height,
if (appointmentsVM.selectSubServicesError != "")
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
appointmentsVM.selectSubServicesError.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10),
8.height,
Row(
children: [
Expanded(
child: ShowFillButton(
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
onPressed: () {
appointmentsVM.resetCategorySelectionBottomSheet();
pop(context);
},
backgroundColor: MyColors.greyButtonColor,
),
),
12.width,
Expanded(
child: Builder(
builder: (BuildContext context) {
return ShowFillButton(
maxHeight: 55,
title: "Next",
onPressed: () async {
bool resp = appointmentsVM.onSubServicesNextPressed();
if (resp) {
Utils.showLoading(context);
await appointmentsVM.mergeServiceIntoAvailableSchedules();
appointmentsVM.resetCategorySelectionBottomSheet();
Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.bookAppointmenServicesView, (Route<dynamic> route) => false);
// appointmentsVM.mergeServiceInAvailableSchedule();
}
},
backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor,
);
},
),
),
],
).horPaddingMain(),
16.height,
],
),
],
);
},
));
}
}

@ -0,0 +1,325 @@
import 'package:car_customer_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/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/service_schedule_model.dart';
import 'package:mc_common_app/models/services/item_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/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class ReviewAppointment extends StatelessWidget {
const ReviewAppointment({Key? key}) : super(key: key);
Widget buildBranchInfoCard({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Padding(
padding: const EdgeInsets.only(
bottom: 10,
left: 21,
right: 21,
),
child: Row(
children: [
Image.asset(
MyAssets.bnCar,
width: 80,
height: 60,
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: [
(appointmentsVM.selectedBranchModel!.branchName ?? "").toText(fontSize: 16, isBold: true),
Row(
children: [
LocaleKeys.location.tr().toText(color: MyColors.lightTextColor, fontSize: 12),
2.width,
": ${appointmentsVM.selectedBranchModel!.branchDescription ?? ""}".toText(fontSize: 12),
],
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
"4.9".toText(
isUnderLine: true,
isBold: true,
fontSize: 12,
),
2.width,
MyAssets.starIcon.buildSvg(width: 12),
],
),
],
),
],
),
),
],
).onPress(() {}).toWhiteContainer(width: double.infinity, allPading: 12));
}
Widget buildServicesInfoCard({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return ListView.builder(
shrinkWrap: true,
itemCount: appointmentsVM.serviceAppointmentScheduleList.length,
itemBuilder: (BuildContext context, int scheduleIndex) {
ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: "Schedule: ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true),
),
],
),
10.height,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: appointmentsVM.servicesInSchedule.length,
itemBuilder: (BuildContext context, int serviceIndex) {
DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex];
return Column(
children: [
Row(
children: [
Expanded(
child: selectedService.value.toText(fontSize: 15, isBold: true),
),
],
),
if (true) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
("Home").toText(fontSize: 12, isBold: true).expand(),
],
),
5.height,
Column(
children: List.generate(scheduleData.serviceItemList!.length, (itemIndex) {
ItemData itemData = scheduleData.serviceItemList![itemIndex];
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true),
],
);
}),
),
],
],
);
},
separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2),
).paddingOnly(bottom: 10),
],
),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
// AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
// return SizedBox(
// width: double.infinity,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: List.generate(
// appointmentsVM.servicesInSchedule.length,
// (serviceIndex) => Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// appointmentsVM.servicesInSchedule[serviceIndex].value.toText(fontSize: 16, isBold: true),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: List.generate(
// appointmentsVM,
// (index) => itemList[index].toText(
// fontSize: 12,
// color: MyColors.lightTextColor,
// isBold: true,
// )),
// ),
// ],
// ).paddingOnly(bottom: 14),
// ),
// ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.symmetric(horizontal: 21)),
// );
}
Widget buildTimeAndLocationInfoCard() {
return SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Time & Location".toText(fontSize: 16, isBold: true),
3.height,
Row(children: [
"Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"2nd Feb, 2023 at 09:30 AM".toText(fontSize: 12, isBold: true),
]),
Row(children: [
"Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"PM58+F97, Al Olaya, Riyadh 12333".toText(fontSize: 12, isBold: true),
]),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10)),
);
}
Widget buildChargesBreakDown({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
List<ItemData> allSelectedItems = [];
double totalServicePrice = 0.0;
appointmentsVM.serviceAppointmentScheduleList.forEach((schedule) {
schedule.serviceItemList!.forEach((item) {
allSelectedItems.add(item);
totalServicePrice = totalServicePrice + double.parse(item.price!);
});
});
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Services".toText(fontSize: 16, isBold: true),
Column(
children: List.generate(
allSelectedItems.length,
(index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${allSelectedItems[index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${allSelectedItems[index].price} SAR".toText(fontSize: 12, isBold: true),
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
"${totalServicePrice.toString()} SAR".toText(fontSize: 16, isBold: true),
],
),
10.height,
Divider(thickness: 0.7),
"Home Location".toText(fontSize: 16, isBold: true),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"10km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"5 x 10".toText(fontSize: 12, isBold: true),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
"50 SAR".toText(fontSize: 16, isBold: true),
],
),
10.height,
Divider(
thickness: 0.7,
),
10.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Total Amount ".toText(fontSize: 16, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"120".toText(fontSize: 29, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
],
)
],
),
10.height,
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10, bottom: 21));
}
Widget buildNextButtonFooter() {
return Container(
height: 90,
color: MyColors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Divider(thickness: 0.7, height: 3),
10.height,
SizedBox(
width: double.infinity,
child: ShowFillButton(
maxHeight: 55,
backgroundColor: MyColors.primaryColor,
title: "Book Appointment",
onPressed: () {},
).paddingOnly(bottom: 12, left: 21, right: 21),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Review Appointment",
isRemoveBackButton: false,
isDrawerEnabled: false,
actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)],
onBackButtonTapped: () => Navigator.pop(context),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildBranchInfoCard(context: context),
buildServicesInfoCard(context: context),
buildTimeAndLocationInfoCard(),
buildChargesBreakDown(context: context),
],
),
),
buildNextButtonFooter(),
],
),
);
}
}

@ -0,0 +1,194 @@
import 'package:car_customer_app/view_models/appointments_view_model.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/models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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 AppointmentServicePickBottomSheet extends StatelessWidget {
const AppointmentServicePickBottomSheet({Key? key}) : super(key: key);
@override
Widget build(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) {
return DropdownField(
(DropValue value) => appointmentsVM.updateProviderCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
list: appointmentsVM.branchCategories,
hint: "Select Category",
dropdownValue: appointmentsVM.branchSelectedCategoryId.selectedId != -1
? DropValue(appointmentsVM.branchSelectedCategoryId.selectedId, appointmentsVM.branchSelectedCategoryId.selectedOption, "")
: null,
);
},
),
if (appointmentsVM.isFetchingServices) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [const CircularProgressIndicator().paddingAll(10)],
),
] else if (appointmentsVM.branchServices.isNotEmpty) ...[
8.height,
Builder(
builder: (context) {
List<DropValue> serviceCategories = [];
for (var element in appointmentsVM.branchServices) {
if (element.categoryId == appointmentsVM.branchSelectedCategoryId.selectedId) {
serviceCategories.add(DropValue(
element.serviceProviderServiceId ?? 0,
element.serviceDescription!,
"",
));
}
}
return DropdownField(
(DropValue value) => appointmentsVM.updateBranchServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
list: serviceCategories,
hint: "Select Service",
dropdownValue: appointmentsVM.branchSelectedServiceId.selectedId != -1
? DropValue(appointmentsVM.branchSelectedServiceId.selectedId, appointmentsVM.branchSelectedServiceId.selectedOption, "")
: null,
);
},
),
],
if (appointmentsVM.branchSelectedServiceId.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',
errorValue: appointmentsVM.pickHomeLocationError,
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,
backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor,
title: "Next",
onPressed: () {
bool isValidated = appointmentsVM.isServiceSelectionValidated();
if (isValidated) {
appointmentsVM.getServiceItems(appointmentsVM.branchSelectedServiceId.selectedId);
navigateWithName(context, AppRoutes.bookAppointmentsItemView);
}
},
),
),
],
),
).paddingOnly(bottom: 20)
],
)).horPaddingMain();
}
}

@ -0,0 +1,51 @@
import 'package:flutter/material.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 ServiceItemWithPriceCheckBox extends StatelessWidget {
final bool isSelected;
final String title, description;
final Widget priceWidget;
final Function(bool) onSelection;
const ServiceItemWithPriceCheckBox({
required this.isSelected,
required this.title,
required this.description,
this.priceWidget = const SizedBox(),
required this.onSelection,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Checkbox(
value: isSelected,
onChanged: (bool? v) {
onSelection(v ?? false);
},
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
title.toText(fontSize: 16, isBold: true).paddingOnly(top: 10),
description.toText(fontSize: 12, color: MyColors.lightTextColor),
priceWidget,
],
),
),
],
),
);
}
}

@ -2,16 +2,17 @@ import 'dart:async';
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/dashboard_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/ads_fragment.dart';
import 'package:car_customer_app/views/dashboard/fragments/appointments_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/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/fragments/settings_fragment.dart';
import 'package:car_customer_app/views/dashboard/widgets/bottom_nav_bar.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:car_customer_app/views/dashboard/widgets/drawer_widget.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/models/widgets_models.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/view_models/ad_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
@ -36,9 +37,9 @@ class _DashboardPageState extends State<DashboardPage> {
fetchUsername(); fetchUsername();
scheduleMicrotask(() { scheduleMicrotask(() {
context.read<AppointmentsVM>().populateAppointmentsFilterList(); context.read<AppointmentsVM>().populateAppointmentsFilterList();
context.read<ProvidersVM>().populateProvidersFilterList(); context.read<AppointmentsVM>().populateProvidersFilterList();
context.read<AdVM>().populateAdsFilterList(); context.read<AdVM>().populateAdsFilterList();
context.read<ProvidersVM>().getAllNearBranches(); context.read<AppointmentsVM>().getAllNearBranches();
_onRefresh(); _onRefresh();
}); });
} }
@ -55,6 +56,22 @@ class _DashboardPageState extends State<DashboardPage> {
if (adVm.exploreAds.isEmpty) { if (adVm.exploreAds.isEmpty) {
await adVm.getExploreAds(); await adVm.getExploreAds();
} }
final adVM = context.read<AdVM>();
if (adVM.vehicleTypes.isEmpty) {
await adVM.getVehicleTypes();
}
if (adVM.vehicleAdsDurations.isEmpty) {
await adVM.getVehicleAdsDuration();
}
adVM.updateVehicleAdDurationId(
SelectionModel(
selectedId: adVM.vehicleAdsDurations.first.id ?? 0,
selectedOption: "${adVM.vehicleAdsDurations.first.days} Days",
itemPrice: adVM.vehicleAdsDurations.first.price!.toInt().toString(),
),
);
} }
fetchUsername() async {} fetchUsername() async {}
@ -69,7 +86,7 @@ class _DashboardPageState extends State<DashboardPage> {
String getPageTitle(int index) { String getPageTitle(int index) {
if (index == 0) { if (index == 0) {
return "Branchs"; return "Branches";
} }
if (index == 1) { if (index == 1) {
return "Appointments"; return "Appointments";
@ -89,6 +106,7 @@ class _DashboardPageState extends State<DashboardPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
bool isHomePage = context.watch<DashboardVM>().selectedNavbarBarIndex == 2; bool isHomePage = context.watch<DashboardVM>().selectedNavbarBarIndex == 2;
bool isAdsPage = context.watch<DashboardVM>().selectedNavbarBarIndex == 3;
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
backgroundColor: null, backgroundColor: null,
@ -97,7 +115,15 @@ class _DashboardPageState extends State<DashboardPage> {
profileImageUrl: MyAssets.bnCar, profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: true, isRemoveBackButton: true,
isDrawerEnabled: isHomePage ? true : false, isDrawerEnabled: isHomePage ? true : false,
actions: [(isHomePage ? MyAssets.notificationsBellIcon : MyAssets.searchIcon).buildSvg().paddingOnly(right: 21)], actions: [
(isHomePage
? MyAssets.notificationsBellIcon.buildSvg()
: InkWell(
onTap: () => navigateWithName(context, AppRoutes.adsSearchFilterScreen),
child: MyAssets.searchIcon.buildSvg(),
))
.paddingOnly(right: 21)
],
), ),
drawer: CustomDrawer(dashboardVM: context.watch<DashboardVM>()), drawer: CustomDrawer(dashboardVM: context.watch<DashboardVM>()),
bottomNavigationBar: CustomBottomNavbar(), bottomNavigationBar: CustomBottomNavbar(),

@ -1,8 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependencies.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/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/widgets_models.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/view_models/ad_view_model.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/views/advertisement/ads_list.dart';
@ -20,6 +25,16 @@ class AdsFragment extends StatelessWidget {
await adVM.getMyAds(); await adVM.getMyAds();
} }
List<AdDetailsModel> getAdsList(AdVM adVM) {
if (adVM.isExploreAdsTapped) {
return adVM.exploreAdsFilteredList;
}
if (adVM.myAdsFilteredList.isNotEmpty) {
return adVM.myAdsFilteredList;
}
return [];
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -62,18 +77,21 @@ class AdsFragment extends StatelessWidget {
), ),
], ],
).horPaddingMain(), ).horPaddingMain(),
if (adVM.isExploreAdsTapped && adVM.exploreAds.isNotEmpty) ...[ if (adVM.isExploreAdsTapped) ...[
16.height, 16.height,
FiltersList(filterList: adVM.exploreAdsFilterOptions, onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnExploreAds(index: index), needLeftPadding: false) FiltersList(
filterList: adVM.exploreAdsFilterOptions,
onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnExploreAds(index: index, createdByRoleFilter: selectedFilterId.toCreatedByRoleEnum()),
needLeftPadding: false)
.paddingOnly(left: 21), .paddingOnly(left: 21),
], ],
if (!adVM.isExploreAdsTapped && adVM.myAds.isNotEmpty) ...[ if (!adVM.isExploreAdsTapped) ...[
16.height, 16.height,
FiltersList( FiltersList(
filterList: adVM.myAdsFilterOptions, filterList: adVM.myAdsFilterOptions,
onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnMyAds(index: index, selectedFilterId: selectedFilterId), onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnMyAds(index: index, adPostStatusEnum: selectedFilterId.toAdPostEnum()),
needLeftPadding: false) needLeftPadding: false,
.paddingOnly(left: 21), ).paddingOnly(left: 21),
], ],
], ],
); );
@ -85,15 +103,7 @@ class AdsFragment extends StatelessWidget {
onRefresh: () => onRefreshAds(context), onRefresh: () => onRefreshAds(context),
child: Consumer( child: Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) { builder: (BuildContext context, AdVM adVM, Widget? child) {
return BuildAdsList( return BuildAdsList(isAdsFragment: true, shouldShowAdStatus: !adVM.isExploreAdsTapped, adsList: getAdsList(adVM));
isAdsFragment: true,
shouldShowAdStatus: !adVM.isExploreAdsTapped,
adsList: adVM.isExploreAdsTapped && adVM.exploreAdsFilteredList.isNotEmpty
? adVM.exploreAdsFilteredList
: !adVM.isExploreAdsTapped && adVM.myAdsFilteredList.isNotEmpty
? adVM.myAdsFilteredList
: [],
);
}, },
), ),
), ),
@ -102,10 +112,8 @@ class AdsFragment extends StatelessWidget {
), ),
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: () { onPressed: () async {
context.read<AdVM>().getVehicleTypes(); navigateWithName(context, AppRoutes.selectAdTypeView, arguments: injector.get<AppState>().currentAppType == AppType.provider);
navigateWithName(context, AppRoutes.createAdView);
}, },
backgroundColor: MyColors.darkPrimaryColor, backgroundColor: MyColors.darkPrimaryColor,
child: Icon( child: Icon(

@ -41,7 +41,11 @@ class AppointmentsFragment extends StatelessWidget {
itemCount: appointmentsVM.myAppointments.length, itemCount: appointmentsVM.myAppointments.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return BuildAppointmentContainerForCustomer( return BuildAppointmentContainerForCustomer(
onTapped: () => navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentsVM.myAppointments[index]), onTapped: () => navigateWithName(
context,
AppRoutes.appointmentDetailView,
arguments: appointmentsVM.myAppointments[index],
),
appointmentListModel: appointmentsVM.myAppointments[index], appointmentListModel: appointmentsVM.myAppointments[index],
); );
}, },

@ -1,17 +1,18 @@
import 'package:car_customer_app/view_models/providers_view_model.dart'; import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:easy_localization/easy_localization.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/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.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/theme/colors.dart';
import 'package:mc_common_app/utils/enums.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/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';
import 'package:easy_localization/easy_localization.dart';
class BranchesFragment extends StatelessWidget { class BranchesFragment extends StatelessWidget {
const BranchesFragment({Key? key}) : super(key: key); const BranchesFragment({Key? key}) : super(key: key);
@ -23,53 +24,53 @@ class BranchesFragment extends StatelessWidget {
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
child: Consumer( child: Consumer(
builder: (BuildContext context, ProvidersVM providersVM, Widget? child) { builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
return Column( return Column(
children: [ children: [
16.height, 16.height,
FiltersList( FiltersList(
filterList: providersVM.providersFilterOptions, filterList: appointmentsVM.providersFilterOptions,
onFilterTapped: (index, selectedFilterId) => providersVM.applyFilterOnProviders(index: index), onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnProviders(index: index),
), ),
16.height, 16.height,
Expanded( Expanded(
child: RefreshIndicator( child: RefreshIndicator(
onRefresh: () async { onRefresh: () async {
context.read<ProvidersVM>().getAllNearBranches(isNeedToRebuild: true); context.read<AppointmentsVM>().getAllNearBranches(isNeedToRebuild: true);
}, },
child: SingleChildScrollView( child: SingleChildScrollView(
child: Container( child: Container(
width: double.infinity, width: double.infinity,
height: MediaQuery.of(context).size.height / 1.37, height: MediaQuery.of(context).size.height / 1.37,
child: Consumer<ProvidersVM>( child: Consumer<AppointmentsVM>(
builder: (context, model, _) { builder: (context, model, _) {
if (model.state == ViewState.busy) { if (model.state == ViewState.busy) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else { } else {
return model.branches?.data == null return model.nearbyBranches.isEmpty
? const Center(child: Text("No Branch Found")) ? Center(child: LocaleKeys.no_branch.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: model.branches!.data!.isEmpty : ListView.separated(
? Center(child: Text(LocaleKeys.no_branch.tr())) itemCount: model.nearbyBranches.length,
: ListView.separated( itemBuilder: (context, index) {
itemBuilder: (context, index) { BranchDetailModel branchDetailModel = model.nearbyBranches[index];
return ProviderDetailsCard(
onCardTapped: () { return ProviderDetailsCard(
navigateWithName(context, AppRoutes.branchDetailPage, arguments: model.branches!.data![index]); onCardTapped: () {
}, navigateWithName(context, AppRoutes.branchDetailPage, arguments: branchDetailModel);
providerImageUrl: MyAssets.bnCar,
title: model.branches!.data![index].branchName ?? "",
providerLocation: model.branches!.data![index].distanceKm.toString() + " KM",
providerName: model.branches!.data![index].serviceProviderName ?? "",
providerRatings: "4.9",
items: model.branches!.data![index].branchServices,
);
},
separatorBuilder: (context, index) {
return 12.height;
}, },
itemCount: model.branches!.data!.length, providerImageUrl: MyAssets.bnCar,
padding: const EdgeInsets.all(12), title: branchDetailModel.branchName ?? "",
providerLocation: branchDetailModel.distanceKm.toString() + " KM",
providerName: branchDetailModel.serviceProviderName ?? "",
providerRatings: "4.9",
services: branchDetailModel.branchServices,
); );
},
separatorBuilder: (context, index) {
return 12.height;
},
padding: const EdgeInsets.all(12),
);
} }
}, },
), ),

@ -1,10 +1,10 @@
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/dashboard_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/appointments/widgets/customer_appointment_slider_widget.dart'; import 'package:car_customer_app/views/appointments/widgets/customer_appointment_slider_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/ad_view_model.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/views/advertisement/ads_list.dart';
import 'package:mc_common_app/widgets/common_widgets/my_service_provider.dart'; import 'package:mc_common_app/widgets/common_widgets/my_service_provider.dart';
@ -43,7 +43,7 @@ class HomeFragment extends StatelessWidget {
onSubtitleTapped: () { onSubtitleTapped: () {
print("value: ${AppState().getUser.data!.accessToken}"); print("value: ${AppState().getUser.data!.accessToken}");
context.read<DashboardVM>().onNavbarTapped(0); context.read<DashboardVM>().onNavbarTapped(0);
context.read<ProvidersVM>().applyFilterOnProviders(index: 0); context.read<AppointmentsVM>().applyFilterOnProviders(index: 0);
}).horPaddingMain(), }).horPaddingMain(),
const ServiceProviderWidget().horPaddingMain(), const ServiceProviderWidget().horPaddingMain(),
Consumer( Consumer(
@ -80,7 +80,7 @@ class HomeFragment extends StatelessWidget {
onSubtitleTapped: () { onSubtitleTapped: () {
context.read<DashboardVM>().onNavbarTapped(3); context.read<DashboardVM>().onNavbarTapped(3);
context.read<AdVM>().updateIsExploreAds(true); context.read<AdVM>().updateIsExploreAds(true);
context.read<AdVM>().applyFilterOnExploreAds(index: 0); context.read<AdVM>().applyFilterOnExploreAds(index: 0, createdByRoleFilter: CreatedByRoleEnum.allAds);
}, },
).horPaddingMain(), ).horPaddingMain(),
BuildAdsList( BuildAdsList(

@ -1,61 +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: "",
title:"", // providerLocation: " 3km",
providerLocation: " 3km", // providerName: "Al Ahmed Maintenance",
providerName: "Al Ahmed Maintenance", // providerRatings: "4.9",
providerRatings: "4.9", // );
); // },
}, // ),
), // ),
), // ),
), // ],
], // );
); // },
}, // ),
), // );
); // }
} // }
}

@ -1,24 +1,25 @@
import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:car_customer_app/views/provider/sheet/items_list_sheet.dart'; import 'package:car_customer_app/views/provider/sheet/items_list_sheet.dart';
import 'package:easy_localization/easy_localization.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/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/services/branch_model.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:mc_common_app/models/services/service_model.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/bottom_sheet.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/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class BranchDetailPage extends StatefulWidget { class BranchDetailPage extends StatefulWidget {
BranchModel branchModel; final BranchDetailModel branchDetailModel;
BranchDetailPage({required this.branchModel}); BranchDetailPage({required this.branchDetailModel});
@override @override
State<BranchDetailPage> createState() => _BranchDetailPageState(); State<BranchDetailPage> createState() => _BranchDetailPageState();
@ -29,7 +30,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
void initState() { void initState() {
// TODO: implement initState // TODO: implement initState
super.initState(); super.initState();
if (widget.branchModel.branchServices!.length > 0) widget.branchModel.branchServices?.first.isExpanded = true; if (widget.branchDetailModel.branchServices!.length > 0) widget.branchDetailModel.branchServices?.first.isExpandedOrSelected = true;
} }
@override @override
@ -52,7 +53,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
children: [ children: [
Image.asset(MyAssets.bnCar), Image.asset(MyAssets.bnCar),
12.height, 12.height,
"${widget.branchModel.branchName} | ${widget.branchModel.serviceProviderName}".toString().toText( "${widget.branchDetailModel.branchName} | ${widget.branchDetailModel.serviceProviderName}".toString().toText(
fontSize: 16, fontSize: 16,
isBold: true, isBold: true,
), ),
@ -60,14 +61,14 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
children: [ children: [
(LocaleKeys.location.tr() + ":").toText(color: MyColors.lightTextColor, fontSize: 12), (LocaleKeys.location.tr() + ":").toText(color: MyColors.lightTextColor, fontSize: 12),
4.width, 4.width,
(widget.branchModel.distanceKm.toString() + " km").toText(fontSize: 12, isBold: true), (widget.branchDetailModel.distanceKm.toString() + " km").toText(fontSize: 12, isBold: true),
], ],
), ),
Row( Row(
children: [ children: [
("Time" + ":").toText(color: MyColors.lightTextColor, fontSize: 12), ("Time" + ":").toText(color: MyColors.lightTextColor, fontSize: 12),
4.width, 4.width,
"${widget.branchModel.openTime} - ${widget.branchModel.closeTime}".toText(fontSize: 12, isBold: true), "${widget.branchDetailModel.openTime} - ${widget.branchDetailModel.closeTime}".toText(fontSize: 12, isBold: true),
], ],
), ),
2.height, 2.height,
@ -123,7 +124,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
) )
.onPress( .onPress(
() { () {
navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchModel.serviceProviderId); navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchDetailModel.serviceProviderId);
}, },
), ),
], ],
@ -134,7 +135,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
color: MyColors.lightTextColor, color: MyColors.lightTextColor,
isBold: true, isBold: true,
), ),
if (widget.branchModel.branchServices!.length == 0) "No Services Available".toText(fontSize: 12, isBold: true), if (widget.branchDetailModel.branchServices!.length == 0) "No Services Available".toText(fontSize: 12, isBold: true),
showServicesList(), showServicesList(),
], ],
).toWhiteContainer( ).toWhiteContainer(
@ -150,11 +151,11 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
title: "Book Appointment", title: "Book Appointment",
maxWidth: double.infinity, maxWidth: double.infinity,
margin: EdgeInsets.all(21), margin: EdgeInsets.all(21),
onPressed: () {}, onPressed: () {
).toContainer( navigateWithName(context, AppRoutes.bookAppointmenServicesView);
paddingAll: 0, context.read<AppointmentsVM>().updateSelectedBranch(widget.branchDetailModel);
backgroundColor: Colors.white, },
), ).toContainer(paddingAll: 0, backgroundColor: Colors.white),
], ],
), ),
); );
@ -165,7 +166,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
return ExpansionTile( return ExpansionTile(
tilePadding: EdgeInsets.zero, tilePadding: EdgeInsets.zero,
title: (widget.branchModel.branchServices![index].serviceDescription ?? "").toText( title: (widget.branchDetailModel.branchServices![index].serviceDescription ?? "").toText(
fontSize: 16, fontSize: 16,
isBold: true, isBold: true,
), ),
@ -173,11 +174,11 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
showItem("Allowing home service:", (widget.branchModel.branchServices![index].isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), showItem("Allowing home service:", (widget.branchDetailModel.branchServices![index].isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green),
showItem("Home service range", widget.branchModel.branchServices![index].customerLocationRange.toString() + "KM"), showItem("Home service range", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "KM"),
showItem("Charges per KM", widget.branchModel.branchServices![index].customerLocationRange.toString() + "SAR"), showItem("Charges per KM", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "SAR"),
8.height, 8.height,
(widget.branchModel.branchServices![index].itemsCount.toString() + "+ items").toText( (widget.branchDetailModel.branchServices![index].itemsCount.toString() + "+ items").toText(
fontSize: 12, fontSize: 12,
isBold: true, isBold: true,
color: MyColors.primaryColor, color: MyColors.primaryColor,
@ -186,18 +187,18 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
20.height, 20.height,
], ],
).onPress(() { ).onPress(() {
showMyBottomSheet(context, child: ItemsListSheet(widget.branchModel.branchServices![index].serviceProviderServiceId ?? 0)); showMyBottomSheet(context, child: ItemsListSheet(widget.branchDetailModel.branchServices![index].serviceProviderServiceId ?? 0));
}), }),
], ],
onExpansionChanged: (value) { onExpansionChanged: (value) {
setState(() { setState(() {
widget.branchModel.branchServices![index].isExpanded = value; widget.branchDetailModel.branchServices![index].isExpandedOrSelected = value;
}); });
}, },
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
collapsedBackgroundColor: Colors.transparent, collapsedBackgroundColor: Colors.transparent,
initiallyExpanded: widget.branchModel.branchServices![index].isExpanded, initiallyExpanded: widget.branchDetailModel.branchServices![index].isExpandedOrSelected,
trailing: widget.branchModel.branchServices![index].isExpanded ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down), trailing: widget.branchDetailModel.branchServices![index].isExpandedOrSelected ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down),
); );
}, },
separatorBuilder: (context, index) { separatorBuilder: (context, index) {
@ -205,7 +206,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
height: 1, height: 1,
); );
}, },
itemCount: widget.branchModel.branchServices!.length, itemCount: widget.branchDetailModel.branchServices!.length,
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
); );

@ -1,4 +1,5 @@
import 'package:car_customer_app/view_models/providers_view_model.dart'; import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:easy_localization/easy_localization.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';
@ -12,10 +13,9 @@ import 'package:mc_common_app/widgets/common_widgets/provider_details_card.dart'
import 'package:mc_common_app/widgets/empty_widget.dart'; import 'package:mc_common_app/widgets/empty_widget.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.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 ProviderProfilePage extends StatefulWidget { class ProviderProfilePage extends StatefulWidget {
int providerId; final int providerId;
ProviderProfilePage({required this.providerId}); ProviderProfilePage({required this.providerId});
@ -27,7 +27,7 @@ class _ProviderProfilePageState extends State<ProviderProfilePage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
context.read<ProvidersVM>().getBranchAndServices(widget.providerId ?? 0); context.read<AppointmentsVM>().getBranchAndServices(widget.providerId);
} }
@override @override
@ -40,11 +40,11 @@ class _ProviderProfilePageState extends State<ProviderProfilePage> {
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
padding: EdgeInsets.all(21), padding: EdgeInsets.all(21),
child: Consumer<ProvidersVM>( child: Consumer<AppointmentsVM>(
builder: (context, model, _) { builder: (context, model, _) {
return model.providerModel == null return model.providerProfileModel == null
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: model.providerModel!.data == null : model.providerProfileModel == null
? const EmptyWidget() ? const EmptyWidget()
: SingleChildScrollView( : SingleChildScrollView(
child: Column( child: Column(
@ -55,7 +55,7 @@ class _ProviderProfilePageState extends State<ProviderProfilePage> {
//TODO: company logo/banner not added form provider app yet //TODO: company logo/banner not added form provider app yet
Image.asset(MyAssets.bnCar), Image.asset(MyAssets.bnCar),
12.height, 12.height,
model.providerModel!.data!.companyName.toString().toText( model.providerProfileModel!.companyName.toString().toText(
fontSize: 16, fontSize: 16,
isBold: true, isBold: true,
), ),
@ -77,28 +77,28 @@ class _ProviderProfilePageState extends State<ProviderProfilePage> {
allPading: 12, allPading: 12,
), ),
12.height, 12.height,
model.providerModel!.data!.serviceProviderBranch == null model.providerProfileModel!.serviceProviderBranch == null
? const Center(child: Text("No Branch Found")) ? const Center(child: Text("No Branch Found"))
: model.providerModel!.data!.serviceProviderBranch!.isEmpty : model.providerProfileModel!.serviceProviderBranch!.isEmpty
? Center(child: Text(LocaleKeys.no_branch.tr())) ? Center(child: Text(LocaleKeys.no_branch.tr()))
: ListView.separated( : ListView.separated(
itemBuilder: (context, index) { itemBuilder: (context, index) {
return ProviderDetailsCard( return ProviderDetailsCard(
onCardTapped: () { onCardTapped: () {
navigateWithName(context, AppRoutes.branchDetailPage, arguments: model.providerModel!.data!.serviceProviderBranch![index]); navigateWithName(context, AppRoutes.branchDetailPage, arguments: model.providerProfileModel!.serviceProviderBranch![index]);
}, },
providerImageUrl: MyAssets.bnCar, providerImageUrl: MyAssets.bnCar,
title: model.providerModel!.data!.serviceProviderBranch![index].branchName ?? "", title: model.providerProfileModel!.serviceProviderBranch![index].branchName ?? "",
providerLocation: model.providerModel!.data!.serviceProviderBranch![index].distanceKm.toString() + " KM", providerLocation: model.providerProfileModel!.serviceProviderBranch![index].distanceKm.toString() + " KM",
providerName: model.providerModel!.data!.serviceProviderBranch![index].serviceProviderName ?? "", providerName: model.providerProfileModel!.serviceProviderBranch![index].serviceProviderName ?? "",
providerRatings: "4.9", providerRatings: "4.9",
items: model.providerModel!.data!.serviceProviderBranch![index].branchServices, services: model.providerProfileModel!.serviceProviderBranch![index].branchServices,
); );
}, },
separatorBuilder: (context, index) { separatorBuilder: (context, index) {
return 12.height; return 12.height;
}, },
itemCount: model.providerModel!.data!.serviceProviderBranch!.length, itemCount: model.providerProfileModel!.serviceProviderBranch!.length,
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
) )

@ -1,19 +1,15 @@
import 'package:flutter_svg/flutter_svg.dart'; import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/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/services/item_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/widgets/empty_widget.dart'; import 'package:mc_common_app/widgets/empty_widget.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../../view_models/providers_view_model.dart';
class ItemsListSheet extends StatefulWidget { class ItemsListSheet extends StatefulWidget {
int serviceId; final int serviceId;
ItemsListSheet(this.serviceId); ItemsListSheet(this.serviceId);
@ -25,74 +21,70 @@ class _ItemsListSheetState extends State<ItemsListSheet> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
context.read<ProvidersVM>().getServiceItems(widget.serviceId ?? 0); context.read<AppointmentsVM>().getServiceItems(widget.serviceId);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
height: MediaQuery.of(context).size.height / 1.2, height: MediaQuery.of(context).size.height / 1.2,
child: Consumer<ProvidersVM>( child: Consumer<AppointmentsVM>(
builder: (context, model, _) { builder: (context, appointmentsVM, _) {
return model.serviceItems == null return appointmentsVM.serviceItems.isEmpty
? const Center(child: CircularProgressIndicator()) ? const EmptyWidget()
: model.serviceItems!.data!.isEmpty : ListView.separated(
? const EmptyWidget() itemCount: appointmentsVM.serviceItems.length,
: ListView.separated( itemBuilder: (BuildContext context, int index) {
itemBuilder: (BuildContext context, int index) { ItemData serviceItemModel = appointmentsVM.serviceItems[index];
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [
serviceItemModel.toString().toText(fontSize: 16, isBold: true),
4.height,
showItem("Available for appointment:", (serviceItemModel.isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green),
showItem("Allowing Workshop service:", (serviceItemModel.isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green),
showItem("Allowing home service:", (serviceItemModel.isAppointmentCustomerLoc ?? false) ? "Yes" : "No", valueColor: Colors.green),
12.height,
"Service Amount".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
model.serviceItems!.data![index].name.toString().toText(fontSize: 16, isBold: true), serviceItemModel.price!.toText(fontSize: 22, isBold: true),
4.height, 2.width,
showItem("Available for appointment:", (model.serviceItems!.data![index].isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), Padding(
showItem("Allowing Workshop service:", (model.serviceItems!.data![index].isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), padding: const EdgeInsets.only(bottom: 4),
showItem("Allowing home service:", (model.serviceItems!.data![index].isAppointmentCustomerLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), child: "SAR".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
12.height,
"Service Amount".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
model.serviceItems!.data![index].price!.toText(fontSize: 22, isBold: true),
2.width,
Padding(
padding: const EdgeInsets.only(bottom: 4),
child: "SAR".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( // Padding(
width: double.infinity, // padding: const EdgeInsets.all(4.0),
allPading: 12, // child: SvgPicture.asset(
); // MyAssets.icEdit,
}, // width: 16,
separatorBuilder: (BuildContext context, int index) { // height: 16,
return 12.height; // ),
}, // )
padding: const EdgeInsets.all(20), ],
itemCount: model.serviceItems!.data!.length, ),
); ).toWhiteContainer(width: double.infinity, allPading: 12);
},
separatorBuilder: (BuildContext context, int index) {
return 12.height;
},
padding: const EdgeInsets.all(20),
);
}, },
), ),
); );

@ -36,7 +36,7 @@ dependencies:
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
mc_common_app: mc_common_app:
path: C:/Users/mirza.shafique/AndroidStudioProjects/mc_common_app path: /Volumes/Data/Projects/Flutter/car_common_app
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -74,7 +74,7 @@ flutter:
# To add custom fonts to your application, add a fonts section here, # To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a # in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a # "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For # list giving the asset and other descriptors for the font. For
# example: # example:
# fonts: # fonts:

Loading…
Cancel
Save