Merge pull request 'Архив консультаций, мои финансы, лента' (#339) from mso7nueh/eatvio_app:main into main

Reviewed-on: eatvio/eatvio_app#339
This commit is contained in:
mso7nueh
2025-04-21 10:16:34 +00:00
12 changed files with 378 additions and 252 deletions

View File

@@ -51,7 +51,7 @@ List<ConsultationsEntity> generateTestData() {
final List<String> names = ["Иван Петров", "Анна Смирнова", "Дмитрий Соколов", "Елена Козлова", "Алексей Иванов"];
final List<String> plans = ["Похудение", "Набор массы", "Детокс", "Здоровое питание", "Вегетарианство"];
List<ConsultationsEntity> testConsultations = List.generate(20, (index) {
List<ConsultationsEntity> testConsultations = List.generate(6, (index) {
DateTime startDate = DateTime.now().subtract(Duration(days: random.nextInt(30)));
DateTime endDate = startDate.add(const Duration(days: 30));

View File

@@ -1,6 +1,8 @@
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/consultations/entities/consultations_entity.dart';
import 'package:eatvio_app/features/consultations/presentation/widgets/consultation_card_widget.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class ConsultationsScreen extends StatelessWidget {
const ConsultationsScreen({super.key});
@@ -18,15 +20,49 @@ class ConsultationsScreen extends StatelessWidget {
),
),
),
body: ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 12),
itemBuilder: (context, index) => ConsultationCardWidget(
consultationsEntity: testData[index],
body: SingleChildScrollView(
child: Column(
children: [
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.symmetric(vertical: 12),
itemBuilder: (context, index) => ConsultationCardWidget(
consultationsEntity: testData[index],
),
separatorBuilder: (context, index) => const SizedBox(
height: 12,
),
itemCount: testData.length,
),
const SizedBox(height: 20),
InkWell(
borderRadius: BorderRadius.circular(20),
onTap: () {
GoRouter.of(context).pushNamed('consultantFinanceScreen');
},
child: Ink(
width: MediaQuery.of(context).size.width - 32,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: appTheme.blueA400,
),
child: const Center(
child: Text(
'Архив консультаций',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
),
const SizedBox(height: 20),
],
),
separatorBuilder: (context, index) => const SizedBox(
height: 12,
),
itemCount: testData.length,
),
);
}

View File

@@ -2,13 +2,13 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:dismissible_page/dismissible_page.dart';
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/enums/complained_content.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/utils/date_time_utils.dart';
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/subscribe_button_widget.dart';
import 'package:flutter/material.dart';
@@ -49,11 +49,9 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
'blogPostScreen',
extra: state.feedBlogPostList[widget.index],
),
child: Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Material(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -179,14 +177,15 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
),
),
if (state.feedBlogPostList[widget.index].description.length > 200)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 12),
child: Text(
'Читать полностью...',
'Показать ещё',
style: TextStyle(
height: 1,
color: appTheme.blueA400,
decoration: TextDecoration.underline,
color: Color(0xFF8B8B8B),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),

View File

@@ -45,11 +45,9 @@ class _DietsWidgetState extends State<DietsWidget> {
'navigateToComments': false,
},
),
child: Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Material(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -49,11 +49,9 @@ class _PlanWidgetState extends State<PlanWidget> {
'navigateToComments': false,
},
),
child: Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Material(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -64,11 +64,9 @@ class _RecipesWidgetState extends State<RecipesWidget> {
'navigateToComments': false,
},
),
child: Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Material(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -188,14 +186,15 @@ class _RecipesWidgetState extends State<RecipesWidget> {
),
),
if (widget.recipe.description.length > 200)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 12),
child: Text(
'Читать полностью...',
'Показать ещё',
style: TextStyle(
height: 1,
color: appTheme.blueA400,
decoration: TextDecoration.underline,
color: Color(0xFF8B8B8B),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),

View File

@@ -1,12 +1,22 @@
import 'package:collection/collection.dart';
import 'package:eatvio_app/core/theme/custom_text_style.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/utils/date_time_utils.dart';
import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart';
import 'package:eatvio_app/features/my_finance/entities/consultant_finance_entity.dart';
import 'package:flutter/material.dart';
class ConsultantFinanceScreen extends StatelessWidget {
class ConsultantFinanceScreen extends StatefulWidget {
const ConsultantFinanceScreen({super.key});
@override
State<ConsultantFinanceScreen> createState() => _ConsultantFinanceScreenState();
}
class _ConsultantFinanceScreenState extends State<ConsultantFinanceScreen> {
final List<String> periods = ['За всё время', 'За месяц', 'За неделю'];
final List<String> statuses = ['Все консультации', 'Отменён', 'Завершён', 'В процессе'];
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -117,13 +127,35 @@ class ConsultantFinanceScreen extends StatelessWidget {
child: Column(
children: [
CustomDropDownButton(
items: const [],
items: periods
.mapIndexed(
(index, value) => DropdownMenuItem(
value: periods[index],
child: Text(
periods[index],
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
),
),
)
.toList(),
onChanged: (value) {},
value: periods.first,
),
const SizedBox(height: 12),
CustomDropDownButton(
items: const [],
items: statuses
.mapIndexed(
(index, value) => DropdownMenuItem(
value: statuses[index],
child: Text(
statuses[index],
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
),
),
)
.toList(),
onChanged: (value) {},
value: statuses.first,
),
const SizedBox(height: 12),
ListView.separated(
@@ -189,6 +221,14 @@ class ConsultantFinanceScreen extends StatelessWidget {
),
),
const SizedBox(height: 8),
Container(
height: 1,
width: double.infinity,
decoration: const BoxDecoration(
color: Color(0xFFDEDEDF),
),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [

View File

@@ -1,3 +1,5 @@
import 'package:collection/collection.dart';
import 'package:eatvio_app/core/theme/custom_text_style.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/utils/date_time_utils.dart';
import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart';
@@ -6,16 +8,23 @@ import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class UserFinanceScreen extends StatelessWidget {
class UserFinanceScreen extends StatefulWidget {
const UserFinanceScreen({super.key});
@override
State<UserFinanceScreen> createState() => _UserFinanceScreenState();
}
class _UserFinanceScreenState extends State<UserFinanceScreen> {
final List<String> periods = ['За всё время', 'За месяц', 'За неделю'];
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF0F2F5),
appBar: AppBar(
shape: const RoundedRectangleBorder(borderRadius: BorderRadiusDirectional.vertical(bottom: Radius.circular(12))),
title: const Text('История операций'),
title: const Text('Финансы'),
centerTitle: true,
),
body: SingleChildScrollView(
@@ -49,73 +58,113 @@ class UserFinanceScreen extends StatelessWidget {
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: [
CustomDropDownButton(items: const [], onChanged: (value) {}),
CustomDropDownButton(
items: periods
.mapIndexed(
(index, value) => DropdownMenuItem(
value: periods[index],
child: Text(
periods[index],
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
),
),
)
.toList(),
onChanged: (value) {},
value: periods.first,
),
const SizedBox(height: 12),
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder:
(context, index) => Material(
color: const Color(0xFFF6F6F6),
borderRadius: BorderRadius.circular(20),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
itemBuilder: (context, index) => Material(
color: const Color(0xFFF6F6F6),
borderRadius: BorderRadius.circular(20),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
testFinanceEntity.consultationsList[index].id,
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontWeight: FontWeight.w500),
),
Text(
testFinanceEntity.consultationsList[index].date.format('dd.MM.yyy', 'RU'),
style: const TextStyle(color: Color(0xFF6D6F71), height: 1, fontWeight: FontWeight.w500),
),
],
Tooltip(
message: testFinanceEntity.consultationsList[index].id,
triggerMode: TooltipTriggerMode.tap,
textStyle: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w500,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha((255 * 0.2).toInt()),
blurRadius: 32,
)
],
),
child: Text(
testFinanceEntity.consultationsList[index].id,
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontWeight: FontWeight.w500),
),
),
const SizedBox(height: 8),
Text(
testFinanceEntity.consultationsList[index].title,
style: TextStyle(color: appTheme.blueA400, height: 1, fontSize: 18, fontWeight: FontWeight.w600),
),
const SizedBox(height: 8),
Text(
'Покупатель: ${testFinanceEntity.consultationsList[index].clientName}',
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 14, fontWeight: FontWeight.w500),
),
const SizedBox(height: 8),
Text(
'${testFinanceEntity.consultationsList[index].planDuration} дней',
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 14, fontWeight: FontWeight.w500),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${testFinanceEntity.consultationsList[index].price} ₽',
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 18, fontWeight: FontWeight.w600),
),
Material(
color: const Color(0xFF0BB450).withAlpha(11),
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: Text(
testFinanceEntity.consultationsList[index].status.name,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xFF0BB450), height: 1),
),
),
),
],
testFinanceEntity.consultationsList[index].date.format('dd.MM.yyy', 'RU'),
style: const TextStyle(color: Color(0xFF6D6F71), height: 1, fontWeight: FontWeight.w500),
),
],
),
),
const SizedBox(height: 8),
Text(
testFinanceEntity.consultationsList[index].title,
style: TextStyle(color: appTheme.blueA400, height: 1, fontSize: 18, fontWeight: FontWeight.w600),
),
const SizedBox(height: 8),
Text(
'Покупатель: ${testFinanceEntity.consultationsList[index].clientName}',
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 14, fontWeight: FontWeight.w500),
),
const SizedBox(height: 8),
Text(
'${testFinanceEntity.consultationsList[index].planDuration} дней',
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 14, fontWeight: FontWeight.w500),
),
const SizedBox(height: 8),
Container(
height: 1,
width: double.infinity,
decoration: const BoxDecoration(
color: Color(0xFFDEDEDF),
),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${testFinanceEntity.consultationsList[index].price} ₽',
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 18, fontWeight: FontWeight.w600),
),
Material(
color: const Color(0xFF0BB450).withAlpha(11),
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: Text(
testFinanceEntity.consultationsList[index].status.name,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xFF0BB450), height: 1),
),
),
),
],
),
],
),
),
),
separatorBuilder: (context, index) => const SizedBox(height: 12),
itemCount: testFinanceEntity.consultationsList.length,
),

