iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 11
0
Mobile Development

Flutter 從零開始,Android、iOS一次搞定,重新挑戰。系列 第 11

[Day11] Flutter 把代辦存進手機,再也不隨便消失(SQLite)。

之前有說到我們的代辦清單,每次都會重新來過。
所以啊!我們要把它存進我們的移動裝置裡。

這邊我們用的套件是sqflite連結

第一步,我們先建立我們的DB Class lib/db/todo_helper.dart

import 'package:sqflite/sqflite.dart' as sql;
import 'package:path/path.dart' as path;
import 'package:sqflite/sqlite_api.dart';

class DBHelper {
  static Future<Database> database() async {
    final dbPath = await sql.getDatabasesPath();
    return sql.openDatabase(path.join(dbPath, 'todos.db'),
        onCreate: (db, version) {
      return db.execute(
          'CREATE TABLE todo_list(id INTEGER PRIMARY KEY, groupId INTEGER, title TEXT, description TEXT, done INTEGER)');
    }, version: 1);
  }

  static Future<void> insert(String table, Map<String, Object> data) async {
    final db = await DBHelper.database();
    db.insert(
      table,
      data,
      conflictAlgorithm: ConflictAlgorithm.replace,
    );
  }

  static Future<void> update(String table, Map<String, Object> data) async {
    final db = await DBHelper.database();
    db.update(table, data, where: 'id = ?', whereArgs: [data['id']]);
  }

  static Future<void> delete(String table, Map<String, Object> data) async {
    final db = await DBHelper.database();
    db.delete(table, where: 'id = ?', whereArgs: [data['id']]);
  }

  static Future<List<Map<String, dynamic>>> getData(String table) async {
    final db = await DBHelper.database();
    return db.query(table);
  }
}

這樣我們就可以正常使用我們的但辦清單DB了,然後看哪邊需要用到它。
就把它加進去。

主要要更改的地方,lib/providers/todos.dart

Class Todo with ChangeNotifier {
// ...
  void toggleDone() {
    done = !done;
    notifyListeners();
    DBHelper.update(
      'todo_list',
      {
        'id': id,
        'groupId': groupId,
        'title': title,
        'done': done,
        'description': description,
      },
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'groupId': groupId,
      'title': title,
      'description': description,
      'done': done,
    };
  }
}

Class Todos with ChangeNotifier {
// ...
  Future<void> fetchAndSetTodos() async {
    final dataList = await DBHelper.getData('todo_list');
    _items = dataList.map(
      (item) {
        print(item['done']);
        return Todo(
          id: item['id'],
          groupId: item['groupId'],
          title: item['title'],
          description: item['description'],
          done: item['done'] == 1 ? true : false,
        );
      },
    ).toList();
    notifyListeners();
  }

  void addTodo(Todo todo) {
    final newTodo = Todo(
      title: todo.title,
      description: todo.description,
      done: false,
      groupId: todo.groupId,
    );
    // _items.add(newTodo);
    _items.insert(0, newTodo); // at the start of list
    notifyListeners();
    DBHelper.insert('todo_list', todo.toMap());
  }

  void deleteTodo(int itemId) {
    final existingTodoIndex = _items.indexWhere((prod) => prod.id == itemId);
    var existingTodo = _items[existingTodoIndex];
    _items.removeAt(existingTodoIndex);
    notifyListeners();
    DBHelper.delete('todo_list', existingTodo.toMap());
  }
  // ...
}

再來,我們開啟代辦清單時,得要先跟SQLite拿資料,所以要到todos_homepage.dart,把我們的fetchAndSetTodos()放到該放的位置。

body: FutureBuilder(
    future: Provider.of<Todos>(context, listen: false).fetchAndSetTodos(),
    builder: (ctx, snapshot) => snapshot.connectionState ==
            ConnectionState.waiting
        ? Center(
            child: CircularProgressIndicator(),
          )
        : Consumer<Todos>(
            child: Center(
              child: const Text('Got no places yet, start adding some!'),
            ),
            builder: (ctx, greatPlaces, ch) => greatPlaces.items.length <= 0
                ? ch
                : ListView.builder(
                    itemCount: greatPlaces.getByGroupId.length,
                    itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
                      value: greatPlaces.getByGroupId[i],
                      child:
                          TodoTile(slidableController: slidableController),
                    ),
                  ),
          ),
  ),

在 Scaffold -> body 我們包了一個 FutureBuilder ,讓我們可以非同步的跟SQLite要資料,
且可以知道是否還在Lodding,所以在這加上了 CircularProgressIndicator(),提高使用者體驗。

明天繼續把群組也存進手機吧!


上一篇
[Day10] Flutter 新增群組Modal。
下一篇
[Day12] Flutter 儲存資料套件,第二招 provider_path。
系列文
Flutter 從零開始,Android、iOS一次搞定,重新挑戰。12

尚未有邦友留言

立即登入留言