Post replies done

filtering
Floens 10 years ago
parent 24f59f50eb
commit afea1d063a
  1. 5
      Clover/app/src/main/java/org/floens/chan/controller/Controller.java
  2. 4
      Clover/app/src/main/java/org/floens/chan/controller/FadeInTransition.java
  3. 4
      Clover/app/src/main/java/org/floens/chan/controller/FadeOutTransition.java
  4. 14
      Clover/app/src/main/java/org/floens/chan/core/model/Post.java
  5. 45
      Clover/app/src/main/java/org/floens/chan/core/model/PostLinkable.java
  6. 5
      Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java
  7. 4
      Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java
  8. 192
      Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java
  9. 10
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java
  10. 2
      Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java
  11. 6
      Clover/app/src/main/java/org/floens/chan/ui/fragment/PostRepliesFragment.java
  12. 63
      Clover/app/src/main/java/org/floens/chan/ui/helper/PostPopupHelper.java
  13. 16
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java
  14. 6
      Clover/app/src/main/java/org/floens/chan/ui/view/LoadView.java
  15. 106
      Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java
  16. 4
      Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java
  17. BIN
      Clover/app/src/main/res/drawable-hdpi/dialog_full_dark.9.png
  18. BIN
      Clover/app/src/main/res/drawable-hdpi/dialog_full_light.9.png
  19. BIN
      Clover/app/src/main/res/drawable-mdpi/dialog_full_dark.9.png
  20. BIN
      Clover/app/src/main/res/drawable-mdpi/dialog_full_light.9.png
  21. BIN
      Clover/app/src/main/res/drawable-xhdpi/dialog_full_dark.9.png
  22. BIN
      Clover/app/src/main/res/drawable-xhdpi/dialog_full_light.9.png
  23. BIN
      Clover/app/src/main/res/drawable-xxhdpi/dialog_full_dark.9.png
  24. BIN
      Clover/app/src/main/res/drawable-xxhdpi/dialog_full_light.9.png
  25. 114
      Clover/app/src/main/res/layout/post_replies.xml
  26. 113
      Clover/app/src/main/res/layout/post_replies_bottombuttons.xml
  27. 22
      Clover/app/src/main/res/layout/post_replies_container.xml

