From b35de1f4e9c17980964039d4dec353bbd01b370d Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Wed, 2 Oct 2024 16:20:42 +0300 Subject: [PATCH 1/4] feat(consultant): add become consultant screen --- lib/app_router.dart | 11 ++++ .../pages/become_consultant_screen.dart | 58 +++++++++++++++++++ .../stepper_become_consultant_screen.dart | 24 ++++++++ .../presentation/pages/settings_screen.dart | 2 +- 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 lib/features/consultant/become_consultant/pages/become_consultant_screen.dart create mode 100644 lib/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart diff --git a/lib/app_router.dart b/lib/app_router.dart index e54fe2da..7b4751e0 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -7,6 +7,8 @@ import 'package:eatvio_app/features/calendar/presentation/pages/calendar_screen. import 'package:eatvio_app/features/chat/presentation/pages/chat_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/pages/become_consultant_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart'; import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart'; import 'package:eatvio_app/features/diets/presentation/pages/about_diet_screen.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; @@ -221,6 +223,15 @@ class AppRouter { name: 'mySettingsScreen', builder: (context, state) => MySettingsScreen.builder(context), ), + GoRoute( + path: '/become-consultant-screen', + name: 'becomeConsultantScreen', + builder: (context, state) => BecomeConsultantScreen(), + ),GoRoute( + path: '/stepper-become-consultant-screen', + name: 'stepperBecomeConsultantScreen', + builder: (context, state) => StepperBecomeConsultantScreen(), + ), GoRoute( path: '/recipe-select-screen', name: 'recipeSelectScreen', diff --git a/lib/features/consultant/become_consultant/pages/become_consultant_screen.dart b/lib/features/consultant/become_consultant/pages/become_consultant_screen.dart new file mode 100644 index 00000000..bf7ec475 --- /dev/null +++ b/lib/features/consultant/become_consultant/pages/become_consultant_screen.dart @@ -0,0 +1,58 @@ +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class BecomeConsultantScreen extends StatefulWidget { + const BecomeConsultantScreen({super.key}); + + @override + State createState() => _BecomeConsultantScreenState(); +} + +class _BecomeConsultantScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Стать консультантом'), + automaticallyImplyLeading: false, + centerTitle: false, + leading: IconButton( + onPressed: () => GoRouter.of(context).pop(), + icon: Icon(Icons.close), + ), + ), + body: Padding( + padding: const EdgeInsets.all(16), + child: Text('Для регистрации потребуется следующий список документов, подготовьте их заранее'), + ), + bottomSheet: _startRegistrationButton(), + ); + } + + _startRegistrationButton() { + return InkWell( + onTap: () => GoRouter.of(context).pushReplacementNamed('stepperBecomeConsultantScreen'), + borderRadius: BorderRadius.circular(20), + child: Ink( + height: 52, + width: MediaQuery.of(context).size.width - 32, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: appTheme.blueA400, + ), + child: Center( + child: Text( + 'Начать регистрацию', + style: TextStyle( + color: Colors.white, + height: 1, + fontWeight: FontWeight.w600, + fontSize: 18, + ), + ), + ), + ), + ); + } +} diff --git a/lib/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart b/lib/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart new file mode 100644 index 00000000..5b010215 --- /dev/null +++ b/lib/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class StepperBecomeConsultantScreen extends StatefulWidget { + const StepperBecomeConsultantScreen({super.key}); + + @override + State createState() => _StepperBecomeConsultantScreenState(); +} + +class _StepperBecomeConsultantScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + leading: IconButton( + onPressed: () => GoRouter.of(context).pop(), + icon: Icon(Icons.close), + ), + ), + ); + } +} diff --git a/lib/features/settings/presentation/pages/settings_screen.dart b/lib/features/settings/presentation/pages/settings_screen.dart index 0a18843f..865247f7 100644 --- a/lib/features/settings/presentation/pages/settings_screen.dart +++ b/lib/features/settings/presentation/pages/settings_screen.dart @@ -345,7 +345,7 @@ class _SettingsScreenState extends State { return Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: InkWell( - onTap: () {}, + onTap: () => GoRouter.of(context).pushNamed('becomeConsultantScreen'), borderRadius: BorderRadius.circular(20), child: Ink( height: 52, From 9ba363e7809c40adf429ce34758fec42a2f7d658 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Wed, 2 Oct 2024 18:15:39 +0300 Subject: [PATCH 2/4] feat(feed): add search in blog posts and diets --- .../presentation/bloc/diets_cubit/diets_cubit.dart | 14 ++++++++++++-- .../feed/presentation/pages/feed_screen.dart | 6 ++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart index 858bbe9e..23d1c657 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart @@ -4,12 +4,22 @@ import 'package:flutter_bloc/flutter_bloc.dart'; class DietsCubit extends Cubit { final FeedRepository feedRepository; + int currentPage = 1; + late int lastPage; + bool isLoading = false; + // String? _query; DietsCubit({required this.feedRepository}) : super(const DietsState.loading()); - loadDiets() async { + loadDiets({ + String? query, + }) async { try { - final diets = await feedRepository.getDiets(); + // _query = query; + final diets = await feedRepository.getDiets( + query: query, + ); + lastPage = diets.meta.lastPage; emit(DietsState.loaded(diets: diets)); } catch (e) { emit(DietsState.error(errorMessage: e.toString())); diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index ab1c9768..115f25f3 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -428,6 +428,9 @@ class _FeedScreenState extends State { case 1: recipesCubit.loadRecipesList(query: query); break; + case 2: + dietsCubit.loadDiets(query: query); + break; } }, ); @@ -443,6 +446,9 @@ class _FeedScreenState extends State { case 1: recipesCubit.loadRecipesList(); break; + case 2: + dietsCubit.loadDiets(query: query); + break; } }, ); From 9c5716bd5a13937e7a61ebee3c0b1377b1b211e6 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Wed, 2 Oct 2024 20:01:22 +0300 Subject: [PATCH 3/4] feat(feed): add lazy loading --- .../bloc/diets_cubit/diets_cubit.dart | 47 +++++++-- .../bloc/diets_cubit/diets_state.dart | 3 +- .../bloc/diets_cubit/diets_state.freezed.dart | 97 ++++++++++--------- .../bloc/recipes_cubit/recipes_cubit.dart | 10 +- .../feed/presentation/pages/feed_screen.dart | 33 +++++-- 5 files changed, 124 insertions(+), 66 deletions(-) diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart index 23d1c657..fa44eafb 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart @@ -7,7 +7,7 @@ class DietsCubit extends Cubit { int currentPage = 1; late int lastPage; bool isLoading = false; - // String? _query; + String? _query; DietsCubit({required this.feedRepository}) : super(const DietsState.loading()); @@ -15,14 +15,49 @@ class DietsCubit extends Cubit { String? query, }) async { try { - // _query = query; - final diets = await feedRepository.getDiets( + _query = query; + final dietsPagination = await feedRepository.getDiets( query: query, ); - lastPage = diets.meta.lastPage; - emit(DietsState.loaded(diets: diets)); + lastPage = dietsPagination.meta.lastPage; + emit(DietsState.loaded( + dietsList: dietsPagination.data, + isLoading: isLoading, + )); } catch (e) { - emit(DietsState.error(errorMessage: e.toString())); + emit(DietsState.error( + errorMessage: e.toString(), + )); + } + } + + loadNextPage() async { + if (currentPage < lastPage && !isLoading) { + isLoading = true; + + emit((state as DietsStateLoaded).copyWith(isLoading: isLoading)); + + try { + if (currentPage < lastPage) { + currentPage++; + final dietPagination = await feedRepository.getDiets( + page: currentPage, + query: _query, + ); + isLoading = false; + emit( + DietsState.loaded( + dietsList: [ + ...(state as DietsStateLoaded).dietsList, + ...dietPagination.data, + ], + isLoading: isLoading, + ), + ); + } + } catch (e) { + emit(DietsState.error(errorMessage: e.toString())); + } } } } diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_state.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_state.dart index 3cd342e8..bc5bbba1 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_state.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_state.dart @@ -10,7 +10,8 @@ abstract class DietsState with _$DietsState { const factory DietsState.loading() = DietsStateLoading; const factory DietsState.loaded({ - required DietsPagination diets, + required List dietsList, + required bool isLoading, }) = DietsStateLoaded; const factory DietsState.error({ diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_state.freezed.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_state.freezed.dart index dd30f73d..8edde15b 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_state.freezed.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_state.freezed.dart @@ -20,7 +20,7 @@ mixin _$DietsState { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) => throw _privateConstructorUsedError; @@ -28,7 +28,7 @@ mixin _$DietsState { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) => throw _privateConstructorUsedError; @@ -36,7 +36,7 @@ mixin _$DietsState { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) => @@ -132,7 +132,7 @@ class _$DietsStateImpl implements _DietsState { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) { return $default(); @@ -143,7 +143,7 @@ class _$DietsStateImpl implements _DietsState { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) { return $default?.call(); @@ -154,7 +154,7 @@ class _$DietsStateImpl implements _DietsState { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { @@ -249,7 +249,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) { return loading(); @@ -260,7 +260,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) { return loading?.call(); @@ -271,7 +271,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { @@ -329,9 +329,7 @@ abstract class _$$DietsStateLoadedImplCopyWith<$Res> { $Res Function(_$DietsStateLoadedImpl) then) = __$$DietsStateLoadedImplCopyWithImpl<$Res>; @useResult - $Res call({DietsPagination diets}); - - $DietsPaginationCopyWith<$Res> get diets; + $Res call({List dietsList, bool isLoading}); } /// @nodoc @@ -347,38 +345,43 @@ class __$$DietsStateLoadedImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? diets = null, + Object? dietsList = null, + Object? isLoading = null, }) { return _then(_$DietsStateLoadedImpl( - diets: null == diets - ? _value.diets - : diets // ignore: cast_nullable_to_non_nullable - as DietsPagination, + dietsList: null == dietsList + ? _value._dietsList + : dietsList // ignore: cast_nullable_to_non_nullable + as List, + isLoading: null == isLoading + ? _value.isLoading + : isLoading // ignore: cast_nullable_to_non_nullable + as bool, )); } - - /// Create a copy of DietsState - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $DietsPaginationCopyWith<$Res> get diets { - return $DietsPaginationCopyWith<$Res>(_value.diets, (value) { - return _then(_value.copyWith(diets: value)); - }); - } } /// @nodoc class _$DietsStateLoadedImpl implements DietsStateLoaded { - const _$DietsStateLoadedImpl({required this.diets}); + const _$DietsStateLoadedImpl( + {required final List dietsList, required this.isLoading}) + : _dietsList = dietsList; + + final List _dietsList; + @override + List get dietsList { + if (_dietsList is EqualUnmodifiableListView) return _dietsList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_dietsList); + } @override - final DietsPagination diets; + final bool isLoading; @override String toString() { - return 'DietsState.loaded(diets: $diets)'; + return 'DietsState.loaded(dietsList: $dietsList, isLoading: $isLoading)'; } @override @@ -386,11 +389,15 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { return identical(this, other) || (other.runtimeType == runtimeType && other is _$DietsStateLoadedImpl && - (identical(other.diets, diets) || other.diets == diets)); + const DeepCollectionEquality() + .equals(other._dietsList, _dietsList) && + (identical(other.isLoading, isLoading) || + other.isLoading == isLoading)); } @override - int get hashCode => Object.hash(runtimeType, diets); + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_dietsList), isLoading); /// Create a copy of DietsState /// with the given fields replaced by the non-null parameter values. @@ -406,10 +413,10 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) { - return loaded(diets); + return loaded(dietsList, isLoading); } @override @@ -417,10 +424,10 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) { - return loaded?.call(diets); + return loaded?.call(dietsList, isLoading); } @override @@ -428,12 +435,12 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { if (loaded != null) { - return loaded(diets); + return loaded(dietsList, isLoading); } return orElse(); } @@ -477,10 +484,12 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { } abstract class DietsStateLoaded implements DietsState { - const factory DietsStateLoaded({required final DietsPagination diets}) = - _$DietsStateLoadedImpl; + const factory DietsStateLoaded( + {required final List dietsList, + required final bool isLoading}) = _$DietsStateLoadedImpl; - DietsPagination get diets; + List get dietsList; + bool get isLoading; /// Create a copy of DietsState /// with the given fields replaced by the non-null parameter values. @@ -561,7 +570,7 @@ class _$DietsStateErrorImpl implements DietsStateError { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) { return error(errorMessage); @@ -572,7 +581,7 @@ class _$DietsStateErrorImpl implements DietsStateError { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) { return error?.call(errorMessage); @@ -583,7 +592,7 @@ class _$DietsStateErrorImpl implements DietsStateError { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { diff --git a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart index 621880fe..93bcf399 100644 --- a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart +++ b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart @@ -13,6 +13,11 @@ class RecipesCubit extends Cubit { bool isLoading = false; String? _query; + RecipesCubit({ + required this.feedRepository, + required this.recipeRepository, + }) : super(const RecipesState.loading()); + loadRecipesList({ String? query, }) async { @@ -35,11 +40,6 @@ class RecipesCubit extends Cubit { } } - RecipesCubit({ - required this.feedRepository, - required this.recipeRepository, - }) : super(const RecipesState.loading()); - loadNextPage() async { if (currentPage < lastPage && !isLoading) { isLoading = true; diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index 115f25f3..0abbb6c2 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -57,11 +57,23 @@ class _FeedScreenState extends State { } } - _onScrollRecipes() {} + _onScrollRecipes() { + if (recipesScrollController.offset >= recipesScrollController.position.maxScrollExtent && !recipesScrollController.position.outOfRange) { + recipesCubit.loadNextPage(); + } + } - _onScrollDiets() {} + _onScrollDiets() { + if (dietsScrollController.offset >= dietsScrollController.position.maxScrollExtent && !dietsScrollController.position.outOfRange) { + dietsCubit.loadNextPage(); + } + } - _onScrollPlans() {} + _onScrollPlans() { + if (plansScrollController.offset >= plansScrollController.position.maxScrollExtent && !plansScrollController.position.outOfRange) { + // plansCubit.loadNextPage(); + } + } @override void dispose() { @@ -133,16 +145,17 @@ class _FeedScreenState extends State { }, body: Builder( builder: (BuildContext context) { - if (_selectedChipIndex == 0) + if (_selectedChipIndex == 0) { return _buildAllBlogPosts(); - else if (_selectedChipIndex == 1) + } else if (_selectedChipIndex == 1) { return _buildAllRecipes(); - else if (_selectedChipIndex == 2) + } else if (_selectedChipIndex == 2) { return _buildDiets(); - else if (_selectedChipIndex == 3) + } else if (_selectedChipIndex == 3) { return _buildPlans(); - else + } else { return Center(child: Text(chipsLabelList[_selectedChipIndex])); + } }, ), ), @@ -274,12 +287,12 @@ class _FeedScreenState extends State { shrinkWrap: true, physics: BouncingScrollPhysics(), itemBuilder: (context, index) { - return DietsWidget(diet: state.diets.data[index]); + return DietsWidget(diet: state.dietsList[index]); }, separatorBuilder: (context, index) { return SizedBox(height: 8); }, - itemCount: state.diets.data.length, + itemCount: state.dietsList.length, ); } else if (state is DietsStateError) { return Scaffold( From 1217c72f2f02a957b4502dc58a0d892a64e4f927 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Thu, 3 Oct 2024 12:48:53 +0300 Subject: [PATCH 4/4] fix: fix lazy loading in chat and feed --- .../chat/presentation/pages/chat_screen.dart | 13 +- .../stepper_become_consultant_screen.dart | 121 +++++++++++++++++- .../bloc/feed_cubit/feed_cubit.dart | 2 + lib/features/feed/services/feed_service.dart | 6 +- .../feed/services/feed_service.g.dart | 11 +- 5 files changed, 140 insertions(+), 13 deletions(-) diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart index 2e96d007..ae20444b 100644 --- a/lib/features/chat/presentation/pages/chat_screen.dart +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -27,16 +27,18 @@ class ChatScreen extends StatefulWidget { class _ChatScreenState extends State { final scrollController = ScrollController(); final TextEditingController textEditingController = TextEditingController(); + final ChatRoomCubit chatRoomCubit = sl(); @override void initState() { - scrollController.addListener(_onScroll); super.initState(); + scrollController.addListener(_onScroll); + chatRoomCubit.initChat(widget.chatId); } _onScroll() { if (scrollController.offset >= scrollController.position.maxScrollExtent && !scrollController.position.outOfRange) { - context.read().loadNextPage(widget.chatId); + chatRoomCubit.loadNextPage(widget.chatId); } } @@ -48,8 +50,9 @@ class _ChatScreenState extends State { Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) => sl()..initChat(widget.chatId), + create: (BuildContext context) => chatRoomCubit, child: BlocBuilder( + bloc: chatRoomCubit, builder: (context, state) { if (state is ChatRoomStateLoaded) { return _buildChat(context, state); @@ -234,7 +237,7 @@ class _ChatScreenState extends State { if (result != null) { List files = result.paths.map((path) => File(path!)).toList(); - context.read().sendMessage( + chatRoomCubit.sendMessage( chatId: widget.chatId, files: files, ); @@ -305,7 +308,7 @@ class _ChatScreenState extends State { customBorder: CircleBorder(), onTap: () { if (textEditingController.text.isNotEmpty) { - context.read().sendMessage( + chatRoomCubit.sendMessage( chatId: widget.chatId, data: textEditingController.text.trim(), ); diff --git a/lib/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart b/lib/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart index 5b010215..c191c402 100644 --- a/lib/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart +++ b/lib/features/consultant/become_consultant/pages/stepper_become_consultant_screen.dart @@ -1,3 +1,6 @@ +import 'package:eatvio_app/core/utils/image_constant.dart'; +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -9,15 +12,127 @@ class StepperBecomeConsultantScreen extends StatefulWidget { } class _StepperBecomeConsultantScreenState extends State { + double progressValue = 1 / 6; + int step = 1; + final pageController = PageController(); + @override Widget build(BuildContext context) { return Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: Row( + children: [ + Container( + height: 48, + width: MediaQuery.of(context).size.width * 0.2, + padding: EdgeInsets.only(left: 16, right: 4), + child: FloatingActionButton.extended( + heroTag: 'backButtonRegistration', + highlightElevation: 0, + focusElevation: 0, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + backgroundColor: Color(0xFFEAF2FD), + onPressed: () async { + setState(() { + pageController.previousPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + ); + }); + }, + label: Icon( + Icons.arrow_back_ios_new_rounded, + color: appTheme.blueA400, + ), + ), + ), + Container( + height: 48, + width: MediaQuery.of(context).size.width * 0.8, + padding: EdgeInsets.only(left: 4, right: 16), + child: FloatingActionButton.extended( + heroTag: 'nextButtonRegistration', + highlightElevation: 0, + elevation: 0, + focusElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + backgroundColor: appTheme.blueA400, + onPressed: () async { + setState(() { + pageController.nextPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + ); + }); + }, + label: Text( + 'Продолжить', + style: theme.textTheme.titleSmall!.copyWith(color: Colors.white), + ), + ), + ), + ], + ), appBar: AppBar( automaticallyImplyLeading: false, - leading: IconButton( - onPressed: () => GoRouter.of(context).pop(), - icon: Icon(Icons.close), + leading: Builder( + builder: (context) => IconButton( + icon: Icon(Icons.close_rounded), + onPressed: () => GoRouter.of(context).pop(), + ), ), + centerTitle: true, + title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 16), + child: Text('шаг $step из 6'), + ), + ], + bottom: PreferredSize( + preferredSize: Size(MediaQuery.of(context).size.width, 32), + child: Padding( + padding: const EdgeInsets.all(16), + child: TweenAnimationBuilder( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + tween: Tween( + begin: 0, + end: progressValue, + ), + builder: (context, value, _) => LinearProgressIndicator( + value: value, + borderRadius: BorderRadius.circular(16), + minHeight: 8, + backgroundColor: Colors.grey.shade100, + valueColor: AlwaysStoppedAnimation(appTheme.blueA400), + ), + ), + ), + ), + ), + body: PageView( + physics: NeverScrollableScrollPhysics(), + controller: pageController, + onPageChanged: (index) { + setState(() { + step = index + 1; + progressValue = step / 6; + }); + }, + children: [ + Container(), + Container(), + Container(), + Container(), + Container(), + Container(), + ], ), ); } diff --git a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart index 83df5eb0..f387a4eb 100644 --- a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart +++ b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart @@ -37,7 +37,9 @@ class FeedCubit extends Cubit { try { if (currentPage < lastPage) { + print('before: $currentPage'); currentPage++; + print('after: $currentPage'); final feedBlogPosts = await feedRepository.getFeedBlogPosts( page: currentPage, query: _query, diff --git a/lib/features/feed/services/feed_service.dart b/lib/features/feed/services/feed_service.dart index 9d0cd1bd..1321fa6b 100644 --- a/lib/features/feed/services/feed_service.dart +++ b/lib/features/feed/services/feed_service.dart @@ -13,20 +13,20 @@ abstract class FeedService { @GET('/api/blogPosts/index') Future getBlogPostList({ - @Path() required int page, + @Query('page') required int page, @Query('query_search') String? query, }); @GET('/api/recipes/index') Future getRecipes({ - @Path() required int page, + @Query('page') required int page, @Query('filters[tags][tags.id][\$in][]') required List? tags, @Query('filters[title][\$contains]') required String? query, }); @GET('/api/diets/index') Future getDiets({ - @Path() required int page, + @Query('page') required int page, @Query('query_search') String? query, }); diff --git a/lib/features/feed/services/feed_service.g.dart b/lib/features/feed/services/feed_service.g.dart index d074b0a2..31b022c4 100644 --- a/lib/features/feed/services/feed_service.g.dart +++ b/lib/features/feed/services/feed_service.g.dart @@ -27,7 +27,10 @@ class _FeedService implements FeedService { String? query, }) async { final _extra = {}; - final queryParameters = {r'query_search': query}; + final queryParameters = { + r'page': page, + r'query_search': query, + }; queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; @@ -66,6 +69,7 @@ class _FeedService implements FeedService { }) async { final _extra = {}; final queryParameters = { + r'page': page, r'filters[tags][tags.id][$in][]': tags, r'filters[title][$contains]': query, }; @@ -105,7 +109,10 @@ class _FeedService implements FeedService { String? query, }) async { final _extra = {}; - final queryParameters = {r'query_search': query}; + final queryParameters = { + r'page': page, + r'query_search': query, + }; queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null;