Compare commits

..

3 Commits

Author SHA1 Message Date
e7073cec67 Add: closing module on errors 2024-05-22 15:46:39 +03:00
80da7e9008 Fix: $ to руб 2024-05-22 15:46:24 +03:00
7907dcf6c2 Add: getting products from API 2024-05-22 15:46:09 +03:00
11 changed files with 461 additions and 287 deletions

View File

@@ -32,52 +32,59 @@ class BasketItemCard extends StatelessWidget {
minWidth: 400,
maxWidth: 600,
),
child: Card(
elevation: 4,
color: Theme.of(context).scaffoldBackgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
child: Padding(
padding: const EdgeInsetsDirectional.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
image,
const SizedBox(width: 20),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
name,
style: Theme.of(context).textTheme.bodyLarge,
),
Text('\$$price'),
],
)
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: onTapMinus,
),
const SizedBox(width: 10),
Text(quantity),
const SizedBox(width: 10),
IconButton(
icon: const Icon(Icons.add),
onPressed: onTapPlus,
),
],
)
],
child: GestureDetector(
onTap: () {
debugPrint('name: $name');
//TODO: сделать переход по клику
// Navigator.of(context).pushReplacement(CustomPageRoute(builder: (context)=>const DetailPage(name: this.name, description: description, price: price, id: id, image: image)))
},
child: Card(
elevation: 4,
color: Theme.of(context).scaffoldBackgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
child: Padding(
padding: const EdgeInsetsDirectional.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
image,
const SizedBox(width: 20),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
name,
style: Theme.of(context).textTheme.bodyLarge,
),
Text('$price руб.'),
],
)
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: onTapMinus,
),
const SizedBox(width: 10),
Text(quantity),
const SizedBox(width: 10),
IconButton(
icon: const Icon(Icons.add),
onPressed: onTapPlus,
),
],
)
],
),
),
),
),

View File

@@ -64,7 +64,7 @@ class HistoryItemCard extends StatelessWidget {
),
MarkdownBody(
data: 'Статус: **${orderStatusMap[status]}**'),
MarkdownBody(data: 'Сумма: **\$$cost**'),
MarkdownBody(data: 'Сумма: **$cost руб.**'),
],
)
],

View File

@@ -46,7 +46,7 @@ class ProductCard extends StatelessWidget {
),
const SizedBox(height: 8),
Text(
'\$$price',
'$price руб.',
style: Theme.of(context).textTheme.titleSmall,
),
],

View File

@@ -46,7 +46,7 @@ class OrderConfirmItemCard extends StatelessWidget {
name,
style: Theme.of(context).textTheme.bodyLarge,
),
Text('\$$price x $count = \$${price * count}'),
Text('$price руб. x $count = ${price * count} руб.'),
],
)
],

80
lib/interfaces/items.dart Normal file
View File

