developed

This commit is contained in:
Komek Hayytnazarov 2024-07-23 15:55:48 +05:00
parent c512f143cb
commit d029b5a3b1
25 changed files with 641 additions and 36 deletions

BIN
assets/images/header.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

49
assets/svg/header.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.2 MiB

View File

@ -1 +1,2 @@
export 'bottom_navbar_cubit/bottom_navbar_cubit.dart';
export 'user_bloc/user_bloc.dart'; export 'user_bloc/user_bloc.dart';

View File

@ -0,0 +1,12 @@
// navigation_cubit.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../core/enums/enums.dart';
class NavigationCubit extends Cubit<NavigationTab> {
NavigationCubit() : super(NavigationTab.homeTab);
void updateTab(NavigationTab tab) => emit(tab);
}

View File

@ -1,8 +1,7 @@
export 'app.dart';
export 'app_dimensions.dart'; export 'app_dimensions.dart';
export 'app_typography.dart'; export 'app_typography.dart';
export 'app_typography_ext.dart'; export 'app_typography_ext.dart';
export 'space.dart'; export 'space.dart';
export 'space_ext.dart'; export 'space_ext.dart';
export 'ui.dart'; export 'ui.dart';

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../application/application.dart'; import '../../application/application.dart';
@ -13,15 +14,17 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider(create: (context) => di.sl<NavigationCubit>()),
BlocProvider( BlocProvider(
create: (context) => di.sl<UserBloc>()..add(CheckUser()), create: (context) => di.sl<UserBloc>(), //..add(CheckUser()),
), ),
], ],
child: const MaterialApp( child: MaterialApp(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: appTitle, title: appTitle,
onGenerateRoute: AppRouter.onGenerateRoute, onGenerateRoute: AppRouter.onGenerateRoute,
initialRoute: AppRouter.splash, onGenerateInitialRoutes: (initialRoute) => AppRouter.generateInitialRoutes(initialRoute),
initialRoute: AppRouter.root,
), ),
); );
} }

View File

@ -1,11 +1,11 @@
sealed class AppAssets { sealed class AppAssets {
//svg ///svg
static const String Logo = 'assets/svg/logo/logo.svg'; static const String Logo = 'assets/svg/logo/logo.svg';
static const String BoxesSvg = 'assets/svg/boxes.svg'; static const String BoxesSvg = 'assets/svg/boxes.svg';
static const String Trucks = 'assets/svg/trucks.svg'; static const String Trucks = 'assets/svg/trucks.svg';
//png ///png
static const String BoxesPng = 'assets/images/boxes.png'; static const String BoxesPng = 'assets/images/boxes.png';
static const String TrucksPng = 'assets/images/trucks.png'; static const String TrucksPng = 'assets/images/trucks.png';
static const String Header = 'assets/images/header.png';
} }

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
sealed class AppColors { sealed class AppColors {
static const Color primary = Color(0xFF343FDE); static const Color primary = Color(0xFF343FDE);
static const Color yellow = Color(0xFFFFC71E); static const Color yellow = Color(0xFFFFC71E);
static const Color surface = Color(0xFFEDEEFC);
static const Color CommonCyan = Color(0xff68C4C6); static const Color CommonCyan = Color(0xff68C4C6);
static const Color GreyText = Color(0xff575757); static const Color GreyText = Color(0xff575757);
static const Color LightGrey = Color(0xfff1f1f1); static const Color LightGrey = Color(0xfff1f1f1);

View File

@ -6,3 +6,4 @@ export 'observer/observer.dart';
export 'usecases/usecases.dart'; export 'usecases/usecases.dart';
export 'networkchecker/network_info.dart'; export 'networkchecker/network_info.dart';
export 'utils/utils.dart'; export 'utils/utils.dart';
export 'enums/enums.dart';

View File

@ -0,0 +1 @@
enum NavigationTab { homeTab, categoriesTab, productsTap, cartTab, profileTab }

View File

@ -4,10 +4,10 @@ import '../../presentation/presentation.dart';
import '../errors/exceptions.dart'; import '../errors/exceptions.dart';
sealed class AppRouter { sealed class AppRouter {
static const String splash = '/'; static const String splash = '/splash';
static const String splash2 = '/splash2'; static const String splash2 = '/splash2';
static const String login = '/login'; static const String login = '/login';
// static const String root = '/root'; static const String root = '/root';
// static const String productDetails = '/product-details'; // static const String productDetails = '/product-details';
// static const String search = '/search'; // static const String search = '/search';
// static const String filter = '/filter'; // static const String filter = '/filter';
@ -34,8 +34,8 @@ sealed class AppRouter {
return MaterialPageRoute(builder: (_) => const Splash2Screen()); return MaterialPageRoute(builder: (_) => const Splash2Screen());
case login: case login:
return MaterialPageRoute(builder: (_) => const LoginScreen()); return MaterialPageRoute(builder: (_) => const LoginScreen());
// case root: case root:
// return MaterialPageRoute(builder: (_) => const RootScreen()); return MaterialPageRoute(builder: (_) => const RootScreen());
// case search: // case search:
// return MaterialPageRoute(builder: (_) => const SearchScreen()); // return MaterialPageRoute(builder: (_) => const SearchScreen());
// case filter: // case filter:
@ -84,4 +84,16 @@ sealed class AppRouter {
throw const RouteException('Route not found!'); throw const RouteException('Route not found!');
} }
} }
static List<Route<dynamic>> generateInitialRoutes(String initialRoute) {
debugPrint('generateInitialRoutes $initialRoute');
return [
MaterialPageRoute(builder: (context) => const RootScreen()),
if (initialRoute != AppRouter.root)
MaterialPageRoute(
builder: (context) => const SplashScreen(),
),
];
}
} }

