Chepuhagram/lib/presentation/screens/forward_contact_picker_scre...

327 lines
15 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:ui';
import 'dart:io';
import '/data/models/message_model.dart';
import '/data/models/contact_model.dart';
import '/logic/contact_provider.dart';
import '/domain/services/api_service.dart';
import '/core/theme_manager.dart';
class ForwardContactPickerScreen extends StatefulWidget {
final MessageModel message;
const ForwardContactPickerScreen({super.key, required this.message});
@override
State<ForwardContactPickerScreen> createState() =>
_ForwardContactPickerScreenState();
}
class _ForwardContactPickerScreenState
extends State<ForwardContactPickerScreen> {
Contact? _selectedContact;
bool _isInitLoading = true;
SharedPreferences? _prefs;
String? token;
@override
void initState() {
super.initState();
_loadActiveChats();
}
Future<void> _loadActiveChats() async {
try {
final contactProvider = context.read<ContactProvider>();
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 != 'Unknown' ? contact.name : ''} ${contact.surname != 'Unknown' ? contact.surname : ''}'.trim();
final id = contact.id;
final savedName = _prefs!.getString('firstname_$id');
final savedSurname = _prefs!.getString('lastname_$id');
String? displayName;
if (savedName != null && savedName.isNotEmpty) {
displayName = savedName;
}
if (savedSurname != null && savedSurname.isNotEmpty) {
(displayName == null || displayName.isEmpty) ? displayName = savedSurname : displayName += " $savedSurname";
}
return displayName ?? '${contact.name != 'Unknown' ? contact.name : ''} ${contact.surname != 'Unknown' ? contact.surname : ''}'.trim();
}
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';
}
String _getInitials(String name) {
if (name.isEmpty) return '?';
final names = name.trim().split(RegExp(r'\s+')).where((s) => s.isNotEmpty).toList();
if (names.length > 1) {
return (names[0][0] + names[1][0]).toUpperCase();
} else if (names.isNotEmpty) {
return names[0][0].toUpperCase();
}
return '?';
}
@override
Widget build(BuildContext context) {
final contactProvider = context.watch<ContactProvider>();
final contacts = contactProvider.contacts;
final isLoading = _isInitLoading || contactProvider.isLoading;
final themeProv = context.watch<ThemeProvider>();
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: colorScheme.surface.withOpacity(0.85),
elevation: 0,
scrolledUnderElevation: 0,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(bottom: Radius.circular(24)),
),
flexibleSpace: ClipRRect(
borderRadius: const BorderRadius.vertical(bottom: Radius.circular(24)),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(color: Colors.transparent),
),
),
leading: IconButton(
icon: Icon(Icons.arrow_back_rounded, color: Theme.of(context).colorScheme.onSurface),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
'Переслать...',
style: TextStyle(fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onSurface),
),
iconTheme: IconThemeData(color: Theme.of(context).colorScheme.onSurface),
actions: [
AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: _selectedContact != null ? 1.0 : 0.5,
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: ElevatedButton(
onPressed: _selectedContact != null
? () => Navigator.of(context).pop(_selectedContact)
: null,
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
padding: const EdgeInsets.symmetric(horizontal: 20),
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
),
child: const Text('Далее'),
),
),
),
],
),
body: Stack(
children: [
SafeArea(
child: () {
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: TextStyle(color: colorScheme.outline),
),
),
);
}
if (contacts.isEmpty) {
return Center(
child: Text(
'Нет активных чатов для пересылки.',
style: TextStyle(color: colorScheme.outline, fontSize: 15),
),
);
}
return ListView.builder(
padding: const EdgeInsets.only(top: 8, left: 8, right: 8),
itemCount: contacts.length,
itemBuilder: (context, index) {
final contact = contacts[index];
final isSelected = _selectedContact?.id == contact.id;
final bool isDecrypted = contact.isLastMsgDecrypted;
final String subtitleText = isDecrypted
? (contact.lastMessage == null
? "Нет сообщений"
: "${contact.lastMessageType != null ? MessageModel.getMediaPreview(contact.lastMessageType!) : ''} ${contact.lastMessage}".trim())
: (contact.lastMessage != null
? "Ожидание дешифровки..."
: "Нет сообщений");
final avatarUrl = contact.effectiveAvatarUrl;
final bool hasAvatar = avatarUrl != null && avatarUrl.isNotEmpty;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15),
child: AnimatedContainer(
duration: const Duration(milliseconds: 250),
decoration: BoxDecoration(
color: isSelected ? colorScheme.primary.withOpacity(0.2) : colorScheme.surfaceVariant.withOpacity(0.4),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? colorScheme.primary : colorScheme.outlineVariant.withOpacity(0.2),
width: isSelected ? 2 : 1,
),
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
setState(() {
_selectedContact = isSelected ? null : contact;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: Row(
children: [
// Avatar
CircleAvatar(
radius: 26,
backgroundColor: colorScheme.primaryContainer,
child: hasAvatar
? ClipOval(
child: Image.network(
avatarUrl,
fit: BoxFit.cover,
width: 52,
height: 52,
loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: Text(
_getInitials(_getDisplayName(contact)),
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: colorScheme.onPrimaryContainer),
),
);
},
errorBuilder: (context, error, stackTrace) {
return Center(
child: Text(
_getInitials(_getDisplayName(contact)),
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: colorScheme.onPrimaryContainer),
),
);
},
),
)
: Center(
child: Text(
_getInitials(_getDisplayName(contact)),
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: colorScheme.onPrimaryContainer),
),
),
),
const SizedBox(width: 12),
// Name and Message
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_getDisplayName(contact),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 2),
Text(
subtitleText,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: colorScheme.outline),
),
],
),
),
const SizedBox(width: 12),
// Checkmark
AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
transitionBuilder: (child, animation) => ScaleTransition(scale: animation, child: child),
child: isSelected
? Container(
key: const ValueKey('checkmark'),
width: 28,
height: 28,
decoration: BoxDecoration(color: colorScheme.primary, shape: BoxShape.circle),
child: const Icon(Icons.check_rounded, color: Colors.white, size: 18),
)
:
Text(
_formatTime(contact.lastMessageTime),
key: ValueKey(_formatTime(contact.lastMessageTime)),
textAlign: TextAlign.end,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: colorScheme.outline),
),
),
],
),
),
),
),
),
),
),
);
},
);
}(),
),
],
),
);
}
}