import 'package:flutter/material.dart'; import '../models/channel.dart'; import '../services/api_service.dart'; import '../services/auth_service.dart'; import 'channel_screen.dart'; import 'login_screen.dart'; import 'notifications_screen.dart'; class ChannelListScreen extends StatefulWidget { const ChannelListScreen({super.key}); @override State createState() => _ChannelListScreenState(); } class _ChannelListScreenState extends State { final _authService = AuthService(); late final ApiService _api; List _channels = []; bool _loading = true; String? _error; int _pendingNotifCount = 0; String? _currentUserId; @override void initState() { super.initState(); _api = ApiService(_authService); _init(); } Future _init() async { _currentUserId = await _authService.getUserId(); await _loadChannels(); await _loadNotifCount(); } Future _loadChannels() async { setState(() { _loading = true; _error = null; }); final channels = await _api.getChannels(); if (!mounted) return; if (channels.isEmpty && _channels.isEmpty) { setState(() { _loading = false; _error = 'کانالی یافت نشد'; }); } else { setState(() { _channels = channels; _loading = false; }); } } Future _loadNotifCount() async { final notifs = await _api.getNotifications(); if (!mounted) return; setState(() { _pendingNotifCount = notifs.where((n) => n.isPending).length; }); } Future _refresh() async { await _loadChannels(); await _loadNotifCount(); } Future _logout() async { await _authService.logout(); if (!mounted) return; Navigator.pushReplacement( context, MaterialPageRoute(builder: (_) => const LoginScreen()), ); } void _enterChannel(Channel ch) { Navigator.push( context, MaterialPageRoute( builder: (_) => ChannelScreen(channel: ch, currentUserId: _currentUserId), ), ); } void _openNotifications() async { await Navigator.push( context, MaterialPageRoute(builder: (_) => const NotificationsScreen()), ); // refresh notif count + reload channels after returning (user may have accepted invite) _refresh(); } Future _showCreateGroupDialog() async { String groupName = ''; final confirmed = await showDialog( context: context, builder: (ctx) => _CreateGroupDialog( onNameChanged: (v) => groupName = v, ), ); if (confirmed == true && groupName.trim().isNotEmpty) { final newChannel = await _api.createGroup(groupName.trim()); if (!mounted) return; if (newChannel != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('گروه ساخته شد', style: TextStyle(fontSize: 11), textAlign: TextAlign.center), backgroundColor: const Color(0xFF1C1C1E), behavior: SnackBarBehavior.floating, duration: const Duration(seconds: 2), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 40), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), ), ); _loadChannels(); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('خطا در ساخت گروه', style: TextStyle(fontSize: 11), textAlign: TextAlign.center), backgroundColor: const Color(0xFF333333), behavior: SnackBarBehavior.floating, duration: const Duration(seconds: 2), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 40), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), ), ); } } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: SafeArea( child: Column( children: [ // Header Padding( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), child: Row( children: [ const SizedBox(width: 4), const Icon(Icons.settings_input_antenna, color: Color(0xFF00C853), size: 16), const SizedBox(width: 4), const Expanded( child: Text( 'کانال‌ها', style: TextStyle( color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold), ), ), // Notifications icon with badge Stack( clipBehavior: Clip.none, children: [ IconButton( onPressed: _openNotifications, padding: EdgeInsets.zero, constraints: const BoxConstraints(minWidth: 32, minHeight: 32), icon: const Icon(Icons.notifications_outlined, color: Colors.white54, size: 18), ), if (_pendingNotifCount > 0) Positioned( top: 4, right: 4, child: Container( width: 8, height: 8, decoration: const BoxDecoration( color: Color(0xFFFF1744), shape: BoxShape.circle, ), ), ), ], ), // Create group IconButton( onPressed: _showCreateGroupDialog, padding: EdgeInsets.zero, constraints: const BoxConstraints(minWidth: 32, minHeight: 32), icon: const Icon(Icons.add_circle_outline, color: Color(0xFF00C853), size: 18), ), // Refresh IconButton( onPressed: _loading ? null : _refresh, padding: EdgeInsets.zero, constraints: const BoxConstraints(minWidth: 32, minHeight: 32), icon: const Icon(Icons.refresh, color: Colors.white54, size: 18), ), // Logout IconButton( onPressed: _logout, padding: EdgeInsets.zero, constraints: const BoxConstraints(minWidth: 32, minHeight: 32), icon: const Icon(Icons.logout, color: Colors.white38, size: 16), ), ], ), ), // Content Expanded( child: _loading ? const Center( child: CircularProgressIndicator( color: Color(0xFF00C853), strokeWidth: 2), ) : _error != null && _channels.isEmpty ? Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.wifi_off, color: Colors.white38, size: 24), const SizedBox(height: 6), Text(_error!, style: const TextStyle( color: Colors.white38, fontSize: 11)), const SizedBox(height: 8), TextButton( onPressed: _refresh, child: const Text('تلاش مجدد', style: TextStyle( color: Color(0xFF00C853), fontSize: 11)), ), ], ), ) : ListView.builder( padding: const EdgeInsets.only(bottom: 4), itemCount: _channels.length, itemBuilder: (ctx, i) { return _ChannelTile( channel: _channels[i], onTap: () => _enterChannel(_channels[i]), ); }, ), ), ], ), ), ); } } class _ChannelTile extends StatelessWidget { final Channel channel; final VoidCallback onTap; const _ChannelTile({required this.channel, required this.onTap}); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), height: 44, decoration: BoxDecoration( color: const Color(0xFF1C1C1E), borderRadius: BorderRadius.circular(14), ), padding: const EdgeInsets.symmetric(horizontal: 12), child: Row( children: [ Icon( channel.type == 'PUBLIC' ? Icons.radio : Icons.lock_outline, color: const Color(0xFF00C853), size: 16, ), const SizedBox(width: 8), Expanded( child: Text( channel.name, style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 4), const Icon(Icons.chevron_right, color: Colors.white24, size: 16), ], ), ), ); } } // ── Create Group Dialog ──────────────────────────────────────────────────── class _CreateGroupDialog extends StatefulWidget { final ValueChanged onNameChanged; const _CreateGroupDialog({required this.onNameChanged}); @override State<_CreateGroupDialog> createState() => _CreateGroupDialogState(); } class _CreateGroupDialogState extends State<_CreateGroupDialog> { final _ctrl = TextEditingController(); @override void dispose() { _ctrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AlertDialog( backgroundColor: const Color(0xFF1C1C1E), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), contentPadding: const EdgeInsets.all(16), content: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.add_circle_outline, color: Color(0xFF00C853), size: 26), const SizedBox(height: 8), const Text( 'گروه جدید', style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), TextField( controller: _ctrl, autofocus: true, textAlign: TextAlign.center, style: const TextStyle(color: Colors.white, fontSize: 12), decoration: InputDecoration( hintText: 'نام گروه', hintStyle: const TextStyle(color: Colors.white38, fontSize: 11), filled: true, fillColor: Colors.white.withValues(alpha: 0.05), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), ), onChanged: widget.onNameChanged, ), const SizedBox(height: 12), Row( children: [ Expanded( child: TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('انصراف', style: TextStyle(color: Colors.white54, fontSize: 11)), ), ), Expanded( child: TextButton( onPressed: () => Navigator.pop(context, true), child: const Text('ساخت', style: TextStyle( color: Color(0xFF00C853), fontSize: 11, fontWeight: FontWeight.bold, )), ), ), ], ), ], ), ); } }