mirror of
https://github.com/foss42/apidash.git
synced 2025-05-22 08:46:33 +08:00
Merge pull request #347 from sudhar08/feat-Add-a-search/filter-for-collection-pane-#305-
feat: Add a search/filter for collection pane
This commit is contained in:
@ -23,3 +23,5 @@ final nameTextFieldFocusNodeProvider =
|
|||||||
});
|
});
|
||||||
return focusNode;
|
return focusNode;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final searchQueryProvider = StateProvider<String>((ref) => '');
|
||||||
|
@ -69,7 +69,39 @@ class CollectionPane extends ConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
kVSpacer8,
|
kVSpacer10,
|
||||||
|
Container(
|
||||||
|
height: 30,
|
||||||
|
margin: const EdgeInsets.only(right: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: kBorderRadius8,
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
kHSpacer5,
|
||||||
|
Icon(
|
||||||
|
Icons.filter_alt,
|
||||||
|
size: 18,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
kHSpacer5,
|
||||||
|
Expanded(
|
||||||
|
child: RawTextField(
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
hintText: "Filter by name or URL",
|
||||||
|
onChanged: (value) {
|
||||||
|
ref.read(searchQueryProvider.notifier).state =
|
||||||
|
value.toLowerCase();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
kVSpacer10,
|
||||||
const Expanded(
|
const Expanded(
|
||||||
child: RequestList(),
|
child: RequestList(),
|
||||||
),
|
),
|
||||||
@ -109,12 +141,14 @@ class _RequestListState extends ConsumerState<RequestList> {
|
|||||||
final requestItems = ref.watch(collectionStateNotifierProvider)!;
|
final requestItems = ref.watch(collectionStateNotifierProvider)!;
|
||||||
final alwaysShowCollectionPaneScrollbar = ref.watch(settingsProvider
|
final alwaysShowCollectionPaneScrollbar = ref.watch(settingsProvider
|
||||||
.select((value) => value.alwaysShowCollectionPaneScrollbar));
|
.select((value) => value.alwaysShowCollectionPaneScrollbar));
|
||||||
|
final filterQuery = ref.watch(searchQueryProvider).trim();
|
||||||
|
|
||||||
return Scrollbar(
|
return Scrollbar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
thumbVisibility: alwaysShowCollectionPaneScrollbar ? true : null,
|
thumbVisibility: alwaysShowCollectionPaneScrollbar ? true : null,
|
||||||
radius: const Radius.circular(12),
|
radius: const Radius.circular(12),
|
||||||
child: ReorderableListView.builder(
|
child: filterQuery.isEmpty
|
||||||
|
? ReorderableListView.builder(
|
||||||
padding: kPe8,
|
padding: kPe8,
|
||||||
scrollController: controller,
|
scrollController: controller,
|
||||||
buildDefaultDragHandles: false,
|
buildDefaultDragHandles: false,
|
||||||
@ -143,6 +177,24 @@ class _RequestListState extends ConsumerState<RequestList> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
: ListView(
|
||||||
|
padding: kPe8,
|
||||||
|
controller: controller,
|
||||||
|
children: requestSequence.map((id) {
|
||||||
|
var item = requestItems[id]!;
|
||||||
|
if (item.url.toLowerCase().contains(filterQuery) ||
|
||||||
|
item.name.toLowerCase().contains(filterQuery)) {
|
||||||
|
return Padding(
|
||||||
|
padding: kP1,
|
||||||
|
child: RequestItem(
|
||||||
|
id: id,
|
||||||
|
requestModel: item,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return const SizedBox();
|
||||||
|
}).toList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -94,14 +94,39 @@ class JsonSearchField extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return RawTextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
style: kCodeStyle,
|
style: kCodeStyle,
|
||||||
decoration: const InputDecoration(
|
hintText: 'Search..',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RawTextField extends StatelessWidget {
|
||||||
|
const RawTextField({
|
||||||
|
super.key,
|
||||||
|
this.onChanged,
|
||||||
|
this.controller,
|
||||||
|
this.hintText,
|
||||||
|
this.style,
|
||||||
|
});
|
||||||
|
|
||||||
|
final void Function(String)? onChanged;
|
||||||
|
final TextEditingController? controller;
|
||||||
|
final String? hintText;
|
||||||
|
final TextStyle? style;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return TextField(
|
||||||
|
controller: controller,
|
||||||
|
onChanged: onChanged,
|
||||||
|
style: style,
|
||||||
|
decoration: InputDecoration(
|
||||||
isDense: true,
|
isDense: true,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
hintText: 'Search..',
|
hintText: hintText,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -214,13 +214,13 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group("Testing selectedIdEditStateProvider", () {
|
group("Testing selectedIdEditStateProvider", () {
|
||||||
testWidgets(
|
testWidgets('It should have an initial value of null', (tester) async {
|
||||||
'selectedIdEditStateProvider should have an initial value of null',
|
|
||||||
(tester) async {
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
const ProviderScope(
|
const ProviderScope(
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: CollectionPane(),
|
home: Scaffold(
|
||||||
|
body: CollectionPane(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -237,7 +237,9 @@ void main() {
|
|||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
const ProviderScope(
|
const ProviderScope(
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: CollectionPane(),
|
home: Scaffold(
|
||||||
|
body: CollectionPane(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -267,7 +269,9 @@ void main() {
|
|||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
const ProviderScope(
|
const ProviderScope(
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: CollectionPane(),
|
home: Scaffold(
|
||||||
|
body: CollectionPane(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -303,7 +307,9 @@ void main() {
|
|||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
const ProviderScope(
|
const ProviderScope(
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: CollectionPane(),
|
home: Scaffold(
|
||||||
|
body: CollectionPane(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user