- Flutter app (Android/iOS): home, explore, albums, search, player with equalizer, mini player, sign up/sign in with email codes, profile, encrypted offline downloads, About page - server/: one-command deploy of self-hosted Supabase behind HestiaCP/nginx (or Caddy), migrations, backups, email templates - supabase/migrations: schema, row-level security, profiles - tools/: song scanner and importer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
1.6 KiB
Dart
54 lines
1.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../app/theme.dart';
|
|
|
|
class SectionHeader extends StatelessWidget {
|
|
const SectionHeader(this.title, {super.key, this.onSeeAll});
|
|
|
|
final String title;
|
|
final VoidCallback? onSeeAll;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
children: [
|
|
Expanded(child: Text(title, style: Theme.of(context).textTheme.titleLarge)),
|
|
if (onSeeAll != null)
|
|
TextButton(
|
|
onPressed: onSeeAll,
|
|
style: TextButton.styleFrom(foregroundColor: const Color(0xFFC9D6CE)),
|
|
child: const Text('See all', style: TextStyle(fontWeight: FontWeight.w600)),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Centered message for empty lists and load errors.
|
|
class EmptyState extends StatelessWidget {
|
|
const EmptyState({super.key, required this.icon, required this.title, this.message});
|
|
|
|
final IconData icon;
|
|
final String title;
|
|
final String? message;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 48),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(icon, size: 48, color: NkColors.teaLeaf),
|
|
const SizedBox(height: 16),
|
|
Text(title, textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleLarge),
|
|
if (message != null) ...[
|
|
const SizedBox(height: 8),
|
|
Text(message!, textAlign: TextAlign.center, style: const TextStyle(color: NkColors.muted, height: 1.4)),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|