feat: полное отображение типов сообщений + предпросмотр ссылок и оптимизация фото

Модели (lib/models/):
- attachment.dart — новые типы ShareAttachment (OG-карточка ссылки) и
  CallAttachment (звонок); FILE получил вложенное превью и поле token;
  LOCATION — поле zoom; единый декодер previewData (сырой WebP → data-URI)
  вынесен в decodeAttachPreview
- poll.dart — корректный парсинг голосов ({userId,timestamp}) и признак
  своего голоса (options & 1); helper withStateMap

Лента сообщений (message_bubble.dart):
- SHARE — карточка предпросмотра ссылки (картинка, домен, заголовок,
  описание), тап открывает URL
- CALL — отображение звонков: аудио/видео/групповые/пропущенные,
  длительность, направление; симметричная иконка
- LOCATION — карточка геопозиции, тап открывает карту
- FILE — превью-картинка над строкой файла
- кликабельные ссылки в тексте и подписях (LinkText)
- фикс лишней ширины бабблов гео/share/опроса (IntrinsicWidth + stretch)
- оптимизация рендера фото: убран fade-in, уменьшен размер декода
  плиток фото-сетки

Опросы:
- интерактивное голосование через opcode 304 (polls.dart, poll_view.dart):
  одиночный/множественный выбор, отметка своего ответа, проценты

Список чатов (chats.dart):
- превью типа вложения для сообщений без текста («Фото», «Опрос: …»,
  «Звонок», «Геопозиция», «Файл: …», «Ссылка: …» и т.д.)

Настройки разработчика:
- тумблер «Предпросмотр ссылок» (app_link_preview.dart) — отключает
  SHARE-карточки, оставляя текст со ссылкой; применяется на лету

Прочее:
- зависимость url_launcher ^6.3.1 (open_external_url / open_location_on_map)
- bump версии 0.5.0+11 → 0.5.0+12
This commit is contained in:
klockky
2026-06-11 17:14:36 +03:00
parent cf154b006b
commit 94d3e44354
14 changed files with 1085 additions and 145 deletions
+6 -10
View File
@@ -63,13 +63,15 @@ class CallsModule {
bool isVideo = false,
}) async {
final conversationId = _uuidV4();
// Структура подтверждена дампом основного сокета (opcode 78).
final internalParams = jsonEncode({
'deviceId': _api.deviceId ?? '',
'sdkVersion': '2.8.9',
'clientAppKey': _clientAppKey(),
'platform': 'ANDROID',
'sdkVersion': '0.1.16.4',
'clientAppKey': 'CGPGAGLGDIHBABABA',
'deviceId': _api.deviceId ?? '',
'protocolVersion': 5,
'domainId': '',
'onlyAdminCanRecord': false,
'waitForAdmin': false,
'capabilities': '3c03f',
});
@@ -120,12 +122,6 @@ class CallsModule {
'-${s.substring(16, 20)}-${s.substring(20)}';
}
static String _clientAppKey() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
final r = Random();
return List.generate(17, (_) => chars[r.nextInt(chars.length)]).join();
}
/// Fetch call history from opcode 79
Future<List<CallLogEntry>> fetchHistory(
int accountId,