diff --git a/lib/features/auth/models/social_exchange_request.dart b/lib/features/auth/models/social_exchange_request.dart new file mode 100644 index 00000000..c322fab6 --- /dev/null +++ b/lib/features/auth/models/social_exchange_request.dart @@ -0,0 +1,12 @@ +class SocialExchangeRequest { + final String provider; + final String accessToken; + + SocialExchangeRequest({required this.provider, required this.accessToken}); + + Map toJson() { + return {'provider': provider, 'access_token': accessToken}; + } +} + + diff --git a/lib/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart b/lib/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart index 20686cce..7b58a4b0 100644 --- a/lib/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart +++ b/lib/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart @@ -6,28 +6,17 @@ import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_state import 'package:eatvio_app/features/auth/repositories/auth_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; - class AuthCubit extends Cubit { final AuthRepository authRepository; - AuthCubit({ - required this.authRepository, - }) : super(const AuthState()); + AuthCubit({required this.authRepository}) : super(const AuthState()); Future getTokenByCredentials(String email, String password) async { emit(const AuthState.loading()); try { - final token = (await authRepository.getTokenByCredentials( - email, - password, - )) - .token; - emit( - AuthState.loaded( - token: token, - ), - ); - await TokenStorage.saveTokenInStorage(token); + final token = (await authRepository.getTokenByCredentials(email, password)).token; + emit(AuthState.loaded(token: token)); + await TokenStorage.saveTokenInStorage(token); return true; } catch (e) { log(e.toString()); @@ -36,4 +25,19 @@ class AuthCubit extends Cubit { return false; } } + + Future getTokenBySocial({required String provider, required String accessToken}) async { + emit(const AuthState.loading()); + try { + final token = (await authRepository.getTokenBySocial(provider: provider, accessToken: accessToken)).token; + emit(AuthState.loaded(token: token)); + await TokenStorage.saveTokenInStorage(token); + return true; + } catch (e) { + log(e.toString()); + showErrorToast('Не удалось войти через $provider'); + emit(AuthState.error(errorMessage: '$e')); + return false; + } + } } diff --git a/lib/features/auth/presentation/pages/auth_screen.dart b/lib/features/auth/presentation/pages/auth_screen.dart index 73162bd2..8a4e711b 100644 --- a/lib/features/auth/presentation/pages/auth_screen.dart +++ b/lib/features/auth/presentation/pages/auth_screen.dart @@ -24,6 +24,7 @@ import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:eatvio_app/features/auth/sdk/social_auth_facade.dart'; class AuthScreen extends StatefulWidget { const AuthScreen({super.key}); @@ -165,6 +166,52 @@ class _AuthScreenState extends State { ), ], ), + // const SizedBox(height: 16), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // _SocialButton( + // onTap: _onVkPressed, + // backgroundColor: const Color(0xFF2787F5), + // tooltip: 'VK ID', + // child: SvgPicture.asset( + // 'assets/icons/vk.svg', + // height: 24, + // width: 24, + // colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + // ), + // ), + // _SocialButton( + // onTap: _onOkPressed, + // backgroundColor: const Color(0xFFF58220), + // tooltip: 'Одноклассники', + // child: SvgPicture.asset( + // 'assets/icons/ok.svg', + // height: 24, + // width: 24, + // colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + // ), + // ), + // const _SocialButton( + // onTap: _onMailRuPressed, + // backgroundColor: Color(0xFF005FF9), + // tooltip: 'Mail.ru', + // child: Text( + // 'Mail', + // style: TextStyle(color: Colors.white, fontWeight: FontWeight.w700), + // ), + // ), + // const _SocialButton( + // onTap: _onYandexPressed, + // backgroundColor: Color(0xFFFFCC00), + // tooltip: 'Яндекс ID', + // child: Text( + // 'Yandex', + // style: TextStyle(color: Colors.black, fontWeight: FontWeight.w700), + // ), + // ), + // ], + // ), const Spacer(), Center( child: RichText( @@ -317,3 +364,86 @@ class _AuthScreenState extends State { ); } } + +class _SocialButton extends StatelessWidget { + const _SocialButton({required this.onTap, required this.child, required this.backgroundColor, required this.tooltip}); + + final VoidCallback onTap; + final Widget child; + final Color backgroundColor; + final String tooltip; + + @override + Widget build(BuildContext context) { + return Tooltip( + message: tooltip, + child: InkWell( + borderRadius: BorderRadius.circular(12), + onTap: onTap, + child: Ink( + height: 48, + width: (MediaQuery.of(context).size.width - 16 * 2 - 12 * 3) / 4, + decoration: BoxDecoration(color: backgroundColor, borderRadius: BorderRadius.circular(12)), + child: Center(child: child), + ), + ), + ); + } +} + +void _onVkPressed() async { + final accessToken = await SocialAuthFacade.signInWithVk(); + if (accessToken == null) return; + final isAuthenticated = await sl().getTokenBySocial(provider: 'vk', accessToken: accessToken); + if (isAuthenticated) { + if (AppRouter.navigatorKey.currentContext != null) { + // Reuse success flow + // ignore: use_build_context_synchronously + await _reconnectAfterAuth(); + } + } +} + +void _onOkPressed() async { + final accessToken = await SocialAuthFacade.signInWithOk(); + if (accessToken == null) return; + final isAuthenticated = await sl().getTokenBySocial(provider: 'ok', accessToken: accessToken); + if (isAuthenticated) { + await _reconnectAfterAuth(); + } +} + +void _onMailRuPressed() async { + final accessToken = await SocialAuthFacade.signInWithMailRu(); + if (accessToken == null) return; + final isAuthenticated = await sl().getTokenBySocial(provider: 'mailru', accessToken: accessToken); + if (isAuthenticated) { + await _reconnectAfterAuth(); + } +} + +void _onYandexPressed() async { + final accessToken = await SocialAuthFacade.signInWithYandex(); + if (accessToken == null) return; + final isAuthenticated = await sl().getTokenBySocial(provider: 'yandex', accessToken: accessToken); + if (isAuthenticated) { + await _reconnectAfterAuth(); + } +} + +Future _reconnectAfterAuth() async { + final context = AppRouter.navigatorKey.currentContext; + if (context == null) return; + try { + await sl().clear(); + await sl().initialize(); + await sl().getMyProfile(); + await sl().getChatRoomsWithLoading(); + await sl().connectToWebSocket(); + await sl().getNotifications(); + await sl().connectToWebSocket(); + await sl().registerPushToken(); + showSuccessToast('Успешный вход'); + } catch (_) {} + AppRouter.navigatorKey.currentContext?.go('/feed-screen', extra: {'needToInitializeWebSocket': false}); +} diff --git a/lib/features/auth/repositories/auth_repository.dart b/lib/features/auth/repositories/auth_repository.dart index d0bfcce5..84df92f6 100644 --- a/lib/features/auth/repositories/auth_repository.dart +++ b/lib/features/auth/repositories/auth_repository.dart @@ -1,6 +1,7 @@ import 'package:eatvio_app/features/auth/models/credentials_model.dart'; import 'package:eatvio_app/features/auth/models/token_model.dart'; import 'package:eatvio_app/features/auth/services/auth_service.dart'; +import 'package:eatvio_app/features/auth/models/social_exchange_request.dart'; class AuthRepository { final AuthService authService; @@ -22,4 +23,17 @@ class AuthRepository { rethrow; } } + + Future getTokenBySocial({ + required String provider, + required String accessToken, + }) async { + try { + return await authService.getTokenBySocial( + body: SocialExchangeRequest(provider: provider, accessToken: accessToken), + ); + } catch (e) { + rethrow; + } + } } diff --git a/lib/features/auth/sdk/social_auth_facade.dart b/lib/features/auth/sdk/social_auth_facade.dart new file mode 100644 index 00000000..62985d5d --- /dev/null +++ b/lib/features/auth/sdk/social_auth_facade.dart @@ -0,0 +1,25 @@ +import 'dart:async'; + +class SocialAuthFacade { + static Future signInWithVk() async { + // TODO: Integrate official VK ID SDK and return access token + return null; + } + + static Future signInWithOk() async { + // TODO: Integrate official OK SDK and return access token + return null; + } + + static Future signInWithMailRu() async { + // TODO: Integrate official Mail.ru SDK and return access token + return null; + } + + static Future signInWithYandex() async { + // TODO: Integrate official Yandex ID SDK and return access token + return null; + } +} + + diff --git a/lib/features/auth/services/auth_service.dart b/lib/features/auth/services/auth_service.dart index 62256f8b..7dabb65b 100644 --- a/lib/features/auth/services/auth_service.dart +++ b/lib/features/auth/services/auth_service.dart @@ -1,6 +1,7 @@ import 'package:dio/dio.dart'; import 'package:eatvio_app/features/auth/models/credentials_model.dart'; import 'package:eatvio_app/features/auth/models/token_model.dart'; +import 'package:eatvio_app/features/auth/models/social_exchange_request.dart'; import 'package:retrofit/retrofit.dart'; part 'auth_service.g.dart'; @@ -13,4 +14,9 @@ abstract class AuthService { Future getTokenByCredentials({ @Body() required CredentialsModel credentials, }); + + @POST('/api/social/login') + Future getTokenBySocial({ + @Body() required SocialExchangeRequest body, + }); } diff --git a/lib/features/consultations/presentation/widgets/consultation_card_widget.dart b/lib/features/consultations/presentation/widgets/consultation_card_widget.dart index 760a8783..3d870e8d 100644 --- a/lib/features/consultations/presentation/widgets/consultation_card_widget.dart +++ b/lib/features/consultations/presentation/widgets/consultation_card_widget.dart @@ -3,9 +3,12 @@ import 'package:eatvio_app/core/const.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/custom_divider.dart'; +import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/core/widgets/show_error_dialog.dart'; import 'package:eatvio_app/features/consultations/models/consultation_model.dart'; import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart'; +import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart'; +import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart'; import 'package:eatvio_app/features/user_details/presentation/user_details_screen.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; @@ -284,6 +287,19 @@ class _ConsultationCardWidgetState extends State { ), ], ), + // Кнопка получения выплаты + if (widget.consultationsModel.chosenPlanState == ChosenPlanStateEnum.stateDone) ...[ + const SizedBox(height: 16), + CustomOutlinedButton( + text: s.collectCharge, + height: 52, + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), + buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.green)), + onPressed: () async { + GoRouter.of(context).push(CardSettingsScreen.path, extra: widget.consultationsModel.id); + }, + ), + ], ], ), ), diff --git a/lib/features/my_plans/presentation/my_plans_screen.dart b/lib/features/my_plans/presentation/my_plans_screen.dart index 3ca9ca3e..f7bdb456 100644 --- a/lib/features/my_plans/presentation/my_plans_screen.dart +++ b/lib/features/my_plans/presentation/my_plans_screen.dart @@ -12,7 +12,6 @@ import 'package:eatvio_app/features/feed/presentation/widgets/plans_filter_botto import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart'; import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_state.dart'; import 'package:eatvio_app/features/my_plans/presentation/widgets/my_plan_widget.dart'; -import 'package:eatvio_app/features/my_plans/presentation/widgets/my_plans_tab.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -64,9 +63,7 @@ class MyPlansScreenContent extends StatelessWidget { headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverAppBar( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(bottom: Radius.circular(12)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(12))), backgroundColor: appTheme.gray100, foregroundColor: appTheme.gray100, automaticallyImplyLeading: false, @@ -76,21 +73,12 @@ class MyPlansScreenContent extends StatelessWidget { snap: true, scrolledUnderElevation: 0, bottom: PreferredSize( - preferredSize: Size( - MediaQuery.sizeOf(context).width, - 64, - ), + preferredSize: Size(MediaQuery.sizeOf(context).width, 32), 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: MyPlansTab(), - ), - const SizedBox(height: 8), Row( children: [ const SizedBox(width: 4), @@ -104,20 +92,14 @@ class MyPlansScreenContent extends StatelessWidget { _ => activePlansSearchController, }, onChanged: (query) { - EasyDebounce.debounce( - 'searchPlans', - const Duration(milliseconds: 500), - () { - context.read().loadPlans(query: query == '' ? null : query); - }, - ); + EasyDebounce.debounce('searchPlans', const Duration(milliseconds: 500), () { + context.read().loadPlans(query: query == '' ? null : query); + }); }, ), ), const SizedBox(width: 12), - AddItemButton( - onTap: () => GoRouter.of(context).pushNamed(CreatePlanScreen.name), - ), + AddItemButton(onTap: () => GoRouter.of(context).pushNamed(CreatePlanScreen.name)), const SizedBox(width: 4), ], ), @@ -134,10 +116,7 @@ class MyPlansScreenContent extends StatelessWidget { child: BlocBuilder( builder: (BuildContext context, MyPlansState state) { if (state.isLoading) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); + return Scaffold(backgroundColor: Colors.grey.shade200, body: const Loader()); } else if (state.error != null) { return DataErrorWidget(onReload: () => context.read().loadPlans()); } else { @@ -162,11 +141,7 @@ class MyPlansScreenContent extends StatelessWidget { Positioned( right: 0, bottom: 74, - child: FilterBadge( - filterBottomSheet: PlansFilterBottomSheet( - myPlansCubit: context.read(), - ), - ), + child: FilterBadge(filterBottomSheet: PlansFilterBottomSheet(myPlansCubit: context.read())), ), ], ); diff --git a/lib/features/my_plans/presentation/widgets/my_plan_widget.dart b/lib/features/my_plans/presentation/widgets/my_plan_widget.dart index ce91acdc..7ecdc653 100644 --- a/lib/features/my_plans/presentation/widgets/my_plan_widget.dart +++ b/lib/features/my_plans/presentation/widgets/my_plan_widget.dart @@ -14,16 +14,13 @@ import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_html/flutter_html.dart'; -import 'package:flutter_svg/svg.dart'; +// Removed SVG icon usage after switching to text buttons import 'package:go_router/go_router.dart'; import 'package:share_plus/share_plus.dart'; class MyPlanWidget extends StatefulWidget { final PlanModel plan; - const MyPlanWidget({ - super.key, - required this.plan, - }); + const MyPlanWidget({super.key, required this.plan}); @override State createState() => _MyPlanWidgetState(); @@ -34,10 +31,7 @@ class _MyPlanWidgetState extends State { Widget build(BuildContext context) { final s = S.of(context); return DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Colors.white, - ), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -48,23 +42,14 @@ class _MyPlanWidgetState extends State { onTap: () => GoRouter.of(context).pushNamed('aboutPlanScreen', extra: {'slug': widget.plan.slug, 'navigateToComments': false}), child: ClipRRect( borderRadius: const BorderRadius.vertical(top: Radius.circular(12)), - child: CachedNetworkImage( - imageUrl: '$baseUrl/storage/${widget.plan.image}', - fit: BoxFit.fitWidth, - width: MediaQuery.of(context).size.width, - ), + child: CachedNetworkImage(imageUrl: '$baseUrl/storage/${widget.plan.image}', fit: BoxFit.fitWidth, width: MediaQuery.of(context).size.width), ), ), Positioned( bottom: 16, child: SizedBox( width: MediaQuery.sizeOf(context).width, - child: InfoRow( - plan: widget.plan, - itemsBackgroundColor: appTheme.whiteA700, - disableDescriptionOfTypes: true, - type: ProductType.plan, - ), + child: InfoRow(plan: widget.plan, itemsBackgroundColor: appTheme.whiteA700, disableDescriptionOfTypes: true, type: ProductType.plan), ), ), ], @@ -75,19 +60,16 @@ class _MyPlanWidgetState extends State { children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text( - widget.plan.name, - style: TextStyles.textMSemibold.copyWith(color: appTheme.black), - ), + child: Text(widget.plan.name, style: TextStyles.textMSemibold.copyWith(color: appTheme.black)), ), if (widget.plan.details.isNotEmpty) ...[ - const SizedBox( - height: 12, - ), + const SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Html( - data: widget.plan.details.length > 200 ? '${widget.plan.details.substring(0, 200).replaceAll('\n', '
')}...' : widget.plan.details.replaceAll('\n', '
'), + data: widget.plan.details.length > 200 + ? '${widget.plan.details.substring(0, 200).replaceAll('\n', '
')}...' + : widget.plan.details.replaceAll('\n', '
'), style: { "*": Style( margin: Margins.zero, @@ -116,26 +98,61 @@ class _MyPlanWidgetState extends State { padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( children: [ + // Buttons aligned with MyRecipeWidget: Delete (gray) and Share (blue) Row( children: [ Expanded( child: CustomOutlinedButton( - text: switch (state.selectedStateIndex) { - 1 => s.publish, - _ => s.edit, + onPressed: () async { + final result = await context.read().deletePlan(widget.plan.slug); + if (result) { + Future.delayed(const Duration(seconds: 3), () { + if (!context.mounted) return; + showBottomSheetWithBlur( + context: context, + child: Column( + children: [ + const SizedBox(height: 20), + const BottomSheetHandlerBar(), + const SizedBox(height: 20), + Text(widget.plan.name, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)), + Text(s.deleted, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)), + const SizedBox(height: 20), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: CustomOutlinedButton( + onPressed: () { + context.pop(); + }, + text: 'Хорошо', + height: 52, + buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700), + buttonStyle: ButtonStyle( + side: const WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + ), + ), + ), + const SizedBox(height: 20), + ], + ), + ); + }); + } }, + text: 'Удалить', height: 52, - buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.black), buttonStyle: ButtonStyle( shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))), - backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + backgroundColor: WidgetStatePropertyAll(appTheme.lightGray0), side: const WidgetStatePropertyAll(BorderSide.none), ), ), ), - if (state.selectedStateIndex == 0) ...[ - const SizedBox(width: 6), - CustomOutlinedButton( + const SizedBox(width: 8), + Expanded( + child: CustomOutlinedButton( onPressed: () async { final box = context.findRenderObject() as RenderBox?; await SharePlus.instance.share( @@ -146,109 +163,14 @@ class _MyPlanWidgetState extends State { ); }, height: 52, - width: 52, - leftIcon: SvgPicture.asset( - 'assets/icons/share2.svg', - width: 20, - height: 20, - colorFilter: ColorFilter.mode(appTheme.whiteA700, BlendMode.srcIn), - ), - buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.red), buttonStyle: ButtonStyle( shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), side: const WidgetStatePropertyAll(BorderSide.none), ), - text: '', + text: s.share, + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), ), - ], - ], - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: CustomOutlinedButton( - text: switch (state.selectedStateIndex) { - 0 => s.removeFromActive, - _ => s.edit, - }, - height: 52, - buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.black), - buttonStyle: ButtonStyle( - shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))), - backgroundColor: WidgetStatePropertyAll(appTheme.lightGray0), - side: const WidgetStatePropertyAll(BorderSide.none), - ), - ), - ), - const SizedBox(width: 6), - CustomOutlinedButton( - onPressed: () async { - final result = await context.read().deletePlan(widget.plan.slug); - if (result) { - Future.delayed(const Duration(seconds: 3), () { - if (!context.mounted) return; - showBottomSheetWithBlur( - context: context, - child: Column( - children: [ - const SizedBox( - height: 20, - ), - const BottomSheetHandlerBar(), - const SizedBox( - height: 20, - ), - Text( - widget.plan.name, - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), - Text( - s.deleted, - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), - const SizedBox( - height: 20, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: CustomOutlinedButton( - onPressed: () { - context.pop(); - }, - text: 'Хорошо', - height: 52, - buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: ButtonStyle( - side: const WidgetStatePropertyAll(BorderSide.none), - backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), - ), - ), - ), - const SizedBox( - height: 20, - ), - ], - ), - ); - }); - } - }, - height: 52, - width: 52, - leftIcon: SvgPicture.asset( - 'assets/icons/trash_can.svg', - width: 20, - height: 20, - ), - buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.red), - buttonStyle: ButtonStyle( - shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))), - backgroundColor: WidgetStatePropertyAll(appTheme.lightGray0), - side: const WidgetStatePropertyAll(BorderSide.none), - ), - text: '', ), ], ), diff --git a/lib/features/my_plans/presentation/widgets/my_plans_tab.dart b/lib/features/my_plans/presentation/widgets/my_plans_tab.dart index c681efd1..2635bef1 100644 --- a/lib/features/my_plans/presentation/widgets/my_plans_tab.dart +++ b/lib/features/my_plans/presentation/widgets/my_plans_tab.dart @@ -1,71 +1,3 @@ -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/animated_option_button.dart'; -import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart'; -import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_state.dart'; -import 'package:eatvio_app/generated/l10n.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; +// File intentionally left minimal after removing tabs for My Plans -class MyPlansTab extends StatefulWidget { - const MyPlansTab({super.key, this.additionalOnTap}); - final void Function()? additionalOnTap; - @override - State createState() => _MyPlansTabState(); -} - -class _MyPlansTabState extends State { - final List tabTitles = []; - @override - void didChangeDependencies() { - final s = S.of(context); - if (tabTitles.isEmpty) { - tabTitles.add(s.published); - tabTitles.add(s.drafted); - } - super.didChangeDependencies(); - } - - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - return Align( - alignment: Alignment.centerLeft, - child: Row( - children: [ - Expanded( - child: Container( - height: 48, - decoration: BoxDecoration( - color: appTheme.whiteA700, - borderRadius: BorderRadius.circular(100), - ), - padding: const EdgeInsets.all(4), - child: Row( - children: [ - ...List.generate( - 2, - (index) => Expanded( - child: AnimatedOptionButton( - textStyle: TextStyles.textSMedium, - isSelected: state.selectedStateIndex == index, - text: tabTitles[index], - onTap: () { - widget.additionalOnTap?.call(); - context.read().changeSelectedStateIndex(index); - }, - ), - ), - ), - ], - ), - ), - ), - ], - ), - ); - }, - ); - } -} +// Drafts/published tab UI removed per requirements diff --git a/lib/features/notifications/presentation/widgets/notification_widget.dart b/lib/features/notifications/presentation/widgets/notification_widget.dart index ed196b00..6b675382 100644 --- a/lib/features/notifications/presentation/widgets/notification_widget.dart +++ b/lib/features/notifications/presentation/widgets/notification_widget.dart @@ -307,7 +307,7 @@ class _ChosenPlanFinishedToConsultantWidget extends StatelessWidget { buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.green)), onPressed: () { - GoRouter.of(context).pushNamed(CardSettingsScreen.name, extra: notification.planId); + GoRouter.of(context).push(CardSettingsScreen.path, extra: notification.planId); }, ), ], diff --git a/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart b/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart index d0d7a932..5ad4a948 100644 --- a/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart +++ b/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart @@ -18,11 +18,7 @@ class ProfileCubit extends Cubit { final ConsultantRepository consultantRepository; String _currentPeriod = '1'; - ProfileCubit({ - required this.profileRepository, - required this.chatRepository, - required this.consultantRepository, - }) : super(const ProfileState.loading()); + ProfileCubit({required this.profileRepository, required this.chatRepository, required this.consultantRepository}) : super(const ProfileState.loading()); Future getProfileBySlug(String slug) async { emit(const ProfileState.loading()); @@ -42,9 +38,7 @@ class ProfileCubit extends Cubit { } } - Future getMyProfile({ - String period = '1', - }) async { + Future getMyProfile({String period = '1'}) async { emit(const ProfileState.loading()); _currentPeriod = period; try { @@ -77,15 +71,14 @@ class ProfileCubit extends Cubit { profile: (state as ProfileStateLoaded).profile, profileDetails: (state as ProfileStateLoaded).profileDetails, blogPosts: feedBlogPostList, + weightPoints: (state as ProfileStateLoaded).weightPoints, + circumferencePoints: (state as ProfileStateLoaded).circumferencePoints, + consultantInfo: (state as ProfileStateLoaded).consultantInfo, ), ); } - Future addCircumference({ - required int chestCircumference, - required int waistCircumference, - required int hipCircumference, - }) async { + Future addCircumference({required int chestCircumference, required int waistCircumference, required int hipCircumference}) async { try { await profileRepository.addCircumference( chestCircumference: chestCircumference, @@ -98,9 +91,7 @@ class ProfileCubit extends Cubit { } } - Future addWeight({ - required double weight, - }) async { + Future addWeight({required double weight}) async { try { await profileRepository.addWeight(weight: weight); await getMyProfile(period: _currentPeriod); @@ -109,25 +100,15 @@ class ProfileCubit extends Cubit { } } - Future getChatRoomIdBySlug({ - required Author author, - }) async { + Future getChatRoomIdBySlug({required Author author}) async { try { final chatIdOrError = await chatRepository.getChatByUserSlug(author.authorSlug); if (chatIdOrError == '404') { - AppRouter.navigatorKey.currentContext?.pushNamed( - 'emptyChatScreen', - extra: author, - ); + AppRouter.navigatorKey.currentContext?.pushNamed('emptyChatScreen', extra: author); } else if (chatIdOrError == 'error') { showErrorToast('Ошибка создания чата'); } else { - AppRouter.navigatorKey.currentContext?.pushNamed( - 'chatScreen', - extra: { - 'uuid': chatIdOrError, - }, - ); + AppRouter.navigatorKey.currentContext?.pushNamed('chatScreen', extra: {'uuid': chatIdOrError}); return chatIdOrError; } } catch (e, st) { diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index c11cb0b0..98966234 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -1,5 +1,4 @@ import 'dart:io'; - import 'package:cached_network_image/cached_network_image.dart'; import 'package:dismissible_page/dismissible_page.dart'; import 'package:eatvio_app/core/app_router.dart';