📱 Responsive library screen

This commit is contained in:
2025-12-17 22:34:07 +08:00
parent 935e77421e
commit 6bc8946fae

View File

@@ -12,6 +12,7 @@ import 'package:groovybox/ui/tabs/albums_tab.dart';
import 'package:groovybox/ui/tabs/playlists_tab.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:path/path.dart' as p;
import 'package:styled_widget/styled_widget.dart';
class LibraryScreen extends HookConsumerWidget {
const LibraryScreen({super.key});
@@ -49,6 +50,7 @@ class LibraryScreen extends HookConsumerWidget {
final searchQuery = useState<String>('');
final isSelectionMode = selectedTrackIds.value.isNotEmpty;
final isLargeScreen = MediaQuery.of(context).size.width > 600;
final isExtraLargeScreen = MediaQuery.of(context).size.width > 800;
final selectedTab = isLargeScreen ? useState<int>(0) : null;
void toggleSelection(int id) {
@@ -104,8 +106,20 @@ class LibraryScreen extends HookConsumerWidget {
],
)
: AppBar(
centerTitle: true,
title: const Text('Library'),
title: isLargeScreen
? Row(
children: [
const Gap(4),
Image.asset(
'assets/images/icon.jpg',
width: 32,
height: 32,
).clipRRect(all: 8).padding(vertical: 16),
const Gap(12),
Text('GroovyBox', style: TextStyle(fontSize: 18)),
],
)
: const Text('Library'),
actions: [
IconButton(
icon: const Icon(Icons.add_circle_outline),
@@ -144,6 +158,7 @@ class LibraryScreen extends HookConsumerWidget {
}
// Import lyrics if any
if (!context.mounted) return;
if (lyricsPaths.isNotEmpty) {
await _batchImportLyricsFromPaths(
context,
@@ -158,9 +173,14 @@ class LibraryScreen extends HookConsumerWidget {
const Gap(8),
],
),
body: Row(
body: Column(
children: [
const Divider(height: 1),
Expanded(
child: Row(
children: [
NavigationRail(
extended: isExtraLargeScreen,
selectedIndex: selectedTab!.value,
onDestinationSelected: (index) => selectedTab.value = index,
destinations: const [
@@ -178,6 +198,7 @@ class LibraryScreen extends HookConsumerWidget {
),
],
),
const VerticalDivider(width: 1),
Expanded(
child: _buildTabContent(
selectedTab.value,
@@ -191,6 +212,9 @@ class LibraryScreen extends HookConsumerWidget {
),
],
),
),
],
),
);
} else {
return DefaultTabController(
@@ -364,25 +388,12 @@ class LibraryScreen extends HookConsumerWidget {
return const Center(child: Text('No tracks match your search.'));
}
return Column(
return Stack(
children: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * 0.04,
vertical: 16.0,
),
child: TextField(
onChanged: (value) => searchQuery.value = value,
decoration: const InputDecoration(
hintText: 'Search tracks...',
prefixIcon: Icon(Icons.search),
),
),
),
Expanded(
child: ListView.builder(
ListView.builder(
padding: EdgeInsets.only(
bottom: 72 + MediaQuery.paddingOf(context).bottom,
top: 80,
),
itemCount: filteredTracks.length,
itemBuilder: (context, index) {
@@ -431,13 +442,11 @@ class LibraryScreen extends HookConsumerWidget {
),
actions: [
TextButton(
onPressed: () =>
Navigator.of(context).pop(false),
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Cancel'),
),
TextButton(
onPressed: () =>
Navigator.of(context).pop(true),
onPressed: () => Navigator.of(context).pop(true),
style: TextButton.styleFrom(
foregroundColor: Colors.red,
),
@@ -508,6 +517,21 @@ class LibraryScreen extends HookConsumerWidget {
);
},
),
Positioned(
top: 0,
left: 0,
right: 0,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: SearchBar(
onChanged: (value) => searchQuery.value = value,
hintText: 'Search tracks...',
leading: const Icon(Icons.search),
padding: WidgetStatePropertyAll(
EdgeInsets.symmetric(horizontal: 24),
),
),
),
),
],
);