Fix incorrect restoring of the scroll position

multisite
Floens 10 years ago
parent edd60126e6
commit 0991bff02b
  1. 11
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java
  2. 7
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java
  3. 111
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java
  4. 4
      Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java
  5. BIN
      Clover/app/src/main/res/drawable-mdpi/partyhat.png

@ -44,7 +44,6 @@ import java.util.List;
import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBus;
import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AndroidUtils.isTablet;
public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewerController.PreviewCallback, SwipeRefreshLayout.OnRefreshListener, ToolbarNavigationController.ToolbarSearchCallback, NfcAdapter.CreateNdefMessageCallback { public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewerController.PreviewCallback, SwipeRefreshLayout.OnRefreshListener, ToolbarNavigationController.ToolbarSearchCallback, NfcAdapter.CreateNdefMessageCallback {
private static final String TAG = "ThreadController"; private static final String TAG = "ThreadController";
@ -62,7 +61,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou
EventBus.getDefault().register(this); EventBus.getDefault().register(this);
navigationItem.collapseToolbar = !isTablet(context); navigationItem.collapseToolbar = true;
threadLayout = (ThreadLayout) LayoutInflater.from(context).inflate(R.layout.layout_thread, null); threadLayout = (ThreadLayout) LayoutInflater.from(context).inflate(R.layout.layout_thread, null);
threadLayout.setCallback(this); threadLayout.setCallback(this);
@ -76,9 +75,8 @@ public abstract class ThreadController extends Controller implements ThreadLayou
swipeRefreshLayout.addView(threadLayout); swipeRefreshLayout.addView(threadLayout);
swipeRefreshLayout.setOnRefreshListener(this); swipeRefreshLayout.setOnRefreshListener(this);
ToolbarNavigationController toolbarNavigationController = (ToolbarNavigationController) navigationController;
if (collapseToolbar()) { if (navigationItem.collapseToolbar) {
int toolbarHeight = getToolbar().getToolbarHeight(); int toolbarHeight = getToolbar().getToolbarHeight();
swipeRefreshLayout.setProgressViewOffset(false, toolbarHeight - dp(40), toolbarHeight + dp(64 - 40)); swipeRefreshLayout.setProgressViewOffset(false, toolbarHeight - dp(40), toolbarHeight + dp(64 - 40));
} }
@ -203,11 +201,6 @@ public abstract class ThreadController extends Controller implements ThreadLayou
return ((ToolbarNavigationController) navigationController).getToolbar(); return ((ToolbarNavigationController) navigationController).getToolbar();
} }
@Override
public boolean collapseToolbar() {
return navigationItem.collapseToolbar;
}
@Override @Override
public void onSearchVisibilityChanged(boolean visible) { public void onSearchVisibilityChanged(boolean visible) {
threadLayout.getPresenter().onSearchVisibilityChanged(visible); threadLayout.getPresenter().onSearchVisibilityChanged(visible);

@ -197,11 +197,6 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T
return callback.getToolbar(); return callback.getToolbar();
} }
@Override
public boolean collapseToolbar() {
return callback.collapseToolbar();
}
@Override @Override
public void showPosts(ChanThread thread, PostsFilter filter) { public void showPosts(ChanThread thread, PostsFilter filter) {
threadListLayout.showPosts(thread, filter, visible != Visible.THREAD); threadListLayout.showPosts(thread, filter, visible != Visible.THREAD);
@ -519,7 +514,5 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T
void hideSwipeRefreshLayout(); void hideSwipeRefreshLayout();
Toolbar getToolbar(); Toolbar getToolbar();
boolean collapseToolbar();
} }
} }

