blob: a5f0ce1441715e881c3380bb799d53b68f13f89b [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data' show Uint8List;
import 'package:fidl/fidl.dart';
import 'package:fidl_fuchsia_ledger/fidl_async.dart' as ledger;
import 'package:fidl_fuchsia_modular/fidl_async.dart' as modular;
import 'package:fuchsia_logger/logger.dart';
import 'package:lib.widgets.dart/model.dart';
import '../ledger_helpers.dart';
/// The model for the todo list module.
class TodoListModel extends Model {
final Random _random = Random(DateTime.now().millisecondsSinceEpoch);
final ledger.PageWatcherBinding _pageWatcherBinding =
ledger.PageWatcherBinding();
final ledger.LedgerProxy _ledger = ledger.LedgerProxy();
final ledger.PageProxy _page = ledger.PageProxy();
/// The todo items. The source of truth is Ledger, so [_items] should never be
/// modified directly.
Map<List<int>, String> _items = <List<int>, String>{};
/// Retrieves the todo items.
Map<List<int>, String> get items => _items;
/// Call this method to connect the model
void connect(modular.ComponentContext componentContext) {
_ledger.ctrl.whenClosed.then((_) => log.warning('Ledger disconnected'));
componentContext.getLedger(_ledger.ctrl.request());
_readInitialData();
}
Future<void> _readInitialData() async {
await _ledger.getRootPage(_page.ctrl.request());
final snapshot = ledger.PageSnapshotProxy();
await _page.getSnapshotNew(
snapshot.ctrl.request(),
Uint8List(0),
_pageWatcherBinding.wrap(_PageWatcher(this)),
);
_readItems(snapshot);
}
/// Call when the module should be terminated.
Future<void> onTerminate() async {
_pageWatcherBinding.close();
_ledger.ctrl.close();
_page.ctrl.close();
}
/// Marks the item of the given [id] as done.
void markItemDone(List<int> id) {
_page.deleteNew(id);
}
/// Adds a new todo item with the given [content].
void addItem(String content) {
_page.putNew(_makeKey(), utf8.encode(content));
}
void _readItems(ledger.PageSnapshotProxy snapshot) {
getEntriesFromSnapshot(snapshot,
(ledger.Status status, Map<List<int>, String> items) {
if (validateLedgerResponse(status, 'getEntries')) {
_items = items;
notifyListeners();
snapshot.ctrl.close();
}
});
}
Uint8List _makeKey() {
Uint8List key = Uint8List(16);
for (int i = 0; i < 16; i++) {
key[i] = _random.nextInt(256);
}
return key;
}
}
class _PageWatcher extends ledger.PageWatcher {
final TodoListModel _model;
_PageWatcher(this._model);
/// Implementation of PageWatcher.onChange().
@override
Future<InterfaceRequest<ledger.PageSnapshot>> onChange(
ledger.PageChange pageChange,
ledger.ResultState resultState,
) async {
if (resultState != ledger.ResultState.completed &&
resultState != ledger.ResultState.partialStarted) {
log.info('Unexpected result state in Ledger watcher: $resultState');
return null;
}
final snapshot = ledger.PageSnapshotProxy();
// need to call request() before _readItems so that the object
// is bound and the subsequent reads do not fail
final request = snapshot.ctrl.request();
_model._readItems(snapshot);
return request;
}
}