View File

@ -19,7 +19,21 @@ class UserRemoteDataSourceImpl implements UserRemoteDataSource {
@override @override
Future<AuthenticationResponseModel> signIn(SignInParams params) async { Future<AuthenticationResponseModel> signIn(SignInParams params) async {
debugPrint('signIn'); debugPrint('signIn');
final response = await client.post(Uri.parse('$baseUrl/authentication/local/sign-in'),
const data = '''
{
"token": "exampleToken123",
"user": {
"_id": "user123",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com"
}
}
''';
return authenticationResponseModelFromJson(data);
/* final response = await client.post(Uri.parse('$baseUrl/authentication/local/sign-in'),
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
@ -33,7 +47,7 @@ class UserRemoteDataSourceImpl implements UserRemoteDataSource {
throw CredentialFailure(); throw CredentialFailure();
} else { } else {
throw ServerException(); throw ServerException();
} } */
} }
@override @override

11
lib/di/cubits.dart Normal file
View File

@ -0,0 +1,11 @@
import '../application/application.dart';
import 'di.dart';
void registerCubits() {
// Navigation
sl.registerFactory(() => NavigationCubit());
//Notiications
// sl.registerLazySingleton(() => FlutterLocalNotificationsPlugin());
// sl.registerFactory(() => NotificationsCubit(sl()));
}

View File

@ -1,6 +1,7 @@
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'common.dart'; import 'common.dart';
import 'cubits.dart';
import 'user.dart'; import 'user.dart';
final sl = GetIt.instance; final sl = GetIt.instance;
@ -16,7 +17,7 @@ Future<void> init() async {
// registerOrderFeature(); // registerOrderFeature();
// Register Cubits // Register Cubits
// registerCubits(); registerCubits();
// Register common dependencies // Register common dependencies
registerCommonDependencies(); registerCommonDependencies();

View File

@ -20,5 +20,10 @@ Future<void> main() async {
DeviceOrientation.portraitDown, DeviceOrientation.portraitDown,
]); ]);
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.dark,
));
runApp(Phoenix(child: const MyApp())); runApp(Phoenix(child: const MyApp()));
} }

View File

