diff --git a/moor/lib/diff_util.dart b/moor/lib/diff_util.dart deleted file mode 100644 index e1ab3119..00000000 --- a/moor/lib/diff_util.dart +++ /dev/null @@ -1,81 +0,0 @@ -/// A utility library to find an edit script that turns a list into another. -/// This is useful when displaying a updating stream of immutable lists in a -/// list that can be updated. -@Deprecated('Will be removed in moor 2.0') -library diff_util; - -import 'package:moor/src/utils/android_diffutils_port.dart' as impl; - -class EditAction { - /// The index of the first list on which this action should be applied. If - /// this action [isDelete], that index and the next [amount] indices should be - /// deleted. Otherwise, this index should be moved back by [amount] and - /// entries from the second list (starting at [indexFromOther]) should be - /// inserted into the gap. - final int index; - - /// The amount of entries affected by this action - final int amount; - - /// If this action [isInsert], this is the first index from the second list - /// from where the items should be taken from. - final int indexFromOther; - - /// Whether this action should delete entries from the first list - bool get isDelete => indexFromOther == null; - - /// Whether this action should insert entries into the first list - bool get isInsert => indexFromOther != null; - - EditAction(this.index, this.amount, this.indexFromOther); - - @override - String toString() { - if (isDelete) { - return 'EditAction: Delete $amount entries from the first list, starting ' - 'at index $index'; - } else { - return 'EditAction: Insert $amount entries into the first list, taking ' - 'them from the second list starting at $indexFromOther. The entries ' - 'should be written starting at index $index'; - } - } -} - -/// Finds the shortest edit script that turns list [a] into list [b]. -/// The implementation is ported from androids DiffUtil, which in turn -/// implements a variation of Eugene W. Myer's difference algorithm. The -/// algorithm is optimized for space and uses O(n) space to find the minimal -/// number of addition and removal operations between the two lists. It has -/// O(N + D^2) time performance, where D is the minimum amount of edits needed -/// to turn a into b. -List diff(List a, List b, - {bool Function(T a, T b) equals}) { - final defaultEquals = equals ?? (T a, T b) => a == b; - final snakes = impl.calculateDiff(impl.DiffInput(a, b, defaultEquals)); - final actions = []; - - var posOld = a.length; - var posNew = b.length; - for (var snake in snakes.reversed) { - final snakeSize = snake.size; - final endX = snake.x + snakeSize; - final endY = snake.y + snakeSize; - - if (endX < posOld) { - // starting (including) with index endX, delete posOld - endX chars from a - actions.add(EditAction(endX, posOld - endX, null)); - } - if (endY < posNew) { - // starting with index endX, insert posNex - endY characters into a. The - // characters should be taken from b, starting (including) at the index - // endY. The char that was at index endX should be pushed back. - actions.add(EditAction(endX, posNew - endY, endY)); - } - - posOld = snake.x; - posNew = snake.y; - } - - return actions; -} diff --git a/moor/lib/src/utils/android_diffutils_port.dart b/moor/lib/src/utils/android_diffutils_port.dart deleted file mode 100644 index 1284aa4e..00000000 --- a/moor/lib/src/utils/android_diffutils_port.dart +++ /dev/null @@ -1,249 +0,0 @@ -// ignore_for_file: cascade_invocations - -/* -This implementation is copied from the DiffUtil class of the android support -library, available at https://chromium.googlesource.com/android_tools/+/refs/heads/master/sdk/sources/android-25/android/support/v7/util/DiffUtil.java -It has the following license: - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -class Snake { - int x; - int y; - int size; - bool removal; - bool reverse; -} - -class Range { - int oldListStart, oldListEnd; - int newListStart, newListEnd; - - Range.nullFields(); - Range(this.oldListStart, this.oldListEnd, this.newListStart, this.newListEnd); -} - -class DiffInput { - final List from; - final List to; - final bool Function(T a, T b) equals; - - DiffInput(this.from, this.to, this.equals); - - bool areItemsTheSame(int fromPos, int toPos) { - return equals(from[fromPos], to[toPos]); - } -} - -@Deprecated('Will be removed in moor 2.0') -List calculateDiff(DiffInput input) { - final oldSize = input.from.length; - final newSize = input.to.length; - - final snakes = []; - final stack = []; - - stack.add(Range(0, oldSize, 0, newSize)); - - final max = oldSize + newSize + (oldSize - newSize).abs(); - - final forward = List(max * 2); - final backward = List(max * 2); - - final rangePool = []; - - while (stack.isNotEmpty) { - final range = stack.removeLast(); - final snake = _diffPartial(input, range.oldListStart, range.oldListEnd, - range.newListStart, range.newListEnd, forward, backward, max); - - if (snake != null) { - if (snake.size > 0) { - snakes.add(snake); - } - - // offset the snake to convert its coordinates from the Range's are to - // global - snake.x += range.oldListStart; - snake.y += range.newListStart; - - // add new ranges for left and right - final left = - rangePool.isEmpty ? Range.nullFields() : rangePool.removeLast(); - left.oldListStart = range.oldListStart; - left.newListStart = range.newListStart; - if (snake.reverse) { - left.oldListEnd = snake.x; - left.newListEnd = snake.y; - } else { - if (snake.removal) { - left.oldListEnd = snake.x - 1; - left.newListEnd = snake.y; - } else { - left.oldListEnd = snake.x; - left.newListEnd = snake.y - 1; - } - } - stack.add(left); - - final right = range; - if (snake.reverse) { - if (snake.removal) { - right.oldListStart = snake.x + snake.size + 1; - right.newListStart = snake.y + snake.size; - } else { - right.oldListStart = snake.x + snake.size; - right.newListStart = snake.y + snake.size + 1; - } - } else { - right.oldListStart = snake.x + snake.size; - right.newListStart = snake.y + snake.size; - } - stack.add(right); - } else { - rangePool.add(range); - } - } - - snakes.sort((a, b) { - final cmpX = a.x - b.x; - return cmpX == 0 ? a.y - b.y : cmpX; - }); - - // add root snake - final first = snakes.isEmpty ? null : snakes.first; - - if (first == null || first.x != 0 || first.y != 0) { - snakes.insert( - 0, - Snake() - ..x = 0 - ..y = 0 - ..removal = false - ..size = 0 - ..reverse = false); - } - - return snakes; -} - -Snake _diffPartial(DiffInput input, int startOld, int endOld, int startNew, - int endNew, List forward, List backward, int kOffset) { - final oldSize = endOld - startOld; - final newSize = endNew - startNew; - - if (endOld - startOld < 1 || endNew - startNew < 1) return null; - - final delta = oldSize - newSize; - final dLimit = (oldSize + newSize + 1) ~/ 2; - - forward.fillRange(kOffset - dLimit - 1, kOffset + dLimit + 1, 0); - backward.fillRange( - kOffset - dLimit - 1 + delta, kOffset + dLimit + 1 + delta, oldSize); - - final checkInFwd = delta.isOdd; - - for (var d = 0; d <= dLimit; d++) { - for (var k = -d; k <= d; k += 2) { - // find forward path - // we can reach k from k - 1 or k + 1. Check which one is further in the - // graph. - int x; - bool removal; - - if (k == -d || - k != d && forward[kOffset + k - 1] < forward[kOffset + k + 1]) { - x = forward[kOffset + k + 1]; - removal = false; - } else { - x = forward[kOffset + k - 1] + 1; - removal = true; - } - - // set y based on x - var y = x - k; - - // move diagonal as long as items match - while (x < oldSize && - y < newSize && - input.areItemsTheSame(startOld + x, startNew + y)) { - x++; - y++; - } - - forward[kOffset + k] = x; - - if (checkInFwd && k >= delta - d + 1 && k <= delta + d - 1) { - if (forward[kOffset + k] >= backward[kOffset + k]) { - final outSnake = Snake()..x = backward[kOffset + k]; - outSnake - ..y = outSnake.x - k - ..size = forward[kOffset + k] - backward[kOffset + k] - ..removal = removal - ..reverse = false; - - return outSnake; - } - } - } - - for (var k = -d; k <= d; k += 2) { - // find reverse path at k + delta, in reverse - final backwardK = k + delta; - int x; - bool removal; - - if (backwardK == d + delta || - backwardK != -d + delta && - backward[kOffset + backwardK - 1] < - backward[kOffset + backwardK + 1]) { - x = backward[kOffset + backwardK - 1]; - removal = false; - } else { - x = backward[kOffset + backwardK + 1] - 1; - removal = true; - } - - // set y based on x - var y = x - backwardK; - // move diagonal as long as items match - while (x > 0 && - y > 0 && - input.areItemsTheSame(startOld + x - 1, startNew + y - 1)) { - x--; - y--; - } - - backward[kOffset + backwardK] = x; - - if (!checkInFwd && k + delta >= -d && k + delta <= d) { - if (forward[kOffset + backwardK] >= backward[kOffset + backwardK]) { - final outSnake = Snake()..x = backward[kOffset + backwardK]; - outSnake - ..y = outSnake.x - backwardK - ..size = - forward[kOffset + backwardK] - backward[kOffset + backwardK] - ..removal = removal - ..reverse = true; - - return outSnake; - } - } - } - } - - throw StateError("Unexpected case: Please make sure the lists don't change " - 'during a diff'); -} diff --git a/moor/test/diff_util_test.dart b/moor/test/diff_util_test.dart deleted file mode 100644 index 3b838add..00000000 --- a/moor/test/diff_util_test.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:test_api/test_api.dart'; -import 'package:moor/diff_util.dart'; - -List applyEditScript(List a, List b, List actions) { - final copy = List.of(a); - - for (var action in actions) { - if (action.isDelete) { - final deleteStartIndex = action.index; - copy.removeRange(deleteStartIndex, deleteStartIndex + action.amount); - } else if (action.isInsert) { - final toAdd = b.getRange( - action.indexFromOther, action.indexFromOther + action.amount); - copy.insertAll(action.index, toAdd); - } - } - - return copy; -} - -void main() { - final a = ['a', 'b', 'c', 'a', 'b', 'b', 'a']; - final b = ['c', 'b', 'a', 'b', 'a', 'c']; - - test('diff matcher should produce a correct edit script', () { - expect(applyEditScript(a, b, diff(a, b)), b); - }); -} diff --git a/moor_flutter/lib/moor_flutter.dart b/moor_flutter/lib/moor_flutter.dart index 8ba481bf..c30d6e1e 100644 --- a/moor_flutter/lib/moor_flutter.dart +++ b/moor_flutter/lib/moor_flutter.dart @@ -12,7 +12,6 @@ import 'package:moor/moor.dart'; import 'package:moor/backends.dart'; import 'package:sqflite/sqflite.dart' as s; -export 'package:moor_flutter/src/animated_list.dart'; export 'package:moor/moor.dart'; /// Signature of a function that runs when a database doesn't exist on file. diff --git a/moor_flutter/lib/src/animated_list.dart b/moor_flutter/lib/src/animated_list.dart deleted file mode 100644 index d1507285..00000000 --- a/moor_flutter/lib/src/animated_list.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/widgets.dart'; - -// ignore: deprecated_member_use -import 'package:moor/diff_util.dart'; - -typedef Widget ItemBuilder( - BuildContext context, T item, Animation anim); -typedef Widget RemovedItemBuilder( - BuildContext context, T item, Animation anim); - -/// An [AnimatedList] that shows the result of a moor query stream. -@Deprecated('Will be removed in moor 2.0. You could use the ' - 'animated_stream_list package as an alternative') -class MoorAnimatedList extends StatefulWidget { - final Stream> stream; - final ItemBuilder itemBuilder; - final RemovedItemBuilder removedItemBuilder; - - /// A function that decides whether two items are considered equal. By - /// default, `a == b` will be used. A customization is useful if the content - /// of items can change (e.g. when a title changes, you'd only want to change - /// one text and not let the item disappear to show up again). - final bool Function(T a, T b) equals; - - MoorAnimatedList( - {@required this.stream, - @required this.itemBuilder, - @required this.removedItemBuilder, - this.equals}); - - @override - _MoorAnimatedListState createState() { - return _MoorAnimatedListState(); - } -} - -class _MoorAnimatedListState extends State> { - List _lastSnapshot; - int _initialItemCount; - - StreamSubscription _subscription; - - final GlobalKey _key = GlobalKey(); - AnimatedListState get listState => _key.currentState; - - @override - void initState() { - _setupSubscription(); - super.initState(); - } - - void _receiveData(List data) { - if (listState == null) { - setState(() { - _lastSnapshot = data; - _initialItemCount = data.length; - }); - return; - } - - if (_lastSnapshot == null) { - // no diff possible. Initialize lists instead of diffing - _lastSnapshot = data; - for (var i = 0; i < data.length; i++) { - listState.insertItem(i); - } - } else { - final editScript = diff(_lastSnapshot, data, equals: widget.equals); - - for (var action in editScript) { - if (action.isDelete) { - // we need to delete action.amount items at index action.index - for (var i = 0; i < action.amount; i++) { - // i items have already been deleted, so + 1 for the index. Notice - // that we don't have to do this when calling removeItem on the - // animated list state, as it will reflect the operation immediately. - final itemHere = _lastSnapshot[action.index + i]; - listState.removeItem(action.index, (ctx, anim) { - return widget.removedItemBuilder(ctx, itemHere, anim); - }); - } - } else { - for (var i = 0; i < action.amount; i++) { - listState.insertItem(action.index + i); - } - } - } - - setState(() { - _lastSnapshot = data; - }); - } - } - - void _setupSubscription() { - _subscription = widget.stream.listen(_receiveData); - } - - @override - void didUpdateWidget(MoorAnimatedList oldWidget) { - _subscription?.cancel(); - _lastSnapshot = null; - _setupSubscription(); - - super.didUpdateWidget(oldWidget); - } - - @override - void dispose() { - _subscription?.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - if (_lastSnapshot == null) return const SizedBox(); - - return AnimatedList( - key: _key, - initialItemCount: _initialItemCount ?? 0, - itemBuilder: (ctx, index, anim) { - final item = _lastSnapshot[index]; - final child = widget.itemBuilder(ctx, item, anim); - - return child; - }, - ); - } -}