Files
sheetless/lib/sheet.dart

130 lines
3.4 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
class Sheet {
final String uuid;
final String name;
final String composerUuid;
final String composerName;
Sheet({
required this.uuid,
required this.name,
required this.composerUuid,
required this.composerName,
});
// Factory constructor for creating a Sheet from JSON
factory Sheet.fromJson(Map<String, dynamic> json) {
return Sheet(
uuid: json['uuid'],
name: json['sheet_name'],
composerUuid: json['composer_uuid'],
composerName: json['composer_name'],
);
}
}
class SheetsWidget extends StatefulWidget {
final List<Sheet> sheets;
final ValueSetter<Sheet> callback;
const SheetsWidget({super.key, required this.sheets, required this.callback});
@override
State<SheetsWidget> createState() => _SheetsWidgetState();
}
class _SheetsWidgetState extends State<SheetsWidget> {
late List<Sheet> filteredSheets;
final TextEditingController _searchController = TextEditingController();
Timer? _debounce;
@override
void initState() {
super.initState();
filteredSheets = widget.sheets;
_searchController.addListener(_onSearchChanged);
}
@override
void dispose() {
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
_debounce?.cancel();
super.dispose();
}
void _onSearchChanged() {
if (_debounce?.isActive ?? false) _debounce!.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
_filterSheets();
});
}
void _filterSheets() {
setState(() {
String query = _searchController.text.toLowerCase().trim();
List<String> terms = query.split(RegExp(r'\s+')); // Split by whitespace
filteredSheets =
widget.sheets.where((sheet) {
String name = sheet.name.toLowerCase();
String composer = sheet.composerName.toLowerCase();
// Each term must be found in either the name or composer
return terms.every(
(term) => name.contains(term) || composer.contains(term),
);
}).toList();
});
}
void _clearSearch() {
_searchController.clear();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Search...',
prefixIcon: const Icon(Icons.search),
suffixIcon:
_searchController.text.isNotEmpty
? IconButton(
icon: const Icon(Icons.clear),
onPressed: _clearSearch,
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
),
Expanded(
child: ListView.builder(
itemCount: filteredSheets.length,
itemBuilder: (context, index) {
var sheet = filteredSheets[index];
return ListTile(
title: Text(sheet.name),
subtitle: Text(sheet.composerName),
onTap: () => widget.callback(sheet),
);
},
),
),
],
);
}
}