Files
eatvio_app/lib/features/my_diets/presentation/my_diets_screen.dart
2026-02-11 16:23:48 +03:00

181 lines
8.1 KiB
Dart

import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/locator_service.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/widgets/add_item_button.dart';
import 'package:eatvio_app/core/widgets/custom_search_bar.dart';
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/diet_filter_bottom_sheet.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart';
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.dart';
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart';
import 'package:eatvio_app/features/my_diets/presentation/widgets/my_diet_widget.dart';
import 'package:eatvio_app/features/my_diets/presentation/widgets/my_diets_tab.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
class MyDietsScreen extends StatelessWidget {
const MyDietsScreen({super.key});
static const name = 'myDietsScreen';
static const path = '/my-diets-screen';
@override
Widget build(BuildContext context) {
return BlocProvider(create: (context) => sl<MyDietsCubit>()..loadAllDiets(), child: MyDietsScreenContent());
}
}
class MyDietsScreenContent extends StatelessWidget {
MyDietsScreenContent({super.key});
final activeDietsScrollController = ScrollController();
final draftDietsScrollController = ScrollController();
final personalDietsScrollController = ScrollController();
final activeDietsSearchController = SearchController();
final draftDietsSearchController = SearchController();
final personalDietsSearchController = SearchController();
@override
Widget build(BuildContext context) {
final s = S.of(context);
return Scaffold(
backgroundColor: appTheme.gray100,
appBar: AppBar(
centerTitle: true,
title: Text(
s.my_diets,
maxLines: 2,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
softWrap: true,
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
),
),
body: BlocBuilder<MyDietsCubit, MyDietsState>(
buildWhen: (previous, current) => previous.selectedStateIndex != current.selectedStateIndex,
builder: (context, state) {
return NestedScrollView(
controller: switch (state.selectedStateIndex) {
1 => draftDietsScrollController,
2 => personalDietsScrollController,
_ => activeDietsScrollController,
},
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(12))),
backgroundColor: appTheme.gray100,
foregroundColor: appTheme.gray100,
automaticallyImplyLeading: false,
stretchTriggerOffset: 1,
floating: true,
primary: false,
snap: true,
scrolledUnderElevation: 0,
bottom: PreferredSize(
preferredSize: Size(MediaQuery.sizeOf(context).width, 64),
child: Padding(
padding: const EdgeInsets.only(bottom: 0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 8),
const Padding(padding: EdgeInsets.symmetric(horizontal: 4), child: MyDietsTab()),
const SizedBox(height: 8),
Row(
children: [
const SizedBox(width: 4),
Expanded(
child: CustomSearchBar(
enableIcon: false,
backgroundColor: appTheme.whiteA700,
borderRadius: 100,
searchController: switch (state.selectedStateIndex) {
1 => draftDietsSearchController,
2 => personalDietsSearchController,
_ => activeDietsSearchController,
},
onChanged: (query) {
EasyDebounce.debounce('searchDiets', const Duration(milliseconds: 500), () {
context.read<MyDietsCubit>().loadCurrentDiets(query: query == '' ? null : query);
});
},
),
),
const SizedBox(width: 12),
AddItemButton(onTap: () => GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: {'isEditing': false})),
const SizedBox(width: 4),
],
),
const SizedBox(height: 16),
],
),
),
),
),
];
},
body: RefreshIndicator(
onRefresh: () => context.read<MyDietsCubit>().loadCurrentDiets(),
child: BlocBuilder<MyDietsCubit, MyDietsState>(
builder: (BuildContext context, MyDietsState state) {
if (state.isLoading) {
return Scaffold(backgroundColor: Colors.grey.shade200, body: const Loader());
} else if (state.error != null) {
return DataErrorWidget(onReload: () => context.read<MyDietsCubit>().loadAllDiets());
} else {
final gotDietLoadingError =
state.activeDietsError != null && state.selectedStateIndex == 0 ||
state.draftDietsError != null && state.selectedStateIndex == 1 ||
state.personalDietsError != null && state.selectedStateIndex == 2;
if (gotDietLoadingError) {
return DataErrorWidget(onReload: () => context.read<MyDietsCubit>().loadCurrentDiets());
}
if (state.isLoading) {
return const Loader();
}
final diets = switch (state.selectedStateIndex) {
2 => state.personalDiets,
1 => state.draftDiets,
_ => state.activeDiets,
};
return Stack(
children: [
const SizedBox.expand(),
ListView.separated(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
return MyDietWidget(diet: diets[index], key: ValueKey(diets[index].id));
},
separatorBuilder: (context, index) {
return const SizedBox(height: 20);
},
itemCount: diets.length,
),
Positioned(
right: 0,
bottom: 74,
child: FilterBadge(filterBottomSheet: DietFilterBottomSheet(myDietsCubit: context.read<MyDietsCubit>())),
),
],
);
}
},
),
),
);
},
),
);
}
}