193 lines
5.2 KiB
Dart
193 lines
5.2 KiB
Dart
import "dart:async";
|
|
|
|
import "package:moxxyv2/ui/constants.dart";
|
|
import "package:moxxyv2/ui/widgets/avatar.dart";
|
|
import "package:moxxyv2/ui/widgets/chat/typing.dart";
|
|
import "package:moxxyv2/shared/helpers.dart";
|
|
import "package:moxxyv2/shared/constants.dart";
|
|
|
|
import "package:flutter/material.dart";
|
|
import "package:badges/badges.dart";
|
|
|
|
class ConversationsListRow extends StatefulWidget {
|
|
final String avatarUrl;
|
|
final String name;
|
|
final String lastMessageBody;
|
|
final int unreadCount;
|
|
final double maxTextWidth;
|
|
final int lastChangeTimestamp;
|
|
final bool update; // Should a timer run to update the timestamp
|
|
final bool typingIndicator;
|
|
|
|
const ConversationsListRow(
|
|
this.avatarUrl,
|
|
this.name,
|
|
this.lastMessageBody,
|
|
this.unreadCount,
|
|
this.maxTextWidth,
|
|
this.lastChangeTimestamp,
|
|
this.update, {
|
|
this.typingIndicator = false,
|
|
Key? key
|
|
}
|
|
) : super(key: key);
|
|
|
|
@override
|
|
_ConversationsListRowState createState() => _ConversationsListRowState(
|
|
avatarUrl,
|
|
name,
|
|
lastMessageBody,
|
|
unreadCount,
|
|
maxTextWidth,
|
|
lastChangeTimestamp,
|
|
update,
|
|
typingIndicator: typingIndicator
|
|
);
|
|
}
|
|
|
|
class _ConversationsListRowState extends State<ConversationsListRow> {
|
|
final String avatarUrl;
|
|
final String name;
|
|
final String lastMessageBody;
|
|
final int unreadCount;
|
|
final double maxTextWidth;
|
|
final int lastChangeTimestamp;
|
|
final bool update; // Should a timer run to update the timestamp
|
|
final bool typingIndicator;
|
|
|
|
late String _timestampString;
|
|
late Timer? _updateTimer;
|
|
|
|
_ConversationsListRowState(
|
|
this.avatarUrl,
|
|
this.name,
|
|
this.lastMessageBody,
|
|
this.unreadCount,
|
|
this.maxTextWidth,
|
|
this.lastChangeTimestamp,
|
|
this.update, {
|
|
this.typingIndicator = false
|
|
}
|
|
) {
|
|
final _now = DateTime.now().millisecondsSinceEpoch;
|
|
|
|
_timestampString = formatConversationTimestamp(
|
|
lastChangeTimestamp,
|
|
_now
|
|
);
|
|
|
|
// NOTE: We could also check and run the timer hourly, but who has a messenger on the
|
|
// conversation screen open for hours on end?
|
|
if (update && lastChangeTimestamp > -1 && _now - lastChangeTimestamp >= 60 * Duration.millisecondsPerMinute) {
|
|
_updateTimer = Timer.periodic(const Duration(minutes: 1), (timer) {
|
|
final now = DateTime.now().millisecondsSinceEpoch;
|
|
setState(() {
|
|
_timestampString = formatConversationTimestamp(
|
|
lastChangeTimestamp,
|
|
now
|
|
);
|
|
});
|
|
|
|
if (now - lastChangeTimestamp >= 60 * Duration.millisecondsPerMinute) {
|
|
_updateTimer!.cancel();
|
|
_updateTimer = null;
|
|
}
|
|
});
|
|
} else {
|
|
_updateTimer = null;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
if (_updateTimer != null) {
|
|
_updateTimer!.cancel();
|
|
}
|
|
|
|
super.dispose();
|
|
}
|
|
|
|
Widget _buildLastMessageBody() {
|
|
if (typingIndicator) {
|
|
return TypingIndicatorWidget(Colors.black, Colors.white);
|
|
}
|
|
|
|
return Text(
|
|
lastMessageBody,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
String badgeText = unreadCount > 99 ? "99+" : unreadCount.toString();
|
|
|
|
return Stack(
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: AvatarWrapper(
|
|
radius: 35.0,
|
|
avatarUrl: avatarUrl,
|
|
// TODO: Make this consistent by moving this inside the AvatarWrapper widget
|
|
alt: Text(name[0] + name[1])
|
|
)
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Container(
|
|
constraints: BoxConstraints(
|
|
maxWidth: maxTextWidth
|
|
),
|
|
child: Text(
|
|
name,
|
|
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 17),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis
|
|
)
|
|
),
|
|
// TODO: Change color and font size
|
|
Container(
|
|
constraints: BoxConstraints(
|
|
maxWidth: maxTextWidth
|
|
),
|
|
// TODO: Colors
|
|
child: _buildLastMessageBody()
|
|
)
|
|
]
|
|
)
|
|
),
|
|
const Spacer(),
|
|
Visibility(
|
|
visible: unreadCount > 0,
|
|
child: Padding(
|
|
padding: const EdgeInsetsDirectional.only(end: 8.0),
|
|
child: Badge(
|
|
badgeContent: Text(badgeText),
|
|
badgeColor: bubbleColorSent
|
|
)
|
|
)
|
|
)
|
|
]
|
|
),
|
|
Visibility(
|
|
visible: lastChangeTimestamp != timestampNever,
|
|
child: Positioned(
|
|
top: 8,
|
|
right: 8,
|
|
child: Text(
|
|
_timestampString
|
|
)
|
|
)
|
|
)
|
|
]
|
|
);
|
|
}
|
|
}
|