358 lines
14 KiB
Dart
358 lines
14 KiB
Dart
import 'dart:convert';
|
||
import 'dart:math';
|
||
|
||
import 'package:carousel_slider/carousel_slider.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/heading.dart';
|
||
import 'package:gymlink_module_web/interfaces/items.dart';
|
||
import 'package:gymlink_module_web/pages/basket.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:http/http.dart' as http;
|
||
import 'package:provider/provider.dart';
|
||
|
||
class DetailPage extends StatefulWidget {
|
||
final String id;
|
||
const DetailPage({
|
||
super.key,
|
||
required this.id,
|
||
});
|
||
|
||
@override
|
||
State<DetailPage> createState() => _DetailPageState();
|
||
}
|
||
|
||
class _DetailPageState extends State<DetailPage> {
|
||
bool isInCart = false;
|
||
int quantity = 0;
|
||
GymItem? item;
|
||
String? categoryName;
|
||
final CarouselController _carouselController = CarouselController();
|
||
int _currentImage = 0;
|
||
|
||
@override
|
||
void initState() {
|
||
getCart().then((value) {
|
||
setState(() {
|
||
isInCart = value.any((element) => element['id'] == widget.id);
|
||
if (isInCart) {
|
||
quantity = value
|
||
.firstWhere((element) => element['id'] == widget.id)['count'];
|
||
}
|
||
});
|
||
});
|
||
_getItem();
|
||
super.initState();
|
||
}
|
||
|
||
Future<void> _getItem() async {
|
||
final Uri url =
|
||
Uri.http('gymlink.freemyip.com:8080', 'api/product/get/${widget.id}');
|
||
final response = await http.get(url, headers: {
|
||
'Authorization': 'Bearer ${context.read<GymLinkProvider>().token}',
|
||
});
|
||
if (response.statusCode == 200) {
|
||
final data =
|
||
GymItem.fromJson(jsonDecode(utf8.decode(response.bodyBytes)));
|
||
setState(() {
|
||
item = data;
|
||
});
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
for (var element in item!.images) {
|
||
precacheImage(NetworkImage(element.url), context);
|
||
}
|
||
});
|
||
if (mounted) {
|
||
getCategories(context).then((value) {
|
||
setState(() {
|
||
categoryName = value
|
||
.firstWhere(
|
||
(element) => element.id == (item!.categoryId),
|
||
orElse: () => GymCategory(id: item!.categoryId, name: ''),
|
||
)
|
||
.name;
|
||
});
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
Widget _buildRowOrCol(
|
||
{required List<Widget> children,
|
||
required BuildContext context,
|
||
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.spaceAround,
|
||
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center}) {
|
||
// if (false && MediaQuery.of(context).size.width > 600) {
|
||
// return Row(
|
||
// mainAxisAlignment: mainAxisAlignment,
|
||
// crossAxisAlignment: crossAxisAlignment,
|
||
// children: children);
|
||
// }
|
||
return Column(
|
||
mainAxisAlignment: mainAxisAlignment,
|
||
crossAxisAlignment: crossAxisAlignment,
|
||
children: children);
|
||
}
|
||
|
||
Widget _buildButton() {
|
||
if (!isInCart) {
|
||
return ElevatedButton(
|
||
onPressed: () async {
|
||
await addItemToCart(widget.id);
|
||
setState(() {
|
||
isInCart = true;
|
||
quantity = 1;
|
||
});
|
||
if (mounted) {
|
||
context.read<CartProvider>().updateCartLength();
|
||
}
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Theme.of(context).primaryColor,
|
||
shape: const RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.all(Radius.circular(50)),
|
||
),
|
||
foregroundColor: Colors.white,
|
||
padding: const EdgeInsetsDirectional.fromSTEB(34, 10, 34, 10)),
|
||
child: const Text('Добавить в корзину'),
|
||
);
|
||
} else {
|
||
return Column(
|
||
children: [
|
||
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 {
|
||
if (item!.count > quantity) {
|
||
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('Открыть корзину'),
|
||
),
|
||
)
|
||
],
|
||
);
|
||
}
|
||
}
|
||
|
||
double _getAspectRatio() {
|
||
double width = MediaQuery.sizeOf(context).width;
|
||
double height = MediaQuery.sizeOf(context).height;
|
||
return max(width, height) / min(width, height);
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: const GymLinkAppBar(),
|
||
body: item != null
|
||
? Column(mainAxisAlignment: MainAxisAlignment.start, children: [
|
||
GymLinkHeader(title: item!.title),
|
||
Expanded(
|
||
child: SingleChildScrollView(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(20),
|
||
child: SizedBox(
|
||
width: MediaQuery.sizeOf(context).width,
|
||
// height: MediaQuery.sizeOf(context).height,
|
||
child: _buildRowOrCol(
|
||
context: context,
|
||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
item!.images.length > 1
|
||
? Column(children: [
|
||
CarouselSlider.builder(
|
||
itemCount: item!.images.length,
|
||
itemBuilder: (context, index, realIdx) {
|
||
return Center(
|
||
child: Image.network(
|
||
item!.images[index].url,
|
||
width: min(
|
||
550,
|
||
MediaQuery.sizeOf(context)
|
||
.width)),
|
||
);
|
||
},
|
||
carouselController: _carouselController,
|
||
options: CarouselOptions(
|
||
enlargeCenterPage: true,
|
||
height: min(
|
||
MediaQuery.sizeOf(context).height -
|
||
100,
|
||
400),
|
||
enableInfiniteScroll: false,
|
||
onPageChanged: (index, reason) {
|
||
setState(() {
|
||
_currentImage = index;
|
||
});
|
||
}),
|
||
),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: item!.images
|
||
.asMap()
|
||
.entries
|
||
.map((entry) {
|
||
return GestureDetector(
|
||
onTap: () => _carouselController
|
||
.animateToPage(entry.key),
|
||
child: Container(
|
||
width: 12.0,
|
||
height: 12.0,
|
||
margin: const EdgeInsets.symmetric(
|
||
vertical: 8.0, horizontal: 4.0),
|
||
decoration: BoxDecoration(
|
||
shape: BoxShape.circle,
|
||
color: (Theme.of(context)
|
||
.brightness ==
|
||
Brightness.dark
|
||
? Colors.white
|
||
: Colors.black)
|
||
.withOpacity(
|
||
_currentImage == entry.key
|
||
? 0.9
|
||
: 0.4)),
|
||
),
|
||
);
|
||
}).toList(),
|
||
),
|
||
])
|
||
: Image.network(
|
||
item!.images[0].url,
|
||
height: 400,
|
||
),
|
||
Center(
|
||
child: Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||
child: Chip(
|
||
label: Text(categoryName != null
|
||
? (categoryName == ""
|
||
? "Без категории"
|
||
: categoryName!)
|
||
: ''),
|
||
backgroundColor: Colors.white,
|
||
),
|
||
),
|
||
),
|
||
Center(
|
||
child: MarkdownBody(
|
||
data: '### Отстаток: _${item!.count}_',
|
||
)),
|
||
item!.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: SingleChildScrollView(
|
||
child: Padding(
|
||
padding:
|
||
const EdgeInsetsDirectional.all(
|
||
15),
|
||
child: ConstrainedBox(
|
||
constraints: const BoxConstraints(
|
||
minHeight: 100,
|
||
),
|
||
child: Text(
|
||
item!.description,
|
||
style: Theme.of(context)
|
||
.textTheme
|
||
.bodyMedium,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
)
|
||
: const SizedBox.shrink(),
|
||
Align(
|
||
alignment: const AlignmentDirectional(0, -1),
|
||
child: Padding(
|
||
padding: const EdgeInsetsDirectional.fromSTEB(
|
||
0, 30, 0, 0),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Text(
|
||
'Стоимость ${item!.price}руб.',
|
||
style:
|
||
Theme.of(context).textTheme.bodyLarge,
|
||
),
|
||
_buildButton()
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
])
|
||
: const Center(
|
||
child: CircularProgressIndicator(),
|
||
),
|
||
);
|
||
}
|
||
}
|