Add reply FAB

filtering
Floens 10 years ago
parent 98ed00c10f
commit 65d07c4043
  1. 5
      Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java
  2. 8
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java
  3. 5
      Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java
  4. 58
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java
  5. 11
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java
  6. 3
      Clover/app/src/main/res/layout/cell_thread_status.xml
  7. 38
      Clover/app/src/main/res/layout/layout_thread.xml

@ -44,7 +44,6 @@ import java.util.List;
public class BrowseController extends ThreadController implements ToolbarMenuItem.ToolbarMenuItemCallback, ThreadLayout.ThreadLayoutCallback, FloatingMenu.FloatingMenuCallback { public class BrowseController extends ThreadController implements ToolbarMenuItem.ToolbarMenuItemCallback, ThreadLayout.ThreadLayoutCallback, FloatingMenu.FloatingMenuCallback {
private static final int REFRESH_ID = 1; private static final int REFRESH_ID = 1;
private static final int POST_ID = 2;
private static final int SEARCH_ID = 101; private static final int SEARCH_ID = 101;
private static final int SHARE_ID = 102; private static final int SHARE_ID = 102;
@ -68,7 +67,6 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
navigationItem.hasBack = false; navigationItem.hasBack = false;
menu.addItem(new ToolbarMenuItem(context, this, REFRESH_ID, R.drawable.ic_refresh_white_24dp)); menu.addItem(new ToolbarMenuItem(context, this, REFRESH_ID, R.drawable.ic_refresh_white_24dp));
menu.addItem(new ToolbarMenuItem(context, this, POST_ID, R.drawable.ic_create_white_24dp));
ToolbarMenuItem overflow = menu.createOverflow(this); ToolbarMenuItem overflow = menu.createOverflow(this);
@ -85,9 +83,6 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
case REFRESH_ID: case REFRESH_ID:
threadLayout.getPresenter().requestData(); threadLayout.getPresenter().requestData();
break; break;
case POST_ID:
openPost(true);
break;
} }
} }

@ -19,8 +19,10 @@ package org.floens.chan.ui.controller;
import android.content.Context; import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import org.floens.chan.Chan; import org.floens.chan.Chan;
import org.floens.chan.R;
import org.floens.chan.controller.Controller; import org.floens.chan.controller.Controller;
import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.PostImage; import org.floens.chan.core.model.PostImage;
@ -45,7 +47,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou
EventBus.getDefault().register(this); EventBus.getDefault().register(this);
threadLayout = new ThreadLayout(context); threadLayout = (ThreadLayout) LayoutInflater.from(context).inflate(R.layout.layout_thread, null);
threadLayout.setCallback(this); threadLayout.setCallback(this);
swipeRefreshLayout = new SwipeRefreshLayout(context) { swipeRefreshLayout = new SwipeRefreshLayout(context) {
@Override @Override
@ -90,10 +92,6 @@ public abstract class ThreadController extends Controller implements ThreadLayou
threadLayout.refreshFromSwipe(); threadLayout.refreshFromSwipe();
} }
public void openPost(boolean open) {
threadLayout.openPost(open);
}
public void presentRepliesController(Controller controller) { public void presentRepliesController(Controller controller) {
presentController(controller); presentController(controller);
} }

