import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:loris/business_logic/network_tools/get_post_from_url.dart'; import 'package:loris/business_logic/timeline/timeline.dart'; import '../business_logic/interactions/interactions.dart' as interactions; import 'package:loris/global.dart' as global; class InteractionButton extends StatefulWidget { const InteractionButton( {required this.model, required this.type, Key? key, this.extended = false}) : super(key: key); final interactions.InteractionType type; final PostModel model; final bool extended; @override State createState() => _InteractionButtonState(); } class _InteractionButtonState extends State { IconData icon = Icons.question_mark; String idkey = global.settings!.activeIdentity; bool active = false; bool busy = false; bool success = false; // user is logged into multiple accounts // decides if the button has been clicked already bool isActive(PostModel post) { switch (widget.type) { case interactions.InteractionType.favorite: return widget.model.favourited; case interactions.InteractionType.reblog: return widget.model.reblogged; } } @override void initState() { active = isActive(widget.model); icon = active ? widget.type.revokeIcon : widget.type.icon; super.initState(); } Future sendRequest({ required String id, bool fromUrl = false, }) async { if (!busy) { setState(() { busy = true; }); int status = fromUrl ? await interactions.makeFullInteraction( id, widget.model.originalId, widget.model.uri, widget.type, revoke: active, ) : await interactions.makeInteractionFromId( id, widget.model.originalId, widget.type, revoke: active, ); setState(() { busy = false; }); if (status == 200 && mounted) { setState(() { active = !active; icon = active ? widget.type.revokeIcon : widget.type.icon; }); showSuccess(); } else { await showError(status); } } } Future showError(int status) async { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("error: $status"))); setState(() { icon = Icons.dangerous; }); await Future.delayed(const Duration(seconds: 1)); setState(() { icon = active ? widget.type.revokeIcon : widget.type.icon; }); } Future> updateIdentities() async { Map idList = {}; for (int i = 0; i < global.settings!.identities.length; i++) { final Map post = await getPostFromUrl( global.settings!.identities.keys.toList()[i], widget.model.uri); if (post.keys.first == 200) { idList.addAll({ global.settings!.identities.keys.toList()[i]: post[post.keys.first] }); } } return idList; } Future showSuccess() async { setState(() { success = true; }); await Future.delayed(const Duration(seconds: 1)); setState(() { success = false; }); } @override Widget build(BuildContext context) { if (!widget.model.visibility.boostable && widget.type == interactions.InteractionType.reblog) { return const Icon(Icons.lock); } if (success) { return const Icon(Icons.check); } if (busy) { return Center( heightFactor: 1, widthFactor: 1, child: SizedBox( height: Theme.of(context).iconTheme.size, width: Theme.of(context).iconTheme.size, child: const CircularProgressIndicator(), ), ); } if (global.settings!.identities.length == 1 || !widget.extended) { return IconButton( tooltip: widget.type.name, onPressed: () async { await sendRequest( id: widget.model.identity, ); }, icon: Icon(icon), ); } return IconButton( onPressed: () async { setState(() { busy = true; }); final idList = await updateIdentities(); setState(() { busy = false; }); await showModalBottomSheet( context: context, builder: ((context) { List c = [ SelectableText( widget.type.name, style: Theme.of(context).textTheme.displayLarge, ) ]; idList.forEach( (key, value) { if (value != null) { c.add( TextButton.icon( onPressed: () async { Navigator.of(context).pop(); setState(() { busy = true; }); final result = await interactions.makeInteractionFromId( key, value.id, widget.type, revoke: isActive(value), ); setState(() { busy = false; }); if (result != 200) { showError(result); } else { showSuccess(); } }, icon: Icon( isActive(value) ? widget.type.revokeIcon : widget.type.icon, ), label: Text(key), ), ); } }, ); return Column( mainAxisAlignment: MainAxisAlignment.center, children: c, ); })); }, icon: Icon(icon)); } }