Files
eatvio_app/lib/core/widgets/custom_popup.dart

230 lines
8.5 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/enums/complained_content.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/utils/toasts.dart';
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
import 'package:eatvio_app/features/feed/models/recipes_model.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
import 'package:eatvio_app/features/menu/presentation/blocked_user_cubit/blocked_users_cubit.dart';
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart';
import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:share_plus/share_plus.dart';
class CustomPopup extends StatelessWidget {
final bool isAuthor;
final ComplainedContent? complainedContentType;
final String path;
final String? slug;
final int? id;
final FeedBlogPostModel? feedBlogPostModel;
final Recipe? recipe;
final Diet? diet;
final String userSlug;
final VoidCallback? onPostsChanged;
const CustomPopup({
super.key,
required this.isAuthor,
this.complainedContentType,
required this.path,
this.id,
this.slug,
this.feedBlogPostModel,
this.recipe,
this.diet,
required this.userSlug,
this.onPostsChanged,
});
@override
Widget build(BuildContext context) {
final s = S.of(context);
return GestureDetector(
onTap: () async {
final RenderBox button = context.findRenderObject() as RenderBox;
final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
final Offset position = button.localToGlobal(Offset.zero, ancestor: overlay);
await showMenu(
context: context,
position: RelativeRect.fromLTRB(
position.dx,
position.dy + button.size.height,
position.dx + button.size.width,
position.dy,
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
color: Colors.white,
constraints: const BoxConstraints(minWidth: 260),
surfaceTintColor: Colors.transparent,
elevation: 2,
items: _buildMenuItems(s, context),
);
},
child: const Icon(
Icons.more_horiz_rounded,
),
);
}
List<PopupMenuEntry> _buildMenuItems(S s,BuildContext context) {
final entries = <PopupMenuEntry>[];
void addItem(String icon, String text, Function() onTap) {
entries.add(_buildCompactItem(icon: icon, text: text, onTap: onTap));
entries.add(_buildDivider());
}
if (isAuthor) {
addItem('assets/icons/copy2.svg', 'Скопировать ссылку', () {
Clipboard.setData(ClipboardData(text: '${sl<AppConfig>().baseUrl}/ru/$path'));
showInfoToast(s.link_was_copied);
});
addItem('assets/icons/share2.svg', 'Поделиться', () {
final box = context.findRenderObject() as RenderBox?;
SharePlus.instance.share(
ShareParams(
uri: Uri.parse(
'${sl<AppConfig>().baseUrl}/ru/$path',
),
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
),
);
});
if (complainedContentType == ComplainedContent.posts) {
addItem('assets/icons/edit_paint.svg', 'Редактировать', () async {
if (complainedContentType == ComplainedContent.posts) {
await GoRouter.of(context).pushNamed('blogPostCreateScreen', extra: feedBlogPostModel);
onPostsChanged?.call();
}
});
}
addItem('assets/icons/red_trash.svg', 'Удалить', () async {
if (complainedContentType == ComplainedContent.posts) {
final result = await sl<BlogPostCreateCubit>().deleteBlogPost(id!);
if (!result && context.mounted) {
showErrorDialog(context, title: S.current.could_not_delete_blog_post);
return;
}
onPostsChanged?.call();
ProfileCubit.myProfileCubit?.reloadBlogPosts();
if (context.mounted) {
try {
context.read<FeedCubit>().loadFeedBlogPostList();
} catch (_) {}
}
showSuccessToast('Пост удален');
} else if (complainedContentType == ComplainedContent.recipe) {
final result = await sl<RecipesCubit>().deleteRecipe(slug!);
if (!result && context.mounted) {
showErrorDialog(context, title: 'Не удалось удалить рецепт');
return;
}
showSuccessToast('Рецепт удален, обновите ленту');
} else if (complainedContentType == ComplainedContent.diet) {
final result = await sl<DietsCubit>().deleteDiet(id!);
if (!result && context.mounted) {
showErrorDialog(context, title: 'Не удалось удалить диету');
return;
}
showSuccessToast('Диета удалена, обновите ленту');
} else if (complainedContentType == ComplainedContent.plan) {
final result = await sl<MyPlansCubit>().deletePlan(slug!);
if (!result && context.mounted) {
showErrorDialog(context, title: 'Не удалось удалить план');
return;
}
showSuccessToast('План удален, обновите ленту');
}
});
} else {
addItem('assets/icons/copy2.svg', 'Скопировать ссылку', () {
Clipboard.setData(ClipboardData(text: '${sl<AppConfig>().baseUrl}/ru/$path'));
showInfoToast(s.link_was_copied);
});
addItem('assets/icons/share2.svg', 'Поделиться', () {
final box = context.findRenderObject() as RenderBox?;
SharePlus.instance.share(
ShareParams(
uri: Uri.parse(
'${sl<AppConfig>().baseUrl}/ru/$path',
),
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
),
);
});
addItem('assets/icons/complain.svg', 'Пожаловаться', () {
if (complainedContentType != null) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => ComplainingBottomSheet(
complainedContentType: complainedContentType!,
id: id,
slug: slug,
),
);
}
});
addItem(
'assets/icons/complain.svg',
'Заблокировать автора',
() {
sl<BlockedUsersCubit>().blockUser(userSlug);
},
);
}
if (entries.isNotEmpty && entries.last is PopupMenuItem) {
entries.removeLast();
}
return entries;
}
PopupMenuItem _buildCompactItem({required String icon, required String text, required Function() onTap}) {
return PopupMenuItem(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
height: 36,
onTap: onTap,
child: SizedBox(
width: double.infinity,
child: Row(
children: [
Text(text, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
const Spacer(),
SvgPicture.asset(icon),
],
),
),
);
}
PopupMenuItem _buildDivider() {
return PopupMenuItem(
enabled: false,
height: 1,
padding: EdgeInsets.zero,
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 12),
height: 1,
color: appTheme.dividerColor,
),
);
}
}