View File

@@ -194,87 +194,89 @@ class _CircumferenceChartWidgetState extends State<CircumferenceChartWidget> {
useRootNavigator: true,
context: context,
builder: (context) {
return Column(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: chestController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
chest = value;
},
children: [
for (int i = 20; i < 200; i++) Text('$i'),
],
return SafeArea(
child: Column(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: chestController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
chest = value;
},
children: [
for (int i = 20; i < 200; i++) Text('$i'),
],
),
),
),
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: waistController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
waist = value;
},
children: [
for (int i = 20; i < 200; i++) Text('$i'),
],
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: waistController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
waist = value;
},
children: [
for (int i = 20; i < 200; i++) Text('$i'),
],
),
),
),
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: hipController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
hip = value;
},
children: [
for (int i = 20; i < 200; i++) Text('$i'),
],
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: hipController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
hip = value;
},
children: [
for (int i = 20; i < 200; i++) Text('$i'),
],
),
),
),
],
),
),
InkWell(
onTap: () {
widget.profileCubit?.addCircumference(
chestCircumference: chest + 20,
waistCircumference: waist + 20,
hipCircumference: hip + 20,
);
Navigator.of(context).pop();
},
borderRadius: BorderRadius.circular(16),
child: Ink(
width: MediaQuery.of(context).size.width - 32,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: appTheme.blueA400,
borderRadius: BorderRadius.circular(16),
],
),
child: const Center(
child: Text(
'Сохранить',
style: TextStyle(
color: Colors.white,
),
InkWell(
onTap: () {
widget.profileCubit?.addCircumference(
chestCircumference: chest + 20,
waistCircumference: waist + 20,
hipCircumference: hip + 20,
);
Navigator.of(context).pop();
},
borderRadius: BorderRadius.circular(16),
child: Ink(
width: MediaQuery.of(context).size.width - 32,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: appTheme.blueA400,
borderRadius: BorderRadius.circular(16),
),
child: const Center(
child: Text(
'Сохранить',
style: TextStyle(
color: Colors.white,
),
),
),
),
),
),
],
],
),
);
},
);

