import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:localization/localization.dart'; import 'package:loris/business_logic/network_tools/get_post_from_url.dart'; import 'package:loris/business_logic/posts/posts.dart'; import 'package:loris/business_logic/timeline/timeline.dart'; import 'package:loris/global.dart' as global; import 'package:loris/themes/themes.dart' as themes; import '../partials/post.dart'; class FullPostView extends StatefulWidget { const FullPostView({ super.key, required this.originPostModel, this.identities, this.hidden = true, this.ancestors, this.descendants, this.forceSensitive = false, }); final PostModel originPostModel; final Map? identities; final bool hidden; final List? ancestors; final List? descendants; final bool forceSensitive; @override State createState() => _FullPostViewState(); } class _FullPostViewState extends State { List ancestors = []; List descendants = []; Map identities = {}; String activeIdentity = ""; int idsChecked = 1; bool sensitive = false; void loadIdentities() async { global.settings!.identities.forEach((key, value) async { if (!identities.containsKey(key)) { final r = await getPostFromUrl(key, widget.originPostModel.uri); if (r.values.first != null && mounted) { setState(() { identities.addAll({key: r.values.first!}); }); } if (mounted) { setState(() { idsChecked++; }); } } }); } void loadPosts() async { if (widget.ancestors == null || widget.descendants == null) { final r = await getContextForPost(widget.originPostModel); if (r.value != null && mounted) { setState(() { ancestors = r.value!.ancestors; descendants = r.value!.descendants; }); } for (var a in ancestors) { if (a.sensitive) { sensitive = true; } } for (var d in descendants) { if (d.sensitive) { sensitive = true; } } } } @override void initState() { if (widget.ancestors != null) { ancestors = widget.ancestors!; } if (widget.descendants != null) { descendants = widget.descendants!; } sensitive = widget.originPostModel.sensitive; if (widget.identities != null) { idsChecked = global.settings!.identities.length; } identities = widget.identities ?? {}; identities.addAll({ widget.originPostModel.identity: widget.originPostModel, }); activeIdentity = widget.originPostModel.identity; loadPosts(); loadIdentities(); super.initState(); } @override Widget build(BuildContext context) { List> dropdownButtons = []; identities.forEach((key, value) { dropdownButtons.add( DropdownMenuItem( alignment: Alignment.center, value: key, child: Text(key, style: Theme.of(context).textTheme.bodyMedium), ), ); }); return BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10, tileMode: TileMode.mirror), child: SimpleDialog( contentPadding: const EdgeInsets.fromLTRB(0, 24, 0, 0), children: [ global.settings!.identities.length > idsChecked ? Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ SelectableText( "${"post-found-on".i18n()} $idsChecked ${idsChecked == 1 ? "instance".i18n() : "instances".i18n()}", textAlign: TextAlign.center, ), const LinearProgressIndicator(), ], ) : Padding( padding: themes.defaultInsideMargins, child: Wrap( alignment: WrapAlignment.spaceAround, crossAxisAlignment: WrapCrossAlignment.center, children: [ DropdownButtonHideUnderline( child: DropdownButton( alignment: Alignment.center, value: activeIdentity, style: Theme.of(context).textTheme.bodyMedium, iconEnabledColor: Theme.of(context).colorScheme.onSurface, items: dropdownButtons, onChanged: (value) { setState(() { Navigator.of(context).pop(); showDialog( barrierColor: Colors.transparent, context: context, builder: (context) => FullPostView( originPostModel: identities[value]!, identities: identities, ), ); }); loadPosts(); }, ), ), if (sensitive || widget.forceSensitive) ElevatedButton.icon( onPressed: () { setState(() { Navigator.of(context).pop(); showDialog( barrierColor: Colors.transparent, context: context, builder: (context) => FullPostView( originPostModel: widget.originPostModel, hidden: !widget.hidden, identities: identities, ancestors: ancestors, descendants: descendants, forceSensitive: true, ), ); }); }, icon: Icon(widget.hidden ? Icons.visibility : Icons.visibility_off), label: Text( widget.hidden ? "show".i18n() : "hide".i18n(), ), ), ], ), ), Container( constraints: BoxConstraints( maxHeight: MediaQuery.of(context).size.height * 2 / 3, maxWidth: global.getConstraints(context).maxWidth), width: global.getWidth(context), child: SingleChildScrollView( child: Padding( padding: themes.defaultMargins, child: SingleFullPostDisplay( ancestors: ancestors, descendants: descendants, hidden: widget.hidden, level: 0, model: identities[activeIdentity]!.reblog ?? identities[activeIdentity]!, ), ), ), ) ], ), ); } } class SingleFullPostDisplay extends StatelessWidget { const SingleFullPostDisplay({ super.key, required this.level, required this.model, required this.ancestors, required this.descendants, this.hidden = true, }); final int level; final PostModel model; final List ancestors; final List descendants; final bool hidden; @override Widget build(BuildContext context) { List ancestorWidgets = ancestors .map( (e) => Post(model: e, hideSensitive: hidden), ) .toList(); List descendantsWidgets = []; // seems most efficient // considering that lists aren't v long for (var element in descendants) { if (element.inReplyTo == model.id) { descendantsWidgets.add(SingleFullPostDisplay( level: level + 1, model: element, ancestors: const [], descendants: descendants, hidden: hidden, )); } } List c = []; c.addAll(ancestorWidgets); c.add(Post( model: model, hideSensitive: hidden, )); c.addAll(descendantsWidgets); return Container( padding: EdgeInsets.fromLTRB( level == 0 ? 0 : 4, themes.defaultSeperatorHeight, level == 0 ? 0 : 4, themes.defaultSeperatorHeight), decoration: BoxDecoration( border: level == 0 ? const Border() : Border( left: BorderSide( width: 4, color: level.isEven ? Theme.of(context).colorScheme.secondary : Theme.of(context).colorScheme.primary, ), ), ), child: Column(children: c)); } }