@ -38,7 +38,6 @@ import java.util.Arrays;
import static org.floens.chan.utils.AndroidUtils.getAttrColor; import static org.floens.chan.utils.AndroidUtils.getAttrColor;
public class ViewThreadController extends ThreadController implements ThreadLayout.ThreadLayoutCallback, ToolbarMenuItem.ToolbarMenuItemCallback { public class ViewThreadController extends ThreadController implements ThreadLayout.ThreadLayoutCallback, ToolbarMenuItem.ToolbarMenuItemCallback {
private static final int POST_ID = 1;
private static final int PIN_ID = 2; private static final int PIN_ID = 2;
private static final int REFRESH_ID = 101; private static final int REFRESH_ID = 101;
private static final int SEARCH_ID = 102; private static final int SEARCH_ID = 102;
@ -64,7 +63,6 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
navigationItem.hasDrawer = true; navigationItem.hasDrawer = true;
navigationItem.menu = new ToolbarMenu(context); navigationItem.menu = new ToolbarMenu(context);
navigationItem.menu.addItem(new ToolbarMenuItem(context, this, POST_ID, R.drawable.ic_create_white_24dp));
pinItem = navigationItem.menu.addItem(new ToolbarMenuItem(context, this, PIN_ID, R.drawable.ic_bookmark_outline_white_24dp)); pinItem = navigationItem.menu.addItem(new ToolbarMenuItem(context, this, PIN_ID, R.drawable.ic_bookmark_outline_white_24dp));
navigationItem.createOverflow(context, this, Arrays.asList( navigationItem.createOverflow(context, this, Arrays.asList(
new FloatingMenuItem(REFRESH_ID, context.getString(R.string.action_reload)), new FloatingMenuItem(REFRESH_ID, context.getString(R.string.action_reload)),
@ -154,9 +152,6 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
case PIN_ID: case PIN_ID:
setPinIconState(threadLayout.getPresenter().pin()); setPinIconState(threadLayout.getPresenter().pin());
break; break;
case POST_ID:
openPost(true);
break;
} }
} }

@ -25,9 +25,12 @@ import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@ -62,16 +65,19 @@ import static org.floens.chan.utils.AndroidUtils.getString;
/** /**
* Wrapper around ThreadListLayout, so that it cleanly manages between loadbar and listview. * Wrapper around ThreadListLayout, so that it cleanly manages between loadbar and listview.
*/ */
public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPresenterCallback, PostPopupHelper.PostPopupHelperCallback, View.OnClickListener { public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.ThreadPresenterCallback, PostPopupHelper.PostPopupHelperCallback, View.OnClickListener, ThreadListLayout.ReplyLayoutStateCallback {
private enum Visible { private enum Visible {
LOADING, LOADING,
THREAD, THREAD,
ERROR; ERROR;
} }
private ThreadLayoutCallback callback; private ThreadLayoutCallback callback;
private ThreadPresenter presenter; private ThreadPresenter presenter;
private LoadView loadView;
private FloatingActionButton replyButton;
private ThreadListLayout threadListLayout; private ThreadListLayout threadListLayout;
private LinearLayout errorLayout; private LinearLayout errorLayout;
@ -81,26 +87,31 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
private Visible visible; private Visible visible;
private ProgressDialog deletingDialog; private ProgressDialog deletingDialog;
private boolean refreshedFromSwipe; private boolean refreshedFromSwipe;
private boolean showingReplyButton = false;
public ThreadLayout(Context context) { public ThreadLayout(Context context) {
super(context); super(context);
init();
} }
public ThreadLayout(Context context, AttributeSet attrs) { public ThreadLayout(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
init();
} }
public ThreadLayout(Context context, AttributeSet attrs, int defStyleAttr) { public ThreadLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
init();
} }
private void init() { @Override
protected void onFinishInflate() {
super.onFinishInflate();
presenter = new ThreadPresenter(this); presenter = new ThreadPresenter(this);
loadView = (LoadView) findViewById(R.id.loadview);
replyButton = (FloatingActionButton) findViewById(R.id.reply_button);
replyButton.setOnClickListener(this);
threadListLayout = (ThreadListLayout) LayoutInflater.from(getContext()).inflate(R.layout.layout_thread_list, this, false); threadListLayout = (ThreadListLayout) LayoutInflater.from(getContext()).inflate(R.layout.layout_thread_list, this, false);
threadListLayout.setCallbacks(presenter, presenter, presenter, presenter); threadListLayout.setCallbacks(presenter, presenter, presenter, presenter, this);
postPopupHelper = new PostPopupHelper(getContext(), presenter, this); postPopupHelper = new PostPopupHelper(getContext(), presenter, this);
@ -118,6 +129,8 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
public void onClick(View v) { public void onClick(View v) {
if (v == errorRetryButton) { if (v == errorRetryButton) {
presenter.requestData(); presenter.requestData();
} else if (v == replyButton) {
threadListLayout.openReply(true);
} }
} }
@ -141,15 +154,16 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
return presenter; return presenter;
} }
public void openPost(boolean open) {
threadListLayout.openReply(open);
}
public void refreshFromSwipe() { public void refreshFromSwipe() {
refreshedFromSwipe = true; refreshedFromSwipe = true;
presenter.requestData(); presenter.requestData();
} }
@Override
public void replyLayoutOpen(boolean open) {
showReplyButton(!open);
}
@Override @Override
public void showPosts(ChanThread thread) { public void showPosts(ChanThread thread) {
threadListLayout.showPosts(thread, visible != Visible.THREAD); threadListLayout.showPosts(thread, visible != Visible.THREAD);
@ -285,7 +299,7 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
@Override @Override
public void quote(Post post, boolean withText) { public void quote(Post post, boolean withText) {
openPost(true); threadListLayout.openReply(true);
threadListLayout.getReplyPresenter().quote(post, withText); threadListLayout.getReplyPresenter().quote(post, withText);
} }
@ -339,6 +353,20 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
return postPopupHelper.isOpen(); return postPopupHelper.isOpen();
} }
private void showReplyButton(boolean show) {
if (show != showingReplyButton) {
showingReplyButton = show;
replyButton.animate()
.setInterpolator(new DecelerateInterpolator(2f))
.setStartDelay(show ? 100 : 0)
.setDuration(200)
.alpha(show ? 1f : 0f)
.scaleX(show ? 1f : 0f)
.scaleY(show ? 1f : 0f)
.start();
}
}
private void switchVisible(Visible visible) { private void switchVisible(Visible visible) {
if (this.visible != visible) { if (this.visible != visible) {
if (this.visible != null) { if (this.visible != null) {
@ -347,6 +375,7 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
threadListLayout.cleanup(); threadListLayout.cleanup();
postPopupHelper.popAll(); postPopupHelper.popAll();
showSearch(false); showSearch(false);
showReplyButton(false);
break; break;
} }
} }
@ -354,7 +383,7 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
this.visible = visible; this.visible = visible;
switch (visible) { switch (visible) {
case LOADING: case LOADING:
View view = setView(null); View view = loadView.setView(null);
// TODO: cleanup // TODO: cleanup
if (refreshedFromSwipe) { if (refreshedFromSwipe) {
refreshedFromSwipe = false; refreshedFromSwipe = false;
@ -362,10 +391,11 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
} }
break; break;
case THREAD: case THREAD:
setView(threadListLayout); loadView.setView(threadListLayout);
showReplyButton(true);
break; break;
case ERROR: case ERROR:
setView(errorLayout); loadView.setView(errorLayout);
break; break;
} }
} }

@ -53,6 +53,7 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
private PostAdapter postAdapter; private PostAdapter postAdapter;
private ChanThread showingThread; private ChanThread showingThread;
private ThreadListLayoutCallback callback; private ThreadListLayoutCallback callback;
private ReplyLayoutStateCallback replyLayoutStateCallback;
private boolean replyOpen; private boolean replyOpen;
public ThreadListLayout(Context context, AttributeSet attrs) { public ThreadListLayout(Context context, AttributeSet attrs) {
@ -74,8 +75,11 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setLayoutManager(linearLayoutManager);
} }
public void setCallbacks(PostAdapter.PostAdapterCallback postAdapterCallback, PostCell.PostCellCallback postCellCallback, ThreadStatusCell.Callback statusCellCallback, ThreadListLayoutCallback callback) { public void setCallbacks(PostAdapter.PostAdapterCallback postAdapterCallback, PostCell.PostCellCallback postCellCallback,
ThreadStatusCell.Callback statusCellCallback, ThreadListLayoutCallback callback,
ReplyLayoutStateCallback replyLayoutStateCallback) {
this.callback = callback; this.callback = callback;
this.replyLayoutStateCallback = replyLayoutStateCallback;
postAdapter = new PostAdapter(recyclerView, postAdapterCallback, postCellCallback, statusCellCallback); postAdapter = new PostAdapter(recyclerView, postAdapterCallback, postCellCallback, statusCellCallback);
recyclerView.setAdapter(postAdapter); recyclerView.setAdapter(postAdapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@ -109,6 +113,7 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
} else { } else {
AndroidUtils.hideKeyboard(reply); AndroidUtils.hideKeyboard(reply);
} }
replyLayoutStateCallback.replyLayoutOpen(open);
} }
} }
@ -251,4 +256,8 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
void requestNewPostLoad(); void requestNewPostLoad();
} }
public interface ReplyLayoutStateCallback {
void replyLayoutOpen(boolean open);
}
} }

@ -17,13 +17,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<org.floens.chan.ui.cell.ThreadStatusCell xmlns:android="http://schemas.android.com/apk/res/android" <org.floens.chan.ui.cell.ThreadStatusCell xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="56dp" android:layout_height="88dp"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="8dp"
android:gravity="center" android:gravity="center"
android:textColor="?text_color_secondary" /> android:textColor="?text_color_secondary" />

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?><!--
Clover - 4chan browser https://github.com/Floens/Clover/
Copyright (C) 2014 Floens
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<org.floens.chan.ui.layout.ThreadLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.floens.chan.ui.view.LoadView
android:id="@+id/loadview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/reply_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:layout_margin="16dp"
android:alpha="0"
android:scaleX="0"
android:scaleY="0"
android:src="@drawable/ic_create_white_24dp" />
</org.floens.chan.ui.layout.ThreadLayout>
Loading…
Cancel
Save