Compare commits

..

2 Commits

Author SHA1 Message Date
15105a7f33 Add: search by category 2024-06-04 16:58:53 +03:00
1e5b235a6c Enhancement: back button to main menu reload 2024-06-04 15:57:17 +03:00
6 changed files with 183 additions and 39 deletions

View File

@@ -1,8 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gymlink_module_web/pages/main.dart';
import 'package:gymlink_module_web/tools/routes.dart';
class GymLinkHeader extends StatelessWidget { class GymLinkHeader extends StatelessWidget {
final String title; final String title;
const GymLinkHeader({super.key, required this.title}); final bool toMain;
const GymLinkHeader({super.key, required this.title, this.toMain = false});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -13,7 +16,13 @@ class GymLinkHeader extends StatelessWidget {
Row( Row(
children: [ children: [
IconButton( IconButton(
onPressed: () => Navigator.pop(context), onPressed: () => toMain
? Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
builder: (context) => const MainPage()),
(route) => route.isFirst)
: Navigator.pop(context),
icon: const Icon(Icons.arrow_back)), icon: const Icon(Icons.arrow_back)),
Text(title, style: Theme.of(context).textTheme.titleLarge), Text(title, style: Theme.of(context).textTheme.titleLarge),
], ],

View File

@@ -3,6 +3,7 @@ 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/basket_item_card.dart';
import 'package:gymlink_module_web/components/heading.dart'; import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/interfaces/items.dart'; import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/pages/main.dart';
import 'package:gymlink_module_web/pages/order_confirmation.dart'; import 'package:gymlink_module_web/pages/order_confirmation.dart';
import 'package:gymlink_module_web/providers/cart.dart'; import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/tools/items.dart'; import 'package:gymlink_module_web/tools/items.dart';
@@ -244,7 +245,11 @@ class _BasketPageState extends State<BasketPage> {
style: Theme.of(context).textTheme.bodyLarge), style: Theme.of(context).textTheme.bodyLarge),
const SizedBox(height: 10), const SizedBox(height: 10),
ElevatedButton( ElevatedButton(
onPressed: () => Navigator.pop(context, true), onPressed: () => Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
builder: (_) => const MainPage()),
(route) => route.isFirst),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(

View File

@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:carousel_slider/carousel_slider.dart'; import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:gymlink_module_web/components/app_bar.dart'; import 'package:gymlink_module_web/components/app_bar.dart';
import 'package:gymlink_module_web/components/heading.dart'; import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/interfaces/items.dart'; import 'package:gymlink_module_web/interfaces/items.dart';
@@ -30,7 +31,7 @@ class _DetailPageState extends State<DetailPage> {
bool isInCart = false; bool isInCart = false;
int quantity = 0; int quantity = 0;
GymItem? item; GymItem? item;
String categoryName = ''; String? categoryName;
final CarouselController _carouselController = CarouselController(); final CarouselController _carouselController = CarouselController();
int _currentImage = 0; int _currentImage = 0;
@@ -68,12 +69,14 @@ class _DetailPageState extends State<DetailPage> {
}); });
if (mounted) { if (mounted) {
getCategories(context).then((value) { getCategories(context).then((value) {
categoryName = value setState(() {
.firstWhere( categoryName = value
(element) => element.id == (item!.categoryId), .firstWhere(
orElse: () => GymCategory(id: item!.categoryId, name: ''), (element) => element.id == (item!.categoryId),
) orElse: () => GymCategory(id: item!.categoryId, name: ''),
.name; )
.name;
});
}); });
} }
} }
@@ -147,10 +150,12 @@ class _DetailPageState extends State<DetailPage> {
IconButton( IconButton(
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
onPressed: () async { onPressed: () async {
await addItemToCart(widget.id); if (item!.count > quantity) {
setState(() { await addItemToCart(widget.id);
quantity++; setState(() {
}); quantity++;
});
}
}, },
), ),
], ],
@@ -260,15 +265,21 @@ class _DetailPageState extends State<DetailPage> {
}).toList(), }).toList(),
), ),
]) ])
: Image.network(item!.images[0].url, : Image.network(
width: min( item!.images[0].url,
550, MediaQuery.sizeOf(context).width)), height: 400,
),
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.symmetric(vertical: 10),
child: Center( child: Center(
child: Text( child: Text(categoryName != null
'Категория: ${categoryName == "" ? "Без категории" : categoryName}'), ? 'Категория: ${categoryName == "" ? "Без категории" : categoryName}'
: ''),
)), )),
Center(
child: MarkdownBody(
data: '### Отстаток: _${item!.count}_',
)),
item!.description != '' item!.description != ''
? Padding( ? Padding(
padding: const EdgeInsetsDirectional.all(30), padding: const EdgeInsetsDirectional.all(30),

View File

@@ -8,6 +8,7 @@ import 'package:gymlink_module_web/pages/basket.dart';
import 'package:gymlink_module_web/pages/detail.dart'; import 'package:gymlink_module_web/pages/detail.dart';
import 'package:gymlink_module_web/pages/order_history.dart'; import 'package:gymlink_module_web/pages/order_history.dart';
import 'package:gymlink_module_web/providers/cart.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/items.dart';
import 'package:gymlink_module_web/tools/prefs.dart'; import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/relative.dart'; import 'package:gymlink_module_web/tools/relative.dart';
@@ -69,7 +70,9 @@ class _MainPageState extends State<MainPage> {
int cartLength = 0; int cartLength = 0;
int itemViewCount = 0; int itemViewCount = 0;
bool isLoading = false; bool isLoading = false;
bool isSearching = false;
List<GymCategory> categories = []; List<GymCategory> categories = [];
GymCategory? selectedCategory;
@override @override
void initState() { void initState() {
@@ -79,17 +82,9 @@ class _MainPageState extends State<MainPage> {
cartLength = value.length; cartLength = value.length;
}); });
}); });
getItems(context).then((value) => setState(() {
filteredData = value;
itemViewCount = min(5, value.length);
WidgetsBinding.instance.addPostFrameCallback((_) {
for (var element in filteredData.sublist(0, itemViewCount)) {
precacheImage(NetworkImage(element.images[0].url), context);
}
});
}));
getCategories(context).then((value) => setState(() { getCategories(context).then((value) => setState(() {
categories = value; categories = value;
_onSearch();
})); }));
} }
@@ -106,18 +101,30 @@ class _MainPageState extends State<MainPage> {
} }
} }
void _onSearch() async { void _searchItems({String searchText = '', String categoryId = ''}) async {
final data = await getItems(context, searchText: searchText); setState(() {
isSearching = true;
});
final data =
await getItems(context, searchText: searchText, categoryId: categoryId);
setState(() { setState(() {
filteredData = data; filteredData = data;
itemViewCount = itemViewCount = min(filteredData.length, 5);
min(filteredData.length, searchText == '' ? 5 : itemViewCount); debugPrint(itemViewCount.toString());
}); });
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
for (var element in filteredData.sublist(0, itemViewCount)) { for (var element in filteredData.sublist(0, itemViewCount)) {
precacheImage(NetworkImage(element.images[0].url), context); precacheImage(NetworkImage(element.images[0].url), context);
} }
}); });
setState(() {
isSearching = false;
});
}
void _onSearch() async {
final categoryId = selectedCategory == null ? '' : selectedCategory!.id;
_searchItems(searchText: searchText, categoryId: categoryId);
} }
@override @override
@@ -136,7 +143,7 @@ class _MainPageState extends State<MainPage> {
Expanded( Expanded(
child: TextField( child: TextField(
onChanged: (value) => setState(() { onChanged: (value) => setState(() {
searchText = value; searchText = value.trim().toLowerCase();
if (searchText == '') { if (searchText == '') {
_onSearch(); _onSearch();
} }
@@ -203,6 +210,43 @@ class _MainPageState extends State<MainPage> {
], ],
), ),
), ),
SizedBox(
height: 60,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: categories.length,
itemBuilder: (context, index) {
final category = categories[index];
return GestureDetector(
onTap: () {
setState(() {
selectedCategory =
selectedCategory == category ? null : category;
});
_onSearch();
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
child: Chip(
label: Text(category.name),
//FIXME: проблема с цветом
backgroundColor: selectedCategory == category
? context
.read<GymLinkProvider>()
.theme
.primaryColorLight
: Colors.white,
labelStyle: TextStyle(
color: selectedCategory == category
? Colors.white
: Colors.black),
),
),
);
}),
),
Expanded( Expanded(
child: LazyLoadScrollView( child: LazyLoadScrollView(
onEndOfPage: _onLoad, onEndOfPage: _onLoad,
@@ -210,9 +254,9 @@ class _MainPageState extends State<MainPage> {
child: Scrollbar( child: Scrollbar(
child: ListView( child: ListView(
children: [ children: [
filteredData.isEmpty && searchText != '' filteredData.isEmpty && searchText != '' && !isSearching
? const Center(child: Text('Ничего не найдено')) ? const Center(child: Text('Ничего не найдено'))
: filteredData.isEmpty : isSearching
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: GridView.builder( : GridView.builder(
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
@@ -247,7 +291,7 @@ class _MainPageState extends State<MainPage> {
); );
}, },
), ),
itemViewCount > 0 itemViewCount > 0 && !isSearching
? Padding( ? Padding(
padding: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.symmetric(vertical: 10),
child: Center( child: Center(

View File

@@ -91,7 +91,10 @@ class _HistoryPageState extends State<HistoryPage> {
body: Column( body: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
const GymLinkHeader(title: 'История заказов'), const GymLinkHeader(
title: 'История заказов',
toMain: true,
),
Expanded( Expanded(
child: Row( child: Row(
children: [ children: [

View File

@@ -25,6 +25,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
carousel_slider:
dependency: "direct main"
description:
name: carousel_slider
sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42"
url: "https://pub.dev"
source: hosted
version: "4.2.1"
characters: characters:
dependency: transitive dependency: transitive
description: description:
@@ -69,10 +77,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: cupertino_icons name: cupertino_icons
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.6" version: "1.0.8"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@@ -118,6 +126,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.7.1"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
url: "https://pub.dev"
source: hosted
version: "2.0.10+1"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@@ -152,6 +168,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
lazy_load_scrollview:
dependency: "direct main"
description:
name: lazy_load_scrollview
sha256: "230c827d6f7ec5e461f0674ef332daae2f78190bf1e4cd84977e51de04b231e3"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
@@ -232,6 +256,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.0" version: "1.9.0"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
url: "https://pub.dev"
source: hosted
version: "1.0.1"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@@ -256,6 +288,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.2.1"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "6.0.2"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@@ -477,6 +517,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -517,6 +581,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
sdks: sdks:
dart: ">=3.3.3 <4.0.0" dart: ">=3.3.3 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.19.0"