Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 162 additions & 42 deletions src/SortableList.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {ScrollView, View, StyleSheet, Platform, RefreshControl, ViewPropTypes} from 'react-native';
import {shallowEqual, swapArrayElements} from './utils';
import {inRange, shallowEqual, swapArrayElements} from './utils';
import Row from './Row';

const AUTOSCROLL_INTERVAL = 100;
Expand Down Expand Up @@ -220,7 +220,6 @@ export default class SortableList extends Component {
const {horizontal, rowActivationTime, sortingEnabled, renderRow} = this.props;
const {animated, order, data, activeRowKey, releasedRowKey, rowsLayouts} = this.state;


let nextX = 0;
let nextY = 0;

Expand Down Expand Up @@ -302,11 +301,13 @@ export default class SortableList extends Component {
}

_onUpdateLayouts() {
const {horizontal} = this.props;
const {order} = this.state;
Promise.all([this._headerLayout, this._footerLayout, ...Object.values(this._rowsLayouts)])
.then(([headerLayout, footerLayout, ...rowsLayouts]) => {
// Can get correct container’s layout only after rows’s layouts.
this._container.measure((x, y, width, height, pageX, pageY) => {
const rowsLayoutsByKey = {};
let rowsLayoutsByKey = {};
let contentHeight = 0;
let contentWidth = 0;

Expand All @@ -315,10 +316,12 @@ export default class SortableList extends Component {
contentHeight += layout.height;
contentWidth += layout.width;
});
rowsLayoutsByKey = this._getRowsLocations(rowsLayoutsByKey, order);

this.setState({
containerLayout: {x, y, width, height, pageX, pageY},
rowsLayouts: rowsLayoutsByKey,
rowsSwapRanges: this._getRowsSwapRanges(rowsLayoutsByKey, order),
headerLayout,
footerLayout,
contentHeight,
Expand All @@ -330,6 +333,54 @@ export default class SortableList extends Component {
});
}

_getRowsLocations(_rowsLayouts, order) {
const {horizontal} = this.props;
const rowsLayouts = {};
let nextX = 0;
let nextY = 0;

for (let i = 0, len = order.length; i < len; i++) {
const rowKey = order[i];
const rowLayout = _rowsLayouts[rowKey];

rowsLayouts[rowKey] = {
...rowLayout,
x: nextX,
y: nextY,
};

if (horizontal) {
nextX += rowLayout.width;
} else {
nextY += rowLayout.height;
}
}

return rowsLayouts;
}

_getRowsSwapRanges(rowsLayouts, order) {
const {horizontal} = this.props;
const rowsSwapRanges = {};

for (let i = 0, len = order.length; i < len; i++) {
const rowKey = order[i];
const rowLayout = rowsLayouts[rowKey];

rowsSwapRanges[rowKey] = horizontal
? {
left: [rowLayout.x + rowLayout.width / 3, rowLayout.x + rowLayout.width],
right: [rowLayout.x, rowLayout.x + 2 * rowLayout.width / 3],
}
: {
top: [rowLayout.y + rowLayout.height / 3, rowLayout.y + rowLayout.height],
bottom: [rowLayout.y, rowLayout.y + 2 * rowLayout.height / 3],
};
}

return rowsSwapRanges;
}

_scroll(animated) {
this._scrollView.scrollTo({...this._contentOffset, animated});
}
Expand All @@ -339,7 +390,8 @@ export default class SortableList extends Component {
* swaps them, else shifts rows.
*/
_setOrderOnMove() {
const {activeRowKey, activeRowIndex, order} = this.state;
const {activeRowKey, activeRowIndex, order, rowsLayouts} = this.state;
const {horizontal} = this.props;

if (activeRowKey === null || this._autoScrollInterval) {
return;
Expand Down Expand Up @@ -369,9 +421,14 @@ export default class SortableList extends Component {
nextOrder.splice(rowUnderActiveIndex, 0, activeRowKey);
}

const nextRowsLayouts = this._getRowsLocations(rowsLayouts, nextOrder);
const nextRowsSwapRanges = this._getRowsSwapRanges(nextRowsLayouts, nextOrder);

this.setState({
order: nextOrder,
activeRowIndex: rowUnderActiveIndex,
rowsLayouts: nextRowsLayouts,
rowsSwapRanges: nextRowsSwapRanges,
}, () => {
if (this.props.onChangeOrder) {
this.props.onChangeOrder(nextOrder);
Expand All @@ -381,53 +438,114 @@ export default class SortableList extends Component {
}

/**
* Finds a row, which was covered with the moving row’s half.
* Finds a row, which was covered with the moving row’s third.
*/
_findRowUnderActiveRow() {
const {horizontal} = this.props;
const {rowsLayouts, activeRowKey, activeRowIndex, order} = this.state;
const movingRowLayout = rowsLayouts[activeRowKey];
const rowLeftX = this._activeRowLocation.x
const rowRightX = rowLeftX + movingRowLayout.width;
const rowTopY = this._activeRowLocation.y;
const rowBottomY = rowTopY + movingRowLayout.height;

for (
let currentRowIndex = 0, x = 0, y = 0, rowsCount = order.length;
currentRowIndex < rowsCount - 1;
currentRowIndex++
const {rowsLayouts, rowsSwapRanges, activeRowKey, activeRowIndex, order} = this.state;
const movingDirection = this._movingDirection;
const rowsCount = order.length;
const activeRowLayout = rowsLayouts[activeRowKey];
const activeRowLeftX = this._activeRowLocation.x
const activeRowRightX = this._activeRowLocation.x + activeRowLayout.width;
const activeRowTopY = this._activeRowLocation.y;
const activeRowBottomY = this._activeRowLocation.y + activeRowLayout.height;

const prevRowIndex = activeRowIndex - 1;
const prevRowKey = order[prevRowIndex];
const prevRowSwapRages = rowsSwapRanges[prevRowKey]
const nextRowIndex = activeRowIndex + 1;
const nextRowKey = order[nextRowIndex];
const nextRowSwapRages = rowsSwapRanges[nextRowKey]

if (horizontal
? (movingDirection === 1
? (
(activeRowIndex === 0 || activeRowLeftX > prevRowSwapRages.right[0]) &&
(activeRowIndex === rowsCount - 1 || activeRowRightX < nextRowSwapRages.left[0])
)
: (
(activeRowIndex === 0 || activeRowLeftX > prevRowSwapRages.right[1]) &&
(activeRowIndex === rowsCount - 1 || activeRowRightX < nextRowSwapRages.left[1])
)
)
: (movingDirection === 1
? (
(activeRowIndex === 0 || activeRowTopY > prevRowSwapRages.bottom[0]) &&
(activeRowIndex === rowsCount - 1 || activeRowBottomY < nextRowSwapRages.top[0])
)
: (
(activeRowIndex === 0 || activeRowTopY > prevRowSwapRages.bottom[1]) &&
(activeRowIndex === rowsCount - 1 || activeRowBottomY < nextRowSwapRages.top[1])
)
)
) {
const currentRowKey = order[currentRowIndex];
const currentRowLayout = rowsLayouts[currentRowKey];
const nextRowIndex = currentRowIndex + 1;
const nextRowLayout = rowsLayouts[order[nextRowIndex]];

x += currentRowLayout.width;
y += currentRowLayout.height;

if (currentRowKey !== activeRowKey && (
horizontal
? ((x - currentRowLayout.width <= rowLeftX || currentRowIndex === 0) && rowLeftX <= x - currentRowLayout.width / 3)
: ((y - currentRowLayout.height <= rowTopY || currentRowIndex === 0) && rowTopY <= y - currentRowLayout.height / 3)
)) {
return {
rowKey: order[currentRowIndex],
rowIndex: currentRowIndex,
};
}
return {
rowKey: activeRowKey,
rowIndex: activeRowIndex,
};
}

if (movingDirection === 1) {
if (horizontal
? (x + nextRowLayout.width / 3 <= rowRightX && (rowRightX <= x + nextRowLayout.width || nextRowIndex === rowsCount - 1))
: (y + nextRowLayout.height / 3 <= rowBottomY && (rowBottomY <= y + nextRowLayout.height || nextRowIndex === rowsCount - 1))
? inRange(activeRowRightX, ...nextRowSwapRages.left)
: inRange(activeRowBottomY, ...nextRowSwapRages.top)
) {
return {
rowKey: order[nextRowIndex],
return {
rowKey: nextRowKey,
rowIndex: nextRowIndex,
};
}
} else {
if (horizontal
? inRange(activeRowLeftX, ...prevRowSwapRages.right)
: inRange(activeRowTopY, ...prevRowSwapRages.bottom)
) {
return {
rowKey: prevRowKey,
rowIndex: prevRowIndex,
};
}
}

return {rowKey: activeRowKey, rowIndex: activeRowIndex};
// let startIndex = 0;
// let endIndex = rowsCount - 1;
// let middleIndex;
// let it = 0
// console.log(movingDirection);
// while (startIndex < endIndex) {
// middleIndex = Math.floor((endIndex - startIndex) / 2);

// if (it++ > 10) {
// console.log(startIndex, middleIndex, endIndex);
// break
// }
// const middleRowSwapRanges = rowsSwapRanges[middleIndex];

// if (horizontal) {
// if (movingDirection === 1) {
// if (inRange(activeRowRightX, ...middleRowSwapRanges.left)) break;
// else if (activeRowRightX < middleRowSwapRanges.left[0]) endIndex = middleIndex;
// else if (activeRowRightX > middleRowSwapRanges.left[1]) startIndex = middleIndex;
// } else {
// if (inRange(activeRowLeftX, ...middleRowSwapRanges.right)) break;
// else if (activeRowLeftX < middleRowSwapRanges.right[0]) endIndex = middleIndex;
// else if (activeRowLeftX > middleRowSwapRanges.right[1]) startIndex = middleIndex;
// }
// } else {
// if (movingDirection === 1) {
// if (inRange(activeRowBottomY, ...middleRowSwapRanges.top)) break;
// else if (activeRowBottomY < middleRowSwapRanges.top[0]) endIndex = middleIndex;
// else if (activeRowBottomY > middleRowSwapRanges.top[1]) startIndex = middleIndex;
// } else {
// if (inRange(activeRowTopY, ...middleRowSwapRanges.bottom)) break;
// else if (activeRowTopY < middleRowSwapRanges.bottom[0]) endIndex = middleIndex;
// else if (activeRowTopY > middleRowSwapRanges.bottom[1]) startIndex = middleIndex;
// }
// }
// }

// return {rowKey: order[middleIndex], rowIndex: middleIndex};
}

_scrollOnMove(e) {
Expand Down Expand Up @@ -595,9 +713,11 @@ export default class SortableList extends Component {
const prevMovingDirection = this._movingDirection;

this._activeRowLocation = location;
this._movingDirection = this.props.horizontal
? prevMovingRowX < this._activeRowLocation.x
: prevMovingRowY < this._activeRowLocation.y;
this._movingDirection = (
this.props.horizontal
? prevMovingRowX <= this._activeRowLocation.x
: prevMovingRowY <= this._activeRowLocation.y
) ? 1 : -1;

this._movingDirectionChanged = prevMovingDirection !== this._movingDirection;
this._setOrderOnMove();
Expand Down
3 changes: 3 additions & 0 deletions src/utils/inRange.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function inRange(number, start, end) {
return start <= number && number <= end;
}
10 changes: 3 additions & 7 deletions src/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import shallowEqual from './shallowEqual';
import swapArrayElements from './swapArrayElements';

export {
shallowEqual,
swapArrayElements
};
export {default as inRange} from './inRange'
export {default as shallowEqual} from './shallowEqual';
export {default as swapArrayElements} from './swapArrayElements';