Files
GymLink_Flutter/lib/pages/main.dart

342 lines
15 KiB
Dart

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/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';
import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
const List<Map<String, String>> testData = [
{
"name": "Протеин 2",
"image": "product.png",
"price": "120",
"details": "Test details",
"id": "34fa3126-bfaf-5dec-8f4a-b246c097ef73"
},
{
"name": "Протеин",
"image": "product.png",
"price": "150",
"details":
"that name factory say string eaten order harbor easier said tone now floor nest it comfortable such difficulty labor bridge fact market women badly chamber heading forest allow shirt possibly story strip elephant extra even joy lungs than low discussion barn rapidly evidence is stream crew let more sold bag river triangle court slept knowledge flat package research balloon station underline careful market better make curious secret boy poor captured creature harder public tool ring subject charge planet tone scientist piece page stone support bush way feathers summer describe back should said complex song giant his that name factory say string eaten order harbor easier said tone now floor nest it comfortable such difficulty labor bridge fact market women badly chamber heading forest allow shirt possibly story strip elephant extra even joy lungs than low discussion barn rapidly evidence is stream crew let more sold bag river triangle court slept knowledge flat package research balloon station underline careful market better make curious secret boy poor captured creature harder public tool ring subject charge planet tone scientist piece page stone support bush way feathers summer describe back should said complex song giant his that name factory say string eaten order harbor easier said tone now floor nest it comfortable such difficulty labor bridge fact market women badly chamber heading forest allow shirt possibly story strip elephant extra even joy lungs than low discussion barn rapidly evidence is stream crew let more sold bag river triangle court slept knowledge flat package research balloon station underline careful market better make curious secret boy poor captured creature harder public tool ring subject charge planet tone scientist piece page stone support bush way feathers summer describe back should said complex song giant his that name factory say string eaten order harbor easier said tone now floor nest it comfortable such difficulty labor bridge fact market women badly chamber heading forest allow shirt possibly story strip elephant extra even joy lungs than low discussion barn rapidly evidence is stream crew let more sold bag river triangle court slept knowledge flat package research balloon station underline careful market better make curious secret boy poor captured creature harder public tool ring subject charge planet tone scientist piece page stone support bush way feathers summer describe back should said complex song giant his",
"id": "34a26e82-7656-5e98-a44a-c2d01d0b1ad1123"
},
{
"name": "Протеин",
"image": "product.png",
"price": "250",
"details": "Test details",
"id": "4fb204b7-3f9e-52a2-bed1-415c00a31a37123"
},
{
"name": "Протеин",
"image": "product.png",
"price": "300",
"details": "Test details",
"id": "09b2f5bb-683e-5c39-ae89-b8e152fa8bcf123"
},
{
"name": "Протеин",
"image": "product.png",
"price": "100",
"details": "Test details",
"id": "cd1b6817-db94-5394-be1d-af88af79749f123"
}
];
class MainPage extends StatefulWidget {
const MainPage({
super.key,
});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
String searchText = '';
List<GymItem> filteredData = [];
List<GymItem> items = [];
int cartLength = 0;
int itemViewCount = 0;
bool isLoading = false;
@override
void initState() {
super.initState();
getCart().then((value) {
setState(() {
cartLength = value.length;
});
});
getItems(context).then((value) => setState(() {
filteredData = value;
items = value;
itemViewCount = min(5, value.length);
WidgetsBinding.instance.addPostFrameCallback((_) {
for (var element in filteredData.sublist(0, itemViewCount)) {
precacheImage(NetworkImage(element.images[0].url), context);
}
});
}));
}
Future<void> _goToPage() async {
final Uri url = Uri.parse('https://google.com');
if (!await launchUrl(url, webOnlyWindowName: '_blank')) {
throw 'Could not launch $url';
}
}
void _onLoad() async {
if (itemViewCount < filteredData.length) {
setState(() {
isLoading = true;
});
await Future.delayed(const Duration(seconds: 1));
setState(() {
itemViewCount = min(filteredData.length, itemViewCount + 5);
isLoading = false;
});
}
}
void _onSearch() {
setState(() {
filteredData = items
.where((element) => (element.title).contains(searchText))
.toList();
itemViewCount = min(filteredData.length, itemViewCount);
});
WidgetsBinding.instance.addPostFrameCallback((_) {
for (var element in filteredData.sublist(0, itemViewCount)) {
precacheImage(NetworkImage(element.images[0].url), context);
}
});
}
@override
Widget build(BuildContext context) {
final cartL = context.watch<CartProvider>().cartLength;
return Scaffold(
appBar: const GymLinkAppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
child: TextField(
onChanged: (value) => setState(() {
searchText = value;
if (searchText == '') {
_onSearch();
}
}),
decoration: InputDecoration(
hintText: 'Поиск',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
suffixIcon: Padding(
padding: const EdgeInsets.only(right: 8),
child: ElevatedButton(
onPressed: _onSearch,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 0,
),
minimumSize:
const Size(50, kMinInteractiveDimension),
backgroundColor: Theme.of(context).primaryColor,
shape: const CircleBorder(),
),
child: const Icon(
Icons.search,
color: Colors.white,
size: 24,
),
),
),
),
),
),
getSpacer(context: context, flex: 2),
const SizedBox(
width: 8,
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(CustomPageRoute(
builder: (context) => const HistoryPage(),
));
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
minimumSize: const Size(50, kMinInteractiveDimension),
backgroundColor: Theme.of(context).primaryColor,
shape: const CircleBorder(
side: BorderSide(
color: Colors.black,
width: 1,
),
),
),
child: const Icon(
Icons.history,
color: Colors.white,
size: 24,
),
),
const SizedBox(
width: 10,
)
],
),
),
Expanded(
child: LazyLoadScrollView(
onEndOfPage: _onLoad,
isLoading: isLoading,
child: Scrollbar(
child: ListView(
children: [
items.isEmpty
? const Center(child: CircularProgressIndicator())
: filteredData.isEmpty
? const Center(child: Text('Ничего не найдено'))
: GridView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: min(
(MediaQuery.sizeOf(context).width ~/
200)
.toInt(),
8),
childAspectRatio: 1.0),
itemCount: itemViewCount,
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(
id: product.id,
),
),
),
);
},
),
itemViewCount > 0
? Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Center(
child: itemViewCount < filteredData.length
? !isLoading
? ElevatedButton(
onPressed: _onLoad,
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(50)),
),
foregroundColor: Colors.white,
),
child: const Text('Загрузить ещё'),
)
: const CircularProgressIndicator()
: const Text(
'Конец списка',
style: TextStyle(
fontSize: 10,
color: Color(0x88000000)),
),
),
)
: const SizedBox.shrink(),
],
),
),
),
),
],
),
floatingActionButton: SizedBox(
height: 80,
width: 80,
child: FittedBox(
child: Stack(
children: [
FloatingActionButton(
onPressed: () => Navigator.of(context).push(CustomPageRoute(
builder: (context) => const BasketPage(),
)),
highlightElevation: 0,
hoverColor: Colors.transparent,
focusColor: Colors.transparent,
hoverElevation: 0,
focusElevation: 0,
splashColor: Colors.transparent,
backgroundColor: Colors.transparent,
elevation: 0,
child: CircleAvatar(
radius: 25,
backgroundColor: Theme.of(context).primaryColor,
foregroundColor: Colors.white,
child: const Icon(Icons.shopping_cart_outlined)),
),
cartL > 0
? Positioned(
right: -3,
bottom: 0,
child: Card(
color: Colors.red,
child: SizedBox(
width: 20,
child: Center(
child: Text(
cartL.toString(),
style: const TextStyle(color: Colors.white),
),
),
),
),
)
: const SizedBox.shrink(),
],
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
);
}
}