Refactoring

aamir_dev
Faiz Hashmi 1 year ago
parent dd308e49de
commit 646ebbd3a5

@ -10,7 +10,7 @@ import 'package:car_provider_app/views/settings/branch/define_branch_view.dart';
import 'package:car_provider_app/views/settings/schedule/add_schedules_page.dart';
import 'package:car_provider_app/views/settings/schedule/schedules_list_page.dart';
import 'package:car_provider_app/views/settings/services/create_item_page.dart';
import 'package:car_provider_app/views/settings/dealership_view.dart';
import 'package:car_provider_app/views/settings/branch/dealer/dealership_view.dart';
import 'package:car_provider_app/views/settings/services/create_services_page3.dart';
import 'package:car_provider_app/views/settings/services/duplication/matched_services_page.dart';
import 'package:car_provider_app/views/settings/services/duplication/sheet/approved_branches_list_sheet.dart';

@ -1,6 +1,6 @@
import 'dart:async';
import 'package:car_provider_app/views/dashboard/widget/appointment_slider_widget.dart';
import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart';
import 'package:car_provider_app/views/settings/schedule/widgets/chips_picker_item.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
@ -65,7 +65,7 @@ class _AddNewServiceAppointmentPageState extends State<AddNewServiceAppointmentP
padding: const EdgeInsets.all(21.0),
child: Column(
children: [
AppointmentSliderWidget(
GeneralAppointmentWidget(
appointmentListModel: widget.appointmentListModel,
isNeedTotalPayment: true,
isNeedToShowItems: true,

@ -1,5 +1,5 @@
import 'package:car_provider_app/config/provider_routes.dart';
import 'package:car_provider_app/views/dashboard/widget/appointment_slider_widget.dart';
import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
@ -33,7 +33,7 @@ class AppointmentDetailListPage extends StatelessWidget {
} else {
return ListView.separated(
itemBuilder: (context, index) {
return AppointmentSliderWidget(
return GeneralAppointmentWidget(
appointmentListModel: appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index],
isNeedTotalPayment: true,
isNeedToShowAppointmentStatus: true,

@ -1,7 +1,7 @@
import 'dart:async';
import 'package:car_provider_app/config/provider_routes.dart';
import 'package:car_provider_app/views/dashboard/widget/appointment_slider_widget.dart';
import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
@ -105,7 +105,7 @@ class _AppointmentPageState extends State<AppointmentPage> {
),
ListView.separated(
itemBuilder: (context, index) {
return AppointmentSliderWidget(
return GeneralAppointmentWidget(
appointmentListModel: appointmentsVM.myFilteredAppointments2[index],
isNeedTotalPayment: false,
onTap: () {

@ -1,4 +1,4 @@
import 'package:car_provider_app/views/dashboard/widget/appointment_slider_widget.dart';
import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
@ -41,7 +41,7 @@ class MergeAppointmentListPage extends StatelessWidget {
? const Center(child: CircularProgressIndicator())
: ListView.separated(
itemBuilder: (context, index) {
return AppointmentSliderWidget(
return GeneralAppointmentWidget(
appointmentListModel: appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index],
isNeedTotalPayment: true,
isSelectable: true,

@ -17,7 +17,7 @@ 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';
import '../dashboard/widget/appointment_slider_widget.dart';
import '../dashboard/widget/general_appointment_widget.dart';
import 'package:easy_localization/easy_localization.dart';
class UpdateAppointmentPage extends StatelessWidget {
@ -45,7 +45,7 @@ class UpdateAppointmentPage extends StatelessWidget {
child: ListView(
padding: const EdgeInsets.all(21),
children: [
AppointmentSliderWidget(
GeneralAppointmentWidget(
appointmentListModel: appointmentListModel,
isNeedTotalPayment: true,
isNeedToShowItems: true,

@ -1,5 +1,5 @@
// import 'package:car_provider_app/config/provider_routes.dart';
// import 'package:car_provider_app/views/dashboard/widget/appointment_slider_widget.dart';
// import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart';
// import 'package:mc_common_app/classes/app_state.dart';
// import 'package:mc_common_app/config/dependency_injection.dart';
// import 'package:mc_common_app/extensions/string_extensions.dart';

@ -1,15 +1,13 @@
import 'package:car_provider_app/config/provider_routes.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:flutter_svg/flutter_svg.dart';
class AppointmentSliderWidget extends StatelessWidget {
class GeneralAppointmentWidget extends StatelessWidget {
final AppointmentListModel appointmentListModel;
final bool isNeedTotalPayment;
final bool isNeedToShowItems;
@ -19,7 +17,7 @@ class AppointmentSliderWidget extends StatelessWidget {
final bool isNeedToShowMergeStatus;
final Function()? onTap;
const AppointmentSliderWidget({
const GeneralAppointmentWidget({
required this.appointmentListModel,
required this.onTap,
this.isNeedTotalPayment = false,

@ -37,28 +37,11 @@ class ServiceProviderWidget extends StatelessWidget {
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
BranchDetailModel branchDetailModel = model.branches!.data!.serviceProviderBranch![index];
// print("profileImage: " + branchDetailModel.branchProfileImage.toString());
// branchDetailModel.branchProfileImage ??= "https://www.businesslinkuae.com/wp-content/uploads/2024/03/forigion-company.jpg";
// print("profileImage: " + branchDetailModel.branchProfileImage.toString());
return SizedBox(
width: 90,
child: Column(
children: [
branchDetailModel.branchProfileImage.buildNetworkImage(height: 73, width: 73, fit: BoxFit.cover).toCircle(borderRadius: 100),
// Image.network(
// branchDetailModel.branchProfileImage == null || branchDetailModel.branchProfileImage!.isEmpty ? "" : branchDetailModel.branchProfileImage!,
// errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
// return const SizedBox(
// width: 73,
// height: 73,
// child: Icon(Icons.error_outline),
// );
// },
// width: 73,
// height: 73,
// fit: BoxFit.cover,
// ).toCircle(borderRadius: 100),
9.height,
Flexible(
child: branchDetailModel.branchName!.toText(fontSize: 14, textAlign: TextAlign.center, letterSpacing: -0.84, height: 18 / 14),

@ -1,69 +0,0 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class AppMap extends StatefulWidget {
final CameraPositionCallback onCameraMove;
Map initialCamera;
late AppMapState _state;
final Function onMapCreated;
AppMap(this.initialCamera,
{required this.onCameraMove, required this.onMapCreated});
@override
State<StatefulWidget> createState() => _state = AppMapState();
moveTo({required CameraPosition cameraPostion}) {
_state.googleMapController
.animateCamera(CameraUpdate.newCameraPosition(cameraPostion));
}
}
class AppMapState extends State<AppMap> {
bool isHuawei = false;
Completer<GoogleMapController> _googleMapControllerComp = Completer();
late GoogleMapController googleMapController;
checkIsHuawei() async {
setState(() {});
}
@override
void initState() {}
@override
void dispose() {
super.dispose();
googleMapController.dispose();
}
@override
Widget build(BuildContext context) {
if (isHuawei == null) return CircularProgressIndicator();
return googleMap();
}
Widget googleMap() {
return GoogleMap(
mapType: MapType.normal,
zoomControlsEnabled: true,
myLocationButtonEnabled: true,
myLocationEnabled: true,
initialCameraPosition: CameraPosition.fromMap(widget.initialCamera) ??
const CameraPosition(
target: LatLng(-26.1711459, 27.9002758), zoom: 2.0),
onCameraMove: widget.onCameraMove,
onMapCreated: (GoogleMapController controller) {
googleMapController = controller;
_googleMapControllerComp.complete(controller);
widget.onMapCreated();
},
);
}
}

@ -1,180 +0,0 @@
import 'dart:async';
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:mc_common_app/generated/locale_keys.g.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/common_widgets/app_bar.dart';
import 'package:permission_handler/permission_handler.dart';
import 'map_selection_widget.dart';
import 'package:geocoding/geocoding.dart';
class PickLocationPage extends StatefulWidget {
Function(double, double, String) onPickAddress;
PickLocationPage({required this.onPickAddress});
@override
State<PickLocationPage> createState() => _PickLocationPageState();
}
class _PickLocationPageState extends State<PickLocationPage> {
double latitude = 0;
double longitude = 0;
final Set<Marker> markers = new Set();
late AppMap appMap;
static CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746,
);
late LatLng currentPostion;
Completer<GoogleMapController> mapController = Completer();
final ValueNotifier<String> _counter = ValueNotifier<String>("");
@override
void initState() {
appMap = AppMap(
_kGooglePlex.toMap() as Map,
onCameraMove: (camera) {
_updatePosition(camera);
},
onMapCreated: () {
// goToCurrentLocation();
_getUserLocation();
setState(() {});
},
);
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.pickLocation.tr(),
isRemoveBackButton: false,
),
body: Column(
children: [
Expanded(
child: Stack(
children: [
if (appMap != null) appMap,
ValueListenableBuilder<String>(
builder: (BuildContext context, String value, Widget? child) {
// This builder will only get called when the _counter
// is updated.
return value.isNotEmpty
? Container(
width: double.infinity,
margin: EdgeInsets.all(12),
child: Card(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Text(value ?? ""),
)),
)
: Container();
},
valueListenable: _counter,
),
const Align(
alignment: Alignment.center,
child: Icon(
Icons.place,
color: Colors.red,
size: 50,
),
),
],
),
),
Container(
width: double.infinity,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: ShowFillButton(
title: LocaleKeys.pickAddress.tr(),
onPressed: () {
widget.onPickAddress(latitude, longitude, _counter.value);
pop(context);
},
),
),
),
],
),
);
}
Future<void> _updatePosition(CameraPosition _position) async {
latitude = _position.target.latitude;
longitude = _position.target.longitude;
print(latitude);
print(latitude);
updateAddress(latitude, longitude);
}
void _getUserLocation() async {
if (await Permission.location.request().isGranted) {
var position = await GeolocatorPlatform.instance.getCurrentPosition();
currentPostion = LatLng(position.latitude, position.longitude);
latitude = position.latitude;
longitude = position.longitude;
setMap();
updateAddress(latitude, longitude);
} else {
requestPermissions().then(
(value) async {
if (value[Permission.location]!.isGranted) {
var position = await GeolocatorPlatform.instance.getCurrentPosition();
currentPostion = LatLng(position.latitude, position.longitude);
latitude = position.latitude;
longitude = position.longitude;
setMap();
updateAddress(latitude, longitude);
}
},
);
}
}
updateAddress(double latitude, double longitude) async {
List<Placemark> placemarks = await placemarkFromCoordinates(latitude, longitude);
_counter.value = '${placemarks.first.street}, ${placemarks.first.subLocality}, ${placemarks.first.locality}, ${placemarks.first.postalCode}, ${placemarks.first.country}';
}
setMap() {
setState(() {
_kGooglePlex = CameraPosition(
target: currentPostion,
zoom: 14.4746,
);
appMap.moveTo(cameraPostion: _kGooglePlex);
});
}
Future<String> getCurrentAddress() async {
// List<Placemark> placemarks = await placemarkFromCoordinates(latitude, longitude);
// return placemarks.first.name ?? "";
return "";
}
}
Future<Map<Permission, PermissionStatus>> requestPermissions() async {
var permissionResults = [Permission.location].request();
return permissionResults;
}

@ -60,6 +60,35 @@ class BranchDetailPage extends StatelessWidget {
branchData.categories = categories;
}
bool validation(BuildContext context) {
bool isValid = false;
for (var element in context.read<ServiceVM>().allProviderDealersList) {
if (element.isBranchUser ?? false) {
isValid = true;
}
}
return isValid;
}
Widget showData(String title, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText(
fontSize: 12,
color: MyColors.darkTextColor,
),
8.width,
Flexible(
child: value.toText(
fontSize: 12,
color: MyColors.textColor,
),
)
],
);
}
Widget buildFooterActionWidget(BuildContext context) {
Widget actionWidget = const SizedBox();
if (AppState().userType == UserType.providerDealer && branchData.branchStatus == BranchStatusEnum.approvedOrActive) {
@ -87,9 +116,17 @@ class BranchDetailPage extends StatelessWidget {
actionWidget = ShowFillButton(
title: "Pending Approval",
maxWidth: double.infinity,
backgroundColor: MyColors.darkWhiteColor,
isDisabled: true,
onPressed: () {},
);
} else if (branchData.branchStatus == BranchStatusEnum.deactivated) {
actionWidget = ShowFillButton(
title: "Activate Now",
maxWidth: double.infinity,
backgroundColor: MyColors.darkPrimaryColor,
borderColor: MyColors.darkPrimaryColor,
txtColor: MyColors.lightTextColor,
txtColor: MyColors.white,
fontSize: 15,
isFilled: true,
onPressed: () {},
);
@ -97,7 +134,9 @@ class BranchDetailPage extends StatelessWidget {
actionWidget = Column(
children: [
Row(
children: [('${LocaleKeys.rejectionComments.tr()}:').toText(fontSize: 16, color: MyColors.darkTextColor, textAlign: TextAlign.right)],
children: [
('${LocaleKeys.rejectionComments.tr()}:').toText(fontSize: 16, color: MyColors.darkTextColor, textAlign: TextAlign.right),
],
),
Row(
children: [
@ -128,10 +167,63 @@ class BranchDetailPage extends StatelessWidget {
return actionWidget.paddingAll(21);
}
Widget buildServiceTileWidget(int pIndex) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(top: 5),
child: SvgPicture.asset(
MyAssets.maintenanceIcon,
width: 14,
height: 14,
),
),
8.width,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
categories[pIndex].categoryName.toString().toText(fontSize: 16),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return Container(
child: (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA" ? categories[pIndex].services![index].serviceDescriptionN.toString() : categories[pIndex].services![index].serviceDescription.toString()).toText(
fontSize: 12,
color: MyColors.lightTextColor,
),
);
},
itemCount: categories[pIndex].services?.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
),
),
],
).withArrow(isArrowEnabled: true)
],
)),
],
).toWhiteContainer(width: double.infinity, allPading: 12);
}
@override
Widget build(BuildContext context) {
filterBranch();
// getBranchUsers(context);
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.branchDetail.tr()),
body: Consumer<ServiceVM>(builder: (context, model, _) {
@ -152,7 +244,7 @@ class BranchDetailPage extends StatelessWidget {
Expanded(
child: Row(
children: [
branchData.branchProfileImage.buildNetworkImage(height: 66, width: 53, fit: BoxFit.cover),
branchData.branchProfileImage.buildNetworkImage(height: 66, width: 53, fit: BoxFit.cover),
11.width,
Expanded(
child: Column(
@ -201,7 +293,6 @@ class BranchDetailPage extends StatelessWidget {
const Icon(
Icons.calendar_month,
color: Colors.white,
),
8.width,
Expanded(
@ -237,11 +328,7 @@ class BranchDetailPage extends StatelessWidget {
backgroundColor: MyColors.darkIconColor,
),
8.width,
LocaleKeys.addNewService.tr().toText(
fontSize: 13,
color: MyColors.lightTextColor,
letterSpacing: -0.52
),
LocaleKeys.addNewService.tr().toText(fontSize: 13, color: MyColors.lightTextColor, letterSpacing: -0.52),
],
)
.toContainer(
@ -263,88 +350,11 @@ class BranchDetailPage extends StatelessWidget {
}),
ListView.separated(
itemBuilder: (context, pIndex) {
return InkWell(
onTap: () {
categories[pIndex].branchId = branchData.id.toString();
categories[pIndex].branchName = branchData.branchName.toString();
navigateWithName(context, ProviderAppRoutes.servicesList, arguments: categories[pIndex]);
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(top: 5),
child: SvgPicture.asset(
MyAssets.maintenanceIcon,
width: 14,
height: 14,
),
),
8.width,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
categories[pIndex].categoryName.toString().toText(fontSize: 16),
// Padding(
// padding: const EdgeInsets.all(4.0),
// child: SvgPicture.asset(
// MyAssets.icEdit,
// width: 16,
// height: 16,
// ),
// ),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return Container(
child: (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA"
? categories[pIndex].services![index].serviceDescriptionN.toString()
: categories[pIndex].services![index].serviceDescription.toString())
.toText(
fontSize: 12,
color: MyColors.lightTextColor,
),
);
},
itemCount: categories[pIndex].services?.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
),
),
// const Padding(
// padding: EdgeInsets.all(4.0),
// child: Icon(
// Icons.arrow_forward,
// size: 20,
// ),
// ),
],
).withArrow(isArrowEnabled: true)
],
)),
],
).toContainer(
borderRadius: 0,
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
isShadowEnabled: true,
),
);
return buildServiceTileWidget(pIndex).onPress(() {
categories[pIndex].branchId = branchData.id.toString();
categories[pIndex].branchName = branchData.branchName.toString();
navigateWithName(context, ProviderAppRoutes.servicesList, arguments: categories[pIndex]);
});
},
itemCount: categories.length,
physics: const NeverScrollableScrollPhysics(),
@ -371,33 +381,4 @@ class BranchDetailPage extends StatelessWidget {
}),
);
}
bool validation(BuildContext context) {
bool isValid = false;
for (var element in context.read<ServiceVM>().allProviderDealersList) {
if (element.isBranchUser ?? false) {
isValid = true;
}
}
return isValid;
}
Widget showData(String title, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText(
fontSize: 12,
color: MyColors.darkTextColor,
),
8.width,
Flexible(
child: value.toText(
fontSize: 12,
color: MyColors.textColor,
),
)
],
);
}
}

@ -6,7 +6,7 @@ import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/service_view_model.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:car_provider_app/views/location/pick_location_page.dart';
import 'package:mc_common_app/views/location_views/pick_location_page.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/theme/colors.dart';

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/categroy.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -12,7 +13,7 @@ import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/widgets/bottom_sheet.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/empty_widget.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/tab/role_type_tab.dart';
@ -99,7 +100,9 @@ class _ServicesListPageState extends State<ServicesListPage> {
const SizedBox(height: 10),
Expanded(
child: services.isEmpty
? const EmptyWidget()
? Center(
child: LocaleKeys.noItemstoShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor),
)
: ListView.separated(
itemBuilder: (context, index) {
return SizedBox(

@ -40,8 +40,8 @@ dependencies:
# path: C:/Users/mirza.shafique/AndroidStudioProjects/mc_common_app
mc_common_app:
# path: /Users/amir/StudioProjects/car_common_app
path: /Users/amir/StudioProjects/car_common_app
path: /Volumes/Data/Projects/Flutter/car_common_app
# path: /Users/amir/StudioProjects/car_common_app

Loading…
Cancel
Save