@ -40,11 +40,14 @@ public abstract class Controller {
public Controller presentingController;
public Controller presentedController;
public boolean alive = false;
public Controller(Context context) {
this.context = context;
}
public void onCreate() {
alive = true;
// Logger.test(getClass().getSimpleName() + " onCreate");
}
@ -57,6 +60,7 @@ public abstract class Controller {
}
public void onDestroy() {
alive = false;
// Logger.test(getClass().getSimpleName() + " onDestroy");
}
@ -111,6 +115,7 @@ public abstract class Controller {
ControllerLogic.transition(this, null, true, false, contentView);
}
((BoardActivity) context).removeController(this);
presentingController.presentedController = null;
}
public View inflateRes(int resId) {

@ -5,14 +5,14 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.AccelerateDecelerateInterpolator;
public class FadeInTransition extends ControllerTransition {
@Override
public void perform() {
Animator toAlpha = ObjectAnimator.ofFloat(to.view, View.ALPHA, 0f, 1f);
toAlpha.setDuration(200);
toAlpha.setInterpolator(new DecelerateInterpolator(2f));
toAlpha.setInterpolator(new AccelerateDecelerateInterpolator());
toAlpha.addListener(new AnimatorListenerAdapter() {
@Override

@ -5,14 +5,14 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.AccelerateDecelerateInterpolator;
public class FadeOutTransition extends ControllerTransition {
@Override
public void perform() {
Animator toAlpha = ObjectAnimator.ofFloat(from.view, View.ALPHA, 1f, 0f);
toAlpha.setDuration(200);
toAlpha.setInterpolator(new DecelerateInterpolator(2f));
toAlpha.setInterpolator(new AccelerateDecelerateInterpolator());
toAlpha.addListener(new AnimatorListenerAdapter() {
@Override

@ -23,7 +23,6 @@ import android.text.TextUtils;
import org.floens.chan.ChanApplication;
import org.floens.chan.chan.ChanUrls;
import org.floens.chan.core.loader.ChanParser;
import org.floens.chan.ui.view.PostView;
import org.jsoup.parser.Parser;
import java.util.ArrayList;
@ -105,22 +104,9 @@ public class Post {
public SpannableString capcodeSpan;
public CharSequence nameTripcodeIdCapcodeSpan;
/**
* The PostView the Post is currently bound to.
*/
private PostView linkableListener;
public Post() {
}
public void setLinkableListener(PostView listener) {
linkableListener = listener;
}
public PostView getLinkableListener() {
return linkableListener;
}
/**
* Finish up the data
*

@ -17,17 +17,21 @@
*/
package org.floens.chan.core.model;
import android.support.annotation.NonNull;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.view.View;
import org.floens.chan.utils.ThemeHelper;
import java.util.ArrayList;
import java.util.List;
/**
* Anything that links to something in a post uses this entity.
*/
public class PostLinkable extends ClickableSpan {
public static enum Type {
public enum Type {
QUOTE, LINK, SPOILER, THREAD
}
@ -36,7 +40,8 @@ public class PostLinkable extends ClickableSpan {
public final Object value;
public final Type type;
private boolean clicked = false;
private List<Callback> callbacks = new ArrayList<>();
private boolean spoilerVisible = false;
public PostLinkable(Post post, String key, Object value, Type type) {
this.post = post;
@ -45,19 +50,33 @@ public class PostLinkable extends ClickableSpan {
this.type = type;
}
public void addCallback(Callback callback) {
callbacks.add(callback);
}
public void removeCallback(Callback callback) {
callbacks.remove(callback);
}
public boolean hasCallback(Callback callback) {
return callbacks.contains(callback);
}
@Override
public void onClick(View widget) {
if (post.getLinkableListener() != null) {
post.getLinkableListener().onLinkableClick(this);
Callback top = topCallback();
if (top != null) {
top.onLinkableClick(this);
}
clicked = true;
spoilerVisible = !spoilerVisible;
}
@Override
public void updateDrawState(TextPaint ds) {
public void updateDrawState(@NonNull TextPaint ds) {
if (type == Type.QUOTE || type == Type.LINK || type == Type.THREAD) {
if (type == Type.QUOTE) {
if (value instanceof Integer && post.getLinkableListener() != null && (Integer) value == post.getLinkableListener().getHighlightQuotesWithNo()) {
Callback top = topCallback();
if (value instanceof Integer && top != null && (Integer) value == top.getHighlightQuotesWithNo(this)) {
ds.setColor(ThemeHelper.getInstance().getHighlightQuoteColor());
} else {
ds.setColor(ThemeHelper.getInstance().getQuoteColor());
@ -70,7 +89,7 @@ public class PostLinkable extends ClickableSpan {
ds.setUnderlineText(true);
} else if (type == Type.SPOILER) {
if (!clicked) {
if (!spoilerVisible) {
ds.setColor(ThemeHelper.getInstance().getSpoilerColor());
ds.bgColor = ThemeHelper.getInstance().getSpoilerColor();
ds.setUnderlineText(false);
@ -78,6 +97,10 @@ public class PostLinkable extends ClickableSpan {
}
}
private Callback topCallback() {
return callbacks.size() > 0 ? callbacks.get(callbacks.size() - 1) : null;
}
public static class ThreadLink {
public String board;
public int threadId;
@ -89,4 +112,10 @@ public class PostLinkable extends ClickableSpan {
this.postId = postId;
}
}
public interface Callback {
void onLinkableClick(PostLinkable postLinkable);
int getHighlightQuotesWithNo(PostLinkable postLinkable);
}
}

@ -77,6 +77,11 @@ public class StartActivity extends Activity {
super.onDestroy();
stackTop().onDestroy();
stack.clear();
System.gc();
System.gc();
System.gc();
System.runFinalization();
}
@Override

@ -137,7 +137,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
}
@Override
public void openThread(Loadable threadLoadable) {
public void showThread(Loadable threadLoadable) {
ViewThreadController viewThreadController = new ViewThreadController(context);
viewThreadController.setLoadable(threadLoadable);
navigationController.pushController(viewThreadController);
@ -149,7 +149,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
@Override
public void onPinClicked(Pin pin) {
openThread(pin.loadable);
showThread(pin.loadable);
}
@Override

@ -0,0 +1,192 @@
package org.floens.chan.ui.controller;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.LinearInterpolator;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.presenter.ThreadPresenter;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.ui.helper.PostPopupHelper;
import org.floens.chan.ui.view.LoadView;
import org.floens.chan.ui.view.PostView;
import org.floens.chan.utils.ThemeHelper;
public class PostRepliesController extends Controller {
private static final int TRANSITION_DURATION = 200;
private PostPopupHelper postPopupHelper;
private ThreadPresenter presenter;
private int statusBarColorPrevious;
private boolean first = true;
private LoadView loadView;
public PostRepliesController(Context context, PostPopupHelper postPopupHelper, ThreadPresenter presenter) {
super(context);
this.postPopupHelper = postPopupHelper;
this.presenter = presenter;
}
@Override
public void onCreate() {
super.onCreate();
view = inflateRes(R.layout.post_replies_container);
// Clicking outside the popup view
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
postPopupHelper.popAll();
}
});
loadView = (LoadView) view.findViewById(R.id.loadview);
if (Build.VERSION.SDK_INT >= 21) {
statusBarColorPrevious = getWindow().getStatusBarColor();
if (statusBarColorPrevious != 0) {
animateStatusBar(true, statusBarColorPrevious);
}
}
}
@Override
public void stopPresenting() {
super.stopPresenting();
if (Build.VERSION.SDK_INT >= 21) {
if (statusBarColorPrevious != 0) {
animateStatusBar(false, statusBarColorPrevious);
}
}
}
public void setPostRepliesData(PostPopupHelper.RepliesData data) {
displayData(data);
}
private void displayData(final PostPopupHelper.RepliesData data) {
View dataView;
if (ChanSettings.repliesButtonsBottom.get()) {
dataView = inflateRes(R.layout.post_replies_bottombuttons);
} else {
dataView = inflateRes(R.layout.post_replies);
}
ListView listView = (ListView) dataView.findViewById(R.id.post_list);
View repliesBack = dataView.findViewById(R.id.replies_back);
repliesBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
postPopupHelper.pop();
}
});
View repliesClose = dataView.findViewById(R.id.replies_close);
repliesClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
postPopupHelper.popAll();
}
});
if (!ThemeHelper.getInstance().getTheme().isLightTheme) {
((TextView) dataView.findViewById(R.id.replies_back_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_back_dark, 0, 0, 0);
((TextView) dataView.findViewById(R.id.replies_close_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_done_dark, 0, 0, 0);
dataView.findViewById(R.id.container).setBackgroundResource(R.drawable.dialog_full_dark);
}
ArrayAdapter<Post> adapter = new ArrayAdapter<Post>(context, 0) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
PostView postView;
if (convertView instanceof PostView) {
postView = (PostView) convertView;
} else {
postView = new PostView(context);
}
final Post p = getItem(position);
postView.setPost(p, presenter);
postView.setHighlightQuotesWithNo(data.forPost.no);
postView.setOnClickListeners(new View.OnClickListener() {
@Override
public void onClick(View v) {
postPopupHelper.postClicked(p);
}
});
return postView;
}
};
adapter.addAll(data.posts);
listView.setAdapter(adapter);
listView.setSelectionFromTop(data.listViewIndex, data.listViewTop);
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
data.listViewIndex = view.getFirstVisiblePosition();
View v = view.getChildAt(0);
data.listViewTop = (v == null) ? 0 : v.getTop();
}
});
loadView.setFadeDuration(first ? 0 : 200);
first = false;
loadView.setView(dataView);
}
@Override
public boolean onBack() {
postPopupHelper.pop();
return true;
}
private void animateStatusBar(boolean in, final int originalColor) {
ValueAnimator statusBar = ValueAnimator.ofFloat(in ? 0f : 0.5f, in ? 0.5f : 0f);
statusBar.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if (Build.VERSION.SDK_INT >= 21) { // Make lint happy
float progress = (float) animation.getAnimatedValue();
if (progress == 0f) {
getWindow().setStatusBarColor(originalColor);
} else {
int r = (int) ((1f - progress) * Color.red(originalColor));
int g = (int) ((1f - progress) * Color.green(originalColor));
int b = (int) ((1f - progress) * Color.blue(originalColor));
getWindow().setStatusBarColor(Color.argb(255, r, g, b));
}
}
}
});
statusBar.setDuration(TRANSITION_DURATION).setInterpolator(new LinearInterpolator());
statusBar.start();
}
private Window getWindow() {
return ((Activity) context).getWindow();
}
}

@ -21,6 +21,16 @@ public abstract class ThreadController extends Controller implements ThreadLayou
view = threadLayout;
}
@Override
public void onDestroy() {
super.onDestroy();
threadLayout.getPresenter().unbindLoadable();
}
public void presentRepliesController(Controller controller) {
presentController(controller);
}
@Override
public void showImages(List<PostImage> images, int index, Loadable loadable, final ThumbnailView thumbnail) {
// Just ignore the showImages request when the image is not loaded

@ -105,7 +105,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
}
@Override
public void openThread(final Loadable threadLoadable) {
public void showThread(final Loadable threadLoadable) {
// TODO implement, scroll to post and fix title
new AlertDialog.Builder(context)
.setNegativeButton(R.string.cancel, null)

@ -51,10 +51,10 @@ public class PostRepliesFragment extends DialogFragment {
public static PostRepliesFragment newInstance(PostPopupHelper.RepliesData repliesData, PostPopupHelper postPopupHelper, ThreadPresenter presenter) {
PostRepliesFragment fragment = new PostRepliesFragment();
fragment.repliesData = repliesData;
fragment.postPopupHelper = postPopupHelper;
fragment.presenter = presenter;
return fragment;
}
@ -75,7 +75,7 @@ public class PostRepliesFragment extends DialogFragment {
super.onDismiss(dialog);
if (postPopupHelper != null) {
postPopupHelper.onPostRepliesPop();
// postPopupHelper.onPostRepliesPop();
}
}
@ -101,7 +101,7 @@ public class PostRepliesFragment extends DialogFragment {
@Override
public void onClick(View v) {
if (postPopupHelper != null) {
postPopupHelper.closeAllPostFragments();
// postPopupHelper.closeAllPostFragments();
}
}
});

@ -17,13 +17,12 @@
*/
package org.floens.chan.ui.helper;
import android.app.Activity;
import android.app.FragmentTransaction;
import android.content.Context;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.presenter.ThreadPresenter;
import org.floens.chan.ui.fragment.PostRepliesFragment;
import org.floens.chan.ui.controller.PostRepliesController;
import java.util.ArrayList;
import java.util.List;
@ -31,13 +30,15 @@ import java.util.List;
public class PostPopupHelper {
private Context context;
private ThreadPresenter presenter;
private final PostPopupHelperCallback callback;
private final List<RepliesData> dataQueue = new ArrayList<>();
private PostRepliesFragment currentPopupFragment;
private PostRepliesController presentingController;
public PostPopupHelper(Context context, ThreadPresenter presenter) {
public PostPopupHelper(Context context, ThreadPresenter presenter, PostPopupHelperCallback callback) {
this.context = context;
this.presenter = presenter;
this.callback = callback;
}
public void showPosts(Post forPost, List<Post> posts) {
@ -45,47 +46,47 @@ public class PostPopupHelper {
dataQueue.add(data);
if (currentPopupFragment != null) {
currentPopupFragment.dismissNoCallback();
if (dataQueue.size() == 1) {
present();
}
presentFragment(data);
presentingController.setPostRepliesData(data);
}
public void onPostRepliesPop() {
if (dataQueue.size() == 0)
return;
dataQueue.remove(dataQueue.size() - 1);
public void pop() {
if (dataQueue.size() > 0) {
dataQueue.remove(dataQueue.size() - 1);
}
if (dataQueue.size() > 0) {
presentFragment(dataQueue.get(dataQueue.size() - 1));
presentingController.setPostRepliesData(dataQueue.get(dataQueue.size() - 1));
} else {
currentPopupFragment = null;
dismiss();
}
}
public void closeAllPostFragments() {
public void popAll() {
dataQueue.clear();
if (currentPopupFragment != null) {
currentPopupFragment.dismissNoCallback();
currentPopupFragment = null;
}
dismiss();
}
public void postClicked(Post p) {
closeAllPostFragments();
popAll();
presenter.highlightPost(p.no);
presenter.scrollToPost(p.no);
}
private void presentFragment(RepliesData data) {
PostRepliesFragment fragment = PostRepliesFragment.newInstance(data, this, presenter);
// TODO fade animations on all platforms
FragmentTransaction ft = ((Activity) context).getFragmentManager().beginTransaction();
ft.add(fragment, "postPopup");
ft.commitAllowingStateLoss();
currentPopupFragment = fragment;
private void dismiss() {
if (presentingController != null) {
presentingController.stopPresenting();
presentingController = null;
}
}
private void present() {
if (presentingController == null) {
presentingController = new PostRepliesController(context, this, presenter);
callback.presentRepliesController(presentingController);
}
}
public static class RepliesData {
@ -99,4 +100,8 @@ public class PostPopupHelper {
this.posts = posts;
}
}
public interface PostPopupHelperCallback {
void presentRepliesController(Controller controller);
}
}

@ -28,6 +28,7 @@ import android.widget.Toast;
import com.android.volley.VolleyError;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.model.ChanThread;
import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Post;
@ -45,7 +46,7 @@ import java.util.List;
/**
* Wrapper around ThreadListLayout, so that it cleanly manages between loadbar and listview.
*/
public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPresenterCallback {
public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPresenterCallback, PostPopupHelper.PostPopupHelperCallback {
private ThreadLayoutCallback callback;
private ThreadPresenter presenter;
@ -74,7 +75,7 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
threadListLayout = new ThreadListLayout(getContext());
threadListLayout.setCallbacks(presenter, presenter);
postPopupHelper = new PostPopupHelper(getContext(), presenter);
postPopupHelper = new PostPopupHelper(getContext(), presenter, this);
switchVisible(false);
}
@ -157,7 +158,7 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
@Override
public void showThread(Loadable threadLoadable) {
callback.openThread(threadLoadable);
callback.showThread(threadLoadable);
}
public void showPostsPopup(Post forPost, List<Post> posts) {
@ -185,11 +186,18 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres
}
}
@Override
public void presentRepliesController(Controller controller) {
callback.presentRepliesController(controller);
}
public interface ThreadLayoutCallback {
void openThread(Loadable threadLoadable);
void showThread(Loadable threadLoadable);
void showImages(List<PostImage> images, int index, Loadable loadable, ThumbnailView thumbnail);
void onShowPosts();
void presentRepliesController(Controller controller);
}
}

@ -25,6 +25,7 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
@ -141,6 +142,10 @@ public class LoadView extends FrameLayout {
final AnimatorSet set = new AnimatorSet();
set.setDuration(fadeDuration);
if (fadeDuration > 0) {
set.setStartDelay(50);
}
set.setInterpolator(new LinearInterpolator());
set.play(ObjectAnimator.ofFloat(view, View.ALPHA, 0f));
animatorsOut.put(view, set);
set.addListener(new AnimatorListenerAdapter() {
@ -156,6 +161,7 @@ public class LoadView extends FrameLayout {
private void animateViewIn(View view) {
final AnimatorSet set = new AnimatorSet();
set.setDuration(fadeDuration);
set.setInterpolator(new LinearInterpolator());
set.play(ObjectAnimator.ofFloat(view, View.ALPHA, 1f));
animatorsIn.put(view, set);
set.addListener(new AnimatorListenerAdapter() {

@ -23,10 +23,12 @@ import android.content.res.TypedArray;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannedString;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
@ -54,7 +56,7 @@ import org.floens.chan.utils.Time;
import static org.floens.chan.utils.AndroidUtils.setPressedDrawable;
public class PostView extends LinearLayout implements View.OnClickListener {
public class PostView extends LinearLayout implements View.OnClickListener, PostLinkable.Callback {
private final static LinearLayout.LayoutParams matchParams = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
private final static LinearLayout.LayoutParams wrapParams = new LinearLayout.LayoutParams(
@ -71,6 +73,8 @@ public class PostView extends LinearLayout implements View.OnClickListener {
private Loadable loadable;
private int highlightQuotesNo = -1;
private boolean ignoreNextOnClick = false;
private boolean isBuild = false;
private LinearLayout full;
private LinearLayout contentContainer;
@ -112,18 +116,23 @@ public class PostView extends LinearLayout implements View.OnClickListener {
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (post != null) {
post.setLinkableListener(null);
if (this.post != null) {
setPostLinkableListener(null);
}
}
public void setPost(final Post post, final PostViewCallback callback) {
if (this.post != null) {
// Remove callbacks from the old post while it is still set
setPostLinkableListener(null);
}
this.post = post;
this.callback = callback;
this.loadable = callback.getLoadable();
highlightQuotesNo = -1;
setPostLinkableListener(this);
boolean boardCatalogMode = loadable.isBoardMode() || loadable.isCatalogMode();
@ -174,11 +183,9 @@ public class PostView extends LinearLayout implements View.OnClickListener {
commentView.setText(post.comment);
if (loadable.isThreadMode()) {
post.setLinkableListener(this);
commentView.setMovementMethod(new PostViewMovementMethod());
commentView.setOnClickListener(this);
} else {
post.setLinkableListener(null);
commentView.setOnClickListener(null);
commentView.setClickable(false);
commentView.setMovementMethod(null);
@ -267,8 +274,20 @@ public class PostView extends LinearLayout implements View.OnClickListener {
highlightQuotesNo = no;
}
public int getHighlightQuotesWithNo() {
return highlightQuotesNo;
private void setPostLinkableListener(PostLinkable.Callback callback) {
if (post.comment instanceof SpannedString) {
SpannedString commentSpannable = (SpannedString) post.comment;
PostLinkable[] linkables = commentSpannable.getSpans(0, commentSpannable.length(), PostLinkable.class);
for (PostLinkable linkable : linkables) {
if (callback == null) {
if (linkable.hasCallback(this)) {
linkable.removeCallback(this);
}
} else {
linkable.addCallback(callback);
}
}
}
}
private void buildView(final Context context, TypedArray ta) {
@ -466,18 +485,35 @@ public class PostView extends LinearLayout implements View.OnClickListener {
wrapper.setOnClickListener(this);
}
public void setOnClickListeners(View.OnClickListener listener) {
commentView.setOnClickListener(listener);
full.setOnClickListener(listener);
public void setOnClickListeners(final View.OnClickListener listener) {
commentView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (ignoreNextOnClick) {
ignoreNextOnClick = false;
} else {
listener.onClick(v);
}
}
});
}
public void onLinkableClick(PostLinkable linkable) {
callback.onPostLinkableClicked(linkable);
}
@Override
public int getHighlightQuotesWithNo(PostLinkable postLinkable) {
return highlightQuotesNo;
}
@Override
public void onClick(View v) {
callback.onPostClicked(post);
if (ignoreNextOnClick) {
ignoreNextOnClick = false;
} else {
callback.onPostClicked(post);
}
}
private boolean isList() {
@ -512,7 +548,51 @@ public class PostView extends LinearLayout implements View.OnClickListener {
boolean isPostLastSeen(Post post);
}
private static BackgroundColorSpan BACKGROUND_SPAN = new BackgroundColorSpan(0x6633B5E5);
private class PostViewMovementMethod extends LinkMovementMethod {
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
ignoreNextOnClick = true;
link[0].onClick(widget);
buffer.removeSpan(BACKGROUND_SPAN);
} else if (action == MotionEvent.ACTION_DOWN) {
buffer.setSpan(BACKGROUND_SPAN, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]), 0);
} else if (action == MotionEvent.ACTION_CANCEL) {
buffer.removeSpan(BACKGROUND_SPAN);
}
return true;
} else {
buffer.removeSpan(BACKGROUND_SPAN);
}
}
return true;
}
}
/*private class PostViewMovementMethod extends LinkMovementMethod {
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
@ -551,5 +631,5 @@ public class PostView extends LinearLayout implements View.OnClickListener {
return true;
}
}
}
}*/
}

@ -136,6 +136,10 @@ public class AndroidUtils {
new Handler(Looper.getMainLooper()).post(runnable);
}
public static void runOnUiThread(Runnable runnable, long delay) {
new Handler(Looper.getMainLooper()).postDelayed(runnable, delay);
}
public static void requestKeyboardFocus(Dialog dialog, final View view) {
view.requestFocus();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -15,65 +15,75 @@ 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/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<org.floens.chan.ui.view.LoadView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/loadview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="320dp"
android:orientation="vertical">
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="12dp"
android:orientation="horizontal"
android:showDividers="middle">
android:layout_gravity="center"
android:minWidth="320dp"
android:background="@drawable/dialog_full_light"
android:orientation="vertical">
<FrameLayout
android:id="@+id/replies_back"
style="?android:actionButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="12dp"
android:orientation="horizontal"
android:showDividers="middle">
<TextView
android:id="@+id/replies_back_icon"
style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_back"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:paddingRight="20dp"
android:text="@string/back" />
</FrameLayout>
<FrameLayout
android:id="@+id/replies_back"
style="?android:actionButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<FrameLayout
android:id="@+id/replies_close"
style="?android:actionButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
android:id="@+id/replies_back_icon"
style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_back"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:paddingRight="20dp"
android:text="@string/back" />
</FrameLayout>
<TextView
android:id="@+id/replies_close_icon"
style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_done"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:paddingRight="20dp"
android:text="@string/close" />
</FrameLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/replies_close"
style="?android:actionButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
android:id="@+id/replies_close_icon"
style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_done"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:paddingRight="20dp"
android:text="@string/close" />
</FrameLayout>
</LinearLayout>
<ListView
android:id="@+id/post_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="@+id/post_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
</org.floens.chan.ui.view.LoadView>

@ -15,66 +15,75 @@ 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/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="320dp"
android:orientation="vertical">
<ListView
android:id="@+id/post_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
android:background="#88000000">
<LinearLayout
android:layout_width="match_parent"
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="12dp"
android:orientation="horizontal"
android:showDividers="middle">
android:layout_gravity="center"
android:minWidth="320dp"
android:background="@drawable/dialog_full_light"
android:orientation="vertical">
<ListView
android:id="@+id/post_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="12dp"
android:orientation="horizontal"
android:showDividers="middle">
<FrameLayout
android:id="@+id/replies_back"
style="?android:actionButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<FrameLayout
android:id="@+id/replies_back"
style="?android:actionButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
android:id="@+id/replies_back_icon"
style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_back"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:paddingRight="20dp"
android:text="@string/back" />
</FrameLayout>
<TextView
android:id="@+id/replies_back_icon"
style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_back"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:paddingRight="20dp"
android:text="@string/back" />
</FrameLayout>
<FrameLayout
android:id="@+id/replies_close"
style="?android:actionButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<FrameLayout
android:id="@+id/replies_close"
style="?android:actionButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
android:id="@+id/replies_close_icon"
style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_done"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:paddingRight="20dp"
android:text="@string/close" />
</FrameLayout>
</LinearLayout>
<TextView
android:id="@+id/replies_close_icon"
style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_done"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:paddingRight="20dp"
android:text="@string/close" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
</FrameLayout>

@ -0,0 +1,22 @@
<?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.view.LoadView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/loadview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#88000000" />
Loading…
Cancel
Save