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) {
return MapEntry(r.statusCode, null);
}
print(r.body);
final json = jsonDecode(r.body);
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:localization/localization.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/post_text_renderer.dart';
import 'package:loris/themes/themes.dart' as themes;
@ -62,7 +63,15 @@ class _ChatState extends State<Chat> {
if (index >= conversations.length) return const LoadingBox();
return ConversationButton(
model: conversations[index],
onPressed: () {},
onTap: () {
showDialog(
barrierColor: Colors.transparent,
context: context,
builder: (context) => Chatwindow(
model: conversations[index],
),
);
},
);
}),
separatorBuilder: (context, index) => const Divider(
@ -86,53 +95,59 @@ class ConversationButton extends StatelessWidget {
const ConversationButton({
super.key,
required this.model,
required this.onPressed,
required this.onTap,
});
final ConversationModel model;
final void Function() onPressed;
final void Function() onTap;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(themes.defaultRadius),
border: Border.fromBorderSide(BorderSide(
color: Theme.of(context).colorScheme.secondary, width: 2)),
),
margin: const EdgeInsets.fromLTRB(themes.defaultSeperatorHeight * 2, 0,
themes.defaultSeperatorHeight * 2, 0),
width: global.getWidth(context),
constraints: global.getConstraints(context),
child: InkWell(
borderRadius: const BorderRadius.all(themes.defaultRadius),
onTap: onPressed,
child: Ink(
decoration: BoxDecoration(
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),
color: Theme.of(context).colorScheme.surface,
side: BorderSide(
color: Theme.of(context).colorScheme.secondary, width: 2),
),
child: Padding(
padding: themes.defaultInsideMargins,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (model.unread)
child: InkWell(
borderRadius: const BorderRadius.all(themes.defaultRadius),
onTap: onTap,
child: Padding(
padding: themes.defaultInsideMargins,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Icon(Icons.mark_chat_unread),
SelectableText("unread".i18n())
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: [
if (model.unread) SelectableText(model.getAccountsString()),
SelectableText("${"you-are".i18n()} ${model.identity}"),
],
),
if (model.lastStatus != null)
PostTextRenderer(input: model.lastStatus!.content),
],
Wrap(
alignment: WrapAlignment.spaceBetween,
children: [
SelectableText(model.getAccountsString()),
SelectableText("${"you-are".i18n()} ${model.identity}"),
],
),
if (model.lastStatus != null)
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())
],
);
}
}