View File

@@ -128,14 +128,15 @@ class _ProfileBlogPostWidgetState extends State<ProfileBlogPostWidget> {
),
),
if (state.blogPosts[widget.index].description.length > 200)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 12),
child: Text(
'Читать полностью...',
'Показать ещё',
style: TextStyle(
height: 1,
color: appTheme.blueA400,
decoration: TextDecoration.underline,
color: Color(0xFF8B8B8B),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),

View File

@@ -135,68 +135,70 @@ class _WeightChartWidgetState extends State<WeightChartWidget> {
useRootNavigator: true,
context: context,
builder: (context) {
return Column(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: weightKiloController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
weightKilo = value + 20;
},
children: [
for (int i = 20; i < 300; i++) Text('$i'),
],
return SafeArea(
child: Column(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: weightKiloController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
weightKilo = value + 20;
},
children: [
for (int i = 20; i < 300; i++) Text('$i'),
],
),
),
),
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: weightGramsController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
weightGrams = value;
},
children: [
for (int i = 0; i < 10; i++) Text('$i'),
],
Expanded(
child: CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
scrollController: weightGramsController,
itemExtent: 24,
onSelectedItemChanged: (int value) {
weightGrams = value;
},
children: [
for (int i = 0; i < 10; i++) Text('$i'),
],
),
),
),
],
),
),
InkWell(
onTap: () {
widget.profileCubit?.addWeight(weight: double.parse('$weightKilo.$weightGrams'));
Navigator.of(context).pop();
},
borderRadius: BorderRadius.circular(16),
child: Ink(
width: MediaQuery.of(context).size.width - 32,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: appTheme.blueA400,
borderRadius: BorderRadius.circular(16),
],
),
child: const Center(
child: Text(
'Сохранить',
style: TextStyle(
color: Colors.white,
),
InkWell(
onTap: () {
widget.profileCubit?.addWeight(weight: double.parse('$weightKilo.$weightGrams'));
Navigator.of(context).pop();
},
borderRadius: BorderRadius.circular(16),
child: Ink(
width: MediaQuery.of(context).size.width - 32,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: appTheme.blueA400,
borderRadius: BorderRadius.circular(16),
),
child: const Center(
child: Text(
'Сохранить',
style: TextStyle(
color: Colors.white,
),
),
),
),
),
),
],
],
),
);
},
);

View File

@@ -46,24 +46,26 @@ class _SettingsScreenState extends State<SettingsScreen> {
appBar: AppBar(
title: const Text('Настройки'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(vertical: 16),
physics: const BouncingScrollPhysics(),
child: Column(
children: [
_additionalInfo(state),
const SizedBox(height: 12),
_notifications(state),
const SizedBox(height: 12),
_aboutEatvio(state),
const SizedBox(height: 12),
if (!state.profile.roles.contains('consultant'))
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: _becomeConsultantButton(state),
),
_deleteAccountButton(state),
],
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(vertical: 16),
physics: const BouncingScrollPhysics(),
child: Column(
children: [
_additionalInfo(state),
const SizedBox(height: 12),
_notifications(state),
const SizedBox(height: 12),
_aboutEatvio(state),
const SizedBox(height: 12),
if (!state.profile.roles.contains('consultant'))
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: _becomeConsultantButton(state),
),
_deleteAccountButton(state),
],
),
),
),
);