/* * Copyright 2016 Hippo Seven * * 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. */ package com.hippo.ehviewer.ui.scene; import android.util.Log; import com.hippo.ehviewer.client.data.GalleryInfo; import java.util.Arrays; import java.util.List; // TODO GridLayoutManager do not work at all ! SpaceGroupIndex is useless for layout! I need to create one by myself public class ThumbSpanHelper { private static final int MIN_ARRAY_LENGTH = 50; private static final int MAX_ROW_INTERVAL = 3; private final List<GalleryInfo> mData; // true for occupied, false for free private boolean[] mCells = new boolean[MIN_ARRAY_LENGTH]; private int mNextIndex; private int mNextGroupIndex; private int mNearSpaceIndex; private int mNearSpaceGroupIndex; private int mAttachedCount; private int mSpanCount; private boolean mEnable; public ThumbSpanHelper(List<GalleryInfo> data) { mData = data; } public void setEnable(boolean enable) { if (enable == mEnable) { return; } mEnable = enable; if (!enable) { clear(); mSpanCount = 0; } else { if (mSpanCount > 0) { rebuild(); } } } public void setSpanCount(int spanCount) { if (!mEnable) { return; } if (spanCount == mSpanCount) { return; } mSpanCount = spanCount; if (spanCount > 0) { rebuild(); } } public void notifyDataSetChanged() { if (!mEnable || mSpanCount <= 0) { return; } rebuild(); } public void notifyItemRangeRemoved(int positionStart, int itemCount) { if (!mEnable || mSpanCount <= 0) { return; } rebuild(); } protected void notifyItemRangeInserted(int positionStart, int itemCount) { if (!mEnable || mSpanCount <= 0) { return; } if (mAttachedCount == positionStart) { append(); } else { rebuild(); } } private void clear() { Log.d("TAG", "=======================clear======================="); if (mSpanCount > 0) { if (mNextGroupIndex > 0 || mNextIndex > 0) { Arrays.fill(mCells, 0, mNextGroupIndex * mSpanCount + mNextIndex, false); } } else { Arrays.fill(mCells, false); } mNextIndex = 0; mNextGroupIndex = 0; mNearSpaceIndex = 0; mNearSpaceGroupIndex = 0; mAttachedCount = 0; } private void rebuild() { clear(); append(); } private void append() { if (1 == mSpanCount) { for (int i = mAttachedCount, n = mData.size(); i < n; i++) { GalleryInfo gi = mData.get(i); gi.spanSize = 1; gi.spanGroupIndex = i; gi.spanIndex = 0; } mAttachedCount = mData.size(); } else if (mSpanCount >= 2) { for (int i = mAttachedCount, n = mData.size(); i < n; i++) { GalleryInfo gi = mData.get(i); int spanSize = gi.thumbWidth <= gi.thumbHeight ? 1 : 2; gi.spanSize = spanSize; if (1 == spanSize) { // Update near space updateNearSpace(); Log.d("TAG", "Update mNearSpaceGroupIndex = " + mNearSpaceGroupIndex + ", mNearSpaceIndex = " + mNearSpaceIndex); if (mNextIndex == mNearSpaceIndex && mNextGroupIndex == mNearSpaceGroupIndex) { // No space, just append gi.spanIndex = mNextIndex; gi.spanGroupIndex = mNextGroupIndex; // Update cell int start = gi.spanGroupIndex * mSpanCount + gi.spanIndex; fillCell(start, start + 1); // Update field mNextIndex++; if (mSpanCount == mNextIndex) { mNextIndex = 0; mNextGroupIndex++; } mNearSpaceIndex = mNextIndex; mNearSpaceGroupIndex = mNextGroupIndex; Log.d("TAG", "type 0"); Log.d("TAG", "i = " + i + ", spanSize = " + spanSize + ", spanGroupIndex = " + gi.spanGroupIndex + ", spanIndex = " + gi.spanIndex); Log.d("TAG", "mNextGroupIndex = " + mNextGroupIndex + ", mNextIndex = " + mNextIndex); Log.d("TAG", "mNearSpaceGroupIndex = " + mNearSpaceGroupIndex + ", mNearSpaceIndex = " + mNearSpaceIndex); } else { // Found space gi.spanIndex = mNearSpaceIndex; gi.spanGroupIndex = mNearSpaceGroupIndex; // Update cell int start = gi.spanGroupIndex * mSpanCount + gi.spanIndex; fillCell(start, start + 1); // Find near space findNearSpace(start + 1); Log.d("TAG", "type 1"); Log.d("TAG", "i = " + i + ", spanSize = " + spanSize + ", spanGroupIndex = " + gi.spanGroupIndex + ", spanIndex = " + gi.spanIndex); Log.d("TAG", "mNextGroupIndex = " + mNextGroupIndex + ", mNextIndex = " + mNextIndex); Log.d("TAG", "mNearSpaceGroupIndex = " + mNearSpaceGroupIndex + ", mNearSpaceIndex = " + mNearSpaceIndex); } } else { boolean syncNear = mNextIndex == mNearSpaceIndex && mNextGroupIndex == mNearSpaceGroupIndex; // false for old, true for new boolean oldOrNew; if (mSpanCount - mNextIndex >= 2) { gi.spanIndex = mNextIndex; gi.spanGroupIndex = mNextGroupIndex; oldOrNew = true; } else { // Go to next row gi.spanIndex = 0; gi.spanGroupIndex = mNextGroupIndex + 1; oldOrNew = false; } // Update cell int start = gi.spanGroupIndex * mSpanCount + gi.spanIndex; fillCell(start, start + 2); // Update field if (syncNear && !oldOrNew) { mNearSpaceIndex = mNextIndex; mNearSpaceGroupIndex = mNextGroupIndex; } mNextIndex = gi.spanIndex + 2; mNextGroupIndex = gi.spanGroupIndex; if (mSpanCount == mNextIndex) { mNextIndex = 0; mNextGroupIndex++; } if (syncNear && oldOrNew) { mNearSpaceIndex = mNextIndex; mNearSpaceGroupIndex = mNextGroupIndex; } Log.d("TAG", "type 2"); Log.d("TAG", "i = " + i + ", spanSize = " + spanSize + ", spanGroupIndex = " + gi.spanGroupIndex + ", spanIndex = " + gi.spanIndex); Log.d("TAG", "mNextGroupIndex = " + mNextGroupIndex + ", mNextIndex = " + mNextIndex); Log.d("TAG", "mNearSpaceGroupIndex = " + mNearSpaceGroupIndex + ", mNearSpaceIndex = " + mNearSpaceIndex); } } mAttachedCount = mData.size(); } } private void updateNearSpace() { // Check is space is near enough if (mNextGroupIndex - mNearSpaceGroupIndex <= MAX_ROW_INTERVAL) { return; } // The space is too far, find a near one int start = Math.max(0, mNextGroupIndex - MAX_ROW_INTERVAL) * mSpanCount; findNearSpace(start); } private void findNearSpace(int start) { int end = mNextGroupIndex * mSpanCount + mNextIndex; boolean[] cells = mCells; for (int i = start; i < end; i++) { if (!cells[i]) { // Find space ! mNearSpaceIndex = i % mSpanCount; mNearSpaceGroupIndex = i / mSpanCount; return; } } // Can't find space mNearSpaceIndex = mNextIndex; mNearSpaceGroupIndex = mNextGroupIndex; } private void fillCell(int start, int end) { boolean[] array = mCells; // Avoid IndexOutOfBoundsException if (end >= array.length) { boolean[] newArray = new boolean[end + (end < (MIN_ARRAY_LENGTH / 2) ? MIN_ARRAY_LENGTH : end >> 1)]; System.arraycopy(array, 0, newArray, 0, array.length); mCells = array = newArray; } Arrays.fill(array, start, end, true); } }