From 756deea82c789eead6ba8137b30ff3807f39f17d Mon Sep 17 00:00:00 2001 From: zoe Date: Sat, 1 Oct 2022 13:00:00 +0200 Subject: [PATCH] replace conversations page with conversations popup --- lib/dialogues/conversations.dart | 208 +++++++++++++++++++++++++++++++ lib/pages/settings/account.dart | 34 +++-- 2 files changed, 235 insertions(+), 7 deletions(-) create mode 100644 lib/dialogues/conversations.dart diff --git a/lib/dialogues/conversations.dart b/lib/dialogues/conversations.dart new file mode 100644 index 0000000..c9f143b --- /dev/null +++ b/lib/dialogues/conversations.dart @@ -0,0 +1,208 @@ +import 'package:flutter/material.dart'; +import 'package:localization/localization.dart'; +import 'package:loris/business_logic/chat/chat.dart'; +import 'package:loris/dialogues/full_post_view.dart'; +import 'package:loris/dialogues/profile_view.dart'; +import 'package:loris/partials/loadingbox.dart'; +import 'package:loris/partials/post.dart'; +import 'package:loris/partials/post_text_renderer.dart'; +import 'package:loris/themes/themes.dart' as themes; +import 'package:loris/global.dart' as global; + +class Chat extends StatefulWidget { + const Chat({super.key}); + + @override + State createState() => _ChatState(); +} + +class _ChatState extends State { + List conversations = []; + // map that stores max ids for each identity + Map maxIds = {}; + final scrollController = ScrollController(); + bool loading = false; + + // loads more conversations and properly stores all ids + Future updateConversations() async { + if (loading) return; + loading = true; + final models = await getAllConversationModels(maxIds); + if (!mounted) return; + setState(() { + conversations.addAll(models.models); + maxIds = models.maxIds; + }); + loading = false; + } + + @override + void initState() { + updateConversations(); + scrollController.addListener(() { + if (scrollController.position.maxScrollExtent - scrollController.offset < + MediaQuery.of(context).size.height) { + updateConversations(); + } + }); + super.initState(); + } + + @override + void dispose() { + scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SimpleDialog( + contentPadding: const EdgeInsets.all(0), + children: [ + Container( + constraints: global.getConstraints(context), + width: global.getWidth(context), + height: MediaQuery.of(context).size.height * 2 / 3, + child: Column( + children: [ + Expanded( + child: ListView.separated( + controller: scrollController, + shrinkWrap: true, + itemBuilder: ((context, index) { + if (index >= conversations.length) { + return const LoadingBox(); + } + return ConversationButton( + model: conversations[index], + onTap: () { + showDialog( + barrierColor: Colors.transparent, + context: context, + builder: (context) { + final con = conversations[index]; + if (con.lastStatus != null) { + return FullPostView( + originPostModel: con.lastStatus!); + } + return ProfileView(model: con.accounts.first); + }); + }, + ); + }), + separatorBuilder: (context, index) => const Divider( + height: themes.defaultSeperatorHeight, + color: Colors.transparent, + ), + itemCount: conversations.length + 1), + ), + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: Theme.of(context).colorScheme.primary, + width: 2))), + ), + ], + ), + ), + ], + ); + } +} + +class ConversationButton extends StatelessWidget { + const ConversationButton({ + super.key, + required this.model, + required this.onTap, + }); + final ConversationModel model; + final void Function() onTap; + + @override + Widget build(BuildContext context) { + final List people = []; + for (var p in model.accounts) { + people.add(DisplayName(account: p)); + } + return Align( + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(themes.defaultRadius), + color: Theme.of(context).colorScheme.surface, + ), + margin: const EdgeInsets.fromLTRB(themes.defaultSeperatorHeight * 2, 0, + themes.defaultSeperatorHeight * 2, 0), + width: global.getWidth(context), + constraints: global.getConstraints(context), + child: Material( + borderOnForeground: true, + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(themes.defaultRadius), + side: BorderSide( + color: Theme.of(context).colorScheme.secondary, width: 2), + ), + child: InkWell( + borderRadius: const BorderRadius.all(themes.defaultRadius), + onTap: onTap, + child: Padding( + padding: themes.defaultInsideMargins, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: people + + [ + Divider( + color: Theme.of(context).hintColor, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ElevatedButton.icon( + onPressed: onTap, + icon: const Icon(Icons.open_in_full), + label: Text("show".i18n())), + if (model.unread) const UnreadIndicator(), + ], + ), + Wrap( + alignment: WrapAlignment.spaceBetween, + children: [ + SelectableText(model.getAccountsString()), + SelectableText( + "${"you-are".i18n()} ${model.identity}"), + ], + ), + if (model.lastStatus != null) + PostTextRenderer( + input: model.lastStatus!.content, + identityName: model.identity, + ), + ], + ), + ), + ), + ), + ), + ); + } +} + +class UnreadIndicator extends StatefulWidget { + const UnreadIndicator({super.key}); + + @override + State createState() => _UnreadIndicatorState(); +} + +class _UnreadIndicatorState extends State { + @override + Widget build(BuildContext context) { + return Row( + children: [ + const Icon(Icons.mark_unread_chat_alt), + SelectableText("unread".i18n()) + ], + ); + } +} diff --git a/lib/pages/settings/account.dart b/lib/pages/settings/account.dart index 8d96a0e..314e6b0 100644 --- a/lib/pages/settings/account.dart +++ b/lib/pages/settings/account.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:localization/localization.dart'; +import 'package:loris/dialogues/conversations.dart'; import 'package:loris/dialogues/followreqs.dart'; import '../../global.dart' as global; @@ -15,6 +16,7 @@ class AccountSettings extends StatelessWidget { } children.add(const NewAccountButton()); children.add(const FollowreqButton()); + children.add(const ConversationButton()); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: children, @@ -82,12 +84,30 @@ class FollowreqButton extends StatelessWidget { @override Widget build(BuildContext context) { return TextButton.icon( - onPressed: (() => showDialog( - barrierColor: Colors.transparent, - context: context, - builder: (context) => const FollowReqScreen(), - )), - icon: const Icon(Icons.check), - label: Text("follow-requests".i18n())); + onPressed: (() => showDialog( + barrierColor: Colors.transparent, + context: context, + builder: (context) => const FollowReqScreen(), + )), + icon: const Icon(Icons.check), + label: Text( + "follow-requests".i18n(), + ), + ); + } +} + +class ConversationButton extends StatelessWidget { + const ConversationButton({super.key}); + + @override + Widget build(BuildContext context) { + return TextButton.icon( + onPressed: () => showDialog( + context: context, + builder: (context) => Chat(), + ), + icon: const Icon(Icons.chat), + label: Text("chat".i18n())); } }