@@ -0,0 +1,80 @@
import 'dart:convert';
class GymItem {
final String id;
final String externalId;
final String title;
final String description;
final int count;
final double price;
final String categoryId;
final List<GymImage> images;
int localCount = 0;
GymItem({
required this.id,
required this.externalId,
required this.title,
required this.description,
required this.count,
required this.price,
required this.categoryId,
required this.images,
});
factory GymItem.fromRawJson(String str) => GymItem.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GymItem.fromJson(Map<String, dynamic> json) => GymItem(
id: json["id"],
externalId: json["ExternalId"],
title: json["title"],
description: json["description"],
count: json["count"],
price: json["price"] / 100,
categoryId: json["categoryId"],
images: List<GymImage>.from(
json["images"].map((x) => GymImage.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"ExternalId": externalId,
"title": title,
"description": description,
"count": count,
"price": price * 100,
"categoryId": categoryId,
"images": List<dynamic>.from(images.map((x) => x.toJson())),
};
}
class GymImage {
final String id;
final dynamic deletedAt;
final String url;
GymImage({
required this.id,
required this.deletedAt,
required this.url,
});
factory GymImage.fromRawJson(String str) =>
GymImage.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GymImage.fromJson(Map<String, dynamic> json) => GymImage(
id: json["id"],
deletedAt: json["deletedAt"],
url: json["url"],
);
Map<String, dynamic> toJson() => {
"id": id,
"deletedAt": deletedAt,
"url": url,
};
}

View File

@@ -2,9 +2,10 @@ import 'package:flutter/material.dart';
import 'package:gymlink_module_web/components/app_bar.dart';
import 'package:gymlink_module_web/components/basket_item_card.dart';
import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/pages/order_confirmation.dart';
import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/providers/main.dart';
import 'package:gymlink_module_web/tools/items.dart';
import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/routes.dart';
import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
@@ -56,46 +57,47 @@ class BasketPage extends StatefulWidget {
}
class _BasketPageState extends State<BasketPage> {
List<Map<String, dynamic>> cartItems = [];
int totalPrice = 0;
List<GymItem> cartItems = [];
double totalPrice = 0;
List<GymItem> gymCart = [];
@override
void initState() {
super.initState();
getCart().then((value) {
setState(() {
cartItems = value.map((element) {
final item = cart.firstWhere((e) => e['id'] == element['id']);
return {...item, 'count': element['count'] as int};
}).toList();
totalPrice = cartItems.fold(
0,
(sum, item) =>
sum + int.parse(item['price']) * item['count'] as int);
});
});
Future.microtask(() => getCart().then((value) async {
final items = await getItems(context);
setState(() {
gymCart = items;
cartItems = value.map((element) {
final item = gymCart.firstWhere((e) => e.id == element['id']);
item.localCount = element['count'] as int;
return item;
}).toList();
totalPrice = cartItems.fold(
0, (sum, item) => sum + item.price * item.localCount);
});
}));
}
void _updateCart() {
Provider.of<CartProvider>(context, listen: false).updateCartLength();
Provider.of<GymLinkProvider>(context, listen: false).onTokenReceived('123');
}
void removeItem(String id) async {
final item = cartItems.firstWhere((element) => element['id'] == id);
final item = cartItems.firstWhere((element) => element.id == id);
bool toDelete = false;
setState(() {
if (item['count'] > 1) {
item['count']--;
cartItems[cartItems.indexOf(item)]['count'] = item['count'];
if (item.localCount > 1) {
item.localCount--;
cartItems[cartItems.indexOf(item)].localCount = item.localCount;
} else {
toDelete = true;
}
totalPrice = cartItems.fold(0,
(sum, item) => sum + int.parse(item['price']) * item['count'] as int);
totalPrice =
cartItems.fold(0, (sum, item) => sum + item.price * item.localCount);
});
if (toDelete) {
await _deleteItemAlert(id, item['name']);
await _deleteItemAlert(id, item.title);
} else {
await removeItemFromCart(id);
}
@@ -103,15 +105,16 @@ class _BasketPageState extends State<BasketPage> {
void addItem(String id) async {
setState(() {
final item = cartItems.firstWhere((element) => element['id'] == id,
orElse: () => {
...cart.firstWhere((element) => element['id'] == id),
'count': 0
});
item['count']++;
cartItems[cartItems.indexOf(item)]['count'] = item['count'];
totalPrice = cartItems.fold(0,
(sum, item) => sum + int.parse(item['price']) * item['count'] as int);
final item =
cartItems.firstWhere((element) => element.id == id, orElse: () {
final cartItem = gymCart.firstWhere((element) => element.id == id);
cartItem.localCount = 0;
return cartItem;
});
item.localCount++;
cartItems[cartItems.indexOf(item)].localCount = item.localCount;
totalPrice =
cartItems.fold(0, (sum, item) => sum + item.price * item.localCount);
});
await addItemToCart(id);
}
@@ -142,7 +145,7 @@ class _BasketPageState extends State<BasketPage> {
onPressed: () {
removeItemFromCart(id);
setState(() {
cartItems.removeWhere((element) => element['id'] == id);
cartItems.removeWhere((element) => element.id == id);
});
if (mounted) {
_updateCart();
@@ -224,76 +227,20 @@ class _BasketPageState extends State<BasketPage> {
body: Column(
children: [
const GymLinkHeader(title: "Корзина"),
cartItems.isEmpty
? Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Корзина пуста',
style: Theme.of(context).textTheme.bodyLarge),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () => Navigator.pop(context, true),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(50)),
),
foregroundColor: Colors.white,
),
child: const Text('Вернуться назад'),
),
],
),
),
)
: Expanded(
child: _buildRowOrCol(
context: context,
children: [
Expanded(
child: LazyLoadScrollView(
onEndOfPage: _onLoad,
child: ListView.builder(
itemCount: cartItems.length,
itemBuilder: (context, index) {
final item = cartItems[index];
return BasketItemCard(
name: item['name'],
price: item['price'],
id: item['id'],
image: Image(
image: AssetImage('assets/${item['image']}'),
width: 50,
),
onTapPlus: () => addItem(item['id'].toString()),
onTapMinus: () {
removeItem(item['id'].toString());
},
quantity: item['count'].toString(),
);
},
),
),
),
_buildSpacer(),
Padding(
padding: const EdgeInsetsDirectional.symmetric(
horizontal: 10, vertical: 10),
gymCart.isEmpty
? const Expanded(
child: Center(child: CircularProgressIndicator()))
: cartItems.isEmpty
? Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Итого: $totalPrice',
),
Text('Корзина пуста',
style: Theme.of(context).textTheme.bodyLarge),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () => Navigator.of(context).push(
CustomPageRoute(
builder: (context) =>
const OrderConfirmationPage(),
),
),
onPressed: () => Navigator.pop(context, true),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
@@ -302,27 +249,89 @@ class _BasketPageState extends State<BasketPage> {
),
foregroundColor: Colors.white,
),
child: const Text('Оформить заказ'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _clearCartAlert,
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(50))),
foregroundColor: Colors.white,
),
child: const Text('Очистить корзину'),
child: const Text('Вернуться назад'),
),
],
),
),
const SizedBox(width: 50),
],
),
),
)
: Expanded(
child: _buildRowOrCol(
context: context,
children: [
Expanded(
child: LazyLoadScrollView(
onEndOfPage: _onLoad,
child: ListView.builder(
itemCount: cartItems.length,
itemBuilder: (context, index) {
final item = cartItems[index];
return BasketItemCard(
name: item.title,
price: item.price.toString(),
id: item.id,
image: Image(
image: NetworkImage(item.images[0].url),
width: 50,
),
onTapPlus: () =>
addItem(item.id.toString()),
onTapMinus: () {
removeItem(item.id.toString());
},
quantity: item.localCount.toString(),
);
},
),
),
),
_buildSpacer(),
Padding(
padding: const EdgeInsetsDirectional.symmetric(
horizontal: 10, vertical: 10),
child: Column(
children: [
Text(
'Итого: $totalPrice',
),
ElevatedButton(
onPressed: () => Navigator.of(context).push(
CustomPageRoute(
builder: (context) =>
const OrderConfirmationPage(),
),
),
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(50)),
),
foregroundColor: Colors.white,
),
child: const Text('Оформить заказ'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _clearCartAlert,
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(50))),
foregroundColor: Colors.white,
),
child: const Text('Очистить корзину'),
),
],
),
),
const SizedBox(width: 50),
],
),
),
],
),
);

