From e5ab4e59686632a28debc6039f1c6927fffe9643 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sun, 16 Nov 2014 13:13:39 +0400 Subject: add gmail-like round drawable for compact mode in place of checkbox --- org.fox.ttrss/src/main/AndroidManifest.xml | 4 +- .../com/amulyakhare/textdrawable/TextDrawable.java | 316 +++++++++++++++++++++ .../textdrawable/util/ColorGenerator.java | 48 ++++ .../main/java/org/fox/ttrss/HeadlinesFragment.java | 51 +++- .../ttrss/offline/OfflineHeadlinesFragment.java | 57 +++- .../src/main/res/drawable-hdpi/check_sm.9.png | Bin 0 -> 1367 bytes .../src/main/res/drawable-xhdpi/check_sm.9.png | Bin 0 -> 2598 bytes .../src/main/res/drawable-xxhdpi/check_sm.9.png | Bin 0 -> 4204 bytes .../src/main/res/layout/headlines_row_compact.xml | 24 +- .../res/layout/headlines_row_selected_compact.xml | 24 +- .../headlines_row_selected_unread_compact.xml | 24 +- .../res/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 (limited to 'org.fox.ttrss') 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 00000000..7cf73521 Binary files /dev/null and b/org.fox.ttrss/src/main/res/drawable-hdpi/check_sm.9.png differ 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 00000000..9981a75f Binary files /dev/null and b/org.fox.ttrss/src/main/res/drawable-xhdpi/check_sm.9.png differ diff --git a/org.fox.ttrss/src/main/res/drawable-xxhdpi/check_sm.9.png b/org.fox.ttrss/src/main/res/drawable-xxhdpi/check_sm.9.png new file mode 100644 index 00000000..8766797f Binary files /dev/null and b/org.fox.ttrss/src/main/res/drawable-xxhdpi/check_sm.9.png differ diff --git a/org.fox.ttrss/src/main/res/layout/headlines_row_compact.xml b/org.fox.ttrss/src/main/res/layout/headlines_row_compact.xml index eec8860f..c0240fda 100644 --- a/org.fox.ttrss/src/main/res/layout/headlines_row_compact.xml +++ b/org.fox.ttrss/src/main/res/layout/headlines_row_compact.xml @@ -10,13 +10,25 @@ android:background="?headlineNormalBackground" tools:ignore="HardcodedText" > - + android:layout_height="wrap_content"> + + + + + + - + android:layout_height="wrap_content"> + + + + + + - + android:layout_height="wrap_content"> + + + + + + - + android:layout_height="wrap_content"> + + + + + +