chat bubble time

This commit is contained in:
zoe 2022-09-29 19:44:01 +02:00
parent 2f32510bce
commit d7a35beb3a
4 changed files with 231 additions and 37 deletions

View File

@ -26,6 +26,7 @@ Future<MapEntry<int, PostContext?>> getContextForPost(PostModel model) async {
if (r.statusCode != 200) { if (r.statusCode != 200) {
return MapEntry(r.statusCode, null); return MapEntry(r.statusCode, null);
} }
print(r.body);
final json = jsonDecode(r.body); final json = jsonDecode(r.body);
List<dynamic> ancestors = json["ancestors"]!; List<dynamic> ancestors = json["ancestors"]!;

View File

@ -0,0 +1,159 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:loris/business_logic/chat/chat.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/partials/post.dart';
import 'package:loris/partials/post_text_renderer.dart';
import 'package:loris/themes/themes.dart' as themes;
class Chatwindow extends StatefulWidget {
const Chatwindow({super.key, required this.model});
final ConversationModel model;
@override
State<Chatwindow> createState() => _ChatwindowState();
}
class _ChatwindowState extends State<Chatwindow> {
List<PostModel> models = [];
Future<void> loadContext(PostModel m) async {
final c = await getContextForPost(m);
if (c.key == 200 && mounted) {
setState(() {
print(c.value!.ancestors);
models = c.value!.ancestors +
[widget.model.lastStatus!] +
c.value!.descendants;
});
print(models);
}
}
@override
void initState() {
if (widget.model.lastStatus != null) loadContext(widget.model.lastStatus!);
super.initState();
}
@override
Widget build(BuildContext context) {
return BackdropFilter(
filter:
ImageFilter.blur(sigmaX: 10, sigmaY: 10, tileMode: TileMode.mirror),
child: SimpleDialog(
contentPadding: const EdgeInsets.all(0),
backgroundColor: Theme.of(context).colorScheme.surface,
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
borderRadius: const BorderRadius.all(themes.defaultRadius)),
width: global.getWidth(context),
constraints: global.getConstraints(context),
height: MediaQuery.of(context).size.height * 2 / 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Flexible(
child: ListView.separated(
shrinkWrap: true,
itemBuilder: (context, index) =>
DirectMessage(model: models[index]),
separatorBuilder: (context, index) => const Divider(
color: Colors.transparent,
height: themes.defaultSeperatorHeight,
),
itemCount: models.length),
),
Container(
padding: themes.defaultInsideMargins,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.only(
bottomLeft: themes.defaultRadius,
bottomRight: themes.defaultRadius,
topLeft: Radius.circular(0),
topRight: Radius.circular(0)),
border: Border.fromBorderSide(BorderSide(
color: Theme.of(context).colorScheme.secondary,
width: 2,
)),
),
child: TextField(
minLines: 1,
maxLines: 4,
style: Theme.of(context).textTheme.bodyMedium,
expands: false,
decoration: InputDecoration(
suffix: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.attach_file)),
IconButton(
onPressed: () {},
icon: const Icon(Icons.send),
),
],
),
),
),
),
],
),
)
],
));
}
}
class DirectMessage extends StatefulWidget {
const DirectMessage({super.key, required this.model});
final PostModel model;
@override
State<DirectMessage> createState() => _DirectMessageState();
}
class _DirectMessageState extends State<DirectMessage> {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(themes.defaultSeperatorHeight * 2),
child: Align(
alignment: (widget.model.identity ==
"${widget.model.account.acct}@${global.settings!.identities[widget.model.identity]!.instanceUrl}")
? Alignment.centerRight
: Alignment.centerLeft,
child: LayoutBuilder(builder: ((ctx, constraints) {
return Container(
constraints: BoxConstraints(maxWidth: constraints.maxWidth * 0.96),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
border: Border.all(
color: Theme.of(context).colorScheme.secondary,
width: 2,
),
borderRadius: const BorderRadius.all(themes.defaultRadius)),
padding: themes.defaultInsideMargins,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DisplayName(account: widget.model.account),
PostTextRenderer(input: widget.model.content),
],
),
);
})),
),
);
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:localization/localization.dart'; import 'package:localization/localization.dart';
import 'package:loris/business_logic/chat/chat.dart'; import 'package:loris/business_logic/chat/chat.dart';
import 'package:loris/dialogues/chatwindow.dart';
import 'package:loris/partials/loadingbox.dart'; import 'package:loris/partials/loadingbox.dart';
import 'package:loris/partials/post_text_renderer.dart'; import 'package:loris/partials/post_text_renderer.dart';
import 'package:loris/themes/themes.dart' as themes; import 'package:loris/themes/themes.dart' as themes;
@ -62,7 +63,15 @@ class _ChatState extends State<Chat> {
if (index >= conversations.length) return const LoadingBox(); if (index >= conversations.length) return const LoadingBox();
return ConversationButton( return ConversationButton(
model: conversations[index], model: conversations[index],
onPressed: () {}, onTap: () {
showDialog(
barrierColor: Colors.transparent,
context: context,
builder: (context) => Chatwindow(
model: conversations[index],
),
);
},
); );
}), }),
separatorBuilder: (context, index) => const Divider( separatorBuilder: (context, index) => const Divider(
@ -86,53 +95,59 @@ class ConversationButton extends StatelessWidget {
const ConversationButton({ const ConversationButton({
super.key, super.key,
required this.model, required this.model,
required this.onPressed, required this.onTap,
}); });
final ConversationModel model; final ConversationModel model;
final void Function() onPressed; final void Function() onTap;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Align(
decoration: BoxDecoration( child: Container(
borderRadius: const BorderRadius.all(themes.defaultRadius), decoration: BoxDecoration(
border: Border.fromBorderSide(BorderSide( borderRadius: const BorderRadius.all(themes.defaultRadius),
color: Theme.of(context).colorScheme.secondary, width: 2)), color: Theme.of(context).colorScheme.surface,
), ),
margin: const EdgeInsets.fromLTRB(themes.defaultSeperatorHeight * 2, 0, margin: const EdgeInsets.fromLTRB(themes.defaultSeperatorHeight * 2, 0,
themes.defaultSeperatorHeight * 2, 0), themes.defaultSeperatorHeight * 2, 0),
width: global.getWidth(context), width: global.getWidth(context),
constraints: global.getConstraints(context), constraints: global.getConstraints(context),
child: InkWell( child: Material(
borderRadius: const BorderRadius.all(themes.defaultRadius), borderOnForeground: true,
onTap: onPressed, shape: RoundedRectangleBorder(
child: Ink(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(themes.defaultRadius), borderRadius: const BorderRadius.all(themes.defaultRadius),
color: Theme.of(context).colorScheme.surface, side: BorderSide(
color: Theme.of(context).colorScheme.secondary, width: 2),
), ),
child: Padding( child: InkWell(
padding: themes.defaultInsideMargins, borderRadius: const BorderRadius.all(themes.defaultRadius),
child: Column( onTap: onTap,
crossAxisAlignment: CrossAxisAlignment.stretch, child: Padding(
children: [ padding: themes.defaultInsideMargins,
if (model.unread) child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const Icon(Icons.mark_chat_unread), ElevatedButton.icon(
SelectableText("unread".i18n()) onPressed: onTap,
icon: const Icon(Icons.open_in_full),
label: Text("show".i18n())),
if (model.unread) const UnreadIndicator(),
], ],
), ),
Wrap( Wrap(
alignment: WrapAlignment.spaceBetween, alignment: WrapAlignment.spaceBetween,
children: [ children: [
if (model.unread) SelectableText(model.getAccountsString()), SelectableText(model.getAccountsString()),
SelectableText("${"you-are".i18n()} ${model.identity}"), SelectableText("${"you-are".i18n()} ${model.identity}"),
], ],
), ),
if (model.lastStatus != null) if (model.lastStatus != null)
PostTextRenderer(input: model.lastStatus!.content), PostTextRenderer(input: model.lastStatus!.content),
], ],
),
), ),
), ),
), ),
@ -140,3 +155,22 @@ class ConversationButton extends StatelessWidget {
); );
} }
} }
class UnreadIndicator extends StatefulWidget {
const UnreadIndicator({super.key});
@override
State<UnreadIndicator> createState() => _UnreadIndicatorState();
}
class _UnreadIndicatorState extends State<UnreadIndicator> {
@override
Widget build(BuildContext context) {
return Row(
children: [
const Icon(Icons.mark_unread_chat_alt),
SelectableText("unread".i18n())
],
);
}
}