View File

@@ -1,8 +1,10 @@
import 'package:flutter/material.dart';
import 'package:gymlink_module_web/components/app_bar.dart';
import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/pages/basket.dart';
import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/routes.dart';
import 'package:provider/provider.dart';
//TODO: Сделать получение инфы через объект
@@ -83,38 +85,59 @@ class _DetailPageState extends State<DetailPage> {
child: const Text('Добавить в корзину'),
);
} else {
return Row(
mainAxisSize: MainAxisSize.min,
return Column(
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: () async {
await removeItemFromCart(widget.id);
setState(() {
if (quantity > 1) {
quantity--;
} else {
isInCart = false;
quantity = 0;
}
});
if (mounted) {
context.read<CartProvider>().updateCartLength();
}
},
),
const SizedBox(width: 10),
Text('$quantity'),
const SizedBox(width: 10),
IconButton(
icon: const Icon(Icons.add),
onPressed: () async {
await addItemToCart(widget.id);
setState(() {
quantity++;
});
},
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: () async {
await removeItemFromCart(widget.id);
setState(() {
if (quantity > 1) {
quantity--;
} else {
isInCart = false;
quantity = 0;
}
});
if (mounted) {
context.read<CartProvider>().updateCartLength();
}
},
),
const SizedBox(width: 10),
Text('$quantity'),
const SizedBox(width: 10),
IconButton(
icon: const Icon(Icons.add),
onPressed: () async {
await addItemToCart(widget.id);
setState(() {
quantity++;
});
},
),
],
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: ElevatedButton(
onPressed: () {
Navigator.pushReplacement(context,
CustomPageRoute(builder: (context) => const BasketPage()));
},
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(50)),
),
foregroundColor: Colors.white,
),
child: const Text('Открыть корзину'),
),
)
],
);
}
@@ -139,37 +162,43 @@ class _DetailPageState extends State<DetailPage> {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
widget.image,
Padding(
padding: const EdgeInsetsDirectional.all(30),
child: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 340,
maxWidth: 340,
maxHeight: 600,
),
child: Card(
elevation: 4,
color: Theme.of(context).scaffoldBackgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsetsDirectional.all(15),
child: ConstrainedBox(
constraints: const BoxConstraints(
minHeight: 100,
widget.description != ''
? Padding(
padding: const EdgeInsetsDirectional.all(30),
child: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 340,
maxWidth: 340,
maxHeight: 600,
),
child: Card(
elevation: 4,
color:
Theme.of(context).scaffoldBackgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Text(
widget.description,
style: Theme.of(context).textTheme.bodyMedium,
child: SingleChildScrollView(
child: Padding(
padding:
const EdgeInsetsDirectional.all(15),
child: ConstrainedBox(
constraints: const BoxConstraints(
minHeight: 100,
),
child: Text(
widget.description,
style: Theme.of(context)
.textTheme
.bodyMedium,
),
),
),
),
),
),
),
),
),
),
)
: const SizedBox.shrink(),
Align(
alignment: const AlignmentDirectional(0, -1),
child: Padding(
@@ -179,7 +208,7 @@ class _DetailPageState extends State<DetailPage> {
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Стоимость ${widget.price}',
'Стоимость ${widget.price}руб.',
style: Theme.of(context).textTheme.bodyLarge,
),
_buildButton()

View File

@@ -3,11 +3,12 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:gymlink_module_web/components/app_bar.dart';
import 'package:gymlink_module_web/components/item_card.dart';
import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/pages/basket.dart';
import 'package:gymlink_module_web/pages/detail.dart';
import 'package:gymlink_module_web/pages/order_history.dart';
import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/providers/main.dart';
import 'package:gymlink_module_web/tools/items.dart';
import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/relative.dart';
import 'package:gymlink_module_web/tools/routes.dart';
@@ -65,22 +66,22 @@ class MainPage extends StatefulWidget {
class _MainPageState extends State<MainPage> {
String searchText = '';
List<Map<String, String>> filteredData = [];
List<GymItem> filteredData = [];
List<GymItem> items = [];
int cartLength = 0;
@override
void initState() {
super.initState();
filteredData = testData;
getCart().then((value) {
setState(() {
cartLength = value.length;
});
}).whenComplete(() {
if (mounted) {
setState(() {});
}
});
getItems(context).then((value) => setState(() {
filteredData = value;
items = value;
}));
}
Future<void> _goToPage() async {
@@ -97,8 +98,8 @@ class _MainPageState extends State<MainPage> {
void _onSearch() {
setState(() {
filteredData = testData
.where((element) => (element['name']!).contains(searchText))
filteredData = items
.where((element) => (element.title).contains(searchText))
.toList();
});
}
@@ -106,7 +107,6 @@ class _MainPageState extends State<MainPage> {
@override
Widget build(BuildContext context) {
final cartL = context.watch<CartProvider>().cartLength;
final onError = context.read<GymLinkProvider>().onError;
return Scaffold(
appBar: const GymLinkAppBar(),
body: Column(
@@ -160,7 +160,6 @@ class _MainPageState extends State<MainPage> {
),
ElevatedButton(
onPressed: () {
onError();
Navigator.of(context).push(CustomPageRoute(
builder: (context) => const HistoryPage(),
));
@@ -193,40 +192,48 @@ class _MainPageState extends State<MainPage> {
onEndOfPage: _onLoad,
child: Stack(
children: [
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: min(
(MediaQuery.sizeOf(context).width ~/ 200).toInt(), 8),
),
itemCount: filteredData.length,
itemBuilder: (context, index) {
final product = filteredData[index];
return ProductCard(
imagePath: Image(
image: Image.network(
'https://rus-sport.net/upload/iblock/311/topb85ez18pq0aavohpa5zipk2sbfxll.jpg')
.image,
width: 50,
),
name: product['name']!,
price: product['price']!,
onTap: () => Navigator.of(context).push(
CustomPageRoute(
builder: (context) => DetailPage(
name: product['name']!,
description: product['details']!,
price: product['price']!,
id: product['id']!,
image: Image(
image:
AssetImage('assets/${product['image']!}'),
width: 300),
items.isEmpty
? const Center(child: CircularProgressIndicator())
: filteredData.isEmpty
? const Center(child: Text('Ничего не найдено'))
: GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: min(
(MediaQuery.sizeOf(context).width ~/ 200)
.toInt(),
8),
),
itemCount: filteredData.length,
itemBuilder: (context, index) {
final product = filteredData[index];
return ProductCard(
imagePath: Image(
image: Image.network(product.images[0].url)
.image,
width: 50,
),
name: product.title,
price: product.price.toString(),
onTap: () => Navigator.of(context).push(
CustomPageRoute(
builder: (context) => DetailPage(
name: product.title,
description: product.description,
price: product.price.toString(),
id: product.id,
image: Image(
image: Image.network(
product.images[0].url)
.image,
width: 300,
),
),
),
),
);
},
),
),
),
);
},
),
],
),
),

View File

@@ -3,8 +3,10 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:gymlink_module_web/components/app_bar.dart';
import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/components/order_confirm_item_card.dart';
import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/pages/order_history.dart';
import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/tools/items.dart';
import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/routes.dart';
import 'package:provider/provider.dart';
@@ -56,24 +58,26 @@ class OrderConfirmationPage extends StatefulWidget {
}
class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
List<Map<String, dynamic>> cartItems = [];
int totalPrice = 0;
List<GymItem> cartItems = [];
double totalPrice = 0;
List<GymItem> gymCart = [];
@override
void initState() {
super.initState();
getCart().then((value) {
setState(() {
cartItems = value.map((element) {
final item = cart.firstWhere((e) => e['id'] == element['id']);
return {...item, 'count': element['count'] as int};
}).toList();
totalPrice = cartItems.fold(
0,
(sum, item) =>
sum + int.parse(item['price']) * item['count'] as int);
});
});
Future.microtask(() => getCart().then((value) async {
final items = await getItems(context);
setState(() {
gymCart = items;
cartItems = value.map((element) {
final item = gymCart.firstWhere((e) => e.id == element['id']);
item.localCount = element['count'] as int;
return item;
}).toList();
totalPrice = cartItems.fold(
0, (sum, item) => sum + item.price * item.localCount);
});
}));
}
Future<void> _goToPage() async {
@@ -101,13 +105,13 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
itemBuilder: (context, index) {
final item = cartItems[index];
return OrderConfirmItemCard(
name: item['name'],
name: item.title,
image: Image(
image: AssetImage('assets/${item['image']}'),
image: NetworkImage(item.images[0].url),
width: 50,
height: 50),
price: double.parse(item['price']),
count: item['count'],
price: item.price,
count: item.localCount,
);
},
),

View File

@@ -39,6 +39,11 @@ class GymLinkProvider with ChangeNotifier {
}
void setOnError(void Function() onError) {
_onError = onError;
_onError = () {
_token = '';
_isLoading = true;
onError();
notifyListeners();
};
}
}

33
lib/tools/items.dart Normal file
View File

@@ -0,0 +1,33 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/providers/main.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
Future<List<GymItem>> getItems(BuildContext context) async {
final token = context.read<GymLinkProvider>().token;
if (token != '') {
final Uri url =
Uri.http('gymlink.freemyip.com:8080', 'api/product/get-list');
try {
final response = await http.get(url, headers: {
'Authorization': 'Bearer $token',
});
if (response.statusCode == 200) {
final data =
jsonDecode(utf8.decode(response.bodyBytes)) as List<dynamic>;
final items = data.map((e) => GymItem.fromJson(e)).toList();
return items;
}
throw Error();
} catch (e) {
debugPrint('error: $e');
return await Future.delayed(
const Duration(seconds: 5), () => getItems(context));
}
}
context.read<GymLinkProvider>().onError();
return [];
}