@ -3,11 +3,10 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import '../../application/user_bloc/user_bloc.dart'; import '../../application/user_bloc/user_bloc.dart';
import '../../configs/app.dart';
import '../../configs/configs.dart'; import '../../configs/configs.dart';
import '../../core/core.dart'; import '../../core/core.dart';
import '../../domain/domain.dart'; import '../../domain/domain.dart';
import '../widgets/button.dart'; import '../widgets/widgets.dart';
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
const LoginScreen({super.key}); const LoginScreen({super.key});
@ -21,6 +20,13 @@ class _LoginScreenState extends State<LoginScreen> {
final TextEditingController _passwordController = TextEditingController(); final TextEditingController _passwordController = TextEditingController();
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
void _nextScreen() {
Navigator.of(context).pushNamedAndRemoveUntil(
AppRouter.root,
(route) => false,
);
}
@override @override
void dispose() { void dispose() {
_userNameController.dispose(); _userNameController.dispose();
@ -82,7 +88,7 @@ class _LoginScreenState extends State<LoginScreen> {
/// form part /// form part
SizedBox( SizedBox(
height: AppDimensions.normalize(145), height: AppDimensions.normalize(165),
child: Stack( child: Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
children: [ children: [
@ -158,11 +164,24 @@ class _LoginScreenState extends State<LoginScreen> {
/// gap /// gap
Space.yf(), Space.yf(),
SizedBox( BlocConsumer<UserBloc, UserState>(
listener: (context, state) {
if (state is UserLogged) {
_nextScreen();
} else if (state is UserLoggedFail) {
if (state.failure is CredentialFailure) {
showCredentialErrorDialog(context);
} else {
showAuthErrorDialog(context);
}
}
},
builder: (context, state) {
return SizedBox(
width: double.infinity, width: double.infinity,
child: AppButton( child: AppButton(
textColor: AppColors.primary, textColor: Colors.white,
btnColor: AppColors.yellow, btnColor: AppColors.primary,
onPressed: () { onPressed: () {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
context.read<UserBloc>().add( context.read<UserBloc>().add(
@ -177,6 +196,8 @@ class _LoginScreenState extends State<LoginScreen> {
}, },
text: 'Yzarlap başlaň', text: 'Yzarlap başlaň',
), ),
);
},
) )
], ],
), ),

View File

@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
import '../../configs/configs.dart';
import '../../core/core.dart';
import '../widgets/order_header.dart';
class OrdersScreen extends StatelessWidget {
const OrdersScreen({super.key});
@override
Widget build(BuildContext context) {
App.init(context);
return Scaffold(
backgroundColor: AppColors.surface,
body: CustomScrollView(
slivers: [
const SliverToBoxAdapter(
child: OrderHeader(),
),
SliverToBoxAdapter(
child: Padding(
padding: Space.all(1, 1),
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Sargytlarym',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
Text(
'öz ýüküňizi yzarlaň',
style: TextStyle(
color: Colors.grey,
),
),
],
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return _buildOrderCard();
},
childCount: 4, // items.length,
),
),
],
),
);
}
Widget _buildOrderCard() {
return Card(
color: Colors.white,
margin: Space.all(.8, 0.5),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'№ABC456789',
style: AppText.b1b,
),
Text(
'Genişleýin >',
style: AppText.b1b?.copyWith(
color: AppColors.primary,
),
),
],
),
const SizedBox(height: 8),
const Row(
children: [
Icon(Icons.circle, color: Colors.green, size: 12),
SizedBox(width: 4),
Text('Ýolda'),
Spacer(),
Text('Ugradylan senesi: 16.07.2024'),
],
),
const SizedBox(height: 16),
const Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Nireden:'),
Text('Urumçy', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text('Nirede:'),
Text('Aşgabat', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text('Ýer sany:'),
Text('10', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text('Göwrümi:'),
Text('1472,31', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Maşyn №:'),
Text('AA1234AA', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text('Dukan №:'),
Text('A1043', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
],
),
],
),
),
);
}
}

View File

@ -0,0 +1,83 @@
import 'package:cargo/core/core.dart';
import 'package:cargo/presentation/screens/orders.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../application/application.dart';
import '../../configs/configs.dart';
import '../widgets/bottom_navbar.dart';
class RootScreen extends StatelessWidget {
const RootScreen({super.key});
Future<bool> onPopInvoked(BuildContext context) async {
return (await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text(
'Exit Application',
style: TextStyle(color: AppColors.primary),
),
content: const Text(
'Are You Sure?',
),
actions: <Widget>[
TextButton(
child: const Text(
'Yes',
style: TextStyle(
color: Colors.red,
),
),
onPressed: () {
SystemNavigator.pop();
},
),
TextButton(
child: const Text(
'No',
style: TextStyle(color: AppColors.primary),
),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
)) ??
false;
}
@override
Widget build(BuildContext context) {
App.init(context);
return PopScope(
onPopInvoked: (didPop) => onPopInvoked(context),
child: Scaffold(
backgroundColor: AppColors.surface,
bottomNavigationBar: const BottomNavigation(),
body: Container(
color: AppColors.surface,
child: Center(
child: BlocBuilder<NavigationCubit, NavigationTab>(
builder: (context, activeTab) {
switch (activeTab) {
case NavigationTab.homeTab:
return const OrdersScreen();
case NavigationTab.categoriesTab:
return const Text(' CategoriesScreen()');
case NavigationTab.productsTap:
return const Text('ProductsListScreen()');
default:
return const Text('HomeScreen()');
}
},
),
),
),
),
);
}
}

View File

@ -1,3 +1,4 @@
export 'splash.dart'; export 'splash.dart';
export 'splash2.dart'; export 'splash2.dart';
export 'login.dart'; export 'login.dart';
export 'root.dart';

View File

@ -0,0 +1,50 @@
import 'package:flutter/material.dart';
import '../../configs/configs.dart';
import '../../core/core.dart';
Future<void> showAuthErrorDialog(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: Container(
height: AppDimensions.normalize(50),
padding: Space.all(1, .5),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Error',
style: AppText.b1b,
),
Space.yf(.5),
Text(
'Try Again!',
style: AppText.b1,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
'Dismiss',
style: AppText.h3b?.copyWith(
color: AppColors.primary,
),
),
)
],
)
],
),
),
),
);
});
}

