changed structure, added login, signUp screen and logic

This commit is contained in:
meylis98 2023-03-08 20:40:07 +05:00
parent eb143d5496
commit 3a8ca71319
45 changed files with 1013 additions and 575 deletions

View File

@ -0,0 +1,46 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import '../constants/global_variables.dart';
import '../themes/app_theme.dart';
class CustomButton extends StatelessWidget {
const CustomButton({
Key? key,
required this.name,
required this.onTap,
required this.backgroundColor,
required this.isMain,
}) : super(key: key);
final String name;
final Color backgroundColor;
final bool isMain;
final void Function() onTap;
@override
Widget build(BuildContext context) {
return Container(
height: GlobalVariables.deviceHeight(context) / 15,
width: double.infinity,
margin: EdgeInsets.symmetric(
vertical: 5.adaptedPx(),
),
child: OutlinedButton(
onPressed: onTap,
style: TextButton.styleFrom(
backgroundColor: backgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.adaptedPx()),
),
),
child: Text(
name,
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: isMain ? AppTheme.whiteColor : AppTheme.blackColor,
fontSize: 14.adaptedPx(),
),
),
),
);
}
}

View File

@ -0,0 +1,65 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import '../../themes/app_theme.dart';
class CustomTextField extends StatelessWidget {
const CustomTextField({
Key? key,
required this.labelText,
required this.controller,
required this.hintText,
required this.obscureText,
required this.inputType,
}) : super(key: key);
final String labelText, hintText;
final TextEditingController controller;
final bool obscureText;
final TextInputType inputType;
@override
Widget build(BuildContext context) {
return TextFormField(
controller: controller,
obscureText: obscureText,
keyboardType: inputType,
cursorColor: AppTheme.lightPrimaryColor,
decoration: InputDecoration(
labelText: labelText,
hintText: hintText,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.adaptedPx()),
borderSide: BorderSide(
color: AppTheme.lightPrimaryColor,
width: 3.adaptedPx(),
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.adaptedPx()),
borderSide: BorderSide(
color: AppTheme.redColor,
width: 3.adaptedPx(),
),
),
labelStyle: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.lightTextColor,
fontSize: 13.adaptedPx(),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.adaptedPx()),
borderSide: BorderSide(
color: AppTheme.lightTextColor,
width: 2.adaptedPx(),
),
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Enter your $hintText';
}
return null;
},
);
}
}

View File

@ -0,0 +1,25 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:sapaly_shop/constants/utils.dart';
void httpErrorHandle({
required http.Response response,
required BuildContext context,
required VoidCallback onSuccess,
}) {
switch (response.statusCode) {
case 200:
onSuccess();
break;
case 400:
showSnackBar(context, 'this_user_exists');
break;
case 500:
showSnackBar(context, 'error_occured');
break;
default:
showSnackBar(context, 'error_occured');
}
}

View File

@ -5,7 +5,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
String kBaseUrl = 'http://sapalymahabat.com.tm';
abstract class AppConstants {
class GlobalVariables {
static const kAppName = 'Sapaly Mahabat';
static double deviceHeight(BuildContext context) =>

9
lib/constants/utils.dart Normal file
View File

@ -0,0 +1,9 @@
import 'package:flutter/material.dart';
void showSnackBar(BuildContext context, String text) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(text),
),
);
}

View File

@ -0,0 +1,158 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/common/custom_button.dart';
import 'package:sapaly_shop/models/auth/login/login_request_model.dart';
import 'package:sapaly_shop/features/services/page_navigator.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
import '../../../../common/widgets/custom_text_field.dart';
import '../../../../constants/global_variables.dart';
import '../../../services/auth_service.dart';
import '../register_screen.dart';
class LoginScreen extends StatefulWidget {
static const String routeName = '/login';
LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final formKey = GlobalKey<FormState>();
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
final AuthService authService = AuthService();
void login() {
debugPrint('EMAIL ${emailController.text}');
authService.login(
loginRequestModel: LoginRequestModel(
email: emailController.text,
password: passwordController.text,
),
context: context,
);
}
@override
void dispose() {
emailController.dispose();
passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Container(),
),
body: Align(
alignment: Alignment.center,
child: Container(
margin: EdgeInsets.symmetric(
vertical: GlobalVariables.verticalPadding(context) * 2,
horizontal: GlobalVariables.horizontalPadding(context),
),
padding: EdgeInsets.symmetric(
vertical: GlobalVariables.verticalPadding(context) / 2,
horizontal: GlobalVariables.horizontalPadding(context),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.adaptedPx()),
border: Border.all(
width: 2.adaptedPx(),
color: AppTheme.blackColor.withOpacity(0.1),
),
),
height: GlobalVariables.deviceHeight(context) / 1.55,
child: Form(
key: formKey,
child: ListView(
physics: const BouncingScrollPhysics(),
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: 30.adaptedPx(),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/sapalyLogo.png',
),
SizedBox(width: 15.adaptedPx()),
Text(
GlobalVariables.kAppName,
style: Theme.of(context)
.primaryTextTheme
.bodyMedium
?.copyWith(
color: AppTheme.blackColor,
fontSize: 18.adaptedPx(),
fontWeight: FontWeight.w600,
),
)
],
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 15.adaptedPx()),
child: CustomTextField(
controller: emailController,
labelText: 'email',
hintText: 'enter_your_email',
obscureText: false,
inputType: TextInputType.emailAddress,
),
),
CustomTextField(
controller: passwordController,
labelText: 'password',
hintText: 'enter_your_password',
obscureText: true,
inputType: TextInputType.visiblePassword,
),
SizedBox(height: 30.adaptedPx()),
CustomButton(
name: 'login',
onTap: () {
if (formKey.currentState!.validate()) {
login();
}
},
backgroundColor: AppTheme.lightPrimaryColor,
isMain: true,
),
Align(
alignment: Alignment.center,
child: Text(
'or',
style: Theme.of(context)
.primaryTextTheme
.bodyMedium
?.copyWith(
fontSize: 15.adaptedPx(),
color: AppTheme.lightTextColor),
),
),
CustomButton(
name: 'register',
onTap: () {
PageNavigator(ctx: context).nextPage(
page: const RegisterScreen(),
);
},
backgroundColor: AppTheme.lightTextColor.withOpacity(0.2),
isMain: false,
),
],
),
),
),
),
);
}
}

