0

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.

emrerdem1
  • 1
  • 1
  • Have you tried using BlocProvider over your main page and BlocBuilder in the delegate builder? It works using an inherited widget, so the builder can get your Bloc from the context. – Alexey Subbotin Feb 25 '21 at 06:30
  • Yes, I can access bloc instance from the context. But `buildSuggestions` or `buildResults` methods get called everytime query input changed. I can cache in BLoC but I would rather keep logic clean instead of finding a workaround to fix what I messed up. Thank you so much for the attention. – emrerdem1 Feb 25 '21 at 08:23

0 Answers0