View File

@ -0,0 +1,53 @@
// bottom_navigation.dart
import 'package:cargo/core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../application/application.dart';
import '../../configs/configs.dart';
class BottomNavigation extends StatelessWidget {
const BottomNavigation({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<NavigationCubit, NavigationTab>(
builder: (context, activeTab) {
return SizedBox(
height: AppDimensions.normalize(27),
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: activeTab.index,
onTap: (index) {
final newTab = NavigationTab.values[index];
context.read<NavigationCubit>().updateTab(newTab);
},
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.list_alt_outlined),
label: 'Sargytlarym',
),
BottomNavigationBarItem(
icon: Icon(Icons.history_rounded),
label: 'Sargytlaryň taryhy',
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline_rounded),
label: 'Şahsy otagym',
),
],
selectedItemColor: AppColors.primary,
// unselectedItemColor: Colors.white,
iconSize: AppDimensions.normalize(12),
selectedLabelStyle: AppText.b2b,
unselectedLabelStyle: AppText.b2!.copyWith(
color: const Color(0xFF96969C),
),
backgroundColor: AppColors.surface,
),
);
},
);
}
}

View File

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import '../../configs/configs.dart';
import '../../core/core.dart';
Future<void> showCredentialErrorDialog(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: Container(
height: AppDimensions.normalize(60),
padding: Space.all(1, .5),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Username/Password Wrong!',
style: AppText.b1b,
),
Space.yf(.5),
Text(
'Try Again!',
style: AppText.b1,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
'Dismiss',
style: AppText.h3b?.copyWith(
color: AppColors.primary,
),
))
],
)
],
),
),
),
);
});
}

View File

@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import '../../configs/configs.dart';
import '../../core/core.dart';
class OrderHeader extends StatelessWidget {
const OrderHeader({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: AppDimensions.normalize(80),
child: Stack(
children: [
Image.asset(
AppAssets.Header,
fit: BoxFit.fill,
),
Positioned(
top: 0,
bottom: 0,
left: AppDimensions.normalize(12),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Cargo goşundy',
style: AppText.h1b?.copyWith(
color: Colors.white,
),
),
Space.yf(0.30),
Text(
'Öz sargydyňyzy yzarlaň',
style: AppText.b1?.copyWith(
color: AppColors.yellow,
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../configs/configs.dart';
import '../../core/core.dart';
Future<void> showSuccessfulAuthDialog(BuildContext context, String text) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: Container(
height: AppDimensions.normalize(77),
padding: Space.all(1, 1.05),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'SUCCESSFULLY ${text.toUpperCase()}',
style: AppText.b1b,
),
Space.yf(.6),
Text(
'Congratulations,\nYour Account Has Been Successfully $text!',
style: AppText.b1?.copyWith(height: 1.5),
),
// Row(
// mainAxisAlignment: MainAxisAlignment.end,
// children: [
// TextButton(
// onPressed: () {
// context.read<CartBloc>().add(const GetCart());
// context.read<DeliveryInfoFetchCubit>().fetchDeliveryInfo();
// Navigator.of(context).pushNamedAndRemoveUntil(
// AppRouter.root,
// ModalRoute.withName(''),
// );
// },
// child: Text(
// 'Ok',
// style: AppText.h3b?.copyWith(color: AppColors.CommonCyan),
// ),
// )
// ],
// )
],
),
),
),
);
},
);
}

View File

@ -1 +1,6 @@
export 'button.dart'; export 'button.dart';
export 'successful_auth_dialog.dart';
export 'credential_failure_dialog.dart';
export 'auth_error_dialog.dart';
export 'bottom_navbar.dart';
export 'order_header.dart';