This immense Dart program contains a nonexistent amount of errors and warnings. This code has no associated html or css.
Find this at dartpad.dartlang.org/?source=83783e68-9c14-4f0b-aad1-112d16d1fd0f.
Created with <3 with dartpad.dartlang.org.
This immense Dart program contains a nonexistent amount of errors and warnings. This code has no associated html or css.
Find this at dartpad.dartlang.org/?source=83783e68-9c14-4f0b-aad1-112d16d1fd0f.
Created with <3 with dartpad.dartlang.org.
| // This algorithm works so that the items in the beginning of the list | |
| // have an older date than the items at the end of the list. | |
| // I.e., the items in the list are ordered the same way as they would | |
| // be visually shown on the UI (older items at the top, recent at the bottom). | |
| main() => new Page(); | |
| class Item { | |
| String user; | |
| String message; | |
| String type; | |
| DateTime createdDate; | |
| Item(this.user, this.message, this.createdDate, {this.type: 'regular'}); | |
| String toString() => '${user}: ${message} (${createdDate.toString()}) – $type'; | |
| } | |
| enum TargetGroup { | |
| Above, Below, Same, New | |
| } | |
| class Page { | |
| List<ItemGroup> groups = []; | |
| Page() { | |
| // Initial items coming in! | |
| var someItems = [ | |
| new Item('kai', 'Kai 5', new DateTime(2015, 6, 1), type: 'notification'), | |
| new Item('kai', 'Kai 6', new DateTime(2015, 6, 2)), | |
| new Item('dave', 'Dave 4', new DateTime(2015, 6, 3)), | |
| new Item('kai', 'Kai 7', new DateTime(2015, 6, 4)), | |
| new Item('kai', 'Kai EARLIER', new DateTime(2015, 6, 10, 12, 10)), | |
| new Item('dave', 'Dave 5', new DateTime(2015, 6, 5)), | |
| new Item('dave', 'Dave 6', new DateTime(2015, 6, 6)), | |
| new Item('kai', 'Kai LATER', new DateTime(2015, 6, 10, 12, 12)), | |
| new Item('dave', 'Dave 7', new DateTime(2015, 6, 7)), | |
| new Item('dave', 'Dave 8', new DateTime(2015, 6, 8)), | |
| new Item('kai', 'Kai 8', new DateTime(2015, 6, 7)) | |
| ]; | |
| processAll(someItems); | |
| // Later we get more items! | |
| var someMoreItems = [ | |
| new Item('kai', 'Kai 1', new DateTime(2015, 5, 1)), | |
| new Item('kai', 'Kai 2', new DateTime(2015, 5, 2)), | |
| new Item('dave', 'Dave 1', new DateTime(2015, 5, 3)), | |
| new Item('kai', 'Kai 3', new DateTime(2015, 5, 4)), | |
| new Item('dave', 'Dave 2', new DateTime(2015, 5, 5)), | |
| new Item('dave', 'Dave 3', new DateTime(2015, 5, 6)), | |
| new Item('dave', 'Dave much later posted than the above', new DateTime(2015, 5, 8)), | |
| new Item('kai', 'Kai 4', new DateTime(2015, 5, 9)) | |
| ]; | |
| processAll(someMoreItems); | |
| printItems(); | |
| } | |
| void processAll(List<Item> items) { | |
| items.forEach(process); | |
| } | |
| void process(Item item) { | |
| // Retrieve the group within this item belongs to, if any. | |
| var group = groups.firstWhere((group) => group.isDateWithin(item.createdDate), orElse: () => null); | |
| if (group != null) { | |
| TargetGroup target = group.determineTargetGroup(item); | |
| if (target == TargetGroup.Same) { | |
| group.put(item); | |
| } else { | |
| var groupIndex = groups.indexOf(group); | |
| var intersection = group.indexOf(item); | |
| var topHalf = group.items.sublist(0, intersection); | |
| var bottomHalf = group.items.sublist(intersection); | |
| groups.remove(group); // Get rid of the old group, we need to split this thing! | |
| if (target == TargetGroup.New) { | |
| groups.insert(groupIndex, new ItemGroup.fromItems(bottomHalf)); | |
| groups.insert(groupIndex, new ItemGroup(item)); | |
| groups.insert(groupIndex, new ItemGroup.fromItems(topHalf)); | |
| } else if (target == TargetGroup.Above) { | |
| topHalf.add(item); | |
| groups.insert(groupIndex, new ItemGroup.fromItems(bottomHalf)); | |
| groups.insert(groupIndex, new ItemGroup.fromItems(topHalf)); | |
| } else if (target == TargetGroup.Below) { | |
| bottomHalf.insert(0, item); | |
| groups.insert(groupIndex, new ItemGroup.fromItems(bottomHalf)); | |
| groups.insert(groupIndex, new ItemGroup.fromItems(topHalf)); | |
| } else { | |
| throw 'Unknown target group!'; | |
| } | |
| } | |
| } else { | |
| // Okay, so the item is not within ANY group. | |
| // This leaves a few options: | |
| // 1) The item belongs to the top or bottom position of some group (i.e. not within). | |
| // 2) The item needs its own new group. | |
| // Fetch the first groups that are after/before this item. i.e. surrounding the item. | |
| var groupBefore = groups.reversed.firstWhere((group) => item.createdDate.isAfter(group.getLatestDate()), orElse: () => null); | |
| var groupAfter = groups.firstWhere((group) => item.createdDate.isBefore(group.getOldestDate()), orElse: () => null); | |
| if (groupBefore == null && groupAfter == null) { | |
| // No groups at all! | |
| groups.add(new ItemGroup(item)); | |
| } else if (groupBefore != null && groupAfter != null) { | |
| if (groupBefore.determineTargetGroup(item) == TargetGroup.New && groupAfter.determineTargetGroup(item) == TargetGroup.New) { | |
| // The item does not belong in either groups, | |
| // so it has to go in between them in its own group. | |
| var index = groups.indexOf(groupAfter); | |
| groups.insert(index, new ItemGroup(item)); | |
| } else if (groupBefore.determineTargetGroup(item) == TargetGroup.Same) { | |
| // We do not belong to groupAfter, but we belong to groupBefore! | |
| groupBefore.put(item); | |
| } else { | |
| // We belong to groupAfter. | |
| groupAfter.put(item); | |
| } | |
| } else if (groupBefore == null) { | |
| // There was no group before this item, but one after. | |
| // Thus if we belong to groupAfter, let's go there, | |
| // otherwise we need a new group at the top. | |
| if (groupAfter.determineTargetGroup(item) == TargetGroup.Same) { | |
| groupAfter.put(item); | |
| } else { | |
| groups.insert(0, new ItemGroup(item)); | |
| } | |
| } else { | |
| // There was no group after this item, but one before. | |
| // Same as earlier, let's put it there or in a new group at the bottom. | |
| if (groupBefore.determineTargetGroup(item) == TargetGroup.Same) { | |
| groupBefore.put(item); | |
| } else { | |
| groups.add(new ItemGroup(item)); | |
| } | |
| } | |
| } | |
| } | |
| void printItems() { | |
| groups.forEach((group) { | |
| print('GROUP ${group.user}'); | |
| group.items.forEach(print); | |
| print('---'); | |
| }); | |
| } | |
| } | |
| class ItemGroup { | |
| String user; | |
| String type; | |
| List<Item> items = []; | |
| ItemGroup(Item item) { | |
| user = item.user; | |
| type = item.type; | |
| items.add(item); | |
| } | |
| ItemGroup.fromItems(List<Item> list) { | |
| user = list.first.user; | |
| items.addAll(list); | |
| } | |
| DateTime getOldestDate() => items.first.createdDate; | |
| DateTime getLatestDate() => items.last.createdDate; | |
| /** | |
| * Returns true when the given [DateTime] is in between | |
| * the oldest and the latest item in this group. | |
| */ | |
| bool isDateWithin(DateTime date) => date.isAfter(getOldestDate()) && date.isBefore(getLatestDate()); | |
| /** | |
| * Returns the index of where the given item should go to in this group. | |
| */ | |
| int indexOf(Item item) { | |
| for (var i = 0; i < items.length; i++) { | |
| if (item.createdDate.isBefore(items[i].createdDate)) { | |
| return i; | |
| } | |
| } | |
| return items.length; | |
| } | |
| /** | |
| * Puts the given item into this group at the right position. | |
| */ | |
| void put(Item item) { | |
| items.insert(indexOf(item), item); | |
| } | |
| /** | |
| * Returns TargetGroup, which specifies where the item belongs to. | |
| */ | |
| TargetGroup determineTargetGroup(Item item) { | |
| var index = indexOf(item); | |
| var lastIndex = items.length - 1; | |
| bool farFromAboveItem = index > 0 && items[index - 1].createdDate.difference(item.createdDate).inSeconds.abs() > 86400; | |
| bool farFromBelowItem = index < lastIndex && items[index + 1].createdDate.difference(item.createdDate).inSeconds.abs() > 86400; | |
| if (item.user != user || item.type == 'notification' || this.isNotification) { | |
| return TargetGroup.New; | |
| } | |
| if (!farFromAboveItem && !farFromBelowItem) { | |
| return TargetGroup.Same; | |
| } | |
| if (!farFromAboveItem && farFromBelowItem) { | |
| return TargetGroup.Above; | |
| } | |
| if (!farFromAboveItem && !farFromBelowItem) { | |
| return TargetGroup.Below; | |
| } | |
| return TargetGroup.New; | |
| } | |
| bool get isNotification => items.first.type == 'notification'; | |
| String get usernameForDisplay => items.first.user; | |
| DateTime get lastCreatedDate => items.last.createdDate; | |
| } |