diff --git a/lib/constants.dart b/lib/constants.dart index cca96fde6..bf9c18170 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -133,3 +133,7 @@ List connectWithUs = [ 'Developers' ]; String softwareLicenses = 'Software Licenses'; +String tryDifferentSearchSuggestion = 'Try a different search term'; +String noInstrumentsFoundMessage = 'No instruments found'; +String searchInstrumentsHint = 'Search instruments...'; +String instrumentsTitle = 'Instruments'; diff --git a/lib/view/instruments_screen.dart b/lib/view/instruments_screen.dart index 44028d04d..d50f88513 100644 --- a/lib/view/instruments_screen.dart +++ b/lib/view/instruments_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:pslab/colors.dart'; import 'package:pslab/constants.dart'; import 'package:pslab/view/widgets/applications_list_item.dart'; import 'package:pslab/view/widgets/main_scaffold_widget.dart'; @@ -13,6 +14,8 @@ class InstrumentsScreen extends StatefulWidget { } class _InstrumentsScreenState extends State { + final TextEditingController _searchController = TextEditingController(); + List _filteredIndices = []; void _onItemTapped(int index) { switch (index) { case 0: @@ -32,18 +35,35 @@ class _InstrumentsScreenState extends State { } } + void _filterInstruments(String query) { + setState(() { + if (query.isEmpty) { + _filteredIndices = + List.generate(instrumentHeadings.length, (index) => index); + } else { + _filteredIndices = List.generate(instrumentHeadings.length, (i) => i) + .where((i) => instrumentHeadings[i] + .toLowerCase() + .contains(query.toLowerCase())) + .toList(); + } + }); + } + @override void initState() { + super.initState(); + _filteredIndices = + List.generate(instrumentHeadings.length, (index) => index); WidgetsBinding.instance.addPostFrameCallback((_) { _setOrientation(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); }); - super.initState(); Permission.microphone.request(); } void _setOrientation() { - SystemChrome.setPreferredOrientations([ + SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); @@ -51,6 +71,7 @@ class _InstrumentsScreenState extends State { @override void dispose() { + _searchController.dispose(); super.dispose(); } @@ -58,23 +79,147 @@ class _InstrumentsScreenState extends State { Widget build(BuildContext context) { return MainScaffold( index: 0, - title: 'Instruments', + title: instrumentsTitle, body: SafeArea( - child: ScrollConfiguration( - behavior: const ScrollBehavior(), - child: ListView.builder( - itemCount: instrumentHeadings.length, - itemBuilder: (context, index) { - return GestureDetector( - onTap: () => _onItemTapped(index), - child: ApplicationsListItem( - heading: instrumentHeadings[index], - description: instrumentDesc[index], - instrumentIcon: instrumentIcons[index], + child: Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30.0), + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.1), + blurRadius: 8, + offset: Offset(0, 2), + ), + ], + ), + child: TextField( + controller: _searchController, + onChanged: _filterInstruments, + decoration: InputDecoration( + hintText: searchInstrumentsHint, + hintStyle: TextStyle( + color: Theme.of(context) + .colorScheme + .onSurface + .withAlpha(153), + ), + prefixIcon: Icon( + Icons.search, + color: Theme.of(context) + .colorScheme + .onSurface + .withAlpha(179), + ), + suffixIcon: _searchController.text.isNotEmpty + ? IconButton( + icon: Icon( + Icons.clear, + color: Theme.of(context) + .colorScheme + .onSurface + .withAlpha(179), + ), + onPressed: () { + _searchController.clear(); + _filterInstruments(''); + }, + ) + : null, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(30.0), + borderSide: BorderSide.none, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(30.0), + borderSide: BorderSide( + color: primaryRed, + width: 1.5, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(30.0), + borderSide: BorderSide( + color: primaryRed, + width: 2.5, + ), + ), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + contentPadding: const EdgeInsets.symmetric( + horizontal: 20.0, + vertical: 16.0, + ), + ), ), - ); - }, - ), + ), + ), + Expanded( + child: _filteredIndices.isEmpty + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.search_off, + size: 64, + color: Theme.of(context) + .colorScheme + .onSurface + .withAlpha(128), + ), + const SizedBox(height: 16), + Text( + noInstrumentsFoundMessage, + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith( + color: Theme.of(context) + .colorScheme + .onSurface + .withAlpha(179), + ), + ), + const SizedBox(height: 8), + Text( + tryDifferentSearchSuggestion, + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + color: Theme.of(context) + .colorScheme + .onSurface + .withAlpha(128), + ), + ), + ], + ), + ) + : ScrollConfiguration( + behavior: const ScrollBehavior(), + child: ListView.builder( + itemCount: _filteredIndices.length, + itemBuilder: (context, index) { + final int originalIndex = _filteredIndices[index]; + return GestureDetector( + onTap: () => _onItemTapped(originalIndex), + child: ApplicationsListItem( + heading: instrumentHeadings[originalIndex], + description: instrumentDesc[originalIndex], + instrumentIcon: instrumentIcons[originalIndex], + ), + ); + }, + ), + ), + ), + ], ), ), );