@ -18,6 +18,9 @@
package org.floens.chan.ui.layout; package org.floens.chan.ui.layout;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
@ -44,6 +47,7 @@ import org.floens.chan.ui.view.ThumbnailView;
import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.AnimationUtils; import org.floens.chan.utils.AnimationUtils;
import java.util.Calendar;
import java.util.List; import java.util.List;
import static org.floens.chan.utils.AndroidUtils.ROBOTO_MEDIUM; import static org.floens.chan.utils.AndroidUtils.ROBOTO_MEDIUM;
@ -51,7 +55,7 @@ import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AndroidUtils.getAttrColor; import static org.floens.chan.utils.AndroidUtils.getAttrColor;
/** /**
* A layout that wraps around a {@link RecyclerView} to manage showing posts. * A layout that wraps around a {@link RecyclerView} and a {@link ReplyLayout} to manage showing and replying to posts.
*/ */
public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLayoutCallback { public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLayoutCallback {
public static final int MAX_SMOOTH_SCROLL_DISTANCE = 20; public static final int MAX_SMOOTH_SCROLL_DISTANCE = 20;
@ -102,9 +106,16 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
// onScrolled can be called after cleanup() // onScrolled can be called after cleanup()
if (showingThread != null) { if (showingThread != null) {
int index = Math.max(0, getTopAdapterPosition()); int index = 0;
View topChild = recyclerView.getLayoutManager().getChildAt(0); int top = 0;
int top = topChild == null ? 0 : topChild.getTop(); if (recyclerView.getChildCount() > 0) {
View topChild = recyclerView.getLayoutManager().getChildAt(0);
index = ((RecyclerView.LayoutParams) topChild.getLayoutParams()).getViewLayoutPosition();
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) topChild.getLayoutParams();
top = layoutManager.getDecoratedTop(topChild) - params.topMargin - recyclerView.getPaddingTop();
}
showingThread.loadable.listViewIndex = index; showingThread.loadable.listViewIndex = index;
showingThread.loadable.listViewTop = top; showingThread.loadable.listViewTop = top;
@ -120,8 +131,8 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
attachToolbarScroll(true); attachToolbarScroll(true);
reply.setPadding(0, topSpacing(), 0, 0); reply.setPadding(0, toolbarHeight(), 0, 0);
searchStatus.setPadding(searchStatus.getPaddingLeft(), searchStatus.getPaddingTop() + topSpacing(), searchStatus.setPadding(searchStatus.getPaddingLeft(), searchStatus.getPaddingTop() + toolbarHeight(),
searchStatus.getPaddingRight(), searchStatus.getPaddingBottom()); searchStatus.getPaddingRight(), searchStatus.getPaddingBottom());
} }
@ -147,7 +158,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
case LIST: case LIST:
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
recyclerViewTopPadding = 0; recyclerViewTopPadding = 0;
recyclerView.setPadding(0, recyclerViewTopPadding + topSpacing(), 0, 0); recyclerView.setPadding(0, recyclerViewTopPadding + toolbarHeight(), 0, 0);
recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setLayoutManager(linearLayoutManager);
layoutManager = linearLayoutManager; layoutManager = linearLayoutManager;
@ -161,7 +172,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
GridLayoutManager gridLayoutManager = new GridLayoutManager(null, spanCount, GridLayoutManager.VERTICAL, false); GridLayoutManager gridLayoutManager = new GridLayoutManager(null, spanCount, GridLayoutManager.VERTICAL, false);
// The cards have a 4dp padding, this way there is always 8dp between the edges // The cards have a 4dp padding, this way there is always 8dp between the edges
recyclerViewTopPadding = dp(4); recyclerViewTopPadding = dp(4);
recyclerView.setPadding(dp(4), recyclerViewTopPadding + topSpacing(), dp(4), dp(4)); recyclerView.setPadding(dp(4), recyclerViewTopPadding + toolbarHeight(), dp(4), dp(4));
recyclerView.setLayoutManager(gridLayoutManager); recyclerView.setLayoutManager(gridLayoutManager);
layoutManager = gridLayoutManager; layoutManager = gridLayoutManager;
@ -188,14 +199,19 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
recyclerView.getRecycledViewPool().clear(); recyclerView.getRecycledViewPool().clear();
int index = thread.loadable.listViewIndex;
int top = thread.loadable.listViewTop;
switch (postViewMode) { switch (postViewMode) {
case LIST: case LIST:
((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(thread.loadable.listViewIndex, thread.loadable.listViewTop); ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(index, top);
break; break;
case CARD: case CARD:
((GridLayoutManager) layoutManager).scrollToPositionWithOffset(thread.loadable.listViewIndex, thread.loadable.listViewTop); ((GridLayoutManager) layoutManager).scrollToPositionWithOffset(index, top);
break; break;
} }
party();
} }
postAdapter.setThread(thread, filter); postAdapter.setThread(thread, filter);
@ -237,7 +253,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerViewTopPadding + height, recyclerView.getPaddingRight(), recyclerView.getPaddingBottom()); recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerViewTopPadding + height, recyclerView.getPaddingRight(), recyclerView.getPaddingBottom());
} else { } else {
AndroidUtils.hideKeyboard(reply); AndroidUtils.hideKeyboard(reply);
recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerViewTopPadding + topSpacing(), recyclerView.getPaddingRight(), recyclerView.getPaddingBottom()); recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerViewTopPadding + toolbarHeight(), recyclerView.getPaddingRight(), recyclerView.getPaddingBottom());
} }
threadListLayoutCallback.replyLayoutOpen(open); threadListLayoutCallback.replyLayoutOpen(open);
@ -254,7 +270,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
} }
public void openSearch(boolean show) { public void openSearch(boolean show) {
if (searchOpen != show) { if (showingThread != null && searchOpen != show) {
searchOpen = show; searchOpen = show;
int height = AnimationUtils.animateHeight(searchStatus, show); int height = AnimationUtils.animateHeight(searchStatus, show);
@ -262,7 +278,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
searchStatus.setText(R.string.search_empty); searchStatus.setText(R.string.search_empty);
recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerViewTopPadding + height, recyclerView.getPaddingRight(), recyclerView.getPaddingBottom()); recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerViewTopPadding + height, recyclerView.getPaddingRight(), recyclerView.getPaddingBottom());
} else { } else {
recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerViewTopPadding + topSpacing(), recyclerView.getPaddingRight(), recyclerView.getPaddingBottom()); recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerViewTopPadding + toolbarHeight(), recyclerView.getPaddingRight(), recyclerView.getPaddingBottom());
} }
attachToolbarScroll(!(show || replyOpen)); attachToolbarScroll(!(show || replyOpen));
@ -294,13 +310,13 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
case LIST: case LIST:
if (getTopAdapterPosition() == 0) { if (getTopAdapterPosition() == 0) {
View top = layoutManager.findViewByPosition(0); View top = layoutManager.findViewByPosition(0);
return top.getTop() != topSpacing(); return top.getTop() != toolbarHeight();
} }
break; break;
case CARD: case CARD:
if (getTopAdapterPosition() == 0) { if (getTopAdapterPosition() == 0) {
View top = layoutManager.findViewByPosition(0); View top = layoutManager.findViewByPosition(0);
return top.getTop() != dp(8) + topSpacing(); // 4dp for the cards, 4dp for this layout return top.getTop() != dp(8) + toolbarHeight(); // 4dp for the cards, 4dp for this layout
} }
break; break;
} }
@ -312,27 +328,13 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
} }
public void cleanup() { public void cleanup() {
/*if (ChanBuild.DEVELOPER_MODE) {
Pin pin = ChanApplication.getWatchManager().findPinByLoadable(showingThread.loadable);
if (pin == null) {
for (Post post : showingThread.posts) {
if (post.comment instanceof SpannedString) {
SpannedString commentSpannable = (SpannedString) post.comment;
PostLinkable[] linkables = commentSpannable.getSpans(0, commentSpannable.length(), PostLinkable.class);
for (PostLinkable linkable : linkables) {
ChanApplication.getRefWatcher().watch(linkable, linkable.key + " " + linkable.value);
}
}
}
}
}*/
postAdapter.cleanup(); postAdapter.cleanup();
reply.cleanup(); reply.cleanup();
openReply(false); openReply(false);
openSearch(false); openSearch(false);
showingThread = null; showingThread = null;
lastPostCount = 0; lastPostCount = 0;
noParty();
} }
public List<Post> getDisplayingPosts() { public List<Post> getDisplayingPosts() {
@ -419,8 +421,8 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
} }
private void attachToolbarScroll(boolean attach) { private void attachToolbarScroll(boolean attach) {
Toolbar toolbar = threadListLayoutCallback.getToolbar(); if (!AndroidUtils.isTablet(getContext())) {
if (toolbar != null && threadListLayoutCallback.collapseToolbar()) { Toolbar toolbar = threadListLayoutCallback.getToolbar();
if (attach) { if (attach) {
toolbar.attachRecyclerViewScrollStateListener(recyclerView); toolbar.attachRecyclerViewScrollStateListener(recyclerView);
} else { } else {
@ -430,13 +432,9 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
} }
} }
private int topSpacing() { private int toolbarHeight() {
Toolbar toolbar = threadListLayoutCallback.getToolbar(); Toolbar toolbar = threadListLayoutCallback.getToolbar();
if (toolbar != null && threadListLayoutCallback.collapseToolbar()) { return toolbar.getToolbarHeight();
return toolbar.getToolbarHeight();
} else {
return 0;
}
} }
private int getTopAdapterPosition() { private int getTopAdapterPosition() {
@ -459,6 +457,41 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
return -1; return -1;
} }
private Bitmap hat;
private final RecyclerView.ItemDecoration PARTY = new RecyclerView.ItemDecoration() {
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (hat == null) {
hat = BitmapFactory.decodeResource(getResources(), R.drawable.partyhat);
}
for (int i = 0, j = parent.getChildCount(); i < j; i++) {
View child = parent.getChildAt(i);
if (child instanceof PostCellInterface) {
PostCellInterface postView = (PostCellInterface) child;
if (postView.getPost().hasImage) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getTop() + params.topMargin;
int left = child.getLeft() + params.leftMargin;
c.drawBitmap(hat, left - parent.getPaddingLeft() - dp(40), top - dp(130) - parent.getPaddingTop() + toolbarHeight(), null);
}
}
}
}
};
private void party() {
Calendar calendar = Calendar.getInstance();
if (calendar.get(Calendar.MONTH) == Calendar.OCTOBER && calendar.get(Calendar.DAY_OF_MONTH) == 1) {
recyclerView.addItemDecoration(PARTY);
}
}
private void noParty() {
recyclerView.removeItemDecoration(PARTY);
}
public interface ThreadListLayoutPresenterCallback { public interface ThreadListLayoutPresenterCallback {
void showThread(Loadable loadable); void showThread(Loadable loadable);
@ -471,7 +504,5 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
void replyLayoutOpen(boolean open); void replyLayoutOpen(boolean open);
Toolbar getToolbar(); Toolbar getToolbar();
boolean collapseToolbar();
} }
} }

@ -230,8 +230,8 @@ public class AndroidUtils {
} }
public static void hideKeyboard(View view) { public static void hideKeyboard(View view) {
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0); inputManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
} }
public static String getReadableFileSize(long bytes, boolean si) { public static String getReadableFileSize(long bytes, boolean si) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Loading…
Cancel
Save