feat: допилил комментарии — локализация и корректный счётчик

This commit is contained in:
klockky
2026-07-20 17:23:50 +03:00
parent 131c1dc775
commit 2bcf75d123
8 changed files with 114 additions and 22 deletions
+38 -18
View File
@@ -735,6 +735,7 @@ class _ChatScreenState extends State<ChatScreen>
_messagesRev.value++;
});
_syncReactionNotifiersFromMessages();
_requestCommentCounts();
_revealOrHoldInitial();
return;
}
@@ -754,6 +755,7 @@ class _ChatScreenState extends State<ChatScreen>
_messages = first;
_messagesRev.value++;
});
_requestCommentCounts();
_revealOrHoldInitial();
}
}
@@ -1550,6 +1552,7 @@ class _ChatScreenState extends State<ChatScreen>
bool markLoaded = false,
}) {
final changed = _chatController.mergeMessages(decodedDesc);
_requestCommentCounts();
if (!changed && !markLoaded) return;
@@ -1564,7 +1567,6 @@ class _ChatScreenState extends State<ChatScreen>
_pruneReactionNotifiers();
_chatController.persistSessionCache();
_reapplyPinIfNeeded();
_requestCommentCounts();
}
}
@@ -1603,26 +1605,33 @@ class _ChatScreenState extends State<ChatScreen>
}
String _commentsLabelFor(String postId) {
final l10n = AppLocalizations.of(context)!;
final count = _commentCounts[postId];
if (count == null || count == 0) return 'Комментировать';
if (count == 1) return '1 комментарий';
if (count % 10 == 1 && count % 100 != 11) return '$count комментарий';
return '$count комментариев';
if (count == null || count == 0) return l10n.commentsWrite;
return l10n.commentsCount(count);
}
void _openComments(CachedMessage post) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ChatScreen(
chatId: widget.chatId,
name: widget.name,
imageUrl: widget.imageUrl,
chatType: 'CHANNEL',
commentPostId: post.id,
postMessage: _stripInlineKeyboard(post),
),
),
);
Navigator.of(context)
.push(
MaterialPageRoute(
builder: (_) => ChatScreen(
chatId: widget.chatId,
name: widget.name,
imageUrl: widget.imageUrl,
chatType: 'CHANNEL',
commentPostId: post.id,
postMessage: _stripInlineKeyboard(post),
),
),
)
.then((_) => _refreshCommentCount(post.id));
}
void _refreshCommentCount(String postId) {
if (!mounted) return;
_commentCountsRequested.remove(postId);
_requestCommentCounts();
}
CachedMessage _stripInlineKeyboard(CachedMessage post) {
@@ -2866,7 +2875,9 @@ class _ChatScreenState extends State<ChatScreen>
cs: cs,
embedded: widget.embedded,
chatId: widget.chatId,
name: _commentsMode ? 'Комментарии' : widget.name,
name: _commentsMode
? AppLocalizations.of(context)!.commentsTitle
: widget.name,
imageUrl: widget.imageUrl,
chatType: widget.chatType,
isOfficial: chat?.isOfficial ?? false,
@@ -4962,6 +4973,9 @@ class _ChatScreenState extends State<ChatScreen>
!_commentsMode &&
(chat?.type ?? widget.chatType) == 'CHANNEL' &&
!message.isControl;
final bool isCommentedPost =
_commentsMode &&
message.id == widget.commentPostId;
final bubble = MessageBubble(
message: message,
@@ -4990,6 +5004,12 @@ class _ChatScreenState extends State<ChatScreen>
_reactToMessage(message, emoji),
peerName: widget.name,
peerAvatarUrl: widget.imageUrl,
senderNameOverride: isCommentedPost
? widget.name
: null,
senderAvatarOverride: isCommentedPost
? widget.imageUrl
: null,
textSelection: _textSelection,
onExitTextSelection: _exitTextSelection,
commentsLabel: isChannelPost
+8 -3
View File
@@ -201,6 +201,8 @@ class MessageBubble extends StatelessWidget {
final void Function(String emoji)? onReactionTap;
final String? peerName;
final String? peerAvatarUrl;
final String? senderNameOverride;
final String? senderAvatarOverride;
final ValueListenable<({String id, Offset pos})?>? textSelection;
final VoidCallback? onExitTextSelection;
final String? commentsLabel;
@@ -226,6 +228,8 @@ class MessageBubble extends StatelessWidget {
this.onReactionTap,
this.peerName,
this.peerAvatarUrl,
this.senderNameOverride,
this.senderAvatarOverride,
this.textSelection,
this.onExitTextSelection,
this.commentsLabel,
@@ -448,7 +452,7 @@ class MessageBubble extends StatelessWidget {
_senderPalette[id.abs() % _senderPalette.length];
Widget _buildSenderHeader(ColorScheme cs, bool needsInset) {
final name = ContactCache.get(message.senderId);
final name = senderNameOverride ?? ContactCache.get(message.senderId);
if (name == null || name.isEmpty) return const SizedBox.shrink();
final header = Padding(
padding: needsInset
@@ -476,8 +480,9 @@ class MessageBubble extends StatelessWidget {
}
Widget _buildLeadingAvatar(ColorScheme cs) {
final senderAvatar = ContactCache.getAvatar(message.senderId);
final displaySender = ContactCache.get(message.senderId);
final senderAvatar =
senderAvatarOverride ?? ContactCache.getAvatar(message.senderId);
final displaySender = senderNameOverride ?? ContactCache.get(message.senderId);
final Widget avatar;
if (senderAvatar != null && senderAvatar.isNotEmpty) {
avatar = CircleAvatar(
+10
View File
@@ -158,6 +158,16 @@
"chatInfoLink": "link:",
"chatInfoOfficial": "official:",
"chatInfoComments": "comments:",
"commentsWrite": "Comment",
"commentsTitle": "Comments",
"commentsCount": "{count, plural, =1{1 comment} other{{count} comments}}",
"@commentsCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"chatInfoAplus": "approved by Roskomnadzor:",
"chatInfoSignAdmin": "admin signature:",
"chatInfoLastChanged": "last changed:",
+18
View File
@@ -950,6 +950,24 @@ abstract class AppLocalizations {
/// **'comments:'**
String get chatInfoComments;
/// No description provided for @commentsWrite.
///
/// In en, this message translates to:
/// **'Comment'**
String get commentsWrite;
/// No description provided for @commentsTitle.
///
/// In en, this message translates to:
/// **'Comments'**
String get commentsTitle;
/// No description provided for @commentsCount.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 comment} other{{count} comments}}'**
String commentsCount(int count);
/// No description provided for @chatInfoAplus.
///
/// In en, this message translates to:
+17
View File
@@ -452,6 +452,23 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get chatInfoComments => 'comments:';
@override
String get commentsWrite => 'Comment';
@override
String get commentsTitle => 'Comments';
@override
String commentsCount(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count comments',
one: '1 comment',
);
return '$_temp0';
}
@override
String get chatInfoAplus => 'approved by Roskomnadzor:';
+19
View File
@@ -455,6 +455,25 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get chatInfoComments => 'комментарии:';
@override
String get commentsWrite => 'Комментировать';
@override
String get commentsTitle => 'Комментарии';
@override
String commentsCount(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count комментария',
many: '$count комментариев',
few: '$count комментария',
one: '$count комментарий',
);
return '$_temp0';
}
@override
String get chatInfoAplus => 'подтверждён Роскомнадзором:';
+3
View File
@@ -158,6 +158,9 @@
"chatInfoLink": "ссылка:",
"chatInfoOfficial": "оффициальный:",
"chatInfoComments": "комментарии:",
"commentsWrite": "Комментировать",
"commentsTitle": "Комментарии",
"commentsCount": "{count, plural, one{{count} комментарий} few{{count} комментария} many{{count} комментариев} other{{count} комментария}}",
"chatInfoAplus": "подтверждён Роскомнадзором:",
"chatInfoSignAdmin": "Подпись админов:",
"chatInfoLastChanged": "последнее изменение:",