import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hacki/blocs/auth/auth_bloc.dart'; import 'package:hacki/cubits/cubits.dart'; import 'package:hacki/extensions/extensions.dart'; import 'package:hacki/main.dart'; import 'package:hacki/models/models.dart'; import 'package:hacki/screens/item/models/models.dart'; import 'package:hacki/screens/item/widgets/widgets.dart'; import 'package:hacki/screens/screens.dart' show ItemScreen, ItemScreenArgs; import 'package:hacki/styles/styles.dart'; import 'package:share_plus/share_plus.dart'; extension StateExtension on State { void showSnackBar({ required String content, VoidCallback? action, String? label, }) { context.showSnackBar( content: content, action: action, label: label, ); } void showErrorSnackBar() => context.showErrorSnackBar(); Future? goToItemScreen({ required ItemScreenArgs args, bool forceNewScreen = false, }) { final bool splitViewEnabled = context.read().state.enabled; if (splitViewEnabled && !forceNewScreen) { context.read().updateItemScreenArgs(args); } else { return HackiApp.navigatorKey.currentState?.pushNamed( ItemScreen.routeName, arguments: args, ); } return Future.value(); } void onMoreTapped(Item item, Rect? rect) { HapticFeedback.lightImpact(); if (item.dead || item.deleted) { return; } final bool isBlocked = context.read().state.blocklist.contains(item.by); showModalBottomSheet( context: context, isScrollControlled: true, builder: (BuildContext context) { return SafeArea( child: MorePopupMenu( item: item, isBlocked: isBlocked, onLoginTapped: onLoginTapped, ), ); }, ).then((MenuAction? action) { if (action != null) { switch (action) { case MenuAction.upvote: break; case MenuAction.downvote: break; case MenuAction.fav: onFavTapped(item); break; case MenuAction.share: onShareTapped(item, rect); break; case MenuAction.flag: onFlagTapped(item); break; case MenuAction.block: onBlockTapped(item, isBlocked: isBlocked); break; case MenuAction.cancel: break; } } }); } void onFavTapped(Item item) { final FavCubit favCubit = context.read(); final bool isFav = favCubit.state.favIds.contains(item.id); if (isFav) { favCubit.removeFav(item.id); } else { favCubit.addFav(item.id); } } Future onShareTapped(Item item, Rect? rect) async { late final String? linkToShare; if (item.url.isNotEmpty) { linkToShare = await showModalBottomSheet( context: context, builder: (BuildContext context) { return Container( height: 140, color: Theme.of(context).canvasColor, child: Material( child: Column( children: [ ListTile( onTap: () => Navigator.pop(context, item.url), title: const Text('Link to article'), ), ListTile( onTap: () => Navigator.pop( context, 'https://news.ycombinator.com/item?id=${item.id}', ), title: const Text('Link to HN'), ), ], ), ), ); }, ); } else { linkToShare = 'https://news.ycombinator.com/item?id=${item.id}'; } if (linkToShare != null) { await Share.share( linkToShare, sharePositionOrigin: rect, ); } } void onFlagTapped(Item item) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Flag this comment?'), content: Text( 'Flag this comment posted by ${item.by}?', style: const TextStyle( color: Palette.grey, ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text( 'Cancel', ), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text( 'Yes', ), ), ], ); }, ).then((bool? yesTapped) { if (yesTapped ?? false) { context.read().add(AuthFlag(item: item)); showSnackBar(content: 'Comment flagged!'); } }); } void onBlockTapped(Item item, {required bool isBlocked}) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('${isBlocked ? 'Unblock' : 'Block'} this user?'), content: Text( 'Do you want to ${isBlocked ? 'unblock' : 'block'} ${item.by}' ' and ${isBlocked ? 'display' : 'hide'} ' 'comments posted by this user?', style: const TextStyle( color: Palette.grey, ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text( 'Cancel', ), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text( 'Yes', ), ), ], ); }, ).then((bool? yesTapped) { if (yesTapped ?? false) { if (isBlocked) { context.read().removeFromBlocklist(item.by); } else { context.read().addToBlocklist(item.by); } showSnackBar(content: 'User ${isBlocked ? 'unblocked' : 'blocked'}!'); } }); } void onLoginTapped() { showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return const LoginDialog(); }, ); } }