авотаро4ки в пересланных сообщениях

This commit is contained in:
Ваше Имя
2026-04-11 00:22:32 +07:00
parent 78635dd327
commit ef1daff896
7 changed files with 87 additions and 42 deletions
+15 -3
View File
@@ -6,13 +6,21 @@ import '../../core/storage/app_database.dart';
import '../../models/attachment.dart';
class ContactCache {
static final Map<int, String> _cache = {};
static final Map<int, String> _nameCache = {};
static final Map<int, String> _avatarCache = {};
static void put(int id, String name) {
_cache[id] = name;
_nameCache[id] = name;
}
static String? get(int id) => _cache[id];
static void putAvatar(int id, String? baseUrl) {
if (baseUrl != null) {
_avatarCache[id] = baseUrl;
}
}
static String? get(int id) => _nameCache[id];
static String? getAvatar(int id) => _avatarCache[id];
}
class CachedMessage {
@@ -371,6 +379,10 @@ class MessagesModule {
? '$firstName $lastName'
: firstName;
ContactCache.put(contactId, fullName);
final baseUrl = contact['baseUrl'] as String?;
ContactCache.putAvatar(contactId, baseUrl);
return fullName;
}
}
@@ -6,6 +6,7 @@ import '../../../backend/api.dart';
import '../../../backend/modules/messages.dart';
import '../../../core/storage/app_database.dart';
import '../../../models/attachment.dart';
import '../../../backend/modules/messages.dart' show ContactCache;
import '../../widgets/message_bubble.dart';
class ChatScreen extends StatefulWidget {
@@ -183,6 +184,7 @@ class _ChatScreenState extends State<ChatScreen>
for (final id in forwardIds) {
final name = await messagesModule.searchContactById(id);
final avatar = ContactCache.getAvatar(id);
if (name != null && mounted) {
setState(() {
for (var i = 0; i < _messages.length; i++) {
@@ -195,6 +197,7 @@ class _ChatScreenState extends State<ChatScreen>
return ForwardedMessageAttachment(
originalSenderId: id,
originalSenderName: name,
originalSenderAvatar: avatar,
originalMessageId: a.originalMessageId,
originalTime: a.originalTime,
originalText: a.originalText,
+42 -2
View File
@@ -360,12 +360,14 @@ class MessageBubble extends StatelessWidget {
ForwardedMessageAttachment forwarded,
Color textColor,
) {
final cs = Theme.of(context).colorScheme;
final headerColor = isMe
? Colors.white.withValues(alpha: 0.7)
: Theme.of(context).colorScheme.onSurfaceVariant;
: cs.onSurfaceVariant;
final senderName = forwarded.originalSenderName;
final displaySender = senderName ?? forwarded.originalSenderId.toString();
final senderAvatar = forwarded.originalSenderAvatar;
final origText = forwarded.originalText;
final hasOrigText = origText != null && origText.isNotEmpty;
@@ -378,6 +380,24 @@ class MessageBubble extends StatelessWidget {
children: [
Icon(Symbols.forward, size: 14, color: headerColor),
const SizedBox(width: 4),
if (senderAvatar != null && senderAvatar.isNotEmpty)
CircleAvatar(
radius: 10,
backgroundImage: NetworkImage(senderAvatar),
backgroundColor: cs.primaryContainer,
)
else
CircleAvatar(
radius: 10,
backgroundColor: cs.primaryContainer,
child: Text(
displaySender.isNotEmpty
? displaySender[0].toUpperCase()
: '?',
style: TextStyle(fontSize: 9, color: cs.onPrimaryContainer),
),
),
const SizedBox(width: 6),
Text(
displaySender,
style: TextStyle(
@@ -580,11 +600,13 @@ class MessageBubble extends StatelessWidget {
ForwardedMessageAttachment forwarded,
List<PhotoAttachment> photos,
) {
final cs = Theme.of(context).colorScheme;
final headerColor = isMe
? Colors.white.withValues(alpha: 0.7)
: Theme.of(context).colorScheme.onSurfaceVariant;
: cs.onSurfaceVariant;
final senderName = forwarded.originalSenderName;
final displaySender = senderName ?? forwarded.originalSenderId.toString();
final senderAvatar = forwarded.originalSenderAvatar;
final hasCaption = message.text != null && message.text!.isNotEmpty;
return Column(
@@ -598,6 +620,24 @@ class MessageBubble extends StatelessWidget {
children: [
Icon(Symbols.forward, size: 14, color: headerColor),
const SizedBox(width: 4),
if (senderAvatar != null && senderAvatar.isNotEmpty)
CircleAvatar(
radius: 10,
backgroundImage: NetworkImage(senderAvatar),
backgroundColor: cs.primaryContainer,
)
else
CircleAvatar(
radius: 10,
backgroundColor: cs.primaryContainer,
child: Text(
displaySender.isNotEmpty
? displaySender[0].toUpperCase()
: '?',
style: TextStyle(fontSize: 9, color: cs.onPrimaryContainer),
),
),
const SizedBox(width: 6),
Text(
displaySender,
style: TextStyle(
+16 -21
View File
@@ -62,8 +62,7 @@ import 'app_localizations_ru.dart';
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
/// property.
abstract class AppLocalizations {
AppLocalizations(String locale)
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
@@ -71,8 +70,7 @@ abstract class AppLocalizations {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
@@ -84,18 +82,17 @@ abstract class AppLocalizations {
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
<LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[
Locale('en'),
Locale('ru'),
Locale('ru')
];
/// No description provided for @loginTitle.
@@ -381,8 +378,7 @@ abstract class AppLocalizations {
String get proxyInvalidHostOrPort;
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
@@ -391,26 +387,25 @@ class _AppLocalizationsDelegate
}
@override
bool isSupported(Locale locale) =>
<String>['en', 'ru'].contains(locale.languageCode);
bool isSupported(Locale locale) => <String>['en', 'ru'].contains(locale.languageCode);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'en':
return AppLocalizationsEn();
case 'ru':
return AppLocalizationsRu();
case 'en': return AppLocalizationsEn();
case 'ru': return AppLocalizationsRu();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.',
'that was used.'
);
}
+3 -6
View File
@@ -12,8 +12,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get loginTitle => 'Sign in to Komet';
@override
String get loginSubtitle =>
'Check your country code and enter your\nphone number.';
String get loginSubtitle => 'Check your country code and enter your\nphone number.';
@override
String get loginCountry => 'Country';
@@ -103,8 +102,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get selectCountrySearchHint => 'Search countries…';
@override
String get codeConfirmationSmsSent =>
'We sent an SMS with a verification code to your phone number.';
String get codeConfirmationSmsSent => 'We sent an SMS with a verification code to your phone number.';
@override
String codeResendInSeconds(int seconds) {
@@ -151,6 +149,5 @@ class AppLocalizationsEn extends AppLocalizations {
String get proxySettingsSaved => 'Proxy settings applied';
@override
String get proxyInvalidHostOrPort =>
'Enter a valid proxy host and port (165535)';
String get proxyInvalidHostOrPort => 'Enter a valid proxy host and port (165535)';
}
+5 -10
View File
@@ -12,8 +12,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get loginTitle => 'Войдите в Komet';
@override
String get loginSubtitle =>
'Проверьте код страны и введите свой\nномер телефона.';
String get loginSubtitle => 'Проверьте код страны и введите свой\nномер телефона.';
@override
String get loginCountry => 'Страна';
@@ -43,8 +42,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get loginDone => 'Готово';
@override
String get loginReadTermsNotification =>
'Сначала прочитайте условия использования';
String get loginReadTermsNotification => 'Сначала прочитайте условия использования';
@override
String get loginSpoofRedacted => 'Подделка спуфа';
@@ -71,8 +69,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get serverUseDefault => 'Сбросить к умолчанию';
@override
String get serverInvalidHostOrPort =>
'Укажите корректный хост и порт (1–65535)';
String get serverInvalidHostOrPort => 'Укажите корректный хост и порт (1–65535)';
@override
String get serverSettingsSaved => 'Настройки сервера применены';
@@ -105,8 +102,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get selectCountrySearchHint => 'Поиск страны…';
@override
String get codeConfirmationSmsSent =>
'Мы отправили SMS с кодом подтверждения на ваш номер телефона.';
String get codeConfirmationSmsSent => 'Мы отправили SMS с кодом подтверждения на ваш номер телефона.';
@override
String codeResendInSeconds(int seconds) {
@@ -153,6 +149,5 @@ class AppLocalizationsRu extends AppLocalizations {
String get proxySettingsSaved => 'Настройки прокси применены';
@override
String get proxyInvalidHostOrPort =>
'Укажите корректный хост и порт прокси (1–65535)';
String get proxyInvalidHostOrPort => 'Укажите корректный хост и порт прокси (1–65535)';
}
+3
View File
@@ -436,6 +436,7 @@ class ControlAttachment extends MessageAttachment {
class ForwardedMessageAttachment extends MessageAttachment {
final int originalSenderId;
final String? originalSenderName;
final String? originalSenderAvatar;
final String? originalMessageId;
final int? originalTime;
final String? originalText;
@@ -445,6 +446,7 @@ class ForwardedMessageAttachment extends MessageAttachment {
const ForwardedMessageAttachment({
required this.originalSenderId,
this.originalSenderName,
this.originalSenderAvatar,
this.originalMessageId,
this.originalTime,
this.originalText,
@@ -493,6 +495,7 @@ class ForwardedMessageAttachment extends MessageAttachment {
'_type': 'FORWARD',
'originalSenderId': originalSenderId,
'originalSenderName': originalSenderName,
'originalSenderAvatar': originalSenderAvatar,
'originalMessageId': originalMessageId,
'originalTime': originalTime,
'originalText': originalText,