Files
Ensemble/lib/widgets/common/disconnected_state.dart
Your NameandClaude Opus 4.5 cecea7c263 feat(i18n): localize all remaining screens and widgets
Localized files:
- screens: album_details, artist_details, audiobook_*, debug_log,
  home, library_*, new_library, playlist_details, queue
- widgets: disconnected_state, empty_state, expandable_player,
  chapters_panel

All hardcoded English strings replaced with S.of(context)! calls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 21:36:51 +00:00

116 lines
3.8 KiB
Dart

import 'package:flutter/material.dart';
import '../../l10n/app_localizations.dart';
import '../../theme/design_tokens.dart';
/// A reusable widget for displaying disconnected/offline state.
class DisconnectedState extends StatelessWidget {
final String title;
final String? subtitle;
final String? actionLabel;
final VoidCallback? onAction;
final IconData? actionIcon;
final double iconSize;
const DisconnectedState({
super.key,
required this.title,
this.subtitle,
this.actionLabel,
this.onAction,
this.actionIcon,
this.iconSize = 64,
});
/// Simple disconnected state without action button
factory DisconnectedState.simple(BuildContext context) => DisconnectedState(
title: S.of(context)!.notConnected,
);
/// Disconnected state with settings button for navigation
factory DisconnectedState.withSettingsAction({
required BuildContext context,
required VoidCallback onSettings,
}) =>
DisconnectedState(
title: S.of(context)!.notConnected,
actionLabel: S.of(context)!.configureServer,
actionIcon: Icons.settings_rounded,
onAction: onSettings,
);
/// Full disconnected state with title, subtitle, and action (for home screen)
factory DisconnectedState.full({
required BuildContext context,
required VoidCallback onSettings,
}) =>
DisconnectedState(
title: S.of(context)!.notConnectedTitle,
subtitle: S.of(context)!.connectHint,
actionLabel: S.of(context)!.configureServer,
actionIcon: Icons.settings_rounded,
onAction: onSettings,
iconSize: 80,
);
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Center(
child: Padding(
padding: Spacing.paddingAll32,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.cloud_off_rounded,
size: iconSize,
color: colorScheme.onSurface.withOpacity(0.54),
),
SizedBox(height: iconSize > IconSizes.xxl ? Spacing.xl : Spacing.lg),
Text(
title,
style: TextStyle(
color: colorScheme.onSurface.withOpacity(subtitle != null ? 1.0 : 0.7),
fontSize: subtitle != null ? 24 : 16,
fontWeight: subtitle != null ? FontWeight.w300 : FontWeight.normal,
),
textAlign: TextAlign.center,
),
if (subtitle != null) ...[
Spacing.vGap12,
Text(
subtitle!,
style: TextStyle(
color: colorScheme.onSurface.withOpacity(0.7),
fontSize: 14,
),
textAlign: TextAlign.center,
),
],
if (actionLabel != null && onAction != null) ...[
SizedBox(height: subtitle != null ? Spacing.xxl : Spacing.xl),
ElevatedButton.icon(
onPressed: onAction,
icon: actionIcon != null ? Icon(actionIcon) : const SizedBox.shrink(),
label: Text(actionLabel!),
style: ElevatedButton.styleFrom(
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
padding: EdgeInsets.symmetric(
horizontal: subtitle != null ? Spacing.xxl : Spacing.xl,
vertical: subtitle != null ? Spacing.lg : Spacing.md,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(Radii.xxl),
),
),
),
],
],
),
),
);
}
}