feat: marcar legenda com markdown, barra de ações nos posts do canal e limites de mensagem na modal
Some checks failed
Main Deploy Workflow / deploy_web (push) Has been cancelled
Main Deploy Workflow / deploy_playstore_internal (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
2026-09-14 19:18:09 -03:00
parent 9d69e833bd
commit 43e0dc177c
12 changed files with 244 additions and 810 deletions

View File

@@ -14,10 +14,12 @@ import 'package:tatchat/utils/adaptive_bottom_sheet.dart';
import 'package:tatchat/utils/date_time_extension.dart';
import 'package:tatchat/utils/file_description.dart';
import 'package:tatchat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:tatchat/utils/show_scaffold_dialog.dart';
import 'package:tatchat/utils/string_color.dart';
import 'package:tatchat/widgets/avatar.dart';
import 'package:tatchat/widgets/matrix.dart';
import 'package:tatchat/widgets/member_actions_popup_menu_button.dart';
import 'package:tatchat/widgets/share_scaffold_dialog.dart';
import 'package:flutter/services.dart';
import 'package:material_ui/material_ui.dart';
import 'package:matrix/matrix.dart';
@@ -247,8 +249,8 @@ class Message extends StatelessWidget {
child: Center(child: Icon(Icons.check_outlined)),
),
direction: AppSettings.swipeRightToLeftToReply.value
? SwipeDirection.endToStart
: SwipeDirection.startToEnd,
? SwipeDirection.startToEnd
: SwipeDirection.endToStart,
onSwipe: (_) => onSwipe(),
child: Container(
constraints: card
@@ -683,7 +685,7 @@ class Message extends StatelessWidget {
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
alignment: Alignment.bottomCenter,
child: !hasReactions
child: card || !hasReactions
? const SizedBox.shrink()
: Container(
alignment: card
@@ -699,6 +701,17 @@ class Message extends StatelessWidget {
child: MessageReactions(event, timeline),
),
),
if (card)
_PostActionBar(
event: event,
timeline: timeline,
hasReactions: hasReactions,
threadCount: threadChildren.length,
onAddReaction: () => onSelect(event),
onOpenThread: enterThread == null
? null
: () => enterThread(event.eventId),
),
Row(
mainAxisAlignment: card
? .start
@@ -990,7 +1003,7 @@ class Message extends StatelessWidget {
),
],
),
if (enterThread != null)
if (enterThread != null && !card)
AnimatedSize(
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
@@ -1177,3 +1190,115 @@ class __AnimateInState extends State<_AnimateIn> {
);
}
}
class _PostActionBar extends StatelessWidget {
final Event event;
final Timeline timeline;
final bool hasReactions;
final int threadCount;
final VoidCallback? onAddReaction;
final VoidCallback? onOpenThread;
const _PostActionBar({
required this.event,
required this.timeline,
required this.hasReactions,
required this.threadCount,
required this.onAddReaction,
required this.onOpenThread,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Theme.of(
context,
).colorScheme.surfaceContainerHighest.withAlpha(150),
border: Border(
top: BorderSide(
color: Theme.of(context).colorScheme.outlineVariant.withAlpha(120),
),
),
),
child: Row(
children: [
_BarAction(
icon: Icons.visibility_outlined,
label: '${event.receipts.length}',
),
Expanded(
child: Row(
children: [
if (hasReactions)
Flexible(
child: Align(
alignment: Alignment.centerLeft,
child: MessageReactions(event, timeline),
),
),
_BarAction(
icon: Icons.add_reaction_outlined,
onPressed: onAddReaction,
),
],
),
),
_BarAction(
icon: Icons.chat_bubble_outline,
label: '$threadCount',
onPressed: onOpenThread,
),
_BarAction(
icon: Icons.share_outlined,
onPressed: () {
showScaffoldDialog(
context: context,
builder: (context) => ShareScaffoldDialog(
items: [ContentShareItem(event.content.copy())],
),
);
},
),
],
),
);
}
}
class _BarAction extends StatelessWidget {
final IconData icon;
final String? label;
final VoidCallback? onPressed;
const _BarAction({required this.icon, this.label, this.onPressed});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return InkWell(
onTap: onPressed,
borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 6),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 18, color: theme.colorScheme.onSurfaceVariant),
if (label != null) ...[
const SizedBox(width: 4),
Text(
label!,
style: TextStyle(
color: theme.colorScheme.onSurfaceVariant,
fontSize: 12,
),
),
],
],
),
),
);
}
}