View File

@ -0,0 +1,179 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/features/screens/auth/login/login_screen.dart';
import 'package:sapaly_shop/features/services/auth_service.dart';
import 'package:sapaly_shop/features/services/page_navigator.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
import '../../../common/custom_button.dart';
import '../../../common/widgets/custom_text_field.dart';
import '../../../constants/global_variables.dart';
import '../../../models/auth/register/register_request_model.dart';
class RegisterScreen extends StatefulWidget {
static const String routeName = '/register';
const RegisterScreen({super.key});
@override
State<RegisterScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<RegisterScreen> {
final TextEditingController emailController = TextEditingController();
final TextEditingController phoneController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final TextEditingController passwordConfirmationController =
TextEditingController();
final AuthService authService = AuthService();
final formKey = GlobalKey<FormState>();
void register() {
authService.register(
registerRequestModel: RegisterRequestModel(
email: emailController.text,
password: passwordController.text,
passwordConfirmation: passwordConfirmationController.text,
phone: phoneController.text,
),
context: context,
);
}
@override
void dispose() {
emailController.dispose();
phoneController.dispose();
passwordController.dispose();
passwordConfirmationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Container(),
),
body: Align(
alignment: Alignment.center,
child: Container(
margin: EdgeInsets.symmetric(
vertical: GlobalVariables.verticalPadding(context) / 2,
horizontal: GlobalVariables.horizontalPadding(context),
),
padding: EdgeInsets.symmetric(
vertical: GlobalVariables.verticalPadding(context) / 2,
horizontal: GlobalVariables.horizontalPadding(context),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.adaptedPx()),
border: Border.all(
width: 2.adaptedPx(),
color: AppTheme.blackColor.withOpacity(0.1),
),
),
height: GlobalVariables.deviceHeight(context) / 1.5,
child: Form(
key: formKey,
child: ListView(
physics: const BouncingScrollPhysics(),
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: 15.adaptedPx(),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/sapalyLogo.png',
),
SizedBox(width: 15.adaptedPx()),
Text(
GlobalVariables.kAppName,
style: Theme.of(context)
.primaryTextTheme
.bodyMedium
?.copyWith(
color: AppTheme.blackColor,
fontSize: 18.adaptedPx(),
fontWeight: FontWeight.w600,
),
)
],
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 15.adaptedPx()),
child: CustomTextField(
controller: emailController,
labelText: 'your_email',
hintText: 'enter_your_email_here',
obscureText: false,
inputType: TextInputType.emailAddress,
),
),
CustomTextField(
controller: phoneController,
labelText: 'your_phone_number',
hintText: '64283513',
obscureText: false,
inputType: TextInputType.phone,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 15.adaptedPx()),
child: CustomTextField(
controller: passwordController,
labelText: 'your_password',
hintText: 'enter_your_password_here',
obscureText: true,
inputType: TextInputType.visiblePassword,
),
),
CustomTextField(
controller: passwordConfirmationController,
labelText: 'repeat_password',
hintText: 'repeat_password_to_confirm',
obscureText: true,
inputType: TextInputType.visiblePassword,
),
SizedBox(height: 20.adaptedPx()),
CustomButton(
name: 'register',
onTap: () async {
if (formKey.currentState!.validate()) {
register();
}
},
isMain: true,
backgroundColor: AppTheme.lightPrimaryColor,
),
Align(
alignment: Alignment.center,
child: Text(
'or',
textAlign: TextAlign.center,
style:
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.blackColor,
fontSize: 14.adaptedPx(),
),
),
),
CustomButton(
name: 'login',
isMain: false,
onTap: () {
PageNavigator(ctx: context)
.nextPageOnly(page: LoginScreen());
},
backgroundColor: AppTheme.lightTextColor.withOpacity(0.150),
),
],
),
),
),
),
);
}
}

View File

@ -2,10 +2,10 @@ import 'package:adaptix/adaptix.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:sapaly_shop/components/sapaly_app_bar.dart';
import 'package:sapaly_shop/features/widgets/sapaly_app_bar.dart';
import 'package:sapaly_shop/models/category_model.dart';
import 'package:sapaly_shop/models/settings_model.dart';
import 'package:sapaly_shop/services/requests.dart';
import 'package:sapaly_shop/features/services/requests.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
class CategoryScreen extends StatefulWidget {

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
import '../../services/app_constants.dart';
import '../../../constants/global_variables.dart';
class Dashboard extends StatelessWidget {
const Dashboard({super.key});
@ -15,7 +15,7 @@ class Dashboard extends StatelessWidget {
color: AppTheme.lightBackgroundColor,
child: Container(
alignment: Alignment.center,
height: AppConstants.deviceHeight(context) / 2,
height: GlobalVariables.deviceHeight(context) / 2,
margin: EdgeInsets.symmetric(horizontal: 15.adaptedPx()),
decoration: BoxDecoration(
color: AppTheme.whiteColor,
@ -33,7 +33,7 @@ class Dashboard extends StatelessWidget {
),
SizedBox(width: 10.adaptedPx()),
Text(
AppConstants.kAppName,
GlobalVariables.kAppName,
style: GoogleFonts.poppins(
textStyle:
Theme.of(context).primaryTextTheme.bodyMedium!.copyWith(

View File

@ -1,10 +1,10 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:sapaly_shop/components/sapaly_app_bar.dart';
import 'package:sapaly_shop/features/widgets/sapaly_app_bar.dart';
import 'package:sapaly_shop/models/details_model.dart';
import 'package:sapaly_shop/models/settings_model.dart';
import 'package:sapaly_shop/services/requests.dart';
import 'package:sapaly_shop/features/services/requests.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
class Details extends StatefulWidget {

View File

@ -2,15 +2,15 @@ import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:sapaly_shop/screens/category/category_screen.dart';
import 'package:sapaly_shop/screens/drawer/contacts.dart';
import 'package:sapaly_shop/screens/drawer/new_arrival.dart';
import 'package:sapaly_shop/screens/drawer/sales.dart';
import 'package:sapaly_shop/screens/drawer/shops.dart';
import 'package:sapaly_shop/features/screens/category/category_screen.dart';
import 'package:sapaly_shop/features/screens/drawer/contacts.dart';
import 'package:sapaly_shop/features/screens/drawer/new_arrival.dart';
import 'package:sapaly_shop/features/screens/drawer/sales.dart';
import 'package:sapaly_shop/features/screens/drawer/shops.dart';
import 'package:url_launcher/url_launcher_string.dart';
import '../../services/app_constants.dart';
import '../../themes/app_theme.dart';
import '../../../constants/global_variables.dart';
import '../../../themes/app_theme.dart';
import 'about_us.dart';
class SapalyDrawer extends StatelessWidget {
@ -62,7 +62,7 @@ class SapalyDrawer extends StatelessWidget {
),
SizedBox(width: 10.adaptedPx()),
Text(
AppConstants.kAppName,
GlobalVariables.kAppName,
style: GoogleFonts.poppins(
textStyle: Theme.of(context)
.primaryTextTheme
@ -121,8 +121,9 @@ class SapalyDrawer extends StatelessWidget {
return TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.symmetric(
vertical: AppConstants.verticalPadding(context) / 2,
horizontal: AppConstants.horizontalPadding(context) / 2,
vertical: GlobalVariables.verticalPadding(context) / 2,
horizontal:
GlobalVariables.horizontalPadding(context) / 2,
),
),
onPressed: () {

View File

@ -8,14 +8,14 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:sapaly_shop/models/settings_model.dart';
import 'package:sapaly_shop/models/sliders_model.dart';
import 'package:sapaly_shop/models/subcategory_model.dart';
import 'package:sapaly_shop/screens/drawer/sapaly_drawer.dart';
import 'package:sapaly_shop/screens/home/product.dart';
import 'package:sapaly_shop/screens/home/search.dart';
import 'package:sapaly_shop/services/app_constants.dart';
import 'package:sapaly_shop/services/requests.dart';
import 'package:sapaly_shop/features/screens/drawer/sapaly_drawer.dart';
import 'package:sapaly_shop/features/screens/home/product.dart';
import 'package:sapaly_shop/features/screens/home/search.dart';
import 'package:sapaly_shop/features/services/requests.dart';
import '../../components/sapaly_app_bar.dart';
import '../../themes/app_theme.dart';
import '../../widgets/sapaly_app_bar.dart';
import '../../../constants/global_variables.dart';
import '../../../themes/app_theme.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@ -92,8 +92,8 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
),
body: Padding(
padding: EdgeInsets.symmetric(
vertical: AppConstants.verticalPadding(context) / 2,
horizontal: AppConstants.horizontalPadding(context),
vertical: GlobalVariables.verticalPadding(context) / 2,
horizontal: GlobalVariables.horizontalPadding(context),
),
child: NestedScrollView(
physics: const BouncingScrollPhysics(),
@ -153,7 +153,8 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
for (int i = 0; i < sliders.length; i++)
CachedNetworkImage(
imageUrl: sliders[i].img,
width: AppConstants.deviceWidth(context),
width:
GlobalVariables.deviceWidth(context),
fit: BoxFit.contain,
progressIndicatorBuilder:
(context, url, progress) =>

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:sapaly_shop/models/product_model.dart';
import '../../components/product_card.dart';
import '../../widgets/product_card.dart';
import '../../services/requests.dart';
import '../details/details.dart';

View File

@ -1,9 +1,9 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import '../../components/sapaly_app_bar.dart';
import '../../services/app_constants.dart';
import '../../themes/app_theme.dart';
import '../../widgets/sapaly_app_bar.dart';
import '../../../constants/global_variables.dart';
import '../../../themes/app_theme.dart';
class SearchScreen extends StatelessWidget {
const SearchScreen({super.key});
@ -25,12 +25,12 @@ class SearchScreen extends StatelessWidget {
),
body: ListView(
padding: EdgeInsets.symmetric(
horizontal: AppConstants.horizontalPadding(context),
horizontal: GlobalVariables.horizontalPadding(context),
),
shrinkWrap: true,
scrollDirection: Axis.vertical,
children: [
SizedBox(height: AppConstants.verticalPadding(context)),
SizedBox(height: GlobalVariables.verticalPadding(context)),
SizedBox(height: 15.adaptedPx()),
],
),

View File

@ -2,7 +2,7 @@ import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
import '../services/app_constants.dart';
import '../../constants/global_variables.dart';
class OnboardingScreen extends StatelessWidget {
OnboardingScreen({super.key});
@ -13,9 +13,9 @@ class OnboardingScreen extends StatelessWidget {
body: Center(
child: Container(
margin: EdgeInsets.symmetric(
horizontal: AppConstants.horizontalPadding(context),
horizontal: GlobalVariables.horizontalPadding(context),
),
height: AppConstants.deviceHeight(context) / (1.7),
height: GlobalVariables.deviceHeight(context) / (1.7),
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(

View File

@ -0,0 +1,80 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:sapaly_shop/constants/global_variables.dart';
import 'package:sapaly_shop/constants/utils.dart';
import 'package:sapaly_shop/models/auth/login/login_request_model.dart';
import 'package:sapaly_shop/models/auth/login/login_response_model.dart';
import 'package:sapaly_shop/models/auth/register/register_request_model.dart';
import 'package:sapaly_shop/models/auth/register/register_response_model.dart';
import '../../constants/error_handling.dart';
class AuthService {
// Register
Future<void> register({
required RegisterRequestModel registerRequestModel,
required BuildContext context,
}) async {
try {
var response = await http.post(
Uri.parse('$kBaseUrl/jwt/register'),
body: registerRequestModel.toJson(),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == HttpStatus.ok) {
var data = response.body;
var registerResponse = registerResponseModelFromJson(data);
}
httpErrorHandle(
response: response,
context: context,
onSuccess: () {
showSnackBar(
context,
'successfully_created_now_login',
);
},
);
} catch (e) {
showSnackBar(context, e.toString());
debugPrint('Register Repsponse $e');
}
}
Future<void> login({
required LoginRequestModel loginRequestModel,
required BuildContext context,
}) async {
try {
var response = await http.post(Uri.parse('$kBaseUrl/jwt/login'),
body: loginRequestModel.toMap(),
headers: {
'Accept': 'application/json',
});
if (response.statusCode == HttpStatus.ok) {
var data = response.body;
var loginResponse = LoginResponseModel.fromJson(data);
debugPrint('EMAIL ${loginResponse.user.email}');
}
httpErrorHandle(
response: response,
context: context,
onSuccess: () {
showSnackBar(
context,
'successfully_created_now_login',
);
},
);
} catch (e) {
showSnackBar(context, e.toString());
debugPrint('Login Response ${e.toString()}');
}
}
}

View File

@ -7,11 +7,11 @@ import 'package:sapaly_shop/models/category_model.dart';
import 'package:sapaly_shop/models/details_model.dart';
import 'package:sapaly_shop/models/settings_model.dart';
import 'package:sapaly_shop/models/sliders_model.dart';
import 'package:sapaly_shop/services/app_constants.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/product_model.dart';
import '../models/subcategory_model.dart';
import '../../constants/global_variables.dart';
import '../../models/product_model.dart';
import '../../models/subcategory_model.dart';
class API {
static Future<dynamic> _getData(String path) async {

View File

@ -0,0 +1,23 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
class EmptyWidget extends StatelessWidget {
const EmptyWidget({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text(
'This Screen is empty',
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
fontSize: 18.adaptedPx(),
color: AppTheme.lightTextColor,
),
),
),
);
}
}

View File

@ -1,9 +1,10 @@
import 'package:adaptix/adaptix.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/services/app_constants.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
import '../../constants/global_variables.dart';
class ProductCard extends StatelessWidget {
final String imageUrl, price, discountPrice, description;
final int discountPriceValue;
@ -45,12 +46,12 @@ class ProductCard extends StatelessWidget {
fit: BoxFit.fitWidth,
alignment: Alignment.center,
placeholder: (context, url) => Container(
height: AppConstants.deviceHeight(context) / 7,
height: GlobalVariables.deviceHeight(context) / 7,
),
errorWidget: (context, url, error) => Container(
height: AppConstants.deviceHeight(context) / 7,
height: GlobalVariables.deviceHeight(context) / 7,
),
height: AppConstants.deviceHeight(context) / 7,
height: GlobalVariables.deviceHeight(context) / 7,
width: double.infinity,
),
),

View File

@ -1,8 +1,8 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/components/sapaly_icon.dart';
import 'package:sapaly_shop/features/widgets/sapaly_icon.dart';
import '../themes/app_theme.dart';
import '../../themes/app_theme.dart';
class SapalyAppBar extends StatelessWidget with PreferredSizeWidget {
const SapalyAppBar({

View File

@ -1,7 +1,7 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import '../themes/app_theme.dart';
import '../../themes/app_theme.dart';
class SapalyIcon extends StatelessWidget {
const SapalyIcon({

View File

@ -0,0 +1,22 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
class NoScreen extends StatelessWidget {
const NoScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(
'This screen does not exist',
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
fontSize: 16.adaptedPx(),
color: AppTheme.blackColor,
),
),
),
);
}
}

View File

@ -1,30 +1,18 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:sapaly_shop/screens/category/category_screen.dart';
import 'package:sapaly_shop/screens/dashboard/dashboard.dart';
import 'package:sapaly_shop/screens/drawer/sapaly_drawer.dart';
import 'package:sapaly_shop/screens/home/home_screen.dart';
import 'package:sapaly_shop/services/app_constants.dart';
import 'package:sapaly_shop/screens/auth/login/login_screen.dart';
import 'package:sapaly_shop/features/screens/category/category_screen.dart';
import 'package:sapaly_shop/features/screens/dashboard/dashboard.dart';
import 'package:sapaly_shop/features/screens/drawer/sapaly_drawer.dart';
import 'package:sapaly_shop/features/screens/home/home_screen.dart';
import 'package:sapaly_shop/features/screens/auth/login/login_screen.dart';
import 'package:sapaly_shop/router.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'models/settings_model.dart';
import 'constants/global_variables.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
await SettingsModel.initLocalization(
prefs.getString('language') ?? kDefaultLanguage);
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => SettingsModel(prefs)),
],
child: const MyApp(),
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
@ -39,6 +27,7 @@ class MyApp extends StatelessWidget {
theme: AppTheme.appLightTheme,
title: 'Sapaly Mahabat',
initialRoute: '/login',
onGenerateRoute: (settings) => generateRoute(settings),
routes: <String, WidgetBuilder>{
'/': (context) => const Dashboard(),
'/drawer': (context) => SapalyDrawer(),
@ -46,8 +35,8 @@ class MyApp extends StatelessWidget {
'/category': (context) => const CategoryScreen(),
'/login': (context) => LoginScreen(),
},
localizationsDelegates: AppConstants.localizationsDelegate,
supportedLocales: AppConstants.supportedLocales,
localizationsDelegates: GlobalVariables.localizationsDelegate,
supportedLocales: GlobalVariables.supportedLocales,
);
},
);

View File

@ -0,0 +1,29 @@
import 'dart:convert';
class LoginRequestModel {
final String email;
final String password;
LoginRequestModel({
required this.email,
required this.password,
});
Map<String, dynamic> toMap() {
return {
'email': email,
'password': password,
};
}
factory LoginRequestModel.fromMap(Map<String, dynamic> map) {
return LoginRequestModel(
email: map['email'] ?? '',
password: map['password'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory LoginRequestModel.fromJson(String source) =>
LoginRequestModel.fromMap(json.decode(source));
}

View File

@ -0,0 +1,110 @@
import 'dart:convert';
import 'package:flutter/material.dart';
// To parse this JSON data, do
//
// final userResponseModel = userResponseModelFromJson(jsonString);
class LoginResponseModel {
final String token;
final String expires;
final User user;
LoginResponseModel({
required this.token,
required this.expires,
required this.user,
});
Map<String, dynamic> toMap() {
return {
'token': token,
'expires': expires,
'user': user.toMap(),
};
}
factory LoginResponseModel.fromMap(Map<String, dynamic> map) {
return LoginResponseModel(
token: map['data']['token'] ?? '',
expires: map['data']['expires'] ?? '',
user: User.fromMap(map['data']['user']),
);
}
String toJson() => json.encode(toMap());
factory LoginResponseModel.fromJson(String source) =>
LoginResponseModel.fromMap(json.decode(source));
}
class User {
final int id;
final String email;
final String name;
final String lastName;
final String middleName;
final String phone;
final String phoneShort;
final bool isActivated;
final String lastLogin;
final int isSuperuser;
final String createdAt;
final String updatedAt;
final List<String> phoneList;
User({
required this.id,
required this.email,
required this.name,
required this.lastName,
required this.middleName,
required this.phone,
required this.phoneShort,
required this.isActivated,
required this.lastLogin,
required this.isSuperuser,
required this.createdAt,
required this.updatedAt,
required this.phoneList,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'email': email,
'name': name,
'lastName': lastName,
'middleName': middleName,
'phone': phone,
'phoneShort': phoneShort,
'isActivated': isActivated,
'lastLogin': lastLogin,
'isSuperuser': isSuperuser,
'createdAt': createdAt,
'updatedAt': updatedAt,
'phone_list': phoneList,
};
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'] ?? 0,
email: map['email'] ?? '',
name: map['name'] ?? '',
lastName: map['lastName'] ?? '',
middleName: map['middleName'] ?? '',
phone: map['phone'] ?? '',
phoneShort: map['phoneShort'] ?? '',
isActivated: map['isActivated'] ?? false,
lastLogin: map['lastLogin'] ?? '',
isSuperuser: map['isSuperuser'] ?? 0,
createdAt: map['createdAt'] ?? '',
updatedAt: map['updatedAt'] ?? '',
phoneList: List<String>.from(map['phone_list']),
);
}
String toJson() => json.encode(toMap());
factory User.fromJson(String source) => User.fromMap(json.decode(source));
}

View File

@ -1,53 +0,0 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
class UserRequestModel {
String? email;
String? password;
UserRequestModel({
this.email,
this.password,
});
UserRequestModel copyWith({
String? email,
String? password,
}) {
return UserRequestModel(
email: email ?? this.email,
password: password ?? this.password,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'email': email,
'password': password,
};
}
factory UserRequestModel.fromMap(Map<String, dynamic> map) {
return UserRequestModel(
email: map['email'] != null ? map['email'] as String : null,
password: map['password'] != null ? map['password'] as String : null,
);
}
String toJson() => json.encode(toMap());
factory UserRequestModel.fromJson(String source) =>
UserRequestModel.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() => 'UserRequestModel(email: $email, password: $password)';
@override
bool operator ==(covariant UserRequestModel other) {
if (identical(this, other)) return true;
return other.email == email && other.password == password;
}
@override
int get hashCode => email.hashCode ^ password.hashCode;
}

View File

@ -1,117 +0,0 @@
// To parse this JSON data, do
//
// final userResponseModel = userResponseModelFromJson(jsonString);
import 'package:meta/meta.dart';
import 'dart:convert';
UserResponseModel userResponseModelFromJson(String str) =>
UserResponseModel.fromJson(json.decode(str));
String userResponseModelToJson(UserResponseModel data) =>
json.encode(data.toJson());
class UserResponseModel {
UserResponseModel({
required this.token,
required this.expires,
required this.user,
});
final String token;
final DateTime expires;
final User user;
factory UserResponseModel.fromJson(Map<String, dynamic> json) =>
UserResponseModel(
token: json["token"],
expires: DateTime.parse(json["expires"]),
user: User.fromJson(json["user"]),
);
Map<String, dynamic> toJson() => {
"token": token,
"expires": expires.toIso8601String(),
"user": user.toJson(),
};
}
class User {
User({
required this.id,
required this.email,
required this.name,
required this.lastName,
required this.middleName,
required this.phone,
required this.phoneShort,
required this.permissions,
required this.isActivated,
required this.activatedAt,
required this.lastLogin,
required this.isSuperuser,
required this.property,
required this.createdAt,
required this.updatedAt,
required this.deletedAt,
required this.phoneList,
});
final int id;
final String email;
final String name;
final String lastName;
final String middleName;
final String phone;
final String phoneShort;
final dynamic permissions;
final bool isActivated;
final dynamic activatedAt;
final DateTime lastLogin;
final int isSuperuser;
final dynamic property;
final DateTime createdAt;
final DateTime updatedAt;
final dynamic deletedAt;
final List<String> phoneList;
factory User.fromJson(Map<String, dynamic> json) => User(
id: json["id"],
email: json["email"],
name: json["name"],
lastName: json["last_name"],
middleName: json["middle_name"],
phone: json["phone"],
phoneShort: json["phone_short"],
permissions: json["permissions"],
isActivated: json["is_activated"],
activatedAt: json["activated_at"],
lastLogin: DateTime.parse(json["last_login"]),
isSuperuser: json["is_superuser"],
property: json["property"],
createdAt: DateTime.parse(json["created_at"]),
updatedAt: DateTime.parse(json["updated_at"]),
deletedAt: json["deleted_at"],
phoneList: List<String>.from(json["phone_list"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"id": id,
"email": email,
"name": name,
"last_name": lastName,
"middle_name": middleName,
"phone": phone,
"phone_short": phoneShort,
"permissions": permissions,
"is_activated": isActivated,
"activated_at": activatedAt,
"last_login": lastLogin.toIso8601String(),
"is_superuser": isSuperuser,
"property": property,
"created_at": createdAt.toIso8601String(),
"updated_at": updatedAt.toIso8601String(),
"deleted_at": deletedAt,
"phone_list": List<dynamic>.from(phoneList.map((x) => x)),
};
}

View File

@ -0,0 +1,38 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
class RegisterRequestModel {
String email;
String password;
String passwordConfirmation;
String phone;
RegisterRequestModel({
required this.email,
required this.password,
required this.passwordConfirmation,
required this.phone,
});
Map<String, dynamic> toMap() {
return {
'email': email,
'password': password,
'password_confirmation': passwordConfirmation,
'phone': phone,
};
}
factory RegisterRequestModel.fromMap(Map<String, dynamic> map) {
return RegisterRequestModel(
email: map['email'] ?? '',
password: map['password'] ?? '',
passwordConfirmation: map['password_confirmation'] ?? '',
phone: map['phone'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory RegisterRequestModel.fromJson(String source) =>
RegisterRequestModel.fromMap(json.decode(source));
}

View File

@ -0,0 +1,109 @@
// To parse this JSON data, do
//
// final registerResponseModel = registerResponseModelFromJson(jsonString);
import 'dart:convert';
import 'package:meta/meta.dart';
RegisterResponseModel registerResponseModelFromJson(String str) =>
RegisterResponseModel.fromJson(json.decode(str));
String registerResponseModelToJson(RegisterResponseModel data) =>
json.encode(data.toJson());
class RegisterResponseModel {
RegisterResponseModel({
required this.token,
required this.expires,
required this.user,
});
final String token;
final DateTime expires;
final User user;
factory RegisterResponseModel.fromJson(Map<String, dynamic> json) =>
RegisterResponseModel(
token: json['data']["token"],
expires: DateTime.parse(json['data']["expires"]),
user: User.fromJson(json['data']["user"]),
);
Map<String, dynamic> toJson() => {
"token": token,
"expires": expires.toIso8601String(),
"user": user.toJson(),
};
}
class User {
final int id;
final String email;
final String name;
final String lastName;
final String middleName;
final String phone;
final String phoneShort;
final bool isActivated;
final DateTime lastLogin;
final int isSuperuser;
final DateTime createdAt;
final DateTime updatedAt;
final List<String> phoneList;
User({
required this.id,
required this.email,
required this.name,
required this.lastName,
required this.middleName,
required this.phone,
required this.phoneShort,
required this.isActivated,
required this.lastLogin,
required this.isSuperuser,
required this.createdAt,
required this.updatedAt,
required this.phoneList,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'email': email,
'name': name,
'lastName': lastName,
'middleName': middleName,
'phone': phone,
'phoneShort': phoneShort,
'isActivated': isActivated,
'lastLogin': lastLogin.millisecondsSinceEpoch,
'isSuperuser': isSuperuser,
'createdAt': createdAt.millisecondsSinceEpoch,
'updatedAt': updatedAt.millisecondsSinceEpoch,
'phone_list': phoneList,
};
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id']?.toInt() ?? 0,
email: map['email'] ?? '',
name: map['name'] ?? '',
lastName: map['lastName'] ?? '',
middleName: map['middleName'] ?? '',
phone: map['phone'] ?? '',
phoneShort: map['phoneShort'] ?? '',
isActivated: map['isActivated'] ?? false,
lastLogin: DateTime.fromMillisecondsSinceEpoch(map['lastLogin']),
isSuperuser: map['isSuperuser']?.toInt() ?? 0,
createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt']),
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updatedAt']),
phoneList: List<String>.from(map['phone_list']),
);
}
String toJson() => json.encode(toMap());
factory User.fromJson(String source) => User.fromMap(json.decode(source));
}

View File

@ -0,0 +1,36 @@
import 'dart:convert';
class Vendor {
final String id;
final String password;
final String address;
final String token;
Vendor({
required this.id,
required this.password,
required this.address,
required this.token,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'password': password,
'address': address,
'token': token,
};
}
factory Vendor.fromMap(Map<String, dynamic> map) {
return Vendor(
id: map['id'] ?? '',
password: map['password'] ?? '',
address: map['address'] ?? '',
token: map['token'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory Vendor.fromJson(String source) => Vendor.fromMap(json.decode(source));
}

16
lib/router.dart Normal file
View File

@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
import 'features/screens/auth/login/login_screen.dart';
import 'features/widgets/empty_widget.dart';
Route<dynamic> generateRoute(RouteSettings routeSettings) {
switch (routeSettings.name) {
case LoginScreen.routeName:
return MaterialPageRoute(builder: (_) => LoginScreen());
default:
return MaterialPageRoute(
settings: routeSettings,
builder: (_) => const EmptyWidget(),
);
}
}

View File

@ -1,194 +0,0 @@
import 'package:adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/models/settings_model.dart';
import 'package:sapaly_shop/services/app_constants.dart';
import 'package:sapaly_shop/themes/app_theme.dart';
class LoginScreen extends StatefulWidget {
LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
@override
Widget build(BuildContext context) {
final EdgeInsets paddingLow = EdgeInsets.symmetric(
vertical: AppConstants.verticalPadding(context) / 2,
horizontal: AppConstants.horizontalPadding(context),
);
return Scaffold(
appBar: AppBar(
leading: Container(),
),
body: Container(
margin: EdgeInsets.symmetric(
vertical: AppConstants.verticalPadding(context) / 2,
horizontal: AppConstants.horizontalPadding(context),
),
padding: EdgeInsets.symmetric(
vertical: AppConstants.verticalPadding(context) / 2,
horizontal: AppConstants.horizontalPadding(context),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.adaptedPx()),
border: Border.all(
width: 2.adaptedPx(),
color: AppTheme.blackColor.withOpacity(0.1),
),
),
height: AppConstants.deviceHeight(context) / 1.450,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: 30.adaptedPx(),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/sapalyLogo.png',
),
SizedBox(width: 15.adaptedPx()),
Text(
AppConstants.kAppName,
style:
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.blackColor,
fontSize: 18.adaptedPx(),
fontWeight: FontWeight.w600,
),
)
],
),
),
SizedBox(height: 40.adaptedPx()),
Text(
'enter_your_email'.translation,
textAlign: TextAlign.left,
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.blackColor,
fontSize: 15.adaptedPx(),
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 15.adaptedPx()),
TextFormField(
decoration: InputDecoration(
labelText: 'Login',
labelStyle:
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.lightTextColor,
fontSize: 13.adaptedPx(),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.adaptedPx()),
borderSide: BorderSide(
color: AppTheme.lightTextColor,
width: 2.adaptedPx(),
),
),
),
),
Padding(
padding:
EdgeInsets.only(top: 30.adaptedPx(), bottom: 10.adaptedPx()),
child: Text(
'enter_your_password'.translation,
textAlign: TextAlign.left,
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.blackColor,
fontSize: 15.adaptedPx(),
fontWeight: FontWeight.w600,
),
),
),
TextFormField(
decoration: InputDecoration(
labelText: 'Password',
labelStyle:
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.lightTextColor,
fontSize: 13.adaptedPx(),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.adaptedPx()),
borderSide: BorderSide(
color: AppTheme.lightTextColor,
width: 2.adaptedPx(),
),
),
),
),
SizedBox(height: 20.adaptedPx()),
Container(
height: AppConstants.deviceHeight(context) / 15,
width: double.infinity,
margin: EdgeInsets.symmetric(
vertical: 5.adaptedPx(),
),
child: OutlinedButton(
onPressed: () {},
style: TextButton.styleFrom(
backgroundColor: AppTheme.lightPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.adaptedPx()),
),
),
child: Text(
'Login',
style:
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.whiteColor,
fontSize: 14.adaptedPx(),
),
),
),
),
Align(
alignment: Alignment.center,
child: Text(
'or',
textAlign: TextAlign.center,
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.blackColor,
fontSize: 14.adaptedPx(),
),
),
),
Container(
height: AppConstants.deviceHeight(context) / 15,
width: double.infinity,
margin: EdgeInsets.symmetric(
vertical: 5.adaptedPx(),
),
child: OutlinedButton(
onPressed: () {},
style: TextButton.styleFrom(
backgroundColor: AppTheme.lightTextColor.withOpacity(0.1),
shape: RoundedRectangleBorder(
side:
const BorderSide(color: Colors.transparent, width: 0),
borderRadius: BorderRadius.circular(10.adaptedPx()),
)),
child: Text(
'Register',
style:
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
color: AppTheme.blackColor,
fontSize: 14.adaptedPx(),
),
),
),
),
],
),
),
);
}
}

View File

@ -1,22 +0,0 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:sapaly_shop/screens/auth/login/login_screen.dart';
import 'package:sapaly_shop/services/app_constants.dart';
import '../../../services/auth/login_service.dart';
abstract class LoginViewModel extends State<LoginScreen> {
late final LoginService loginService;
@override
void initState() {
loginService = LoginService(
Dio(
BaseOptions(
baseUrl: kBaseUrl,
),
),
);
super.initState();
}
}

View File

@ -1,29 +0,0 @@
import 'dart:io';
import 'package:dio/dio.dart';
import '../../models/auth/login/user_request_model.dart';
import '../../models/auth/login/user_response_model.dart';
abstract class ILoginService {
final String path = '/jwt/login';
ILoginService(this.dio);
Future<UserResponseModel?> fetchLogin(UserRequestModel model);
final Dio dio;
}
class LoginService extends ILoginService {
LoginService(Dio dio) : super(dio);
@override
Future<UserResponseModel?> fetchLogin(UserRequestModel model) async {
final response = await dio.post(path, data: model);
if (response.statusCode == HttpStatus.ok) {
return UserResponseModel.fromJson(response.data);
}
return null;
}
}

View File

@ -24,10 +24,10 @@ abstract class AppTheme {
),
);
static const Color lightBackgroundColor = Color(0xfff5f5f5);
static const Color lightPrimaryColor = Color(0xFF5677FC);
static const Color lightTextColor = Color(0xFF4B4B4B);
static const Color whiteColor = Color(0xFFFFFFFF);
static const Color redColor = Color(0xFFEE2F3D);
static const Color blackColor = Color(0xFF151515);
static const Color lightBackgroundColor = Color.fromRGBO(245, 245, 245, 1);
static const Color lightPrimaryColor = Color.fromRGBO(86, 119, 252, 1);
static const Color lightTextColor = Color.fromRGBO(75, 75, 75, 1);
static const Color whiteColor = Color.fromRGBO(255, 255, 255, 1);
static const Color redColor = Color.fromRGBO(238, 47, 61, 1);
static const Color blackColor = Color.fromRGBO(21, 21, 21, 1);
}

View File

@ -146,14 +146,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.1"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9"
url: "https://pub.dev"
source: hosted
version: "0.3.3+4"
crypto:
dependency: transitive
description:
@ -194,14 +186,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.0"
dio:
dependency: "direct main"
description:
name: dio
sha256: "3709d74615bba5e443eb141f6a7f4bcc4788f8fae6f743edadfb79c2a8e6287e"
url: "https://pub.dev"
source: hosted
version: "5.0.1"
fake_async:
dependency: transitive
description:
@ -276,14 +260,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.16"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "4bef634684b2c7f3468c77c766c831229af829a0cd2d4ee6c1b99558bd14e5d2"
url: "https://pub.dev"
source: hosted
version: "2.0.8"
flutter_svg:
dependency: "direct main"
description:
@ -342,46 +318,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.3.0"
image_picker:
dependency: transitive
description:
name: image_picker
sha256: "22207768556b82d55ec70166824350fee32298732d5efa4d6e756f848f51f66a"
url: "https://pub.dev"
source: hosted
version: "0.8.6+3"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
sha256: "68d067baf7f6e401b1124ee83dd6967e67847314250fd68012aab34a69beb344"
url: "https://pub.dev"
source: hosted
version: "0.8.5+7"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "66fc6e3877bbde82c33d122f3588777c3784ac5bd7d1cdd79213ef7aecb85b34"
url: "https://pub.dev"
source: hosted
version: "2.1.11"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: "39aa70b5f1e5e7c94585b9738632d5fdb764a5655e40cd9e7b95fbd2fc50c519"
url: "https://pub.dev"
source: hosted
version: "0.8.6+9"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8"
url: "https://pub.dev"
source: hosted
version: "2.6.3"
intl:
dependency: "direct main"
description:
@ -590,16 +526,8 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.2.4"
progress_hud:
dependency: "direct main"
description:
name: progress_hud
sha256: c7a79d70d278328cf3b0732c119a89ba96329825deb03b5dd64415c77dfb8ac4
url: "https://pub.dev"
source: hosted
version: "1.1.0"
provider:
dependency: "direct main"
dependency: transitive
description:
name: provider
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
@ -683,14 +611,6 @@ packages:
description: flutter
source: sdk
version: "0.0.99"
snippet_coder_utils:
dependency: "direct main"
description:
name: snippet_coder_utils
sha256: fb60b8a6b4cab3dddc17ce903cc073d2f5d42ebed676146dde0faba040dc4158
url: "https://pub.dev"
source: hosted
version: "1.0.13"
source_span:
dependency: transitive
description:

View File

@ -51,10 +51,6 @@ dependencies:
shimmer: ^2.0.0
url_launcher: ^6.1.9
shared_preferences: ^2.0.17
provider: ^6.0.5
snippet_coder_utils: ^1.0.13
progress_hud: ^1.1.0
dio: ^5.0.1
dev_dependencies:
flutter_test: