You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用同一Bloc结合日历查询Firestore指定日期的任务条目?

Hey there! Great job getting your Firestore CRUD working with Bloc—that’s a solid foundation. Let’s tackle your date filtering problem step by step, and clear up your confusion along the way.

First off: you don’t need a separate Calendar Bloc. Date selection is a UI trigger that should feed into your existing TasksBloc to filter tasks. Here’s exactly what to modify:


1. Add a New Event to Trigger Date Filtering

First, update your TasksEvent to include an event that tells the bloc to filter tasks by the selected date:

abstract class TasksEvent extends Equatable {
  const TasksEvent();

  @override
  List<Object> get props => [];
}

// Keep your existing events (LoadTasks, AddTask, etc.)
// Add this new event:
class FilterTasksByDate extends TasksEvent {
  final DateTime selectedDate;

  const FilterTasksByDate(this.selectedDate);

  @override
  List<Object> get props => [selectedDate];
}

2. Update TasksBloc to Handle the Filter Event

Modify your TasksBloc to listen for the new FilterTasksByDate event, and fetch only tasks from the selected day. We’ll also fix the initial load to fetch today’s tasks properly:

class TasksBloc extends Bloc<TasksEvent, TasksState> {
  final TaskRepository _taskRepository;
  StreamSubscription _taskSubscription;

  TasksBloc({@required TaskRepository taskRepository}) : 
        assert(taskRepository != null),
        _taskRepository = taskRepository;

  @override
  TasksState get initialState => TasksLoading();

  @override
  Stream<TasksState> mapEventToState(TasksEvent event) async* {
    if (event is LoadTasks) {
      yield* _mapLoadTasksToState(DateTime.now());
    } else if (event is AddTask) {
      yield* _mapAddTaskToState(event);
    } else if (event is UpdateTask) {
      yield* _mapUpdateTaskToState(event);
    } else if (event is DeleteTask) {
      yield* _mapDeleteTaskToState(event);
    } else if (event is TasksUpdated) {
      yield* _mapTaskUpdatedToState(event);
    } else if (event is FilterTasksByDate) { // Handle the new filter event
      yield* _mapFilterTasksByDateToState(event.selectedDate);
    }
  }

  // Updated initial load to fetch only today's tasks
  Stream<TasksState> _mapLoadTasksToState(DateTime currentDate) async* {
    _taskSubscription?.cancel();
    final startOfDay = DateTime(currentDate.year, currentDate.month, currentDate.day);
    final endOfDay = startOfDay.add(const Duration(days: 1));
    _taskSubscription = _taskRepository.tasks(startOfDay, endOfDay).listen((tasks) {
      add(TasksUpdated(tasks));
    });
  }

  // New method to handle date filtering
  Stream<TasksState> _mapFilterTasksByDateToState(DateTime selectedDate) async* {
    _taskSubscription?.cancel();
    // Define the start/end of the selected day for precise Firestore query
    final startOfDay = DateTime(selectedDate.year, selectedDate.month, selectedDate.day);
    final endOfDay = startOfDay.add(const Duration(days: 1));
    _taskSubscription = _taskRepository.tasks(startOfDay, endOfDay).listen((tasks) {
      add(TasksUpdated(tasks));
    });
  }

  // Keep your existing _mapAddTaskToState, _mapUpdateTaskToState, etc.
}

3. Fix Firestore Repository Query

Your current tasks() method only uses isGreaterThan, which won’t restrict results to a single day. Update it to query a date range (start of the selected day to start of the next day):

class FirebaseTaskRepository extends TaskRepository {
  final taskCollection = Firestore.instance.collection('tasks');

  // Keep your addTask, deleteTask, updateTask methods

  @override
  Stream<List<Task>> tasks(DateTime startOfDay, DateTime endOfDay) {
    return taskCollection
        .where('date', isGreaterThanOrEqualTo: startOfDay)
        .where('date', isLessThan: endOfDay)
        .snapshots()
        .map((snapshot) {
          return snapshot.documents
              .map((doc) => Task.fromEntity(TaskEntity.fromJson(doc.data)))
              .toList();
        });
  }
}

4. Trigger the Filter from the Calendar Component

Update your _buildTableCalendar to dispatch the FilterTasksByDate event when a day is selected. Make sure to pass the BuildContext to access the bloc:

Widget _buildTableCalendar(BuildContext context) {
  return TableCalendar(
    onDaySelected: (DateTime day, List events) {
      pickedDate = day;
      // Tell the TasksBloc to filter tasks for the selected day
      BlocProvider.of<TasksBloc>(context).add(FilterTasksByDate(day));
    },
    calendarController: _calendarController,
    startingDayOfWeek: StartingDayOfWeek.monday,
    calendarStyle: CalendarStyle(
      selectedColor: Colors.blue,
      todayColor: Colors.blue[200],
    ),
  );
}

5. Verify MultiBlocProvider Usage

Your MultiBlocProvider setup is correct! Since it wraps the MaterialApp, all routes (including CalendarScreen) can access the TasksBloc via BlocProvider.of<TasksBloc>(context). No changes needed here.


Key Notes to Test

  • Ensure your Task model stores the date as a DateTime (and your Firestore entity converts it to/from a Timestamp correctly—Firestore handles DateTime ↔ Timestamp comparisons automatically).
  • When you select a date, the TasksBloc will fetch the filtered tasks, update the TasksLoaded state, and your existing BlocBuilder in _buildCalendarListView will automatically refresh the ListView with only that day’s tasks.

内容的提问来源于stack exchange,提问作者Fluzzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 17:27:50