-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
/
local_storage_todos_api.dart
108 lines (94 loc) · 3.17 KB
/
local_storage_todos_api.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import 'dart:async';
import 'dart:convert';
import 'package:meta/meta.dart';
import 'package:rxdart/subjects.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:todos_api/todos_api.dart';
/// {@template local_storage_todos_api}
/// A Flutter implementation of the [TodosApi] that uses local storage.
/// {@endtemplate}
class LocalStorageTodosApi extends TodosApi {
/// {@macro local_storage_todos_api}
LocalStorageTodosApi({
required SharedPreferences plugin,
}) : _plugin = plugin {
_init();
}
final SharedPreferences _plugin;
late final _todoStreamController = BehaviorSubject<List<Todo>>.seeded(
const [],
);
/// The key used for storing the todos locally.
///
/// This is only exposed for testing and shouldn't be used by consumers of
/// this library.
@visibleForTesting
static const kTodosCollectionKey = '__todos_collection_key__';
String? _getValue(String key) => _plugin.getString(key);
Future<void> _setValue(String key, String value) =>
_plugin.setString(key, value);
void _init() {
final todosJson = _getValue(kTodosCollectionKey);
if (todosJson != null) {
final todos = List<Map<dynamic, dynamic>>.from(
json.decode(todosJson) as List,
)
.map((jsonMap) => Todo.fromJson(Map<String, dynamic>.from(jsonMap)))
.toList();
_todoStreamController.add(todos);
} else {
_todoStreamController.add(const []);
}
}
@override
Stream<List<Todo>> getTodos() => _todoStreamController.asBroadcastStream();
@override
Future<void> saveTodo(Todo todo) {
final todos = [..._todoStreamController.value];
final todoIndex = todos.indexWhere((t) => t.id == todo.id);
if (todoIndex >= 0) {
todos[todoIndex] = todo;
} else {
todos.add(todo);
}
_todoStreamController.add(todos);
return _setValue(kTodosCollectionKey, json.encode(todos));
}
@override
Future<void> deleteTodo(String id) async {
final todos = [..._todoStreamController.value];
final todoIndex = todos.indexWhere((t) => t.id == id);
if (todoIndex == -1) {
throw TodoNotFoundException();
} else {
todos.removeAt(todoIndex);
_todoStreamController.add(todos);
return _setValue(kTodosCollectionKey, json.encode(todos));
}
}
@override
Future<int> clearCompleted() async {
final todos = [..._todoStreamController.value];
final completedTodosAmount = todos.where((t) => t.isCompleted).length;
todos.removeWhere((t) => t.isCompleted);
_todoStreamController.add(todos);
await _setValue(kTodosCollectionKey, json.encode(todos));
return completedTodosAmount;
}
@override
Future<int> completeAll({required bool isCompleted}) async {
final todos = [..._todoStreamController.value];
final changedTodosAmount =
todos.where((t) => t.isCompleted != isCompleted).length;
final newTodos = [
for (final todo in todos) todo.copyWith(isCompleted: isCompleted),
];
_todoStreamController.add(newTodos);
await _setValue(kTodosCollectionKey, json.encode(newTodos));
return changedTodosAmount;
}
@override
Future<void> close() {
return _todoStreamController.close();
}
}