Index: pkg/immi_samples/lib/ios/ImmiSamples/SlidingWindowPresenter.mm |
diff --git a/pkg/immi_samples/lib/ios/ImmiSamples/SlidingWindowPresenter.mm b/pkg/immi_samples/lib/ios/ImmiSamples/SlidingWindowPresenter.mm |
deleted file mode 100644 |
index add30578a1faa8cb3f044142150b1d66dc142446..0000000000000000000000000000000000000000 |
--- a/pkg/immi_samples/lib/ios/ImmiSamples/SlidingWindowPresenter.mm |
+++ /dev/null |
@@ -1,284 +0,0 @@ |
-// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE.md file. |
- |
-#import "SlidingWindowPresenter.h" |
- |
-@interface SlidingWindowPresenter () |
- |
-@property id<CellPresenter> cellPresenter; |
-@property UITableView* tableView; |
- |
-// Is the TableView of this sliding window currently scrolling. |
-@property bool scrolling; |
- |
-// Internal properties for updating the sliding-window display range. |
-// These are not "presentation state" but are rather mostly-constant values |
-// representing the physical dimensions of the screen. |
- |
-// Number of items in the sliding-window display. |
-// Must be > 2 * bufferAdvance + |visible items on screen|. |
-@property int bufferCount; |
- |
-// Access to an item within 'slack' distance of the start or end of |
-// the sliding-window triggers a sliding-window shift. |
-// Must be > 1 (a zero value will result in no shifting). |
-@property int bufferSlack; |
- |
-// Number of items to shift the buffer by when shifting. |
-// Must be >= bufferSlack. |
-@property int bufferAdvance; |
- |
-@property SlidingWindowNode* root; |
- |
-@end |
- |
-@implementation SlidingWindowPresenter |
- |
-- (id)initWithCellPresenter:(id<CellPresenter>)presenter |
- tableView:(UITableView*)tableView { |
- self.scrolling = false; |
- self.cellPresenter = presenter; |
- self.tableView = tableView; |
- [self setBufferParametersBasedOnViewSize]; |
- return self; |
-} |
- |
-- (void)setBufferParametersBasedOnViewSize { |
- CGFloat rowHeight = self.cellPresenter.minimumCellHeight; |
- CGFloat tableHeight = self.tableView.bounds.size.height; |
- int cellCount = (int) (tableHeight / rowHeight); |
- |
- self.bufferSlack = 1; |
- self.bufferAdvance = cellCount; |
- self.bufferCount = 3 * self.bufferAdvance + cellCount; |
-} |
- |
-- (void)presentSlidingWindow:(SlidingWindowNode*)node { |
- [self checkDisplayWindow:node]; |
- dispatch_async(dispatch_get_main_queue(), ^{ |
- [self presentOnMainThread:node]; |
- }); |
-} |
- |
-- (void)patchSlidingWindow:(SlidingWindowPatch*)patch { |
- assert(patch.updated); |
- [self checkDisplayWindow:patch.current]; |
- dispatch_async(dispatch_get_main_queue(), ^{ |
- [self patchOnMainThread:patch]; |
- }); |
-} |
- |
-- (void)checkDisplayWindow:(SlidingWindowNode*)node { |
- if (node.window.count == 0) { |
- node.display(0, self.bufferCount); |
- } |
-} |
- |
-- (NSInteger)tableView:(UITableView*)tableView |
- numberOfRowsInSection:(NSInteger)section { |
- return self.root == nil ? 0 : self.root.minimumCount; |
-} |
- |
-- (UITableViewCell*)tableView:(UITableView*)tableView |
- cellForRowAtIndexPath:(NSIndexPath*)indexPath { |
- Node* node = [self itemAtIndex:indexPath.row]; |
- return [self.cellPresenter tableView:tableView |
- indexPath:indexPath |
- present:node]; |
-} |
- |
-// To track what items are visible on screen we rely on the fact that only |
-// visible items are accessed by cellForRowAtIndexPath. When accessing an index |
-// that is in the proximity of either the start or the end of the sliding |
-// window, we shift the window. |
-- (id)itemAtIndex:(int)index { |
- assert(self.root != nil); |
- if (index < self.windowStart + self.bufferSlack) { |
- [self shiftDown:index]; |
- } else if (index + self.bufferSlack >= self.windowEnd) { |
- [self shiftUp:index]; |
- } |
- int adjusted = [self windowIndex:index]; |
- // Return nil if the adjusted index is outside the sliding window. |
- return (adjusted < 0) ? nil : [self.root.window objectAtIndex:adjusted]; |
-} |
- |
-- (void)shiftDown:(int)index { |
- int start = (index > self.bufferAdvance) ? index - self.bufferAdvance : 0; |
- if (start == self.windowStart) return; |
- [self refreshDisplayStart:start end:start + self.bufferCount]; |
-} |
- |
-- (void)shiftUp:(int)index { |
- int end = index + self.bufferAdvance + 1; |
- if (end > self.maximumCount) end = self.maximumCount; |
- if (end == self.windowEnd) return; |
- if (end > self.bufferCount) { |
- [self refreshDisplayStart:end - self.bufferCount end:end]; |
- } else { |
- [self refreshDisplayStart:0 end:self.bufferCount]; |
- } |
-} |
- |
-- (void)refreshDisplayStart:(int)start end:(int)end { |
- self.root.display(start, end); |
-} |
- |
-// Adjust the scroll position if the visible rows are outside the window buffer. |
-// Returns true if it is or if scroll position was adjusted. |
-- (bool)adjustScrollPosition { |
- // TODO(zerny): Identify "scroll to top" as scrolling and enable this again. |
- return false; |
- // TODO(zerny): Properly track the scroll position. |
- // If the current view is outside the visible view adjust the visible view. |
- if (!self.scrolling && self.tableView.indexPathsForVisibleRows.count > 0) { |
- int start = self.windowStart; |
- int end = self.windowEnd; |
- int row = [[self.tableView.indexPathsForVisibleRows objectAtIndex:0] row]; |
- if (row < start || end <= row) { |
- // Adjust the start by buffer slack so we don't trigger a window shift. |
- if (start != 0) start += self.bufferSlack + 1; |
- NSIndexPath* path = [NSIndexPath indexPathForRow:start inSection:0]; |
- [self.tableView reloadData]; |
- if (start < end) { |
- [self.tableView scrollToRowAtIndexPath:path |
- atScrollPosition:UITableViewScrollPositionTop |
- animated:NO]; |
- } |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-- (void)presentOnMainThread:(SlidingWindowNode*)node { |
- self.root = node; |
- if ([self adjustScrollPosition]) return; |
- [self.tableView reloadData]; |
-} |
- |
-- (void)patchOnMainThread:(SlidingWindowPatch*)patch { |
- self.root = patch.current; |
- if ([self adjustScrollPosition]) return; |
- |
- int previousCount = patch.previous.minimumCount; |
- int currentCount = patch.current.minimumCount; |
- assert(previousCount == [self.tableView numberOfRowsInSection:0]); |
- |
- // The stable range is positions in the view both before and after the patch. |
- int stableCount = MIN(previousCount, currentCount); |
- |
- // Independently track if insert or removes have been made. |
- bool containsInserts = false; |
- bool containsRemoves = false; |
- |
- // Find an update ranges: |
- NSMutableArray* updatePaths = [[NSMutableArray alloc] init]; |
- for (int i = 0; i < patch.window.regions.count; ++i) { |
- ListRegionPatch* region = patch.window.regions[i]; |
- if (!region.isUpdate) { |
- containsInserts = containsInserts || region.isInsert; |
- containsRemoves = containsRemoves || region.isRemove; |
- continue; |
- } |
- ListRegionUpdatePatch* update = (id)region; |
- for (int j = 0; j < update.updates.count; ++j) { |
- int position = [self windowIndexToTableIndex:update.index + j]; |
- if (position >= stableCount) continue; |
- [updatePaths addObject:[NSIndexPath indexPathForRow:position inSection:0]]; |
- } |
- } |
- |
- // This patch routine assumes that the diff algorithm will not produce |
- // both an insertion and a deletion region in the same patch. |
- assert(!containsInserts || !containsRemoves); |
- |
- // Find either the insert or the remove positions: |
- NSMutableArray* insertPaths; |
- NSMutableArray* removePaths; |
- if (stableCount < currentCount) { |
- insertPaths = [[NSMutableArray alloc] init]; |
- for (int i = stableCount; i < currentCount; ++i) { |
- [insertPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]]; |
- } |
- } else if (stableCount < previousCount) { |
- removePaths = [[NSMutableArray alloc] init]; |
- for (int i = stableCount; i < previousCount; ++i) { |
- [removePaths addObject:[NSIndexPath indexPathForRow:i inSection:0]]; |
- } |
- } |
- |
- // Batch notify the table view of the changes. |
- [self.tableView beginUpdates]; |
- [self.tableView reloadRowsAtIndexPaths:updatePaths |
- withRowAnimation:UITableViewRowAnimationNone]; |
- if (insertPaths != nil) { |
- [self.tableView insertRowsAtIndexPaths:insertPaths |
- withRowAnimation:UITableViewRowAnimationNone]; |
- } |
- if (removePaths != nil) { |
- [self.tableView deleteRowsAtIndexPaths:removePaths |
- withRowAnimation:UITableViewRowAnimationNone]; |
- } |
- [self.tableView endUpdates]; |
- |
- assert(currentCount == [self.tableView numberOfRowsInSection:0]); |
-} |
- |
-- (int)windowIndexToTableIndex:(int)index { |
- int indexDelta = index - self.root.windowOffset; |
- if (indexDelta < 0) indexDelta += self.root.window.count; |
- return [self windowStart] + indexDelta; |
-} |
- |
-- (int)windowIndex:(int)index { |
- assert(self.root != nil); |
- if (index < self.windowStart || self.windowEnd <= index) return -1; |
- int i = self.root.windowOffset + index - self.windowStart; |
- return i % self.windowCount; |
-} |
- |
-// The maximum number of items that can be in the list. |
-- (int)maximumCount { |
- return self.root.maximumCount < 0 ? INT_MAX : self.root.maximumCount; |
-} |
- |
-- (int)windowCount { |
- return self.root.window.count; |
-} |
- |
-- (int)windowEnd { |
- return self.root.startOffset + self.windowCount; |
-} |
- |
-- (int)windowStart { |
- return self.root.startOffset; |
-} |
- |
-- (void)tableView:(UITableView*)tableView |
- didSelectRowAtIndexPath:(NSIndexPath*)indexPath { |
- self.root.toggle(indexPath.row); |
-} |
- |
-- (CGFloat)tableView:(UITableView*)tableView |
- heightForRowAtIndexPath:(NSIndexPath*)indexPath { |
- return [self.cellPresenter tableView:tableView |
- heightForRowAtIndexPath:indexPath]; |
-} |
- |
-- (CGFloat)tableView:(UITableView*)tableView |
- estimatedHeightForRowAtIndexPath:(NSIndexPath*)indexPath { |
- return [self.cellPresenter tableView:tableView |
- estimatedHeightForRowAtIndexPath:indexPath]; |
-} |
- |
-- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { |
- self.scrolling = true; |
-} |
- |
-- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { |
- self.scrolling = false; |
-} |
- |
-@end |