Chepuhagram/lib/presentation/widgets/contact_tile.dart

187 lines
6.4 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:chepuhagram/domain/services/aPI_service.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '/data/models/contact_model.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:chepuhagram/data/models/message_model.dart';
class ContactTile extends StatefulWidget {
final Contact contact;
final VoidCallback? onTap;
ContactTile({super.key, required this.contact, this.onTap});
@override
State<ContactTile> createState() => _ContactTileState();
}
class _ContactTileState extends State<ContactTile> {
SharedPreferences? _prefs;
String? token;
@override
void initState() {
super.initState();
_initPrefs();
}
Future<void> _initPrefs() async {
final apiService = ApiService();
final accessToken = await apiService.getAccessToken();
final shared = await SharedPreferences.getInstance();
if (mounted) {
setState(() {
_prefs = shared;
token = accessToken;
});
}
}
String get displayName {
if (_prefs == null) return widget.contact.name;
final id = widget.contact.id;
final savedName = _prefs!.getString('firstname_$id');
final savedSurname = _prefs!.getString('lastname_$id');
final name = savedName ?? widget.contact.name;
final surname = savedSurname ?? widget.contact.surname;
final full =
'${name != 'Unknown' ? name : ''} ${surname != 'Unknown' ? surname : ''}'
.trim();
if (full.isNotEmpty) return full;
if (widget.contact.username != 'Unknown') return widget.contact.username;
return 'User';
}
@override
Widget build(BuildContext context) {
final primary = Theme.of(context).colorScheme.primary;
final username = widget.contact.username; //
final initials =
(displayName.isNotEmpty
? displayName
: (username != 'Unknown' ? username : 'U'))
.trim()
.split(RegExp(r'\s+'))
.where((p) => p.isNotEmpty)
.take(2)
.map((p) => p[0].toUpperCase())
.join(); //
debugPrint(
'=== CONTACT DEBUG: ${widget.contact.name} -> URL: ${widget.contact.effectiveAvatarUrl}',
);
return ListTile(
onTap: widget.onTap, //
contentPadding: EdgeInsets.symmetric(
horizontal: 16,
vertical: 4,
), //
// Переписываем ведущий виджет (аватарку)
leading: SizedBox(
width: 56, // Соответствует радиусу 28 * 2
height: 56,
child:
widget.contact.effectiveAvatarUrl !=
null //
? CachedNetworkImage(
imageUrl: widget.contact.effectiveAvatarUrl!, //
// Передаем токен для FastAPI, чтобы сервер разрешил скачивание файла
httpHeaders: {
if (token != null) 'Authorization': 'Bearer $token',
},
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
// Пока картинка качается — показываем цветной круг с инициалами
placeholder: (context, url) => CircleAvatar(
radius: 28,
backgroundColor: primary.withAlpha((0.1 * 255).round()),
child: Text(
initials,
style: TextStyle(
color: primary,
fontWeight: FontWeight.bold,
),
),
),
// Ошибка 401, 404 или упал интернет? Без паники, плавно вернем инициалы
errorWidget: (context, url, error) => CircleAvatar(
radius: 28,
backgroundColor: primary.withAlpha((0.1 * 255).round()),
child: Text(
initials,
style: TextStyle(
color: primary,
fontWeight: FontWeight.bold,
),
),
),
)
: CircleAvatar(
radius: 28,
backgroundColor: primary.withAlpha((0.1 * 255).round()), //
child: Text(
initials,
style: TextStyle(color: primary, fontWeight: FontWeight.bold),
),
),
),
title: Text(
displayName, //
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), //
),
subtitle: Text(
widget.contact.isLastMsgDecrypted
? widget.contact.lastMessage == null
? "Нет сообщений"
: "${widget.contact.lastMessageType != null ? MessageModel.getMediaPreview(widget.contact.lastMessageType!) : ''} ${widget.contact.lastMessage}"
: (widget.contact.lastMessage != null
? "Ожидание дешифровки..."
: "Нет сообщений"),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Colors.grey), //
),
trailing: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
_formatTime(widget.contact.lastMessageTime), //
style: TextStyle(color: Colors.grey, fontSize: 12), //
),
SizedBox(height: 4), //
if (widget.contact.unreadCount > 0) //
Container(
padding: EdgeInsets.all(6), //
decoration: BoxDecoration(
color: primary.withAlpha((0.5 * 255).round()), //
shape: BoxShape.circle, //
),
child: Text(
'${widget.contact.unreadCount}', //
style: TextStyle(color: Colors.white, fontSize: 10), //
),
),
],
),
);
}
String _formatTime(DateTime? time) {
if (time == null) return "";
return "${time.hour}:${time.minute.toString().padLeft(2, '0')}";
}
}