import 'package:flutter/material.dart'; import '/domain/services/api_service.dart'; import 'package:http/http.dart' as http; import '/core/constants.dart'; import 'dart:convert'; class AdminBroadcastScreen extends StatefulWidget { const AdminBroadcastScreen({Key? key}) : super(key: key); @override State createState() => _AdminBroadcastScreenState(); } class _AdminBroadcastScreenState extends State { final TextEditingController _messageController = TextEditingController(); final ApiService _apiService = ApiService(); bool _isLoading = false; bool _broadcastToAll = true; Set _selectedUserIds = {}; List> _allUsers = []; bool _isLoadingUsers = false; @override void initState() { super.initState(); _loadAllUsers(); } @override void dispose() { _messageController.dispose(); super.dispose(); } Future _loadAllUsers() async { setState(() => _isLoadingUsers = true); try { final token = await _apiService.getAccessToken(); final response = await http.get( Uri.parse('${AppConstants.baseUrl}/users/all'), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', }, ); if (response.statusCode == 200) { final List data = jsonDecode(utf8.decode(response.bodyBytes)); setState(() { _allUsers = data.map((user) { return { 'id': user['id'], 'username': user['username'], 'name': user['name'], }; }).toList(); }); } else { _showErrorDialog('Не удалось загрузить список пользователей'); } } catch (e) { _showErrorDialog('Ошибка при загрузке пользователей: $e'); } finally { setState(() => _isLoadingUsers = false); } } Future _sendBroadcast() async { final message = _messageController.text.trim(); if (message.isEmpty) { _showErrorDialog('Введите текст сообщения'); return; } if (!_broadcastToAll && _selectedUserIds.isEmpty) { _showErrorDialog('Выберите хотя бы одного пользователя'); return; } setState(() => _isLoading = true); try { final token = await _apiService.getAccessToken(); final payload = { 'content': message, if (!_broadcastToAll) 'user_ids': _selectedUserIds.toList(), }; final response = await http.post( Uri.parse('${AppConstants.baseUrl}/admin/broadcast'), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', }, body: jsonEncode(payload), ); if (response.statusCode == 200) { final data = jsonDecode(utf8.decode(response.bodyBytes)); _messageController.clear(); setState(() => _selectedUserIds.clear()); _showSuccessDialog(data['message'] ?? 'Рассылка отправлена успешно'); } else { final errorData = jsonDecode(utf8.decode(response.bodyBytes)); _showErrorDialog( errorData['detail'] ?? 'Не удалось отправить рассылку', ); } } catch (e) { _showErrorDialog('Ошибка при отправке рассылки: $e'); } finally { setState(() => _isLoading = false); } } void _showErrorDialog(String message) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Ошибка'), content: Text(message), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('OK'), ), ], ), ); } void _showSuccessDialog(String message) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Успешно'), content: Text(message), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('OK'), ), ], ), ); } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Scaffold( body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Message input section Text( 'Текст сообщения', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), TextField( controller: _messageController, decoration: InputDecoration( hintText: 'Введите текст для рассылки...', border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), filled: true, fillColor: colorScheme.surface, ), maxLines: 5, minLines: 3, ), const SizedBox(height: 24), // Recipient selection section Text( 'Получатели', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 12), // "All users" toggle Card( child: ListTile( title: const Text('Отправить всем'), leading: Radio( value: true, groupValue: _broadcastToAll, onChanged: (value) { setState(() { _broadcastToAll = value ?? true; if (_broadcastToAll) { _selectedUserIds.clear(); } }); }, ), ), ), const SizedBox(height: 12), // "Selected users" toggle Card( child: ListTile( title: const Text('Отправить выбранным'), leading: Radio( value: false, groupValue: _broadcastToAll, onChanged: (value) { setState(() { _broadcastToAll = value ?? false; }); }, ), ), ), const SizedBox(height: 16), // User list for selection if (!_broadcastToAll) ...[ if (_isLoadingUsers) const Center(child: CircularProgressIndicator()) else if (_allUsers.isEmpty) const Padding( padding: EdgeInsets.all(16), child: Text('Нет пользователей'), ) else Card( child: Column( children: [ Padding( padding: const EdgeInsets.all(12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Выбрано: ${_selectedUserIds.length}', style: Theme.of(context).textTheme.bodyMedium, ), if (_selectedUserIds.isNotEmpty) TextButton( onPressed: () { setState(() => _selectedUserIds.clear()); }, child: const Text('Очистить'), ), ], ), ), Divider(height: 0, color: colorScheme.outlineVariant), SizedBox( height: 250, child: ListView.builder( itemCount: _allUsers.length, itemBuilder: (context, index) { final user = _allUsers[index]; final userId = user['id'] as int; final isSelected = _selectedUserIds.contains(userId); return CheckboxListTile( value: isSelected, onChanged: (selected) { setState(() { if (selected == true) { _selectedUserIds.add(userId); } else { _selectedUserIds.remove(userId); } }); }, title: Text(user['name'] ?? 'Неизвестный'), subtitle: Text('@${user['username']}'), ); }, ), ), ], ), ), ], const SizedBox(height: 24), // Send button SizedBox( width: double.infinity, child: FilledButton.icon( onPressed: _isLoading ? null : _sendBroadcast, icon: _isLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Icon(Icons.send), label: Text( _isLoading ? 'Отправка...' : 'Отправить рассылку', ), ), ), ], ), ), ); } }