import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:forui/forui.dart'; import '../../core/contracts/auth.dart'; import '../../core/contracts/server.dart'; import '../../providers/item_counts_provider.dart'; import '../../providers/server_connectivity_provider.dart'; import '../../providers/server_provider.dart'; import '../../providers/server_sync_provider.dart'; import '../../providers/session_provider.dart'; import 'add_server_modal.dart'; import 'app_dialog.dart'; import 'icon_picker_dialog.dart'; import 'server_change_password_dialog.dart'; typedef ServerActionCallbacks = ({ VoidCallback? onRefresh, VoidCallback? onChangeIcon, VoidCallback? onEdit, VoidCallback? onChangePassword, VoidCallback? onTogglePause, VoidCallback? onDelete, }); ServerActionCallbacks buildServerActionCallbacks({ required BuildContext context, required WidgetRef ref, required EmbyServer? server, AuthedSession? session, }) { Future changeIcon(EmbyServer server) async { final picked = await showIconPickerDialog( context, currentIconUrl: server.iconUrl, ); if (picked == null) return; await ref .read(serverListProvider.notifier) .save( EmbyServerSaveReq( id: server.id, name: server.name, baseUrl: server.baseUrl, iconUrl: picked, ), ); } Future togglePause(EmbyServer server) async { final wasPaused = server.paused; final sessions = ref.read(sessionProvider).value; final wasActive = sessions?.activeServerId == server.id; await ref.read(serverListProvider.notifier).togglePause(server.id); if (!wasPaused && wasActive) { final updatedServers = ref.read(serverListProvider).value ?? const []; final pausedIds = { for (final s in updatedServers) if (s.paused) s.id, }; final nextSession = sessions?.sessions .where( (s) => s.serverId != server.id && !pausedIds.contains(s.serverId), ) .firstOrNull; if (nextSession != null) { await ref .read(sessionProvider.notifier) .switchSession(nextSession.serverId); } else { await ref.read(sessionProvider.notifier).logout(serverId: server.id); } } await ref.read(serverSyncProvider.notifier).upload(); } Future delete(EmbyServer server) async { final confirmed = await showAppConfirmDialog( context, title: '删除服务器', body: Text('确定删除「${server.name}」?此操作不可撤销。'), confirmLabel: '删除', destructive: true, ); if (!confirmed) return; await ref.read(serverListProvider.notifier).delete(server.id); await ref.read(sessionProvider.notifier).refresh(); } final s = server; return ( onRefresh: s == null ? null : () { ref.invalidate(serverConnectivityProvider(s.baseUrl)); ref.invalidate(serverItemCountsProvider(s.id)); }, onChangeIcon: s == null ? null : () => changeIcon(s), onEdit: s == null ? null : () => showAddServerModal(context, initial: s), onChangePassword: session == null ? null : () => showServerChangePasswordDialog( context: context, serverId: session.serverId, serverName: s?.name ?? session.serverName, ), onTogglePause: s == null ? null : () => togglePause(s), onDelete: s == null ? null : () => delete(s), ); } List buildServerActionMenuItems({ VoidCallback? onRefresh, VoidCallback? onChangeIcon, VoidCallback? onEdit, VoidCallback? onChangePassword, bool paused = false, VoidCallback? onTogglePause, VoidCallback? onDelete, }) => [ if (onRefresh != null) FItem( prefix: const Icon(Icons.refresh_outlined, size: 16), title: const Text('刷新'), onPress: onRefresh, ), if (onChangeIcon != null) FItem( prefix: const Icon(Icons.image_outlined, size: 16), title: const Text('更换图标'), onPress: onChangeIcon, ), if (onEdit != null) FItem( prefix: const Icon(Icons.edit_outlined, size: 16), title: const Text('编辑'), onPress: onEdit, ), if (onChangePassword != null) FItem( prefix: const Icon(Icons.lock_outline, size: 16), title: const Text('修改密码'), onPress: onChangePassword, ), if (onTogglePause != null) FItem( prefix: Icon( paused ? Icons.play_circle_outline : Icons.pause_circle_outline, size: 16, ), title: Text(paused ? '恢复使用' : '暂停使用'), onPress: onTogglePause, ), if (onDelete != null) FItem( variant: FItemVariant.destructive, prefix: const Icon(Icons.delete_outline, size: 16), title: const Text('删除'), onPress: onDelete, ), ];