Added getTexts and action recorder, fixed github issue report token
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
package com.stardust.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/4.
|
||||
*/
|
||||
|
||||
public class ExpandableRecyclerView extends RecyclerView {
|
||||
|
||||
public void setOnChildClickListener(OnChildClickListener onChildClickListener) {
|
||||
mOnChildClickListener = onChildClickListener;
|
||||
}
|
||||
|
||||
public interface OnChildClickListener {
|
||||
|
||||
void onClick(View view, int position);
|
||||
}
|
||||
|
||||
|
||||
private OnClickListener mOnTitleClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
toggle();
|
||||
}
|
||||
|
||||
};
|
||||
private OnClickListener mOnChildClickListenerWrapper = new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mOnChildClickListener != null) {
|
||||
mOnChildClickListener.onClick(v, getChildViewHolder(v).getAdapterPosition() - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
private boolean mExpanded;
|
||||
private OnChildClickListener mOnChildClickListener;
|
||||
|
||||
public ExpandableRecyclerView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public ExpandableRecyclerView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public ExpandableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
if (isExpanded()) {
|
||||
collapse();
|
||||
} else {
|
||||
expand();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isExpanded() {
|
||||
return mExpanded;
|
||||
}
|
||||
|
||||
public void expand() {
|
||||
if (mExpanded)
|
||||
return;
|
||||
mExpanded = true;
|
||||
((Adapter) getAdapter()).notifyExpanded();
|
||||
}
|
||||
|
||||
public void collapse() {
|
||||
if (!mExpanded)
|
||||
return;
|
||||
mExpanded = false;
|
||||
((Adapter) getAdapter()).notifyCollapsed();
|
||||
}
|
||||
|
||||
public abstract class Adapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
protected static final int VIEW_TYPE_TITLE = 1;
|
||||
|
||||
public void notifyExpanded() {
|
||||
notifyItemChanged(0);
|
||||
notifyItemRangeInserted(1, getChildItemCount());
|
||||
}
|
||||
|
||||
public void notifyCollapsed() {
|
||||
notifyItemRangeRemoved(1, getChildItemCount());
|
||||
notifyItemChanged(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mExpanded ? getChildItemCount() + 1 : 1;
|
||||
}
|
||||
|
||||
protected abstract int getChildItemCount();
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return position == 0 ? VIEW_TYPE_TITLE : getChildItemViewType(position - 1);
|
||||
}
|
||||
|
||||
protected abstract int getChildItemViewType(int position);
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
if (viewType == VIEW_TYPE_TITLE) {
|
||||
ViewHolder holder = onCreateTitleViewHolder(parent);
|
||||
holder.itemView.setOnClickListener(mOnTitleClickListener);
|
||||
return holder;
|
||||
} else {
|
||||
ViewHolder holder = onCreateChildViewHolder(parent, viewType);
|
||||
holder.itemView.setOnClickListener(mOnChildClickListenerWrapper);
|
||||
return holder;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ViewHolder onCreateTitleViewHolder(ViewGroup parent);
|
||||
|
||||
protected abstract ViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType);
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
if (holder.getItemViewType() == VIEW_TYPE_TITLE) {
|
||||
onBindTitleViewHolder(holder);
|
||||
} else {
|
||||
onBindChildViewHolder(holder, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void onBindChildViewHolder(ViewHolder holder, int position);
|
||||
|
||||
protected abstract void onBindTitleViewHolder(ViewHolder holder);
|
||||
|
||||
}
|
||||
|
||||
public abstract class DefaultTitleAdapter extends Adapter {
|
||||
|
||||
private int mIconResId = -1;
|
||||
private String mTitle;
|
||||
|
||||
public void setIcon(int iconResId) {
|
||||
mIconResId = iconResId;
|
||||
}
|
||||
|
||||
public void setTitle(int resId) {
|
||||
mTitle = getContext().getString(resId);
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
mTitle = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView.ViewHolder onCreateTitleViewHolder(ViewGroup parent) {
|
||||
return new TitleViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.expanded_recycler_view_default_title, parent, false));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onBindTitleViewHolder(RecyclerView.ViewHolder holder) {
|
||||
TitleViewHolder viewHolder = (TitleViewHolder) holder;
|
||||
viewHolder.mExpandHint.setImageResource(isExpanded() ? R.drawable.ic_expanded : R.drawable.ic_collapsed);
|
||||
}
|
||||
|
||||
|
||||
private class TitleViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
ImageView mExpandHint;
|
||||
|
||||
TitleViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
mExpandHint = (ImageView) itemView.findViewById(R.id.expand_hint);
|
||||
((TextView) itemView.findViewById(R.id.title)).setText(mTitle);
|
||||
if (mIconResId != -1) {
|
||||
((ImageView) itemView.findViewById(R.id.icon)).setImageResource(mIconResId);
|
||||
} else {
|
||||
itemView.findViewById(R.id.icon).setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
61
app/src/main/java/com/stardust/widget/MarkdownView.java
Normal file
61
app/src/main/java/com/stardust/widget/MarkdownView.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package com.stardust.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.zzhoujay.markdown.MarkDown;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/1.
|
||||
*/
|
||||
|
||||
public class MarkdownView extends TextView {
|
||||
public MarkdownView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public MarkdownView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public MarkdownView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public MarkdownView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setMovementMethod(ScrollingMovementMethod.getInstance());
|
||||
setVerticalScrollBarEnabled(true);
|
||||
setTextIsSelectable(true);
|
||||
setClickable(true);
|
||||
}
|
||||
|
||||
public void loadMarkdown(final String text, final Html.ImageGetter imageGetter) {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Spanned spanned = MarkDown.fromMarkdown(text, imageGetter, MarkdownView.this);
|
||||
setText(spanned);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void loadMarkdown(final String text) {
|
||||
loadMarkdown(text, null);
|
||||
}
|
||||
|
||||
}
|
||||
118
app/src/main/java/com/stardust/widget/SlidingUpPanel.java
Normal file
118
app/src/main/java/com/stardust/widget/SlidingUpPanel.java
Normal file
@@ -0,0 +1,118 @@
|
||||
package com.stardust.widget;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/24.
|
||||
*/
|
||||
|
||||
public class SlidingUpPanel extends FrameLayout {
|
||||
|
||||
private static final long DEFAULT_ANIMATION_DURATION = 300;
|
||||
|
||||
private Animation mSlideUpAnimation, mSlideDownAnimation;
|
||||
private View mShadow;
|
||||
private boolean mShowing = false;
|
||||
private FrameLayout mContentContainer;
|
||||
|
||||
public SlidingUpPanel(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public SlidingUpPanel(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public SlidingUpPanel(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public SlidingUpPanel(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
setVisibility(VISIBLE);
|
||||
mContentContainer.startAnimation(mSlideUpAnimation);
|
||||
mShowing = true;
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
mContentContainer.startAnimation(mSlideDownAnimation);
|
||||
postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SlidingUpPanel.this.setVisibility(GONE);
|
||||
}
|
||||
}, mSlideDownAnimation.getDuration());
|
||||
mShowing = false;
|
||||
}
|
||||
|
||||
public void setAnimationDuration(long animationDuration) {
|
||||
mSlideUpAnimation.setDuration(animationDuration);
|
||||
mSlideDownAnimation.setDuration(animationDuration / 2);
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mShowing;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
LayoutInflater.from(getContext()).inflate(R.layout.sliding_up_panel, this, true);
|
||||
initShadow();
|
||||
initAnimation();
|
||||
setVisibility(GONE);
|
||||
mContentContainer = (FrameLayout) findViewById(R.id.content_container);
|
||||
}
|
||||
|
||||
private void initAnimation() {
|
||||
mSlideUpAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.slide_up);
|
||||
mSlideDownAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.slide_down);
|
||||
setAnimationDuration(DEFAULT_ANIMATION_DURATION);
|
||||
}
|
||||
|
||||
private void initShadow() {
|
||||
mShadow = findViewById(R.id.shadow);
|
||||
mShadow.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SlidingUpPanel.this.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_UP && isShowing()) {
|
||||
dismiss();
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child, int index, ViewGroup.LayoutParams params) {
|
||||
if (mContentContainer != null)
|
||||
mContentContainer.addView(child, index, params);
|
||||
else
|
||||
super.addView(child, index, params);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
90
app/src/main/java/com/stardust/widget/ToolbarMenuItem.java
Normal file
90
app/src/main/java/com/stardust/widget/ToolbarMenuItem.java
Normal file
@@ -0,0 +1,90 @@
|
||||
package com.stardust.widget;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/29.
|
||||
*/
|
||||
|
||||
public class ToolbarMenuItem extends LinearLayout {
|
||||
|
||||
private static final int COLOR_DISABLED = 0X77e0e0e0;
|
||||
private ImageView mImageView;
|
||||
private TextView mTextView;
|
||||
private Drawable mEnabledDrawable, mDisabledDrawable;
|
||||
|
||||
public ToolbarMenuItem(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
public ToolbarMenuItem(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public ToolbarMenuItem(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
private void init(AttributeSet attrs) {
|
||||
inflate(getContext(), R.layout.toolbar_menu_item, this);
|
||||
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ToolbarMenuItem);
|
||||
String text = a.getString(R.styleable.ToolbarMenuItem_text);
|
||||
int iconResId = a.getResourceId(R.styleable.ToolbarMenuItem_icon, 0);
|
||||
int iconColor = a.getColor(R.styleable.ToolbarMenuItem_icon_color, Color.TRANSPARENT);
|
||||
a.recycle();
|
||||
mImageView = (ImageView) findViewById(R.id.icon);
|
||||
mTextView = (TextView) findViewById(R.id.text);
|
||||
mTextView.setText(text);
|
||||
mImageView.setImageResource(iconResId);
|
||||
if (iconColor != Color.TRANSPARENT) {
|
||||
mImageView.setImageDrawable(convertDrawableToGrayScale(mImageView.getDrawable(), iconColor));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (enabled == isEnabled())
|
||||
return;
|
||||
super.setEnabled(enabled);
|
||||
ensureEnabledDrawable();
|
||||
ensureDisabledDrawable();
|
||||
mImageView.setImageDrawable(enabled ? mEnabledDrawable : mDisabledDrawable);
|
||||
mTextView.setTextColor(enabled ? Color.WHITE : COLOR_DISABLED);
|
||||
}
|
||||
|
||||
private void ensureDisabledDrawable() {
|
||||
if (mDisabledDrawable == null) {
|
||||
mDisabledDrawable = convertDrawableToGrayScale(mEnabledDrawable, COLOR_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureEnabledDrawable() {
|
||||
if (mEnabledDrawable == null) {
|
||||
mEnabledDrawable = mImageView.getDrawable();
|
||||
}
|
||||
}
|
||||
|
||||
public static Drawable convertDrawableToGrayScale(Drawable drawable, int color) {
|
||||
if (drawable == null || drawable.getConstantState() == null)
|
||||
return null;
|
||||
Drawable res = drawable.getConstantState().newDrawable().mutate();
|
||||
res.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user