【Flutter】ToDoアプリを作ってみた【riverpod】

カテゴリー:Flutter投稿日:2024-01-20

おばんです。

昨日はQiitaのオンラインイベントがあったのと、勉強がてら作っていたアプリに目処が立ったので進捗報告がてら記事にしたいと思います。

ToDoアプリ

今回はFlutterを使ってToDoアプリを作ってみました。きっかけは現在業務の方でもFlutterのアプリが作られているのですが、これに参画したいというのが一番でした。そこで使う要素はその業務のものに寄せようとして見ましたが、全部採用すると大変なのでまずはriverpodからやって見ました。

最終的にこんなのが完成しました。

イメージしたのはソシャゲのデイリーミッションとかです。個人的にもこの日に何かをやろうとかよりも毎日継続してやったほうがいいものとか、そういうのが多かったのでこんな形式にして見ました。流れとしてはタスクを追加。タスクをこなすとポイントがもらえる。ポイントを使って自分にご褒美をあげる。といった感じです。

riverpod

riverpod自体にもなれなかったのですが、一番困ったのがアーキテクチャです。

以前はBlocを使っていたのもあってあまり迷わなかったのですが、今回のriverpodは正直どうすればいいのか全くわかりませんでした。そこでこのZennの記事を参考にアーキテクチャを組みました。

こんなControllerクラスとProviderを作ってViewに渡す形になりました

class TaskController {
  final ProviderRef ref;
  final TaskRepository taskRepository;
  final PointRepository pointRepository;

  TaskController(
      {required this.ref,
      required this.taskRepository,
      required this.pointRepository});

  addTask(Task task) async {
    task.isComplete = false;
    taskRepository.insertTask(task);
    ref.invalidate(tasksProvider);
    ref.invalidate(tasksFilteredByTaskTypeProvider);
  }
}
final taskRepositoryProvider = Provider<TaskRepository>((ref) {
  return TaskRepository();
});

final taskProvider = FutureProvider.family<Task, int>((ref, id) {
  final taskRepository = ref.watch(taskRepositoryProvider);
  return taskRepository.getTaskById(id);
});

final tasksFilteredByTaskTypeProvider =
    FutureProvider.family<List<Task>, TaskType>((ref, taskType) {
  final taskRepository = ref.watch(taskRepositoryProvider);
  return taskRepository.getTasksFilteredByTaskType(taskType);
});

final taskContollerProvider = Provider<TaskController>((ref) {
  final taskRepository = ref.watch(taskRepositoryProvider);
  final pointRepository = ref.watch(pointRepositoryProvider);
  return TaskController(
      ref: ref,
      taskRepository: taskRepository,
      pointRepository: pointRepository);
});
@override
  Widget build(BuildContext context, WidgetRef ref) {
    return ExpansionTile(title: Text(title), children: <Widget>[
      ref.watch(tasksFilteredByTaskTypeProvider(taskType)).when(
            loading: () => const Center(child: CircularProgressIndicator()),
            error: (error, stackTrace) => const Center(
              child: Text("エラーが発生しました"),
            ),
            data: (tasks) {
              if (tasks.isEmpty) {
                return const Center(
                 // :TODO Write Widget

ロジックに関するものを全てControllerクラスに実装。ViewからはContollerをProvider経由で取得して画面に描画するという方法に落ち着きました。ちなみにコード全体はこれです。

正直実装している感じだと個人的にはBlocのほうが好みかもっていう感じです。ただまだまだ両者ともそんなに使っていないというのもあるのでもう少しriverpodも頑張ってみようと思います。また他にもfreezed, Navigator2.0, riverpod_generator, sealed class...もろもろ使いこなせていないのがあるので、このアプリでここら辺の技術をもっと遊んでいきたいなと思います。