developed
This commit is contained in:
parent
9177c08239
commit
1eebe2c468
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
|
|
@ -4,7 +4,7 @@
|
|||
"follow_orders": "öz ýüküňizi yzarlaň",
|
||||
"order_history": "Sargytlaryň taryhy",
|
||||
"order_history_desc": "şu ýerde siziň sargytlaryňyz wagt tertipi boyunça görkezilen",
|
||||
"order_not_available": "Sargyt yok",
|
||||
"order_not_available": "Siziň ýapylan sargytlaryňyz ýok",
|
||||
"personal_cabinet": "Şahsy otagym",
|
||||
"splash_text": "Довезём всё!",
|
||||
"start_tracking": "Yzarlap başlaň",
|
||||
|
|
@ -29,14 +29,14 @@
|
|||
"order_status": "Ýagdaýy",
|
||||
"order_carrier": "Awtoulag №",
|
||||
"order_shop": "Dükan №",
|
||||
"order_from": "Nireden ugradyldy:",
|
||||
"order_to": "Nirä barmaly:",
|
||||
"order_placement_count": "'Ýer sany",
|
||||
"order_from": "Nireden ugradyldy",
|
||||
"order_to": "Nirä barmaly",
|
||||
"order_placement_count": "Ýer sany",
|
||||
"order_volume": "Kuby",
|
||||
"order_dimensions": "Göwrümi",
|
||||
"order_dimensions_desc": "(ini, uzynlygy, beýikligi)",
|
||||
"order_product_name": "Harydyň ady",
|
||||
"contact_support": "Tehniki goldaw bilen habarlaşmak",
|
||||
"contact_support": "Habarlaşmak üçin",
|
||||
"privacy_policy": "Gizlinlik syýasaty",
|
||||
"use_terms": "Ulanyş şertleri",
|
||||
"logout": "Şahsy otagdan çykmak",
|
||||
|
|
@ -47,5 +47,6 @@
|
|||
"Reserved": "Rezerw",
|
||||
"Received": "Kabul edildi",
|
||||
"Delivered": "Gowşuryldy",
|
||||
"image_preview": "Image Preview"
|
||||
"image_preview": "Image Preview",
|
||||
"error_message": "Something went wrong. Please try again."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"follow_orders": "öz ýüküňizi yzarlaň",
|
||||
"order_history": "Sargytlaryň taryhy",
|
||||
"order_history_desc": "şu ýerde siziň sargytlaryňyz wagt tertipi boyunça görkezilen",
|
||||
"order_not_available": "Sargyt yok",
|
||||
"order_not_available": "Siziň ýapylan sargytlaryňyz ýok",
|
||||
"personal_cabinet": "Şahsy otagym",
|
||||
"splash_text": "Довезём всё!",
|
||||
"start_tracking": "Yzarlap başlaň",
|
||||
|
|
@ -29,14 +29,14 @@
|
|||
"order_status": "Ýagdaýy",
|
||||
"order_carrier": "Awtoulag №",
|
||||
"order_shop": "Dükan №",
|
||||
"order_from": "Nireden ugradyldy:",
|
||||
"order_to": "Nirä barmaly:",
|
||||
"order_placement_count": "'Ýer sany",
|
||||
"order_from": "Nireden ugradyldy",
|
||||
"order_to": "Nirä barmaly",
|
||||
"order_placement_count": "Ýer sany",
|
||||
"order_volume": "Kuby",
|
||||
"order_dimensions": "Göwrümi",
|
||||
"order_dimensions_desc": "(ini, uzynlygy, beýikligi)",
|
||||
"order_product_name": "Harydyň ady",
|
||||
"contact_support": "Tehniki goldaw bilen habarlaşmak",
|
||||
"contact_support": "Habarlaşmak üçin",
|
||||
"privacy_policy": "Gizlinlik syýasaty",
|
||||
"use_terms": "Ulanyş şertleri",
|
||||
"logout": "Şahsy otagdan çykmak",
|
||||
|
|
@ -47,5 +47,6 @@
|
|||
"Reserved": "Rezerw",
|
||||
"Received": "Kabul edildi",
|
||||
"Delivered": "Gowşuryldy",
|
||||
"image_preview": "Image Preview"
|
||||
"image_preview": "Image Preview",
|
||||
"error_message": "Something went wrong. Please try again."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../core/core.dart';
|
||||
import '../../domain/domain.dart';
|
||||
|
||||
part 'contact_state.dart';
|
||||
|
||||
class ContactCubit extends Cubit<ContactState> {
|
||||
final GetContactsUseCase _getContactsUseCase;
|
||||
|
||||
ContactCubit(this._getContactsUseCase) : super(ContactInitial());
|
||||
|
||||
Future<void> getContacts() async {
|
||||
try {
|
||||
emit(ContactLoading());
|
||||
final result = await _getContactsUseCase(NoParams());
|
||||
result.fold(
|
||||
(failure) => emit(ContactError()),
|
||||
(response) => emit(
|
||||
ContactLoaded(contacts: response.contacts),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(ContactError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
part of 'contact_cubit.dart';
|
||||
|
||||
sealed class ContactState extends Equatable {
|
||||
const ContactState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class ContactInitial extends ContactState {}
|
||||
|
||||
final class ContactLoading extends ContactState {}
|
||||
|
||||
final class ContactError extends ContactState {}
|
||||
|
||||
final class ContactLoaded extends ContactState {
|
||||
final List<ContactEntity> contacts;
|
||||
|
||||
const ContactLoaded({required this.contacts});
|
||||
|
||||
@override
|
||||
List<Object> get props => [contacts];
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ class SplashCubit extends Cubit<SplashState> {
|
|||
SplashCubit(this._splashUseCase) : super(SplashInitial());
|
||||
|
||||
Future<void> checkToken() async {
|
||||
await Future.delayed(const Duration(seconds: 1)); // Simulating some loading time
|
||||
// await Future.delayed(const Duration(seconds: 1)); // Simulating some loading time
|
||||
try {
|
||||
final result = await _splashUseCase(NoParams());
|
||||
result.fold((failure) => emit(NavigateToSplash2()), (result) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:cargo/application/contact_cubit/contact_cubit.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../application/application.dart';
|
||||
import '../../di/di.dart' as di;
|
||||
import '../../domain/entities/order/filter_params_model.dart';
|
||||
import '../core.dart';
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
|
|
@ -18,6 +18,9 @@ class MyApp extends StatelessWidget {
|
|||
BlocProvider(
|
||||
create: (context) => di.sl<SplashCubit>()..checkToken(),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => di.sl<ContactCubit>(),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => di.sl<LanguageBloc>()..add(LanguageInitial()),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ sealed class AppAssets {
|
|||
static const String boxesPng = 'assets/images/boxes.png';
|
||||
static const String trucksPng = 'assets/images/trucks.png';
|
||||
static const String header = 'assets/images/header.png';
|
||||
static const String search = 'assets/images/search.png';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../core/core.dart';
|
||||
import '../../data.dart';
|
||||
|
||||
abstract class ContactRemoteDataSource {
|
||||
Future<ContactResponseModel> getContacts(String token);
|
||||
}
|
||||
|
||||
class ContactRemoteDataSourceImpl implements ContactRemoteDataSource {
|
||||
final http.Client client;
|
||||
ContactRemoteDataSourceImpl({required this.client});
|
||||
|
||||
@override
|
||||
Future<ContactResponseModel> getContacts(String token) async {
|
||||
final response = await client.get(
|
||||
Uri.parse('$baseUrl/odata/Contact'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'accept': '*/*',
|
||||
'Authorization': 'Bearer $token',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return contactResponseModelFromJson(response.body);
|
||||
} else {
|
||||
throw ServerException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ class OrderRemoteDataSourceImpl implements OrderRemoteDataSource {
|
|||
Uri uri;
|
||||
if (params.filter == OrderFilter.Home) {
|
||||
uri = Uri.parse(
|
||||
'$baseUrl/Goods?pageNumber=${params.offset}&pageSize=${params.limit}&state=Reserved&state=Received',
|
||||
'$baseUrl/Goods?pageNumber=${params.offset}&pageSize=${params.limit}&state=Received',
|
||||
);
|
||||
} else {
|
||||
uri = Uri.parse(
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
export 'user_remote_data_source.dart';
|
||||
export 'order_remote_data_source.dart';
|
||||
export 'contact_remote_data_source.dart';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import '../../../domain/entities/contact/contact.dart';
|
||||
|
||||
class ContactModel extends ContactEntity {
|
||||
ContactModel({
|
||||
required super.oid,
|
||||
required super.number,
|
||||
required super.name,
|
||||
});
|
||||
|
||||
factory ContactModel.fromJson(Map<String, dynamic> json) {
|
||||
return ContactModel(
|
||||
oid: json['Oid'],
|
||||
number: json['Number'],
|
||||
name: json['Name'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'Oid': oid,
|
||||
'Number': number,
|
||||
'Name': name,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import '../../../domain/entities/entities.dart';
|
||||
import 'contact_model.dart';
|
||||
|
||||
ContactResponseModel contactResponseModelFromJson(String str) => ContactResponseModel.fromJson(json.decode(str));
|
||||
|
||||
class ContactResponseModel extends ContactResponse {
|
||||
ContactResponseModel({required super.contacts});
|
||||
|
||||
factory ContactResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
return ContactResponseModel(
|
||||
contacts: List<ContactModel>.from(
|
||||
json['value'].map((contact) => ContactModel.fromJson(contact)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Map<String, dynamic> toJson() {
|
||||
// return {
|
||||
// 'value': contacts.map((contact) => contact.toJson()).toList(),
|
||||
// };
|
||||
// }
|
||||
}
|
||||
|
|
@ -4,3 +4,5 @@ export 'user/user_model.dart';
|
|||
export 'order/order_model.dart';
|
||||
export 'order/order_response_model.dart';
|
||||
export 'route/route_model.dart';
|
||||
export 'contact/contact_model.dart';
|
||||
export 'contact/contact_response_model.dart';
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class UserModel extends User {
|
|||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'Oid': oid,
|
||||
'FulName': fullName,
|
||||
'Fulname': fullName,
|
||||
'PhoneNo': phone,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import 'package:dartz/dartz.dart';
|
||||
|
||||
import '../../core/core.dart';
|
||||
import '../../domain/domain.dart';
|
||||
import '../data_sources/data_sources.dart';
|
||||
import '../models/contact/contact_response_model.dart';
|
||||
|
||||
class ContactRepositoryImpl extends ContactRepository {
|
||||
final ContactRemoteDataSource remoteDataSource;
|
||||
final UserLocalDataSource localDataSource;
|
||||
final NetworkInfo networkInfo;
|
||||
|
||||
ContactRepositoryImpl({
|
||||
required this.remoteDataSource,
|
||||
required this.localDataSource,
|
||||
required this.networkInfo,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Either<Failure, ContactResponseModel>> getContacts() async {
|
||||
if (!await networkInfo.isConnected) {
|
||||
return Left(NetworkFailure());
|
||||
}
|
||||
|
||||
try {
|
||||
final String token = await localDataSource.getToken();
|
||||
final response = await remoteDataSource.getContacts(token);
|
||||
return Right(response);
|
||||
} on Failure catch (failure) {
|
||||
return Left(failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export 'user_repository_impl.dart';
|
||||
export 'splash_repository_impl.dart';
|
||||
export 'order_repository_impl.dart';
|
||||
export 'contact_repository_impl.dart';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import '../application/contact_cubit/contact_cubit.dart';
|
||||
import '../data/data.dart';
|
||||
import '../domain/domain.dart';
|
||||
import 'di.dart';
|
||||
|
||||
void registerContactFeature() {
|
||||
// Contact cubit and Use Cases
|
||||
sl.registerFactory(() => ContactCubit(sl()));
|
||||
sl.registerLazySingleton(() => GetContactsUseCase(sl()));
|
||||
|
||||
// Contact Repository and Data Sources
|
||||
sl.registerLazySingleton<ContactRepository>(
|
||||
() => ContactRepositoryImpl(
|
||||
localDataSource: sl(),
|
||||
remoteDataSource: sl(),
|
||||
networkInfo: sl(),
|
||||
),
|
||||
);
|
||||
|
||||
sl.registerLazySingleton<ContactRemoteDataSource>(
|
||||
() => ContactRemoteDataSourceImpl(client: sl()),
|
||||
);
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:get_it/get_it.dart';
|
||||
|
||||
import 'common.dart';
|
||||
import 'contact.dart';
|
||||
import 'cubits.dart';
|
||||
import 'language.dart';
|
||||
import 'order.dart';
|
||||
|
|
@ -17,6 +18,7 @@ Future<void> init() async {
|
|||
registerLanguageFeature();
|
||||
registerSplashFeature();
|
||||
registerOrderFeature();
|
||||
registerContactFeature();
|
||||
// registerCategoryFeature();
|
||||
// registerProductFeature();
|
||||
// registerDeliveryInfoFeature();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class ContactEntity extends Equatable {
|
||||
final String oid;
|
||||
final String number;
|
||||
final String name;
|
||||
|
||||
const ContactEntity({
|
||||
required this.oid,
|
||||
required this.number,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [oid, number, name];
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import 'contact.dart';
|
||||
|
||||
class ContactResponse {
|
||||
final List<ContactEntity> contacts;
|
||||
|
||||
ContactResponse({
|
||||
required this.contacts,
|
||||
});
|
||||
}
|
||||
|
|
@ -5,3 +5,5 @@ export 'order/order_response.dart';
|
|||
export 'order/pagination_meta_data.dart';
|
||||
export 'route/route.dart';
|
||||
export 'route/route_response.dart';
|
||||
export 'contact/contact.dart';
|
||||
export 'contact/contact_response.dart';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
import 'package:dartz/dartz.dart';
|
||||
|
||||
import '../../core/core.dart';
|
||||
import '../../data/models/contact/contact_response_model.dart';
|
||||
|
||||
abstract class ContactRepository {
|
||||
Future<Either<Failure, ContactResponseModel>> getContacts();
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export 'user_repository.dart';
|
||||
export 'splash_repository.dart';
|
||||
export 'order_repository.dart';
|
||||
export 'contact_repository.dart';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import 'package:dartz/dartz.dart';
|
||||
|
||||
import '../../../core/core.dart';
|
||||
import '../../domain.dart';
|
||||
|
||||
class GetContactsUseCase implements UseCase<ContactResponse, NoParams> {
|
||||
final ContactRepository repository;
|
||||
GetContactsUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, ContactResponse>> call(NoParams params) async {
|
||||
return await repository.getContacts();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export 'user/user.dart';
|
||||
export 'splash/splash_usecase.dart';
|
||||
export 'contact/get_contacts_usecase.dart';
|
||||
export 'order/order.dart';
|
||||
export 'splash/splash_usecase.dart';
|
||||
export 'user/user.dart';
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ class _HistoriesScreenState extends State<HistoriesScreen> {
|
|||
'order_history'.tr(),
|
||||
style: AppText.h1b,
|
||||
),
|
||||
Space.yf(0.4),
|
||||
Text(
|
||||
'order_history_desc'.tr(),
|
||||
style: const TextStyle(
|
||||
|
|
@ -77,6 +78,12 @@ class _HistoriesScreenState extends State<HistoriesScreen> {
|
|||
),
|
||||
);
|
||||
} else if (state is OrderLoaded) {
|
||||
if (state.orders.isEmpty) {
|
||||
return const SliverToBoxAdapter(
|
||||
child: EmptyOrder(),
|
||||
);
|
||||
}
|
||||
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
|
|
@ -93,11 +100,7 @@ class _HistoriesScreenState extends State<HistoriesScreen> {
|
|||
),
|
||||
);
|
||||
} else {
|
||||
return SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: Text('order_not_available'.tr()),
|
||||
),
|
||||
);
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class _OrderDetailsScreenState extends State<OrderDetailsScreen> {
|
|||
children: [
|
||||
Text(
|
||||
'${'order_info'.tr()} №${widget.order.no}',
|
||||
style: AppText.b1b,
|
||||
style: AppText.h2b,
|
||||
),
|
||||
|
||||
/// gap
|
||||
|
|
@ -131,7 +131,7 @@ class _OrderDetailsScreenState extends State<OrderDetailsScreen> {
|
|||
children: [
|
||||
Text(
|
||||
'route'.tr(),
|
||||
style: AppText.b1b,
|
||||
style: AppText.h2b,
|
||||
),
|
||||
|
||||
/// gap
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../application/order_bloc/order_bloc.dart';
|
||||
|
|
@ -54,7 +55,7 @@ class _OrdersScreenState extends State<OrdersScreen> with AutomaticKeepAliveClie
|
|||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Space.yf(0.30),
|
||||
Space.yf(0.40),
|
||||
Text(
|
||||
'follow_orders'.tr(),
|
||||
style: const TextStyle(
|
||||
|
|
@ -83,6 +84,14 @@ class _OrdersScreenState extends State<OrdersScreen> with AutomaticKeepAliveClie
|
|||
),
|
||||
);
|
||||
} else if (state is OrderLoaded) {
|
||||
if (state.orders.isEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 2.5,
|
||||
child: const EmptyOrder(),
|
||||
),
|
||||
);
|
||||
}
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
|
|
@ -99,11 +108,7 @@ class _OrdersScreenState extends State<OrdersScreen> with AutomaticKeepAliveClie
|
|||
),
|
||||
);
|
||||
} else {
|
||||
return const SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: Text('No orders available'),
|
||||
),
|
||||
);
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../../application/contact_cubit/contact_cubit.dart';
|
||||
import '../../application/user_bloc/user_bloc.dart';
|
||||
import '../../configs/configs.dart';
|
||||
import '../../core/core.dart';
|
||||
import '../../domain/entities/contact/contact.dart';
|
||||
import '../../domain/entities/user/user.dart';
|
||||
import '../widgets/lang_selection.dart';
|
||||
import '../presentation.dart';
|
||||
|
||||
class ProfileScreen extends StatefulWidget {
|
||||
const ProfileScreen({super.key});
|
||||
|
|
@ -20,6 +24,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
context.read<UserBloc>().add(GetUser());
|
||||
context.read<ContactCubit>().getContacts();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -55,138 +60,199 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||
}
|
||||
|
||||
Widget _buildProfileContent(BuildContext context, User user) {
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: Space.all(1, 1),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
/// gap
|
||||
Space.yf(1.3),
|
||||
return Padding(
|
||||
padding: Space.all(1, 1),
|
||||
child: Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
/// gap
|
||||
Space.yf(1.3),
|
||||
|
||||
/// header
|
||||
Text(
|
||||
'personal_cabinet'.tr(),
|
||||
style: AppText.h1b,
|
||||
/// header
|
||||
Text(
|
||||
'personal_cabinet'.tr(),
|
||||
style: AppText.h1b,
|
||||
),
|
||||
|
||||
Space.y!,
|
||||
|
||||
/// user card
|
||||
_buildUserCard(context, user),
|
||||
|
||||
///gap
|
||||
Space.yf(2),
|
||||
|
||||
/// settings card
|
||||
_buildSettingsCard(context),
|
||||
|
||||
///gap
|
||||
Space.yf(2),
|
||||
|
||||
/// contacts list
|
||||
BlocBuilder<ContactCubit, ContactState>(
|
||||
builder: (context, state) {
|
||||
if (state is ContactLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is ContactLoaded) {
|
||||
return state.contacts.isEmpty ? const SizedBox.shrink() : _buildContactsList(state.contacts);
|
||||
} else if (state is ContactError) {
|
||||
return RetryWidget(
|
||||
onRetry: () {
|
||||
context.read<ContactCubit>().getContacts();
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Space.y!,
|
||||
|
||||
/// card
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Card(
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
/// name surname
|
||||
RowWidget(
|
||||
text: user.fullName,
|
||||
leadingIcon: Icons.person_2_outlined,
|
||||
),
|
||||
|
||||
/// gap
|
||||
Space.yf(1),
|
||||
|
||||
/// phone
|
||||
RowWidget(
|
||||
text: user.phone,
|
||||
leadingIcon: Icons.phone_android_outlined,
|
||||
),
|
||||
],
|
||||
),
|
||||
/// logout at the bottom
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
context.read<UserBloc>().add(SignOutUser());
|
||||
},
|
||||
child: Text(
|
||||
'logout'.tr(),
|
||||
style: AppText.b1!.copyWith(
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///gap
|
||||
Space.yf(2),
|
||||
Widget _buildUserCard(BuildContext context, User user) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Card(
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
/// name surname
|
||||
RowWidget(
|
||||
text: user.fullName,
|
||||
leadingIcon: Icons.person_2_outlined,
|
||||
),
|
||||
|
||||
/// card
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Card(
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
/// phone
|
||||
if (user.phone.isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
/// gap
|
||||
Space.yf(1),
|
||||
|
||||
/// phone
|
||||
RowWidget(
|
||||
text: user.phone,
|
||||
leadingIcon: Icons.phone_android_outlined,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSettingsCard(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Card(
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
/// language
|
||||
GestureDetector(
|
||||
onTap: () => onSelectLang(context),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: RowWidget(
|
||||
text: 'contact_support'.tr(),
|
||||
leadingIcon: Icons.contact_support_outlined,
|
||||
text: 'profile_select_lang'.tr(),
|
||||
leadingIcon: Icons.language_outlined,
|
||||
trailingIcon: Icons.arrow_forward_ios,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///gap
|
||||
Space.yf(2),
|
||||
|
||||
/// card
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Card(
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
Widget _buildContactsList(List<ContactEntity> contacts) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'contact_support'.tr(),
|
||||
style: AppText.h3b,
|
||||
),
|
||||
Space.yf(0.8),
|
||||
...contacts.map(
|
||||
(contact) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
/// language
|
||||
GestureDetector(
|
||||
onTap: () => onSelectLang(context),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: RowWidget(
|
||||
text: 'profile_select_lang'.tr(),
|
||||
leadingIcon: Icons.language_outlined,
|
||||
trailingIcon: Icons.arrow_forward_ios,
|
||||
),
|
||||
const Icon(Icons.phone_iphone),
|
||||
const SizedBox(width: 8),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${contact.number} ',
|
||||
style: const TextStyle(
|
||||
color: Colors.black, // Use appropriate color
|
||||
fontWeight: FontWeight.bold, // You can choose different font styles
|
||||
fontSize: 16, // Set font size
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
final Uri phoneUri = Uri(scheme: 'tel', path: contact.number);
|
||||
launchUrl(phoneUri);
|
||||
},
|
||||
),
|
||||
TextSpan(
|
||||
text: contact.name,
|
||||
style: TextStyle(
|
||||
color: Colors.grey[700], // A different color for the name
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
/// name surname
|
||||
RowWidget(
|
||||
text: 'privacy_policy'.tr(),
|
||||
leadingIcon: Icons.gpp_maybe_outlined,
|
||||
trailingIcon: Icons.arrow_forward_ios,
|
||||
),
|
||||
|
||||
/// phone
|
||||
RowWidget(
|
||||
text: 'use_terms'.tr(),
|
||||
leadingIcon: Icons.file_copy_outlined,
|
||||
trailingIcon: Icons.arrow_forward_ios,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
///gap
|
||||
Space.yf(2),
|
||||
|
||||
/// logout
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
context.read<UserBloc>().add(SignOutUser());
|
||||
},
|
||||
child: Text(
|
||||
'logout'.tr(),
|
||||
style: AppText.b1!.copyWith(
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
///gap
|
||||
Space.yf(2),
|
||||
],
|
||||
),
|
||||
Space.yf(0.6)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../configs/space.dart';
|
||||
import '../../core/constants/constants.dart';
|
||||
|
||||
class EmptyOrder extends StatelessWidget {
|
||||
const EmptyOrder({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: MediaQuery.of(context).size.height - kToolbarHeight * 3,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset(AppAssets.search),
|
||||
Space.yf(),
|
||||
Text('order_not_available'.tr()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -60,10 +60,11 @@ class RowTextWidget extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: AppText.b1!.copyWith(
|
||||
style: AppText.h3!.copyWith(
|
||||
color: const Color(0xFF57575C),
|
||||
),
|
||||
maxLines: 2,
|
||||
|
|
@ -72,7 +73,7 @@ class RowTextWidget extends StatelessWidget {
|
|||
Expanded(
|
||||
child: Text(
|
||||
info,
|
||||
style: AppText.b1!.copyWith(
|
||||
style: AppText.h3!.copyWith(
|
||||
color: const Color(0xFF0C0C0D),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class LocationCard extends StatelessWidget {
|
|||
Space.x!,
|
||||
Text(
|
||||
routes[index].name,
|
||||
style: AppText.b1b,
|
||||
style: AppText.h3b,
|
||||
),
|
||||
const Spacer(),
|
||||
Text(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ import '../../core/core.dart';
|
|||
import '../../domain/domain.dart';
|
||||
import 'vertical_line.dart';
|
||||
|
||||
final infoStyle = AppText.b2b!.copyWith(
|
||||
color: const Color(0xFF57575C),
|
||||
fontSize: 16,
|
||||
);
|
||||
|
||||
class OrderCard extends StatelessWidget {
|
||||
final OrderEntity order;
|
||||
|
||||
|
|
@ -61,11 +66,30 @@ class OrderCard extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Text(
|
||||
/* Text(
|
||||
'${'order_sent'.tr()}: ${order.departedAt}',
|
||||
style: AppText.b2b!.copyWith(
|
||||
color: AppColors.grey,
|
||||
),
|
||||
), */
|
||||
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: '${'order_sent'.tr()}: ',
|
||||
style: AppText.b2b!.copyWith(
|
||||
color: AppColors.grey,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: order.departedAt,
|
||||
style: AppText.b2b!.copyWith(
|
||||
color: const Color(0xFF57575C),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -107,9 +131,7 @@ class OrderCard extends StatelessWidget {
|
|||
),
|
||||
Text(
|
||||
order.from,
|
||||
style: AppText.b2b!.copyWith(
|
||||
color: const Color(0xFF57575C),
|
||||
),
|
||||
style: infoStyle,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
|
@ -122,9 +144,7 @@ class OrderCard extends StatelessWidget {
|
|||
),
|
||||
Text(
|
||||
order.to,
|
||||
style: AppText.b2b!.copyWith(
|
||||
color: const Color(0xFF57575C),
|
||||
),
|
||||
style: infoStyle,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
|
@ -148,9 +168,7 @@ class OrderCard extends StatelessWidget {
|
|||
),
|
||||
Text(
|
||||
order.placesCount.toString(),
|
||||
style: AppText.b2b!.copyWith(
|
||||
color: const Color(0xFF57575C),
|
||||
),
|
||||
style: infoStyle,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
|
|
@ -161,9 +179,7 @@ class OrderCard extends StatelessWidget {
|
|||
),
|
||||
Text(
|
||||
order.volume.toString(),
|
||||
style: AppText.b2b!.copyWith(
|
||||
color: const Color(0xFF57575C),
|
||||
),
|
||||
style: infoStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -194,9 +210,7 @@ class OrderCard extends StatelessWidget {
|
|||
),
|
||||
Text(
|
||||
order.shopNo,
|
||||
style: AppText.b2b!.copyWith(
|
||||
color: const Color(0xFF57575C),
|
||||
),
|
||||
style: infoStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class RetryWidget extends StatelessWidget {
|
||||
|
|
@ -7,7 +8,7 @@ class RetryWidget extends StatelessWidget {
|
|||
const RetryWidget({
|
||||
super.key,
|
||||
required this.onRetry,
|
||||
this.message = 'Something went wrong. Please try again.',
|
||||
this.message = 'error_message',
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -19,7 +20,7 @@ class RetryWidget extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
message,
|
||||
message.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 16, color: Colors.black54),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ export 'retry_widget.dart';
|
|||
export 'successful_auth_dialog.dart';
|
||||
export 'vertical_line.dart';
|
||||
export 'images.dart';
|
||||
export 'empty_order.dart';
|
||||
|
|
|
|||
64
pubspec.lock
64
pubspec.lock
|
|
@ -626,6 +626,70 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
url_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.0"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.9"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.1"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ dependencies:
|
|||
intl: ^0.19.0
|
||||
# cached_network_image: ^3.4.1
|
||||
flutter_native_splash: ^2.4.1
|
||||
url_launcher: ^6.3.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue