import 'package:eatvio_app/core/app_router.dart'; import 'package:eatvio_app/core/enums/complained_content.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/bottom_sheet_handler_bar.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/complaining/presentation/cubit/complaining_cubit.dart'; import 'package:eatvio_app/features/complaining/presentation/cubit/complaining_state.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; import 'package:collection/collection.dart'; class ComplainingBottomSheet extends StatefulWidget { const ComplainingBottomSheet({super.key, required this.complainedContentType, this.slug, this.id}); final ComplainedContent complainedContentType; final String? slug; final int? id; @override State createState() => _ComplainingBottomSheetState(); } class _ComplainingBottomSheetState extends State { @override Widget build(BuildContext context) { return BlocProvider( create: (context) => sl()..setContentTypeAndIdentifier(contentType: widget.complainedContentType, slug: widget.slug, id: widget.id), child: Container( padding: const EdgeInsets.only(top: 8, bottom: 24, left: 16, right: 16), decoration: const BoxDecoration( borderRadius: BorderRadius.vertical(top: Radius.circular(12)), ), child: BlocBuilder( builder: (context, state) { final category = state.category; if (state.wasSentSuccessfully == true) { return const _ComplaintSentWidget(); } else if (state.wasSentSuccessfully == false) { return const _ComplaintFailedWidget(); } if (category != null) { return switch (category) { ComplainType.spam => const _SpamWidget(), ComplainType.lawViolation => const _LawViolationWidget(), ComplainType.deception => const _DeceptionWidget(), ComplainType.violenceDndHostility => const _ViolenceAndHostility(), ComplainType.explicitImage => const _ExplicitImageWidget(), }; } return const _CategoryWidget(); }, ), ), ); } } class _CategoryWidget extends StatelessWidget { const _CategoryWidget(); final categories = ComplainType.values; @override Widget build(BuildContext context) { final s = S.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ const BottomSheetHandlerBar(), const SizedBox(height: 20), Text( s.complaint, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), ), const SizedBox(height: 8), Text( s.complaint_question, textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), const SizedBox(height: 24), ...List.generate( categories.length, (index) => Column( children: [ _CategoryButton( category: categories[index], onTap: () { context.read().setCategory(categories[index]); }, ), if (index != categories.length - 1) const SizedBox(height: 20), ], ), ), const SizedBox(height: 24), ], ); } } class _SpamWidget extends StatelessWidget { const _SpamWidget(); @override Widget build(BuildContext context) { final s = S.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ const BottomSheetHandlerBar(), const SizedBox(height: 20), Text( s.spam, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), ), const SizedBox(height: 8), SizedBox( width: MediaQuery.sizeOf(context).width * 0.7, child: Text( s.spam_description, textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), ), const SizedBox(height: 24), const _ComplainButton(), ], ); } } class _ExplicitImageWidget extends StatelessWidget { const _ExplicitImageWidget(); @override Widget build(BuildContext context) { final s = S.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ const BottomSheetHandlerBar(), const SizedBox(height: 20), Text( s.explicitImages, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), ), const SizedBox(height: 8), SizedBox( width: MediaQuery.sizeOf(context).width * 0.7, child: Text( s.explicitImagesDescription, textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), ), const SizedBox(height: 24), const _ComplainButton(), ], ); } } class _LawViolationWidget extends StatefulWidget { const _LawViolationWidget(); @override State<_LawViolationWidget> createState() => _LawViolationWidgetState(); } class _LawViolationWidgetState extends State<_LawViolationWidget> { final List<(bool, String)> tags = []; @override void didChangeDependencies() { super.didChangeDependencies(); final s = S.of(context); if (tags.isEmpty) { tags.addAll([ (false, s.alcohol), (false, s.drugs), (false, s.nicotine), (false, s.weapon), (false, s.fake_documents), (false, s.prostitution), (false, s.other), ]); } } @override Widget build(BuildContext context) { final s = S.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ const BottomSheetHandlerBar(), const SizedBox(height: 20), Text( s.lawViolation, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), ), const SizedBox(height: 8), SizedBox( width: MediaQuery.sizeOf(context).width * 0.7, child: Text( s.what_do_you_want_to_complaint_about, textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), ), const SizedBox(height: 24), ...tags.mapIndexed((index, element) { return Row( children: [ Checkbox( activeColor: appTheme.blueA400, side: BorderSide(width: 2, color: tags[index].$1 ? appTheme.blueA400 : appTheme.blueGray), value: element.$1, onChanged: (isChecked) { setState(() { if (isChecked == null) return; if (index == tags.length - 1 && !isChecked) { context.read().toggleDescription(); } tags[index] = (isChecked, element.$2); final activeTags = tags.where((elem) => elem.$1).map((e) => e.$2).toList(); context.read().setTags(activeTags); }); }, ), Text( element.$2, style: TextStyles.textLSemibold.copyWith(color: appTheme.black), ), ], ); }), if (tags.last.$1) ...[ const SizedBox(height: 12), CustomTextFormField( hintText: s.type_here_your_complaint, onChanged: (value) { context.read().setDescription(value); }, ), ], const SizedBox(height: 20), const _ComplainButton(), ], ); } } class _ViolenceAndHostility extends StatefulWidget { const _ViolenceAndHostility(); @override State<_ViolenceAndHostility> createState() => _ViolenceAndHostilityState(); } class _ViolenceAndHostilityState extends State<_ViolenceAndHostility> { final List<(bool, String)> tags = []; @override void didChangeDependencies() { super.didChangeDependencies(); final s = S.of(context); if (tags.isEmpty) { tags.addAll([ (false, s.violence_against_people_or_animal), (false, s.hatred), (false, s.suicide), (false, s.hatred_description), (false, s.extremism), (false, s.calls_for_bullying), ]); } } @override Widget build(BuildContext context) { final s = S.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ const BottomSheetHandlerBar(), const SizedBox(height: 20), Text( s.lawViolation, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), ), const SizedBox(height: 8), SizedBox( width: MediaQuery.sizeOf(context).width * 0.7, child: Text( s.what_do_you_want_to_complaint_about, textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), ), const SizedBox(height: 24), ...tags.mapIndexed((index, element) { return Row( children: [ Checkbox( activeColor: appTheme.blueA400, side: BorderSide(width: 2, color: tags[index].$1 ? appTheme.blueA400 : appTheme.blueGray), value: element.$1, onChanged: (isChecked) { setState(() { if (isChecked == null) return; tags[index] = (isChecked, element.$2); final activeTags = tags.where((elem) => elem.$1).map((e) => e.$2).toList(); context.read().setTags(activeTags); }); }, ), Expanded( child: Text( element.$2, style: TextStyles.textLSemibold.copyWith(color: appTheme.black), ), ), ], ); }), const SizedBox(height: 20), const _ComplainButton(), ], ); } } class _DeceptionWidget extends StatefulWidget { const _DeceptionWidget(); @override State<_DeceptionWidget> createState() => _DeceptionWidgetState(); } class _DeceptionWidgetState extends State<_DeceptionWidget> { final List<(bool, String)> tags = []; final List descriptions = []; @override void didChangeDependencies() { super.didChangeDependencies(); final s = S.of(context); if (tags.isEmpty && descriptions.isEmpty) { tags.addAll([ (false, s.misrepresentation), (false, s.fraud), ]); descriptions.addAll([ s.misrepresentation_description, s.fraud_description, ]); } } @override Widget build(BuildContext context) { final s = S.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ const BottomSheetHandlerBar(), const SizedBox(height: 20), Text( s.lawViolation, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), ), const SizedBox(height: 8), SizedBox( width: MediaQuery.sizeOf(context).width * 0.7, child: Text( s.what_do_you_want_to_complaint_about, textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), ), const SizedBox(height: 24), ...tags.mapIndexed((index, element) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Checkbox( materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, activeColor: appTheme.blueA400, side: BorderSide(width: 2, color: tags[index].$1 ? appTheme.blueA400 : appTheme.blueGray), value: element.$1, onChanged: (isChecked) { setState(() { if (isChecked == null) return; tags[index] = (isChecked, element.$2); final activeTags = tags.where((elem) => elem.$1).map((e) => e.$2).toList(); context.read().setTags(activeTags); }); }, ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 8), Text( element.$2, style: TextStyles.textLSemibold.copyWith(color: appTheme.black), ), SizedBox( width: MediaQuery.sizeOf(context).width * 0.7, child: Text( descriptions[index], style: TextStyles.textSSemibold.copyWith(color: appTheme.lightGray600), ), ), ], ), ], ); }), const SizedBox(height: 20), const _ComplainButton(), ], ); } } class _ComplaintSentWidget extends StatelessWidget { const _ComplaintSentWidget(); @override Widget build(BuildContext context) { final s = S.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ const BottomSheetHandlerBar(), const SizedBox(height: 20), Text( s.complaint_sent, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), ), const SizedBox(height: 8), SizedBox( width: MediaQuery.sizeOf(context).width * 0.7, child: Text( s.complaint_sent_description, textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), ), const SizedBox(height: 24), CustomOutlinedButton( text: s.ok, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), buttonStyle: ButtonStyle( side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), ), onPressed: () { AppRouter.navigatorKey.currentContext?.pop(); }, ), ], ); } } class _ComplaintFailedWidget extends StatelessWidget { const _ComplaintFailedWidget(); @override Widget build(BuildContext context) { final s = S.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ const BottomSheetHandlerBar(), const SizedBox(height: 20), Text( s.could_not_send_complain, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), ), const SizedBox(height: 8), SizedBox( width: MediaQuery.sizeOf(context).width * 0.7, child: Text( s.please_try_again_later, textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), ), const SizedBox(height: 24), CustomOutlinedButton( text: s.ok, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), buttonStyle: ButtonStyle( side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), ), onPressed: () { AppRouter.navigatorKey.currentContext?.pop(); }, ), ], ); } } class _ComplainButton extends StatelessWidget { const _ComplainButton(); @override Widget build(BuildContext context) { final s = S.of(context); return BlocBuilder( builder: (context, state) { if (state.isLoading) { return const Loader(); } return CustomOutlinedButton( text: s.send_complain, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), buttonStyle: ButtonStyle( side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), ), onPressed: () async { await context.read().complain(); }, ); }, ); } } class _CategoryButton extends StatelessWidget { const _CategoryButton({required this.category, required this.onTap}); final ComplainType category; final void Function() onTap; @override Widget build(BuildContext context) { return InkWell( onTap: onTap, child: Ink( child: Row( children: [ Text( category.getTranslatedText(), style: TextStyles.textLSemibold.copyWith(color: appTheme.black), ), const Spacer(), SvgPicture.asset('assets/icons/right_arrow.svg'), ], ), ), ); } } enum ComplainType { spam, lawViolation, deception, violenceDndHostility, explicitImage; String getTranslatedText() => switch (this) { ComplainType.spam => S.current.spam, ComplainType.lawViolation => S.current.lawViolation, ComplainType.deception => S.current.deception, ComplainType.violenceDndHostility => S.current.violenceAndHostility, ComplainType.explicitImage => S.current.explicitImage, }; String getValue() => switch (this) { ComplainType.spam => 'spam', ComplainType.lawViolation => 'legalViolation', ComplainType.deception => 'fraud', ComplainType.violenceDndHostility => 'violenceAndHatred', ComplainType.explicitImage => 'explicitImage', }; }