From e5ab4e59686632a28debc6039f1c6927fffe9643 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sun, 16 Nov 2014 13:13:39 +0400 Subject: [PATCH] add gmail-like round drawable for compact mode in place of checkbox --- org.fox.ttrss/src/main/AndroidManifest.xml | 4 +- .../textdrawable/TextDrawable.java | 316 ++++++++++++++++++ .../textdrawable/util/ColorGenerator.java | 48 +++ .../java/org/fox/ttrss/HeadlinesFragment.java | 51 ++- .../offline/OfflineHeadlinesFragment.java | 57 +++- .../src/main/res/drawable-hdpi/check_sm.9.png | Bin 0 -> 1367 bytes .../main/res/drawable-xhdpi/check_sm.9.png | Bin 0 -> 2598 bytes .../main/res/drawable-xxhdpi/check_sm.9.png | Bin 0 -> 4204 bytes .../main/res/layout/headlines_row_compact.xml | 24 +- .../layout/headlines_row_selected_compact.xml | 24 +- .../headlines_row_selected_unread_compact.xml | 24 +- .../layout/headlines_row_unread_compact.xml | 24 +- 12 files changed, 542 insertions(+), 30 deletions(-) create mode 100644 org.fox.ttrss/src/main/java/com/amulyakhare/textdrawable/TextDrawable.java create mode 100644 org.fox.ttrss/src/main/java/com/amulyakhare/textdrawable/util/ColorGenerator.java create mode 100644 org.fox.ttrss/src/main/res/drawable-hdpi/check_sm.9.png create mode 100644 org.fox.ttrss/src/main/res/drawable-xhdpi/check_sm.9.png create mode 100644 org.fox.ttrss/src/main/res/drawable-xxhdpi/check_sm.9.png diff --git a/org.fox.ttrss/src/main/AndroidManifest.xml b/org.fox.ttrss/src/main/AndroidManifest.xml index da9c5538..a0de789e 100644 --- a/org.fox.ttrss/src/main/AndroidManifest.xml +++ b/org.fox.ttrss/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="284" + android:versionName="1.76" > 0) { + drawBorder(canvas); + } + + int count = canvas.save(); + canvas.translate(r.left, r.top); + + // draw text + int width = this.width < 0 ? r.width() : this.width; + int height = this.height < 0 ? r.height() : this.height; + int fontSize = this.fontSize < 0 ? (Math.min(width, height) / 2) : this.fontSize; + textPaint.setTextSize(fontSize); + canvas.drawText(text, width / 2, height / 2 - ((textPaint.descent() + textPaint.ascent()) / 2), textPaint); + + canvas.restoreToCount(count); + + } + + private void drawBorder(Canvas canvas) { + RectF rect = new RectF(getBounds()); + rect.inset(borderThickness/2, borderThickness/2); + + if (shape instanceof OvalShape) { + canvas.drawOval(rect, borderPaint); + } + else if (shape instanceof RoundRectShape) { + canvas.drawRoundRect(rect, radius, radius, borderPaint); + } + else { + canvas.drawRect(rect, borderPaint); + } + } + + @Override + public void setAlpha(int alpha) { + textPaint.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter cf) { + textPaint.setColorFilter(cf); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public int getIntrinsicWidth() { + return width; + } + + @Override + public int getIntrinsicHeight() { + return height; + } + + public static IShapeBuilder builder() { + return new Builder(); + } + + public static class Builder implements IConfigBuilder, IShapeBuilder, IBuilder { + + private String text; + + private int color; + + private int borderThickness; + + private int width; + + private int height; + + private Typeface font; + + private RectShape shape; + + public int textColor; + + private int fontSize; + + private boolean isBold; + + private boolean toUpperCase; + + public float radius; + + private Builder() { + text = ""; + color = Color.GRAY; + textColor = Color.WHITE; + borderThickness = 0; + width = -1; + height = -1; + shape = new RectShape(); + font = Typeface.create("sans-serif-light", Typeface.NORMAL); + fontSize = -1; + isBold = false; + toUpperCase = false; + } + + public IConfigBuilder width(int width) { + this.width = width; + return this; + } + + public IConfigBuilder height(int height) { + this.height = height; + return this; + } + + public IConfigBuilder textColor(int color) { + this.textColor = color; + return this; + } + + public IConfigBuilder withBorder(int thickness) { + this.borderThickness = thickness; + return this; + } + + public IConfigBuilder useFont(Typeface font) { + this.font = font; + return this; + } + + public IConfigBuilder fontSize(int size) { + this.fontSize = size; + return this; + } + + public IConfigBuilder bold() { + this.isBold = true; + return this; + } + + public IConfigBuilder toUpperCase() { + this.toUpperCase = true; + return this; + } + + @Override + public IConfigBuilder beginConfig() { + return this; + } + + @Override + public IShapeBuilder endConfig() { + return this; + } + + @Override + public IBuilder rect() { + this.shape = new RectShape(); + return this; + } + + @Override + public IBuilder round() { + this.shape = new OvalShape(); + return this; + } + + @Override + public IBuilder roundRect(int radius) { + this.radius = radius; + float[] radii = {radius, radius, radius, radius, radius, radius, radius, radius}; + this.shape = new RoundRectShape(radii, null, null); + return this; + } + + @Override + public TextDrawable buildRect(String text, int color) { + rect(); + return build(text, color); + } + + @Override + public TextDrawable buildRoundRect(String text, int color, int radius) { + roundRect(radius); + return build(text, color); + } + + @Override + public TextDrawable buildRound(String text, int color) { + round(); + return build(text, color); + } + + @Override + public TextDrawable build(String text, int color) { + this.color = color; + this.text = text; + return new TextDrawable(this); + } + } + + public interface IConfigBuilder { + public IConfigBuilder width(int width); + + public IConfigBuilder height(int height); + + public IConfigBuilder textColor(int color); + + public IConfigBuilder withBorder(int thickness); + + public IConfigBuilder useFont(Typeface font); + + public IConfigBuilder fontSize(int size); + + public IConfigBuilder bold(); + + public IConfigBuilder toUpperCase(); + + public IShapeBuilder endConfig(); + } + + public static interface IBuilder { + + public TextDrawable build(String text, int color); + } + + public static interface IShapeBuilder { + + public IConfigBuilder beginConfig(); + + public IBuilder rect(); + + public IBuilder round(); + + public IBuilder roundRect(int radius); + + public TextDrawable buildRect(String text, int color); + + public TextDrawable buildRoundRect(String text, int color, int radius); + + public TextDrawable buildRound(String text, int color); + } +} \ No newline at end of file diff --git a/org.fox.ttrss/src/main/java/com/amulyakhare/textdrawable/util/ColorGenerator.java b/org.fox.ttrss/src/main/java/com/amulyakhare/textdrawable/util/ColorGenerator.java new file mode 100644 index 00000000..99e7467f --- /dev/null +++ b/org.fox.ttrss/src/main/java/com/amulyakhare/textdrawable/util/ColorGenerator.java @@ -0,0 +1,48 @@ +package com.amulyakhare.textdrawable.util; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * @author amulya + * @datetime 14 Oct 2014, 5:20 PM + */ +public class ColorGenerator { + + public static ColorGenerator DEFAULT; + + static { + DEFAULT = create(Arrays.asList( + 0xfff16364, + 0xfff58559, + 0xfff9a43e, + 0xffe4c62e, + 0xff67bf74, + 0xff59a2be, + 0xff2093cd, + 0xffad62a7, + 0xff805781 + )); + } + + private final List mColors; + private final Random mRandom; + + public static ColorGenerator create(List colorList) { + return new ColorGenerator(colorList); + } + + private ColorGenerator(List colorList) { + mColors = colorList; + mRandom = new Random(System.currentTimeMillis()); + } + + public int getRandomColor() { + return mColors.get(mRandom.nextInt(mColors.size())); + } + + public int getColor(Object key) { + return mColors.get(Math.abs(key.hashCode()) % mColors.size()); + } +} diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java index b17dd02e..36e5b6c6 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java @@ -41,6 +41,8 @@ import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; +import com.amulyakhare.textdrawable.TextDrawable; +import com.amulyakhare.textdrawable.util.ColorGenerator; import com.google.gson.JsonElement; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; @@ -603,6 +605,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, public ProgressBar flavorImageLoadingBar; public View flavorImageArrow; public View headlineFooter; + public ImageView textImage; + public ImageView textChecked; } private class ArticleListAdapter extends ArrayAdapter
{ @@ -619,6 +623,9 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, private final Integer[] origTitleColors = new Integer[VIEW_COUNT]; private final int titleHighScoreUnreadColor; + private ColorGenerator m_colorGenerator = ColorGenerator.DEFAULT; + private TextDrawable.IBuilder m_drawableBuilder = TextDrawable.builder().round(); + public ArticleListAdapter(Context context, int textViewResourceId, ArrayList
items) { super(context, textViewResourceId, items); this.items = items; @@ -650,13 +657,27 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, } } + private void updateTextCheckedState(HeadlineViewHolder holder, Article item) { + String tmp = item.title.length() > 0 ? item.title.substring(0, 1) : "?"; + + if (m_selectedArticles.contains(item)) { + holder.textImage.setImageDrawable(m_drawableBuilder.build(" ", 0xff616161)); + + holder.textChecked.setVisibility(View.VISIBLE); + } else { + holder.textImage.setImageDrawable(m_drawableBuilder.build(tmp, m_colorGenerator.getColor(item.title))); + + holder.textChecked.setVisibility(View.GONE); + } + } + @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; final Article article = items.get(position); - HeadlineViewHolder holder; + final HeadlineViewHolder holder; int headlineFontSize = Integer.parseInt(m_prefs.getString("headlines_font_size_sp", "13")); int headlineSmallFontSize = Math.max(10, Math.min(18, headlineFontSize - 2)); @@ -698,6 +719,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, holder.flavorImageLoadingBar = (ProgressBar) v.findViewById(R.id.flavorImageLoadingBar); holder.flavorImageArrow = v.findViewById(R.id.flavorImageArrow); holder.headlineFooter = v.findViewById(R.id.headline_footer); + holder.textImage = (ImageView) v.findViewById(R.id.text_image); + holder.textChecked = (ImageView) v.findViewById(R.id.text_checked); v.setTag(holder); @@ -716,7 +739,31 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, } }); } - + + if (holder.textImage != null) { + updateTextCheckedState(holder, article); + + holder.textImage.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + Log.d(TAG, "textImage : onclicked"); + + if (!m_selectedArticles.contains(article)) { + m_selectedArticles.add(article); + } else { + m_selectedArticles.remove(article); + } + + updateTextCheckedState(holder, article); + + m_listener.onArticleListSelectionChange(m_selectedArticles); + + Log.d(TAG, "num selected: " + m_selectedArticles.size()); + } + }); + + } + if (holder.titleView != null) { holder.titleView.setText(Html.fromHtml(article.title)); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineHeadlinesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineHeadlinesFragment.java index 0b8ec6c1..3af3c237 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineHeadlinesFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/offline/OfflineHeadlinesFragment.java @@ -36,6 +36,9 @@ import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; +import com.amulyakhare.textdrawable.TextDrawable; +import com.amulyakhare.textdrawable.util.ColorGenerator; + import org.fox.ttrss.GlobalState; import org.fox.ttrss.R; import org.fox.ttrss.util.TypefaceCache; @@ -448,6 +451,8 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis public ProgressBar flavorImageLoadingBar; public View flavorImageArrow; public View headlineFooter; + public ImageView textImage; + public ImageView textChecked; } private class ArticleListAdapter extends SimpleCursorAdapter { @@ -461,6 +466,9 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis private final Integer[] origTitleColors = new Integer[VIEW_COUNT]; private final int titleHighScoreUnreadColor; + + private ColorGenerator m_colorGenerator = ColorGenerator.DEFAULT; + private TextDrawable.IBuilder m_drawableBuilder = TextDrawable.builder().round(); public ArticleListAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { @@ -493,14 +501,32 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis } } + private void updateTextCheckedState(HeadlineViewHolder holder, Cursor item) { + String title = item.getString(item.getColumnIndex("title")); + + String tmp = title.length() > 0 ? title.substring(0, 1) : "?"; + + boolean isChecked = item.getInt(item.getColumnIndex("selected")) == 1; + + if (isChecked) { + holder.textImage.setImageDrawable(m_drawableBuilder.build(" ", 0xff616161)); + + holder.textChecked.setVisibility(View.VISIBLE); + } else { + holder.textImage.setImageDrawable(m_drawableBuilder.build(tmp, m_colorGenerator.getColor(title))); + + holder.textChecked.setVisibility(View.GONE); + } + } + @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; - Cursor article = (Cursor)getItem(position); + final Cursor article = (Cursor)getItem(position); - HeadlineViewHolder holder; + final HeadlineViewHolder holder; final int articleId = article.getInt(0); @@ -544,6 +570,8 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis holder.flavorImageLoadingBar = (ProgressBar) v.findViewById(R.id.flavorImageLoadingBar); holder.flavorImageArrow = v.findViewById(R.id.flavorImageArrow); holder.headlineFooter = v.findViewById(R.id.headline_footer); + holder.textImage = (ImageView) v.findViewById(R.id.text_image); + holder.textChecked = (ImageView) v.findViewById(R.id.text_checked); v.setTag(holder); @@ -563,6 +591,31 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis }); } + if (holder.textImage != null) { + updateTextCheckedState(holder, article); + + holder.textImage.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + Log.d(TAG, "textImage : onclicked"); + + SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET selected = NOT selected " + + "WHERE " + BaseColumns._ID + " = ?"); + + stmtUpdate.bindLong(1, articleId); + stmtUpdate.execute(); + stmtUpdate.close(); + + updateTextCheckedState(holder, article); + + refresh(); + + m_activity.invalidateOptionsMenu(); + } + }); + + } + if (holder.titleView != null) { holder.titleView.setText(Html.fromHtml(article.getString(article.getColumnIndex("title")))); diff --git a/org.fox.ttrss/src/main/res/drawable-hdpi/check_sm.9.png b/org.fox.ttrss/src/main/res/drawable-hdpi/check_sm.9.png new file mode 100644 index 0000000000000000000000000000000000000000..7cf7352170d3e45fe031711641e449a271d78c37 GIT binary patch literal 1367 zcmeAS@N?(olHy`uVBq!ia0vp^RUpj41|$n2-JdWpu*!M5IEGZjy`AfwAsi^u=Bu=E z!QGA@4Uf2Ycdb~l;zDajN3|e}U}0dug+&Y2iG=Ukq!8ljSn&AJ)I1h(rAw{aTRZr7 zedx_wRjS?;_~yrbBV|>U;`et{s?OW~cbK8_ea_|LfBEO;o;;(Xdp0ZIQ|690pV=+n zUF(z;HEtf^n6+T4#)2h2WhRc=fexNC-()m}Eozu#bn_z1S{Fvu)J=;yqdJ+qPNldD zZxLdhGUa4n7|X2~CFKt%8l?}g$XccZ%QlHBav1CQUlu(4>U z;eNb3NcwZ?k-H3a)(H#N1}VRoc1q=>UC-SNqdcn`fdjF16V0dOHZ3T2_?)4IoI3w+)feBeWGN)y|P&ei~7A9@FFEODK;UgEv8OmVB$G*^|3&xI#qymGe9INip4 zc3F(Wx`Z4ierD_ZNS^=aHwv6fvkg@DVR&sLWIvHvarf(F*#z79ne6vBSJZ0pKe%$` zO2N_~OG(L;;J!6|Y->b4e$7?x*eaRxgZIGmg-72rzw!MeAs)G4x%pWY$wOI38rx<* zGH1RgQDgV8a{kff^4s!d9(kEeWVdRqm3ZwfcJ!=C9^Z<0k0#zddGpj$6NUMcJuVog z&s-3Eqd6kJSjXgi4$lPhG6laAicgyS66KHl%9_ok&-|i4_ZY|BShE*Rzu%-8d}A)! zT)o|yJ>10pCs1SihJ8UBe(5*tS+Sr$FtmaZb+q+mA-LslD+|`kH TVd-&TfyvgTe~DWM4f-&Am7 literal 0 HcmV?d00001 diff --git a/org.fox.ttrss/src/main/res/drawable-xhdpi/check_sm.9.png b/org.fox.ttrss/src/main/res/drawable-xhdpi/check_sm.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9981a75fb9b7a17e01c719ec079f084952cca8ad GIT binary patch literal 2598 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 - + android:layout_height="wrap_content"> + + + + + + - + android:layout_height="wrap_content"> + + + + + + - + android:layout_height="wrap_content"> + + + + + + - + android:layout_height="wrap_content"> + + + + + +