iT邦幫忙

2022 iThome 鐵人賽

DAY 29
0
自我挑戰組

30天學習flutter系列 第 29

29.完善我們的flutter Todo App

  • 分享至 

  • xImage
  •  

今天我們來完善我們的Todo App

首先,我們先修改我們的model,打開todo\lib\models\todo_model.dart並修改

import 'dart:convert';

class TodoModel {
  TodoModel({
    this.id,
    required this.title,
    required this.done,
    required this.date,
  });

  final int? id;
  final String title;
  final bool done;
  final String date;

  TodoModel copyWith({
    int? id,
    String? title,
    bool? done,
    String? date,
  }) =>
      TodoModel(
        id: id ?? this.id,
        title: title ?? this.title,
        done: done ?? this.done,
        date: date ?? this.date,
      );

  factory TodoModel.fromJson(String str) => TodoModel.fromMap(json.decode(str));

  String toJson() => json.encode(toMap());

  factory TodoModel.fromMap(Map<String, dynamic> json) => TodoModel(
        id: json["id"],
        title: json["title"],
        done: json["done"] == 1 ? true : false,
        date: json["date"],
      );

  Map<String, dynamic> toMap() => {
        "id": id,
        "title": title,
        "done": done,
        "date": date,
      };
}

我們先在todo\lib\services\db_services.dart加入刪除和編輯資料庫的方法

import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:todo/models/todo_model.dart';

class DbService {
  static final DbService instance = DbService._init();
  static Database? _db;

  //o banco de dados sera iniciado na instancia da classe
  DbService._init();

  Future<Database> get db async {
    if (_db != null) return _db!;
    _db = await _useDatabase('notes.db');
    return _db!;
  }

  Future<Database> _useDatabase(String filePath) async {
    final dbPath = await getDatabasesPath();

    return await openDatabase(
      join(dbPath, 'todo.db'),
      onCreate: (db, version) {
        return db.execute('''
            create table Todo ( 
              id integer primary key autoincrement, 
              title text not null,
              date text,
              done integer not null
            )
          ''');
      },
      version: 1,
    );
  }

  Future<List<TodoModel>> getTodos() async {
    final db = await instance.db;
    final result = await db.rawQuery('SELECT * FROM Todo');
    print(result);
    return result.map((i) {
      return TodoModel.fromMap(i);
    }).toList();
  }

  Future addTodo(TodoModel todo) async {
    final db = await instance.db;
    final id = await db.rawInsert(
        'INSERT INTO Todo (Title, Date, Done) VALUES (?,?,?)',
        [todo.title, todo.date, todo.done]);
  }

  Future deleteTodo(TodoModel todo) async {
    final db = await instance.db;
    final _todo =
        await db.delete("Todo", where: "id = ?", whereArgs: [todo.id]);
  }

  Future editTodo(TodoModel todo) async {
    final db = await instance.db;
    final data = todo.toMap();
    final result =
        await db.update('Todo', data, where: "id = ?", whereArgs: [todo.id]);

    print(result);
  }

  //fechar conexao com o banco de dados, funcao nao usada nesse app
  Future close() async {
    final db = await instance.db;
    db.close();
  }
}

打開todo\lib\states\Itodo_state.dart,加入delete和edit方法

import 'package:todo/models/todo_model.dart';

abstract class ITodoState {
  Future<List<TodoModel>> getTodos();
  void addTodo(TodoModel todo);
  void deleteTodo(TodoModel todo);
  void editTodo(TodoModel todo);
}

打開todo\lib\states\todo_state.dart,實現我們delete和edit方法

  @override
  void deleteTodo(TodoModel todo) async {
    // TODO: implement deleteTodo
    try {
      await _dbProvider.deleteTodo(todo);
      getTodos();
    } catch (e) {
      throw Exception();
    }
  }

  @override
  void editTodo(TodoModel todo) async {
    // TODO: implement editTodo
    try {
      await _dbProvider.editTodo(todo);
      getTodos();
    } catch (e) {
      throw Exception();
    }
  }
}
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:todo/services/db_services.dart';
import 'package:todo/models/todo_model.dart';
import 'package:todo/states/Itodo_state.dart';

class TodoState extends StateNotifier<List<TodoModel>> implements ITodoState {
  TodoState(this.ref)
      : _dbProvider = ref.watch(dbProvider),
        super([]);

  final Ref ref;
  final DbService _dbProvider;

  @override
  Future<List<TodoModel>> getTodos() async {
    // TODO: implement getTodos
    try {
      await Future.delayed(const Duration(seconds: 1));
      final todos = await _dbProvider.getTodos();
      state = todos;
    } catch (e) {
      throw Exception();
    }

    return state;
  }

  @override
  void addTodo(TodoModel todo) async {
    // TODO: implement addTodo
    try {
      await _dbProvider.addTodo(todo);
      getTodos();
    } catch (e) {
      throw Exception();
    }
    // state = [
    //   ...state,
    //   todo,
    // ];
  }

  @override
  void deleteTodo(TodoModel todo) async {
    // TODO: implement deleteTodo
    try {
      await _dbProvider.deleteTodo(todo);
      getTodos();
    } catch (e) {
      throw Exception();
    }
  }

  @override
  void editTodo(TodoModel todo) async {
    // TODO: implement editTodo
    try {
      await _dbProvider.editTodo(todo);
      getTodos();
    } catch (e) {
      throw Exception();
    }
  }
}

final dbProvider = Provider((ref) => DbService.instance);

final todosProvider = StateNotifierProvider<TodoState, List<TodoModel>>((ref) {
  return TodoState(ref);
});

打開todo\lib\ui\widgets\todo_item_widget.dart並修改

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:todo/models/todo_model.dart';
import 'package:todo/states/todo_state.dart';

class TodoItem extends ConsumerWidget {
  final TodoModel todo;

  const TodoItem({
    Key? key,
    required this.todo,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Container(
      color: Colors.grey,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const FlutterLogo(),
          Text(todo.title),
          TextButton(onPressed: () {}, child: Text('Done')),
          ElevatedButton(
              onPressed: () {
                ref.read(todosProvider.notifier).deleteTodo(todo);
              },
              child: Text('Delete')),
        ],
      ),
    );
  }
}

todo\lib\ui\widgets\todo_list_widget.dart也做修改,順便解決初始化todo list沒出現的問題

import 'package:flutter/cupertino.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:todo/models/todo_model.dart';
import 'package:todo/states/todo_state.dart';
import 'package:todo/ui/widgets/todo_item_widget.dart';

class TodoList extends ConsumerStatefulWidget {
  const TodoList({Key? key}) : super(key: key);

  @override
  _TodoListState createState() => _TodoListState();
}

class _TodoListState extends ConsumerState<TodoList> {
  @override
  void initState() {
    super.initState();
    final todos = ref.read(todosProvider.notifier).getTodos();
  }

  @override
  Widget build(BuildContext context) {
    final todos = ref.watch(todosProvider);
    return Column(
      children: todos
          .map(
            (e) => TodoItem(
              todo: e,
            ),
          )
          .toList(),
    );
  }
}

現在我們能刪除我們的todo item了
https://ithelp.ithome.com.tw/upload/images/20221014/201089313iDXNPNzOu.png
Delete
https://ithelp.ithome.com.tw/upload/images/20221014/20108931S4tWje6nCE.png


上一篇
28.關於flutter的dev tool(二)
下一篇
30.flutter構建與發佈
系列文
30天學習flutter30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言