import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:jiffy/jiffy.dart'; import '../../../../api/marianumcloud/talk/actions/talk_actions.dart'; import '../../../../api/marianumcloud/talk/chat/richObjectStringProcessor.dart'; import '../../../../api/marianumcloud/talk/room/getRoomResponse.dart'; import '../../../../api/marianumcloud/talk/setReadMarker/setReadMarker.dart'; import '../../../../api/marianumcloud/talk/setReadMarker/setReadMarkerParams.dart'; import '../../../../model/account_data.dart'; import '../../../../state/app/modules/chat/bloc/chat_bloc.dart'; import '../../../../state/app/modules/chatList/bloc/chat_list_bloc.dart'; import '../../../../widget/async_action_button.dart'; import '../../../../widget/confirm_dialog.dart'; import '../../../../widget/debug/debug_tile.dart'; import '../../../../widget/user_avatar.dart'; import '../chat_view.dart'; import '../talk_navigator.dart'; class ChatTile extends StatefulWidget { final GetRoomResponseObject data; final bool disableContextActions; final bool hasDraft; const ChatTile({super.key, required this.data, this.disableContextActions = false, this.hasDraft = false}); @override State createState() => _ChatTileState(); } class _ChatTileState extends State { String? selfUsername; @override void initState() { super.initState(); AccountData().waitForPopulation().then((_) { if (!mounted) return; setState(() => selfUsername = AccountData().isPopulated() ? AccountData().getUsername() : null); }); } void _refreshList() => context.read().refresh(); Future _setCurrentAsRead() async { await SetReadMarker( widget.data.token, true, setReadMarkerParams: SetReadMarkerParams(lastReadMessage: widget.data.lastMessage.id), ).run(); if (!mounted) return; _refreshList(); } @override Widget build(BuildContext context) { final chatBloc = context.watch(); final isGroup = widget.data.type != GetRoomResponseObjectConversationType.oneToOne; final circleAvatar = UserAvatar(id: isGroup ? widget.data.token : widget.data.name, isGroup: isGroup); return ListTile( style: ListTileStyle.list, tileColor: chatBloc.state.data?.currentToken == widget.data.token && TalkNavigator.isSecondaryVisible(context) ? Theme.of(context).primaryColor.withAlpha(100) : null, leading: Stack( children: [ circleAvatar, Visibility( visible: widget.data.isFavorite, child: Positioned( right: 0, bottom: 0, child: Container( padding: const EdgeInsets.all(1), decoration: BoxDecoration( color: Theme.of(context).primaryColor.withAlpha(200), borderRadius: BorderRadius.circular(90.0), ), child: const Icon(Icons.star, color: Colors.amberAccent, size: 15), ), ), ) ], ), title: Row( mainAxisSize: MainAxisSize.min, children: [ Flexible(child: Text(widget.data.displayName, overflow: TextOverflow.ellipsis)), if (widget.hasDraft) ...[ const SizedBox(width: 5), const Icon(Icons.edit_outlined, size: 15), ], ], ), subtitle: Text( '${Jiffy.parseFromMillisecondsSinceEpoch(widget.data.lastMessage.timestamp * 1000).fromNow()}: ' '${RichObjectStringProcessor.parseToString(widget.data.lastMessage.message.replaceAll("\n", " "), widget.data.lastMessage.messageParameters)}', overflow: TextOverflow.ellipsis, ), trailing: widget.data.unreadMessages <= 0 ? null : Container( padding: const EdgeInsets.all(1), decoration: BoxDecoration( color: Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(30), ), constraints: const BoxConstraints(minWidth: 20, minHeight: 20), child: Text( '${widget.data.unreadMessages}', style: const TextStyle(color: Colors.white, fontSize: 15), textAlign: TextAlign.center, ), ), onTap: () { if (selfUsername == null) return; unawaited(_setCurrentAsRead()); final view = ChatView(room: widget.data, selfId: selfUsername!, avatar: circleAvatar); TalkNavigator.pushSplitView(context, view, overrideToSingleSubScreen: true); context.read().setToken(widget.data.token); }, onLongPress: () { if (widget.disableContextActions) return; showDialog(context: context, builder: (dialogCtx) => SimpleDialog( children: [ if (widget.data.unreadMessages > 0) AsyncListTile( leading: const Icon(Icons.mark_chat_read_outlined), title: const Text('Als gelesen markieren'), onPressed: _setCurrentAsRead, ) else AsyncListTile( leading: const Icon(Icons.mark_chat_unread_outlined), title: const Text('Als ungelesen markieren'), onPressed: () async { await SetReadMarker(widget.data.token, false).run(); if (mounted) _refreshList(); }, ), if (widget.data.isFavorite) AsyncListTile( leading: const Icon(Icons.stars_outlined), title: const Text('Von Favoriten entfernen'), onPressed: () async { await SetFavorite(widget.data.token, false).run(); if (mounted) _refreshList(); }, ) else AsyncListTile( leading: const Icon(Icons.star_outline), title: const Text('Zu Favoriten hinzufügen'), onPressed: () async { await SetFavorite(widget.data.token, true).run(); if (mounted) _refreshList(); }, ), ListTile( leading: const Icon(Icons.delete_outline), title: const Text('Konversation verlassen'), onTap: () { Navigator.of(dialogCtx).pop(); ConfirmDialog( title: 'Chat verlassen', content: 'Du benötigst ggf. eine Einladung um erneut beizutreten.', confirmButton: 'Verlassen', onConfirmAsync: () async { await LeaveRoom(widget.data.token).run(); if (mounted) _refreshList(); }, ).asDialog(context); }, ), DebugTile(dialogCtx).jsonData(widget.data.toJson()), ], )); }, ); } }