init
This commit is contained in:
commit
d205277cdd
182 changed files with 22978 additions and 0 deletions
119
lib/screens/search_screen.dart
Normal file
119
lib/screens/search_screen.dart
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../state/providers.dart';
|
||||
import '../theme/tokens.dart';
|
||||
import 'browser_screen.dart';
|
||||
|
||||
/// Search — `search3` across artists / albums / songs.
|
||||
class SearchScreen extends ConsumerStatefulWidget {
|
||||
const SearchScreen({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<SearchScreen> createState() => _SearchScreenState();
|
||||
}
|
||||
|
||||
class _SearchScreenState extends ConsumerState<SearchScreen> {
|
||||
final _controller = TextEditingController();
|
||||
String _query = '';
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final accent = Theme.of(context).colorScheme.primary;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: TextField(
|
||||
controller: _controller,
|
||||
autofocus: true,
|
||||
textInputAction: TextInputAction.search,
|
||||
style: const TextStyle(color: RatuneColors.foreground),
|
||||
cursorColor: accent,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Search artists, albums, songs…',
|
||||
hintStyle: TextStyle(color: RatuneColors.dimmed),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
onSubmitted: (v) => setState(() => _query = v),
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: _query.trim().isEmpty
|
||||
? const Center(
|
||||
child: Text('Type and press search.',
|
||||
style: TextStyle(color: RatuneColors.dimmed)),
|
||||
)
|
||||
: _Results(query: _query),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Results extends ConsumerWidget {
|
||||
const _Results({required this.query});
|
||||
|
||||
final String query;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final results = ref.watch(searchProvider(query));
|
||||
return results.when(
|
||||
loading: () => const Center(
|
||||
child: SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
),
|
||||
error: (e, _) => Center(
|
||||
child: Text('$e', style: const TextStyle(color: RatuneColors.dimmed)),
|
||||
),
|
||||
data: (r) {
|
||||
if (r.artists.isEmpty && r.albums.isEmpty && r.songs.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No results.',
|
||||
style: TextStyle(color: RatuneColors.dimmed)),
|
||||
);
|
||||
}
|
||||
return ListView(
|
||||
children: [
|
||||
for (final a in r.artists)
|
||||
BrowseRow(
|
||||
title: a.name ?? 'Unknown artist',
|
||||
onTap: () => Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => ArtistScreen(id: a.id)),
|
||||
),
|
||||
),
|
||||
for (final a in r.albums)
|
||||
BrowseRow(
|
||||
title: a.name ?? 'Unknown album',
|
||||
trailing: a.artist,
|
||||
onTap: () => Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => AlbumScreen(id: a.id)),
|
||||
),
|
||||
),
|
||||
for (var i = 0; i < r.songs.length; i++)
|
||||
BrowseRow(
|
||||
title: r.songs[i].title ?? 'Untitled',
|
||||
trailing: r.songs[i].artist,
|
||||
onTap: () => ref
|
||||
.read(playbackProvider.notifier)
|
||||
.playSongs(r.songs, startIndex: i),
|
||||
onPlayNext: () => ref
|
||||
.read(playbackProvider.notifier)
|
||||
.playNext(r.songs[i]),
|
||||
onAddToQueue: () => ref
|
||||
.read(playbackProvider.notifier)
|
||||
.addToQueue(r.songs[i]),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue