import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/msn_api.dart'; import '../../core/session_controller.dart'; import '../../theme/toss_theme.dart'; import '../profile/user_profile_sheet.dart'; import 'home_providers.dart'; /// Members of the selected messenger space: row tap opens DM; profile icon opens sheet. class ContextMembersTab extends ConsumerWidget { const ContextMembersTab({super.key, required this.contextId}); final String contextId; @override Widget build(BuildContext context, WidgetRef ref) { final session = ref.watch(sessionProvider).value; final myId = session?.userId; final async = ref.watch(membersForContextProvider(contextId)); return async.when( loading: () => const Center(child: CircularProgressIndicator(color: TossColors.blue)), error: (e, _) => Center(child: Text('$e')), data: (members) { if (members.isEmpty) { return ListView( physics: const AlwaysScrollableScrollPhysics(), children: const [ SizedBox(height: 120), Center(child: Text('친구가 없습니다')), ], ); } return RefreshIndicator( color: TossColors.blue, onRefresh: () async { ref.invalidate(membersForContextProvider(contextId)); await ref.read(membersForContextProvider(contextId).future); }, child: ListView.separated( physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.fromLTRB(16, 8, 16, 100), itemCount: members.length, separatorBuilder: (_, __) => const SizedBox(height: 10), itemBuilder: (context, i) { final m = members[i]; final isSelf = myId != null && m.userId == myId; Future openChat() async { final roomId = await ref.read(msnApiProvider).openDirectRoom(contextId, m.userId); if (!context.mounted) return; await context.push('/chat?roomId=$roomId&contextId=$contextId'); } Future openProfile() async { await showUserProfileSheet( context, ref, contextId: contextId, userId: m.userId, ); } return Material( color: TossColors.surface, borderRadius: BorderRadius.circular(16), child: Ink( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), border: Border.all(color: TossColors.line), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 6), child: Row( children: [ Expanded( child: InkWell( borderRadius: BorderRadius.circular(12), onTap: () async { if (isSelf) { await openProfile(); } else { await openChat(); } }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), child: Row( children: [ CircleAvatar( radius: 22, backgroundColor: TossColors.blue.withValues(alpha: 0.1), backgroundImage: m.avatarUrl != null && m.avatarUrl!.isNotEmpty ? NetworkImage(m.avatarUrl!) : null, child: m.avatarUrl == null || m.avatarUrl!.isEmpty ? Text( m.displayName.isNotEmpty ? m.displayName[0].toUpperCase() : '?', style: const TextStyle( color: TossColors.blue, fontWeight: FontWeight.w600, ), ) : null, ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( m.displayName.isNotEmpty ? m.displayName : m.userId, style: Theme.of(context).textTheme.titleMedium, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), if (isSelf) Padding( padding: const EdgeInsets.only(left: 8), child: Text( '나', style: Theme.of(context) .textTheme .labelSmall ?.copyWith( color: TossColors.textSecondary, ), ), ), ], ), if (m.statusMessage != null && m.statusMessage!.isNotEmpty) ...[ const SizedBox(height: 4), Text( m.statusMessage!, style: Theme.of(context).textTheme.bodySmall, maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ], ), ), if (!isSelf) Icon( Icons.chat_bubble_outline, size: 20, color: TossColors.blue.withValues(alpha: 0.7), ), ], ), ), ), ), IconButton( tooltip: '프로필', icon: Icon( Icons.person_outline_rounded, color: Theme.of(context).colorScheme.onSurfaceVariant, ), onPressed: () async { await openProfile(); }, ), ], ), ), ), ); }, ), ); }, ); } }