developed

This commit is contained in:
komekh 2024-08-29 13:48:59 +05:00
parent 9177c08239
commit 1eebe2c468
38 changed files with 598 additions and 166 deletions

BIN
assets/images/search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -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."
}

View File

@ -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."
}

View File

@ -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());
}
}
}

View File

@ -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];
}

View File

@ -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) {

View File

@ -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()),
),

View File

@ -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';
}

View File

@ -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();
}
}
}

View File

@ -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(

View File

@ -1,2 +1,3 @@
export 'user_remote_data_source.dart';
export 'order_remote_data_source.dart';
export 'contact_remote_data_source.dart';

View File

@ -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,
};
}
}

View File

@ -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(),
// };
// }
}

View File

@ -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';

View File

@ -29,7 +29,7 @@ class UserModel extends User {
Map<String, dynamic> toJson() => {
'Oid': oid,
'FulName': fullName,
'Fulname': fullName,
'PhoneNo': phone,
};
}

View File

@ -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);
}
}
}

View File

@ -1,3 +1,4 @@
export 'user_repository_impl.dart';
export 'splash_repository_impl.dart';
export 'order_repository_impl.dart';
export 'contact_repository_impl.dart';

23
lib/di/contact.dart Normal file
View File

@ -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()),
);
}

View File

@ -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();

View File

@ -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];
}

View File

@ -0,0 +1,9 @@
import 'contact.dart';
class ContactResponse {
final List<ContactEntity> contacts;
ContactResponse({
required this.contacts,
});
}

View File

@ -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';

View File

@ -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();
}

View File

@ -1,3 +1,4 @@
export 'user_repository.dart';
export 'splash_repository.dart';
export 'order_repository.dart';
export 'contact_repository.dart';

View File

@ -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();
}
}

View File

@ -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';

View File

@ -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();
}
},
),

View File

@ -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

View File

@ -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();
}
},
),

View File

@ -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)
],
);
},
),
],
),
);
}

View File

@ -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()),
],
),
),
);
}
}

View File

@ -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,
),

View File

@ -52,7 +52,7 @@ class LocationCard extends StatelessWidget {
Space.x!,
Text(
routes[index].name,
style: AppText.b1b,
style: AppText.h3b,
),
const Spacer(),
Text(

View File

@ -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,
),
],
),

View File

@ -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),
),

View File

@ -12,3 +12,4 @@ export 'retry_widget.dart';
export 'successful_auth_dialog.dart';
export 'vertical_line.dart';
export 'images.dart';
export 'empty_order.dart';

View File

@ -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:

View File

@ -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: