category fetch static
This commit is contained in:
parent
5bb32c3296
commit
8bc1d2c4d7
|
|
@ -1,37 +0,0 @@
|
|||
import 'package:adaptix/adaptix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sapaly_shop/services/app_constants.dart';
|
||||
import 'package:sapaly_shop/themes/app_theme.dart';
|
||||
|
||||
Widget customButton({
|
||||
void Function()? tap,
|
||||
bool? status = false,
|
||||
String? text = 'Save',
|
||||
String? statusText,
|
||||
bool? isValid = false,
|
||||
BuildContext? context,
|
||||
}) {
|
||||
return Container(
|
||||
height: 48.adaptedPx(),
|
||||
width: AppConstants.deviceWidth(context!),
|
||||
margin: EdgeInsets.symmetric(
|
||||
vertical: 15.adaptedPx(), horizontal: 10.adaptedPx()),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8.adaptedPx()),
|
||||
color: status == false
|
||||
? AppTheme.lightPrimaryColor
|
||||
: AppTheme.blackColor.withOpacity(0.3),
|
||||
),
|
||||
child: TextButton(
|
||||
onPressed: status == true ? null : tap,
|
||||
child: Text(
|
||||
status == false ? text! : statusText!,
|
||||
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
|
||||
fontSize: 18.adaptedPx(),
|
||||
color: AppTheme.whiteColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
import 'package:adaptix/adaptix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sapaly_shop/themes/app_theme.dart';
|
||||
|
||||
// void successMessage({String? message, BuildContext? context}) {
|
||||
// ScaffoldMessenger.of(context!).showSnackBar(
|
||||
// SnackBar(
|
||||
// content: Text(
|
||||
// message!,
|
||||
// style: Theme.of(context).primaryTextTheme.bodyMedium,
|
||||
// ),
|
||||
// backgroundColor: AppTheme.blackColor,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
// void errorMessage({String? message, BuildContext? context}) {
|
||||
// ScaffoldMessenger.of(context!).showSnackBar(
|
||||
// SnackBar(
|
||||
// content: Text(
|
||||
// message!,
|
||||
// style: Theme.of(context).primaryTextTheme.bodyMedium,
|
||||
// ),
|
||||
// backgroundColor: AppTheme.redColor,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
void showMessage({String? message, BuildContext? context}) {
|
||||
ScaffoldMessenger.of(context!).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
message!,
|
||||
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
|
||||
fontSize: 16.adaptedPx(),
|
||||
color: AppTheme.blackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import 'package:adaptix/adaptix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sapaly_shop/themes/app_theme.dart';
|
||||
|
||||
Widget customTextField({
|
||||
String? title,
|
||||
String? hint,
|
||||
TextEditingController? controller,
|
||||
int? maxLines = 1,
|
||||
BuildContext? context,
|
||||
}) {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
title!,
|
||||
style: Theme.of(context!).primaryTextTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppTheme.blackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextFormField(
|
||||
controller: controller,
|
||||
maxLines: maxLines,
|
||||
cursorColor: AppTheme.lightPrimaryColor,
|
||||
decoration: InputDecoration(
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(15.adaptedPx()),
|
||||
borderSide: const BorderSide(
|
||||
color: AppTheme.lightPrimaryColor,
|
||||
),
|
||||
),
|
||||
focusColor: AppTheme.lightPrimaryColor,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
import 'package:adaptix/adaptix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:sapaly_shop/onboard.dart';
|
||||
import 'package:sapaly_shop/providers/auth_provider/auth_provider.dart';
|
||||
import 'package:sapaly_shop/screens/auth/login.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';
|
||||
|
|
@ -23,7 +20,6 @@ Future<void> main() async {
|
|||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => SettingsModel(prefs)),
|
||||
ChangeNotifierProvider(create: (_) => AuthenticatonProvider()),
|
||||
],
|
||||
child: const MyApp(),
|
||||
),
|
||||
|
|
@ -41,13 +37,11 @@ class MyApp extends StatelessWidget {
|
|||
debugShowCheckedModeBanner: false,
|
||||
theme: AppTheme.appLightTheme,
|
||||
title: 'Sapaly Mahabat',
|
||||
initialRoute: '/login',
|
||||
initialRoute: '/home',
|
||||
routes: <String, WidgetBuilder>{
|
||||
'/': (context) => const Dashboard(),
|
||||
'/drawer': (context) => SapalyDrawer(),
|
||||
'/onboard': (context) => const Onboard(),
|
||||
'/home': (context) => const HomeScreen(),
|
||||
'/login': (context) => const LoginScreen(),
|
||||
'/category': (context) => const CategoryScreen(),
|
||||
},
|
||||
localizationsDelegates: AppConstants.localizationsDelegate,
|
||||
|
|
|
|||
|
|
@ -5,13 +5,11 @@ class CategoryModel {
|
|||
required this.id,
|
||||
required this.name,
|
||||
required this.translations,
|
||||
required this.icon,
|
||||
});
|
||||
|
||||
final int id;
|
||||
final String name;
|
||||
final List<Translation> translations;
|
||||
final Iconca icon;
|
||||
|
||||
factory CategoryModel.fromJson(
|
||||
Map<String, dynamic> json, String currentLang) {
|
||||
|
|
@ -30,31 +28,10 @@ class CategoryModel {
|
|||
translations: (json['translations'] as List)
|
||||
.map((e) => Translation.fromJson(e))
|
||||
.toList(),
|
||||
icon: Iconca.fromJson(json["icon"] ?? ''),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Iconca {
|
||||
Iconca({
|
||||
required this.id,
|
||||
required this.path,
|
||||
});
|
||||
|
||||
final int id;
|
||||
final String path;
|
||||
|
||||
factory Iconca.fromJson(Map<String, dynamic> json) => Iconca(
|
||||
id: json["id"] ?? 0,
|
||||
path: json["path"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"id": id,
|
||||
"path": path,
|
||||
};
|
||||
}
|
||||
|
||||
class Translation {
|
||||
Translation({
|
||||
required this.locale,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class ProductModel {
|
|||
final String name;
|
||||
final String slug;
|
||||
final int categoryId;
|
||||
final PreviewImage previewImage;
|
||||
final PreviewImage? previewImage;
|
||||
final List<Translation> translations;
|
||||
final List<Offer> offer;
|
||||
|
||||
|
|
@ -38,7 +38,9 @@ class ProductModel {
|
|||
name: language,
|
||||
slug: json["slug"] ?? '',
|
||||
categoryId: json["category_id"] ?? '',
|
||||
previewImage: PreviewImage.fromJson(json["preview_image"] ?? ''),
|
||||
previewImage: (json["preview_image"] != null)
|
||||
? PreviewImage.fromJson(json["preview_image"])
|
||||
: null,
|
||||
translations: List<Translation>.from(
|
||||
json["translations"].map((x) => Translation.fromJson(x))),
|
||||
offer: List<Offer>.from(json["offer"].map((x) => Offer.fromJson(x))),
|
||||
|
|
@ -50,7 +52,7 @@ class ProductModel {
|
|||
"name": name,
|
||||
"slug": slug,
|
||||
"category_id": categoryId,
|
||||
"preview_image": previewImage.toJson(),
|
||||
"preview_image": previewImage!.toJson(),
|
||||
"translations": List<dynamic>.from(translations.map((x) => x.toJson())),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:sapaly_shop/screens/auth/login.dart';
|
||||
|
||||
class Onboard extends StatefulWidget {
|
||||
const Onboard({super.key});
|
||||
|
||||
@override
|
||||
State<Onboard> createState() => _OnboardState();
|
||||
}
|
||||
|
||||
class _OnboardState extends State<Onboard> {
|
||||
void navigate(BuildContext context) {
|
||||
Future.delayed(const Duration(seconds: 3), () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const LoginScreen(),
|
||||
),
|
||||
(route) => false);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
navigate(context);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: Text('On Board'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:sapaly_shop/services/app_constants.dart';
|
||||
|
||||
class AuthenticatonProvider extends ChangeNotifier {
|
||||
// Base URL
|
||||
final requestBaseUrl = kBaseUrl;
|
||||
bool _isLoading = false;
|
||||
String _resMessage = '';
|
||||
|
||||
// Getter
|
||||
bool get isLoading => _isLoading;
|
||||
String get resMeessage => _resMessage;
|
||||
|
||||
// for sign_up
|
||||
void register({
|
||||
required String email,
|
||||
required String phoneNumber,
|
||||
required String password,
|
||||
required String repeatPassword,
|
||||
BuildContext? context,
|
||||
}) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
String url = '$requestBaseUrl/api/jwt/register';
|
||||
|
||||
final body = {
|
||||
'email': email,
|
||||
'phone': phoneNumber,
|
||||
'password': password,
|
||||
'password_confirmation': repeatPassword,
|
||||
};
|
||||
|
||||
debugPrint('This is SIGNUP BODY ${body.toString()}');
|
||||
|
||||
try {
|
||||
final req = await http.post(Uri.parse(url), body: json.encode(body));
|
||||
|
||||
if (req.statusCode == 200 || req.statusCode == 201) {
|
||||
debugPrint('SIGNUP success ${req.body}');
|
||||
} else {
|
||||
final res = json.decode(req.body);
|
||||
debugPrint('SIGNUP error ${res.body}');
|
||||
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
} on SocketException catch (error) {
|
||||
_isLoading = false;
|
||||
_resMessage = 'Internet connection is not available';
|
||||
notifyListeners();
|
||||
} catch (err) {
|
||||
_isLoading = false;
|
||||
_resMessage = 'Please try again';
|
||||
notifyListeners();
|
||||
|
||||
debugPrint('::::: ${err.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
// for sign_in
|
||||
void login({
|
||||
required String email,
|
||||
required String password,
|
||||
BuildContext? context,
|
||||
}) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
String url = '$requestBaseUrl/api/jwt/login';
|
||||
|
||||
final body = {
|
||||
'email': email,
|
||||
'password': password,
|
||||
};
|
||||
|
||||
debugPrint('This is SIGNUP BODY ${body.toString()}');
|
||||
|
||||
try {
|
||||
final req = await http.post(Uri.parse(url), body: json.encode(body));
|
||||
|
||||
if (req.statusCode == 200 || req.statusCode == 201) {
|
||||
debugPrint('LOGIN success ${req.body}');
|
||||
} else {
|
||||
final res = json.decode(req.body);
|
||||
debugPrint('LOGIN error ${res.body}');
|
||||
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
} on SocketException catch (error) {
|
||||
_isLoading = false;
|
||||
_resMessage = 'Internet connection is not available';
|
||||
notifyListeners();
|
||||
} catch (err) {
|
||||
_isLoading = false;
|
||||
_resMessage = 'Please try again';
|
||||
notifyListeners();
|
||||
|
||||
debugPrint('::::: ${err.toString()}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
import 'package:adaptix/adaptix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:sapaly_shop/components/custom_button.dart';
|
||||
import 'package:sapaly_shop/components/snack_message.dart';
|
||||
import 'package:sapaly_shop/components/text_field.dart';
|
||||
import 'package:sapaly_shop/providers/auth_provider/auth_provider.dart';
|
||||
import 'package:sapaly_shop/screens/auth/register.dart';
|
||||
import 'package:sapaly_shop/services/app_constants.dart';
|
||||
import 'package:sapaly_shop/themes/app_theme.dart';
|
||||
|
||||
import '../../services/page_navigator.dart';
|
||||
|
||||
class LoginScreen extends StatefulWidget {
|
||||
const LoginScreen({super.key});
|
||||
|
||||
@override
|
||||
State<LoginScreen> createState() => _LoginScreenState();
|
||||
}
|
||||
|
||||
class _LoginScreenState extends State<LoginScreen> {
|
||||
final TextEditingController _email = TextEditingController();
|
||||
final TextEditingController _password = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_email.clear();
|
||||
_password.clear();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: AppConstants.horizontalPadding(context),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: AppConstants.horizontalPadding(context),
|
||||
),
|
||||
height: AppConstants.deviceHeight(context) / (1.4),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 2.adaptedPx(),
|
||||
color: AppTheme.blackColor.withOpacity(0.1),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15.adaptedPx()),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset('assets/images/sapalyLogo.png'),
|
||||
SizedBox(width: 20.adaptedPx()),
|
||||
Text(
|
||||
AppConstants.kAppName,
|
||||
style:
|
||||
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
|
||||
color: AppTheme.blackColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 20.adaptedPx(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20.adaptedPx()),
|
||||
customTextField(
|
||||
title: 'Email',
|
||||
context: context,
|
||||
hint: 'Enter your valid email address',
|
||||
controller: _email,
|
||||
),
|
||||
SizedBox(height: 20.adaptedPx()),
|
||||
customTextField(
|
||||
title: 'Password',
|
||||
context: context,
|
||||
hint: 'Enter your secured password',
|
||||
controller: _password,
|
||||
),
|
||||
SizedBox(height: 45.adaptedPx()),
|
||||
Consumer<AuthenticatonProvider>(builder: (context, auth, child) {
|
||||
return customButton(
|
||||
text: 'Login',
|
||||
tap: () {
|
||||
if (_email.text.isEmpty || _password.text.isEmpty) {
|
||||
showMessage(
|
||||
context: context,
|
||||
message: 'All fields are required',
|
||||
);
|
||||
} else {
|
||||
auth.login(
|
||||
email: _email.text.trim(),
|
||||
password: _password.text.trim());
|
||||
}
|
||||
},
|
||||
context: context,
|
||||
statusText: 'Loggin in...',
|
||||
status: auth.isLoading,
|
||||
);
|
||||
}),
|
||||
Text(
|
||||
'Or',
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
|
||||
color: AppTheme.blackColor,
|
||||
fontSize: 18.adaptedPx(),
|
||||
),
|
||||
),
|
||||
customButton(
|
||||
text: 'Register',
|
||||
tap: () {
|
||||
PageNavigator(ctx: context).nextPage(
|
||||
page: const RegisterScreen(),
|
||||
);
|
||||
},
|
||||
context: context,
|
||||
isValid: false,
|
||||
status: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
import 'package:adaptix/adaptix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sapaly_shop/components/custom_button.dart';
|
||||
import 'package:sapaly_shop/components/text_field.dart';
|
||||
import 'package:sapaly_shop/screens/auth/login.dart';
|
||||
import 'package:sapaly_shop/services/app_constants.dart';
|
||||
import 'package:sapaly_shop/themes/app_theme.dart';
|
||||
|
||||
import '../../services/page_navigator.dart';
|
||||
|
||||
class RegisterScreen extends StatefulWidget {
|
||||
const RegisterScreen({super.key});
|
||||
|
||||
@override
|
||||
State<RegisterScreen> createState() => _RegisterScreenState();
|
||||
}
|
||||
|
||||
class _RegisterScreenState extends State<RegisterScreen> {
|
||||
final TextEditingController _email = TextEditingController();
|
||||
final TextEditingController _password = TextEditingController();
|
||||
final TextEditingController _passwordConfirm = TextEditingController();
|
||||
final TextEditingController _phone = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_email.clear();
|
||||
_password.clear();
|
||||
_passwordConfirm.clear();
|
||||
_phone.clear();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: AppConstants.horizontalPadding(context),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: AppConstants.horizontalPadding(context),
|
||||
),
|
||||
height: AppConstants.deviceHeight(context) / (1.13),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 2.adaptedPx(),
|
||||
color: AppTheme.blackColor.withOpacity(0.1),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15.adaptedPx()),
|
||||
),
|
||||
child: ListView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset('assets/images/sapalyLogo.png'),
|
||||
SizedBox(width: 20.adaptedPx()),
|
||||
Text(
|
||||
AppConstants.kAppName,
|
||||
style:
|
||||
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
|
||||
color: AppTheme.blackColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 20.adaptedPx(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20.adaptedPx()),
|
||||
customTextField(
|
||||
title: 'Your email',
|
||||
context: context,
|
||||
controller: _email,
|
||||
hint: '',
|
||||
),
|
||||
SizedBox(height: 15.adaptedPx()),
|
||||
customTextField(title: 'Phone number', context: context),
|
||||
SizedBox(height: 15.adaptedPx()),
|
||||
customTextField(title: 'Password', context: context),
|
||||
SizedBox(height: 15.adaptedPx()),
|
||||
customTextField(title: 'Password confirmation', context: context),
|
||||
SizedBox(height: 15.adaptedPx()),
|
||||
customButton(
|
||||
text: 'Register',
|
||||
context: context,
|
||||
status: false,
|
||||
statusText: 'Registering...',
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 15.adaptedPx()),
|
||||
child: Text(
|
||||
'Or',
|
||||
textAlign: TextAlign.center,
|
||||
style:
|
||||
Theme.of(context).primaryTextTheme.bodyMedium?.copyWith(
|
||||
color: AppTheme.blackColor,
|
||||
fontSize: 18.adaptedPx(),
|
||||
),
|
||||
),
|
||||
),
|
||||
customButton(
|
||||
text: 'Login',
|
||||
context: context,
|
||||
tap: () {
|
||||
PageNavigator(ctx: context).nextPageOnly(
|
||||
page: const LoginScreen(),
|
||||
);
|
||||
},
|
||||
statusText: 'Loggin in...',
|
||||
status: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ 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:provider/provider.dart';
|
||||
import 'package:sapaly_shop/components/sapaly_app_bar.dart';
|
||||
import 'package:sapaly_shop/models/category_model.dart';
|
||||
import 'package:sapaly_shop/models/settings_model.dart';
|
||||
|
|
@ -91,17 +90,17 @@ class _CategoryScreenState extends State<CategoryScreen> {
|
|||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: categories[index].icon.path,
|
||||
width: MediaQuery.of(context).size.width / 7,
|
||||
fit: BoxFit.contain,
|
||||
progressIndicatorBuilder:
|
||||
(context, url, progress) => const Center(
|
||||
child: CircularProgressIndicator()),
|
||||
),
|
||||
),
|
||||
// Expanded(
|
||||
// flex: 3,
|
||||
// child: CachedNetworkImage(
|
||||
// imageUrl: categories[index].icon.path,
|
||||
// width: MediaQuery.of(context).size.width / 7,
|
||||
// fit: BoxFit.contain,
|
||||
// progressIndicatorBuilder:
|
||||
// (context, url, progress) => const Center(
|
||||
// child: CircularProgressIndicator()),
|
||||
// ),
|
||||
// ),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ 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/auth/login.dart';
|
||||
import 'package:sapaly_shop/screens/auth/register.dart';
|
||||
import 'package:sapaly_shop/screens/category/category_screen.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
|
|
@ -33,8 +31,8 @@ class SapalyDrawer extends StatelessWidget {
|
|||
|
||||
List<Widget> routes = [
|
||||
const CategoryScreen(),
|
||||
const LoginScreen(),
|
||||
const RegisterScreen(),
|
||||
Container(),
|
||||
Container(),
|
||||
Container(),
|
||||
Container(),
|
||||
Container(),
|
||||
|
|
|
|||
|
|
@ -5,16 +5,14 @@ import 'package:carousel_slider/carousel_slider.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:sapaly_shop/models/product_model.dart';
|
||||
import 'package:sapaly_shop/models/settings_model.dart';
|
||||
import 'package:sapaly_shop/models/sliders_model.dart';
|
||||
import 'package:sapaly_shop/screens/drawer/sapaly_drawer.dart';
|
||||
import 'package:sapaly_shop/screens/details/details.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 '../../components/product_card.dart';
|
||||
import '../../components/sapaly_app_bar.dart';
|
||||
import '../../models/category_model.dart';
|
||||
import '../../themes/app_theme.dart';
|
||||
|
|
@ -31,8 +29,7 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
|||
int currentPage = 0;
|
||||
int categoryId = 0;
|
||||
bool hasError = false;
|
||||
late TabController tabController;
|
||||
List<ProductModel> products = [];
|
||||
TabController? tabController;
|
||||
List<CategoryModel> categories = [];
|
||||
List<SlidersModel> sliders = [];
|
||||
|
||||
|
|
@ -59,7 +56,6 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
|||
hasError = false;
|
||||
});
|
||||
}
|
||||
|
||||
tabController = TabController(length: categories.length, vsync: this);
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
|
|
@ -69,24 +65,11 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> getProductsByCategory(int id) async {
|
||||
try {
|
||||
var list = await API().getProductsByCategory(id);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
products = list;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
getSliders();
|
||||
getCategories();
|
||||
getProductsByCategory(categoryId);
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
|
@ -248,39 +231,24 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
|||
),
|
||||
),
|
||||
SizedBox(height: 15.adaptedPx()),
|
||||
products.isEmpty && categories.isEmpty
|
||||
? SizedBox(
|
||||
height: AppConstants.deviceHeight(context) / 1.190,
|
||||
child: const Center(child: CircularProgressIndicator()),
|
||||
)
|
||||
: SizedBox(
|
||||
height: AppConstants.deviceHeight(context),
|
||||
width: double.infinity,
|
||||
child: TabBarView(
|
||||
SizedBox(
|
||||
height: AppConstants.deviceHeight(context),
|
||||
width: double.infinity,
|
||||
child: tabController != null
|
||||
? TabBarView(
|
||||
controller: tabController,
|
||||
children: [
|
||||
for (ProductModel product in products)
|
||||
ProductCard(
|
||||
imageUrl: product.previewImage.path,
|
||||
price: '${product.offer.first.price}.M',
|
||||
discountPrice: '${product.offer.first.oldPrice}.M',
|
||||
description: product.offer.first.name,
|
||||
discountPriceValue:
|
||||
product.offer.first.discountPriceValue,
|
||||
onPressed: () => Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => Details(
|
||||
id: product.id,
|
||||
image: product.previewImage.path,
|
||||
price: '${product.offer.first.price}.M',
|
||||
description: product.offer.first.name,
|
||||
children: categories.isNotEmpty
|
||||
? categories
|
||||
.map(
|
||||
(category) => Products(
|
||||
id: category.id,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList()
|
||||
: [],
|
||||
)
|
||||
: Container(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,48 +1,28 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:sapaly_shop/models/category_model.dart';
|
||||
import 'package:sapaly_shop/models/product_model.dart';
|
||||
|
||||
import '../../components/product_card.dart';
|
||||
import '../../services/app_constants.dart';
|
||||
import '../../services/requests.dart';
|
||||
import '../details/details.dart';
|
||||
|
||||
class Products extends StatefulWidget {
|
||||
const Products({
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.length,
|
||||
required this.controller,
|
||||
});
|
||||
final int id, length;
|
||||
final TabController controller;
|
||||
|
||||
const Products({super.key, required this.id});
|
||||
final int id;
|
||||
@override
|
||||
State<Products> createState() => _ProductsState();
|
||||
}
|
||||
|
||||
class _ProductsState extends State<Products> {
|
||||
List<ProductModel> products = [];
|
||||
List<CategoryModel> categories = [];
|
||||
|
||||
Future<void> getCategories() async {
|
||||
try {
|
||||
var data = await API().getCategories();
|
||||
setState(() {
|
||||
categories = data;
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint('Category error ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getProductsByCategory(int id) async {
|
||||
try {
|
||||
var list = await API().getProductsByCategory(id);
|
||||
setState(() {
|
||||
products = list;
|
||||
});
|
||||
debugPrint("THIS IS PRODUCTS $products");
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
products = list;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
}
|
||||
|
|
@ -50,8 +30,8 @@ class _ProductsState extends State<Products> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
getCategories();
|
||||
getProductsByCategory(widget.id);
|
||||
print('category id :${widget.id}');
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
|
@ -59,44 +39,33 @@ class _ProductsState extends State<Products> {
|
|||
Widget build(BuildContext context) {
|
||||
return products == null
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: SizedBox(
|
||||
height: AppConstants.deviceHeight(context),
|
||||
width: double.infinity,
|
||||
child: TabBarView(
|
||||
controller: widget.controller,
|
||||
children: [
|
||||
for (CategoryModel category in categories)
|
||||
GridView.builder(
|
||||
shrinkWrap: true,
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
),
|
||||
itemCount: products.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ProductCard(
|
||||
imageUrl: products[index].previewImage.path,
|
||||
price: '${products[index].offer.first.price}.M',
|
||||
discountPrice:
|
||||
'${products[index].offer.first.oldPrice}.M',
|
||||
description: products[index].offer.first.name,
|
||||
discountPriceValue:
|
||||
products[index].offer.first.discountPriceValue,
|
||||
onPressed: () => Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => Details(
|
||||
id: products[index].id,
|
||||
image: products[index].previewImage.path,
|
||||
price: '${products[index].offer.first.price}.M',
|
||||
description: products[index].offer.first.name,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
: GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
),
|
||||
itemCount: products.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ProductCard(
|
||||
imageUrl: products[index].previewImage?.path ?? '',
|
||||
price: '${products[index].offer.first.price}.M',
|
||||
discountPrice: '${products[index].offer.first.oldPrice}.M',
|
||||
description: products[index].offer.first.name,
|
||||
discountPriceValue:
|
||||
products[index].offer.first.discountPriceValue,
|
||||
onPressed: () => Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => Details(
|
||||
id: products[index].id,
|
||||
image: products[index].previewImage?.path ?? '',
|
||||
price: '${products[index].offer.first.price}.M',
|
||||
description: products[index].offer.first.name,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,12 @@ class API {
|
|||
String currentLang = prefs.getString('language') ?? 'ru';
|
||||
try {
|
||||
final products = await _getData('v1/products/category/$id');
|
||||
return (products['data']['data'] as List)
|
||||
.map((e) => ProductModel.fromJson(e, currentLang))
|
||||
.toList();
|
||||
|
||||
return products.containsKey('data')
|
||||
? (products['data']['data'] as List)
|
||||
.map((e) => ProductModel.fromJson(e, currentLang))
|
||||
.toList()
|
||||
: [].cast<ProductModel>();
|
||||
} catch (e) {
|
||||
debugPrint('product by categ ' + e.toString());
|
||||
rethrow;
|
||||
|
|
@ -55,11 +58,26 @@ class API {
|
|||
}
|
||||
}
|
||||
|
||||
Future<List<CategoryModel>> getSubCategories(int id) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
String currentLanguage = prefs.getString('language') ?? 'ru';
|
||||
try {
|
||||
final categories = await _getData("v1/category/sub/$id");
|
||||
return (categories["data"] as List)
|
||||
.map((item) => CategoryModel.fromJson(item, currentLanguage))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
debugPrint('Category ' + e.toString());
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<CategoryModel>> getCategories() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
String currentLanguage = prefs.getString('language') ?? 'ru';
|
||||
try {
|
||||
final categories = await _getData("v1/categories");
|
||||
final categories = await _getData("v1/category/sub/19");
|
||||
|
||||
return (categories["data"] as List)
|
||||
.map((item) => CategoryModel.fromJson(item, currentLanguage))
|
||||
.toList();
|
||||
|
|
@ -80,4 +98,27 @@ class API {
|
|||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> register(String email, String phone, String password,
|
||||
String password_confirmation) async {
|
||||
Map<String, String> requestHeaders = {'Content-Type': 'application/json'};
|
||||
var url = Uri.http(kBaseUrl, 'jwt/register');
|
||||
|
||||
var response = await http.post(
|
||||
url,
|
||||
headers: requestHeaders,
|
||||
body: jsonEncode({
|
||||
'email': email,
|
||||
'password': password,
|
||||
'password_confirmation': password_confirmation,
|
||||
'phone': phone,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
72
pubspec.lock
72
pubspec.lock
|
|
@ -146,6 +146,14 @@ 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:
|
||||
|
|
@ -260,6 +268,14 @@ 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:
|
||||
|
|
@ -318,6 +334,46 @@ 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:
|
||||
|
|
@ -526,6 +582,14 @@ 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"
|
||||
description:
|
||||
|
|
@ -611,6 +675,14 @@ 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:
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ dependencies:
|
|||
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
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue