I want to have separated logics for accesing data and using SearchDelegate. But I couldn't provide data from BLoC to SearchDelegate in a clean way.
The problem is, I want to load data only when search icon in appBar is clicked. Not everytime DashboardScreen is loaded. So I cannot simply wrap my IconButton widget in a BLoC screen.
I just want to have an independent SearchDelegate to be able to test it with whatever data I pass in to. Yes, I can set a stub test environment for that BLoC, but I would rather to keep them independent if it is possible.
Simple screen:
class DashboardScreen extends StatelessWidget {
const DashboardScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dashboard'),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () async {
await showSearch(
context: context,
delegate: SearchListView(
listData: data,
),
);
},
),
],
),
body: null,
);
}
}
BLoC:
class SearchScreen extends StatefulWidget {
SearchScreen({Key key}) : super(key: key);
@override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
SearchBloc _bloc;
@override
void initState() {
super.initState();
_bloc = SearchBloc(repository: getIt<SearchRepository>());
_bloc.add(LoadSearch());
}
@override
Widget build(BuildContext context) {
return BlocBuilder<SearchBloc, CallsApi<SearchState>>(
cubit: _bloc,
builder: (context, state) {
if (state is ApiSuccess<SearchState>) {
// Just need to pass state.response.data to searchDelegate.
// I cannot return or call Widget inside onPressed in IconButton.
return SizedBox.shrink();
}
},
);
}
}
SearchDelegate:
class SearchListView extends SearchDelegate<Widget> {
final List<String> listData;
SearchListView({this.listData});
// Change input and hint colors while extending Theme from app.
@override
ThemeData appBarTheme(BuildContext context) {
final theme = Theme.of(context);
return theme.copyWith(
textTheme: theme.textTheme.copyWith(
headline6: theme.textTheme.headline6.copyWith(
color: theme.primaryTextTheme.headline5.color,
),
),
// Extend and reduce color strength by half for hint text.
hintColor: theme.primaryTextTheme.headline5.color.withOpacity(0.5),
);
}
;
// Clear icon at the end of appBar.
@override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = '';
},
),
];
}
// Navigator icon at the start of appBar.
@override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
close(context, null);
},
);
}
// We do not need this since we show all data at first
// and do filtering in buildSuggestion.
@override
Widget buildResults(BuildContext context) {
return SizedBox.shrink();
}
@override
Widget buildSuggestions(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: Space[8]),
child: ListView.separated(
itemCount: listData.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(listData[index]),
contentPadding: EdgeInsets.symmetric(horizontal: Space[24]),
visualDensity: VisualDensity(vertical: -Space[2]),
onTap: () { },
);
},
separatorBuilder: (context, index) => Divider(),
),
);
}
}
I would really appreciate any suggestions.