import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cached_network_image/cached_network_image.dart'; import '/core/constants.dart'; import '/data/models/message_model.dart'; import '/data/models/contact_model.dart'; import '/logic/contact_provider.dart'; import '/domain/services/api_service.dart'; class ForwardContactPickerScreen extends StatefulWidget { final MessageModel message; const ForwardContactPickerScreen({ super.key, required this.message, }); @override State createState() => _ForwardContactPickerScreenState(); } class _ForwardContactPickerScreenState extends State { Contact? _selectedContact; bool _isInitLoading = true; SharedPreferences? _prefs; String? token; @override void initState() { super.initState(); _loadActiveChats(); } Future _loadActiveChats() async { try { final contactProvider = context.read(); await contactProvider.loadContacts(); final apiService = ApiService(); final accessToken = await apiService.getAccessToken(); final shared = await SharedPreferences.getInstance(); if (mounted) { setState(() { _prefs = shared; token = accessToken; }); } } catch (e) { debugPrint("Ошибка при загрузке данных для пересылки: $e"); } finally { if (mounted) { setState(() { _isInitLoading = false; }); } } } String _getDisplayName(Contact contact) { if (_prefs == null) return contact.name; final id = contact.id; final savedName = _prefs!.getString('firstname_$id'); if (savedName != null && savedName.isNotEmpty) { return savedName; } return contact.name; } String _formatTime(DateTime? time) { if (time == null) return ''; final localTime = time.toLocal(); final hour = localTime.hour.toString().padLeft(2, '0'); final minute = localTime.minute.toString().padLeft(2, '0'); return '$hour:$minute'; } @override Widget build(BuildContext context) { final contactProvider = context.watch(); final contacts = contactProvider.contacts; final isLoading = _isInitLoading || contactProvider.isLoading; final primaryColor = Theme.of(context).colorScheme.primary; return Scaffold( appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back_rounded), onPressed: () => Navigator.of(context).pop(), ), title: const Text( 'Переслать...', style: TextStyle(fontWeight: FontWeight.w600), ), actions: [ AnimatedOpacity( duration: const Duration(milliseconds: 200), opacity: _selectedContact != null ? 1.0 : 0.4, child: TextButton( onPressed: _selectedContact != null ? () => Navigator.of(context).pop(_selectedContact) : null, child: const Text( 'Продолжить', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), const SizedBox(width: 8), ], ), body: () { if (isLoading) { return const Center(child: CircularProgressIndicator()); } if (contactProvider.error != null) { return Center( child: Padding( padding: const EdgeInsets.all(24.0), child: Text( 'Ошибка: ${contactProvider.error}', textAlign: TextAlign.center, style: const TextStyle(color: Colors.grey), ), ), ); } if (contacts.isEmpty) { return const Center( child: Text( 'Нет активных чатов для пересылки.', style: TextStyle(color: Colors.grey, fontSize: 15), ), ); } return ListView.builder( itemCount: contacts.length, itemBuilder: (context, index) { final contact = contacts[index]; final isSelected = _selectedContact?.id == contact.id; // Логика формирования текста сообщения (1-в-1 как в твоем ContactTile) final bool isDecrypted = contact.isLastMsgDecrypted ?? false; final String subtitleText = isDecrypted ? (contact.lastMessage == null ? "Нет сообщений" : "${contact.lastMessageType != null ? MessageModel.getMediaPreview(contact.lastMessageType!) : ''} ${contact.lastMessage}".trim()) : (contact.lastMessage != null ? "Ожидание дешифровки..." : "Нет сообщений"); // Логика формирования URL аватарки final avatarUrl = contact.effectiveAvatarUrl; final bool hasAvatar = avatarUrl != null && avatarUrl.isNotEmpty; return InkWell( onTap: () { setState(() { if (isSelected) { _selectedContact = null; } else { _selectedContact = contact; } }); }, child: Container( color: isSelected ? primaryColor.withOpacity(0.08) : Colors.transparent, child: ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), // 1. АВАТАРКА leading: Stack( children: [ if (hasAvatar) CircleAvatar( radius: 24, backgroundColor: Colors.grey[200], child: ClipOval( child: CachedNetworkImage( imageUrl: avatarUrl, width: 48, height: 48, fit: BoxFit.cover, httpHeaders: token != null ? {'Authorization': 'Bearer $token'} : null, placeholder: (context, url) => const CircularProgressIndicator(strokeWidth: 2), errorWidget: (context, url, error) => CircleAvatar( radius: 24, backgroundColor: primaryColor.withOpacity(0.1), child: Text( _getDisplayName(contact).isNotEmpty ? _getDisplayName(contact)[0].toUpperCase() : '?', style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), ), ), ), ) else CircleAvatar( radius: 24, backgroundColor: primaryColor.withOpacity(0.1), child: Text( _getDisplayName(contact).isNotEmpty ? _getDisplayName(contact)[0].toUpperCase() : '?', style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), ), if (contact.isOnline == true) Positioned( right: 0, bottom: 0, child: Container( width: 12, height: 12, decoration: BoxDecoration( color: Colors.green, shape: BoxShape.circle, border: Border.all(color: Theme.of(context).scaffoldBackgroundColor, width: 2), ), ), ), ], ), // 2. ИМЯ title: Text( _getDisplayName(contact), maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16), ), // 3. ПОСЛЕДНЕЕ СООБЩЕНИЕ subtitle: Text( subtitleText, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.grey), ), // 4. ПРАВАЯ ЧАСТЬ (Анимация переключения Время <-> Галочка) trailing: AnimatedSwitcher( duration: const Duration(milliseconds: 200), transitionBuilder: (Widget child, Animation animation) { return ScaleTransition(scale: animation, child: child); }, child: isSelected ? Container( key: const ValueKey('checkmark'), width: 24, height: 24, decoration: BoxDecoration( color: primaryColor, shape: BoxShape.circle, ), child: const Icon(Icons.check_rounded, color: Colors.white, size: 16), ) : Column( key: const ValueKey('time_and_badge'), mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ Text( _formatTime(contact.lastMessageTime), style: const TextStyle(color: Colors.grey, fontSize: 12), ), if (contact.unreadCount > 0) ...[ const SizedBox(height: 4), Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: primaryColor.withAlpha((0.5 * 255).round()), shape: BoxShape.circle, ), child: Text( '${contact.unreadCount}', style: const TextStyle(color: Colors.white, fontSize: 10), ), ), ], ], ), ), ), ), ); }, ); }(), ); } }