Files
eatvio_app/lib/presentation/glossary/glossary_screen/glossary_screen.dart
2024-07-15 17:06:13 +03:00

333 lines
10 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:cached_network_image/cached_network_image.dart';
import 'package:eatvio_app/core/app_export.dart';
import 'package:eatvio_app/presentation/glossary/glossary_screen/widgets/glossary_scroll_item.dart';
import 'package:eatvio_app/presentation/glossary/glossary_screen/widgets/glossary_search_widget.dart';
import 'package:eatvio_app/widgets/custom_drop_down.dart';
import 'package:eatvio_app/widgets/custom_outlined_button.dart';
import 'package:flutter/material.dart';
import 'bloc/glossary_screen_bloc.dart';
import 'models/glossary_screen_model.dart';
class GlossaryScreen extends StatelessWidget {
const GlossaryScreen({Key? key}) : super(key: key);
static Widget builder(BuildContext context) {
return BlocProvider<GlossaryBloc>(
create: (context) => GlossaryBloc(GlossaryState(glossaryModelObj: GlossaryModel()))..add(GlossaryInitialEvent()),
child: GlossaryScreen(),
);
}
Widget build(BuildContext context) {
return BlocBuilder<GlossaryBloc, GlossaryState>(
builder: (context, state) {
if (state is GlossaryInitialState) {
// Это начальное состояние, данные ещё не загружены.
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
} else if (state is GlossaryLoadedState) {
// Данные загружены, можно строить экран.
return _buildGlossary(context, state);
} else if (state is GlossaryErrorState) {
// Произошла ошибка при загрузке данных.
return Center(child: Text(state.errorMessage));
} else {
// Другие состояния, если они есть.
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
},
);
}
_buildGlossary(BuildContext context, GlossaryLoadedState state) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 0,
automaticallyImplyLeading: false,
),
backgroundColor: Colors.grey[200],
resizeToAvoidBottomInset: true,
body: SingleChildScrollView(
child: Container(
width: double.maxFinite,
decoration: BoxDecoration(color: Colors.grey[200]),
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(height: 20),
_buildSearch(context),
SizedBox(height: 20),
_buildMenu(context),
SizedBox(height: 20),
_buildProducts(context, state),
],
),
),
),
),
);
}
_buildSearch(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(12)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: [
CustomSearchView(
hintText: "Поиск записей",
),
SizedBox(height: 10),
CustomOutlinedButton(
text: "Найти продукт",
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
),
],
),
),
);
}
_buildMenu(BuildContext context) {
return Container(
padding: EdgeInsets.all(12),
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(12)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
"Поиск по алфавиту",
style: CustomTextStyles.titleMediumSemiBold,
),
),
SizedBox(
height: 8,
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(33, _fillAlphabet),
),
),
],
),
);
}
_buildProducts(BuildContext context, GlossaryLoadedState state) {
return Container(
padding: EdgeInsets.all(12),
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(12)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
"Группа продуктов",
style: CustomTextStyles.titleMediumSemiBold,
),
),
SizedBox(
height: 8,
),
CustomDropDown(
items: state.productGroups,
value: state.productGroups?[0],
fillColor: Colors.grey[200]!,
hintText: 'Выберите категорию',
borderDecoration: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(8)),
borderSide: BorderSide(color: Colors.grey[200]!, width: 1),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 9,
),
onChanged: _changeProductGroup(context, state),
width: MediaQuery.of(context).size.width, // Set a percentage value as per your layout
),
SizedBox(
height: 8,
),
Align(alignment: Alignment.centerLeft, child: Text("*КБЖУ указано за 100гр")),
SizedBox(
height: 8,
),
_buildProductList(context, state),
],
),
);
}
_buildProductList(BuildContext context, GlossaryLoadedState state) {
List<Widget> postWidgets = [];
if (state.productList != null) {
for (var post in state.productList!) {
postWidgets.add(_buildProductEntry(post, context));
}
}
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: postWidgets,
);
}
_buildProductEntry(product, BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(12)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 3,
offset: Offset(0, 3),
),
],
),
child: Column(
children: [
ListTile(
trailing: CachedNetworkImage(
imageUrl: baseUrl + '/storage/' + (product['image'] ?? ''),
imageBuilder: (context, imageProvider) => CircleAvatar(
backgroundImage: imageProvider,
radius: 25,
),
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => CircleAvatar(
child: Icon(Icons.person),
backgroundColor: Colors.white,
radius: 25,
),
),
title: Text(
product?['name'] ?? '',
style: CustomTextStyles.titleMediumSemiBold,
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Row(
children: [
Column(
children: [
Text("Ккал - ${product['energy_on_100gr'].toString()}"),
SizedBox(height: 8),
Text("Белки - ${product['proteins_on_100gr'].toString()}"),
],
),
Spacer(),
Padding(
padding: const EdgeInsets.only(right: 24.0),
child: Column(
children: [
Text("Жиры - ${product['fats_on_100gr'].toString()}"),
SizedBox(height: 8),
Text("Углеводы - ${product['carbohydrates_on_100gr'].toString()}"),
],
),
),
],
),
],
),
),
],
),
);
}
Widget _fillAlphabet(int index) {
return ScrollItem(title: String.fromCharCode(1040 + index));
}
List<SelectionPopupModel> fillProductGroups(List<dynamic> productGroups) {
List<SelectionPopupModel> result = [];
for (int i = 0; i < productGroups.length; i++) {
result.add(
SelectionPopupModel(
id: productGroups[i]['id'],
title: productGroups[i]['name'],
isSelected: true,
),
);
}
return result;
}
///Handling page based on route
Widget getCurrentPage(
BuildContext context,
String currentRoute,
) {
switch (currentRoute) {
case '/glossary':
return GlossaryScreen.builder(context);
default:
return GlossaryScreen();
}
}
_changeProductGroup(BuildContext context, GlossaryLoadedState state) {
return (value) {
context.read<GlossaryBloc>().add(ChangeProductGroup(value.id));
};
}
}