flesh out grid view items

This commit is contained in:
dosiecki 2018-02-23 07:06:38 -08:00
parent b5fa158dc7
commit 7d425df6f2
13 changed files with 295 additions and 103 deletions

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- on API 14 and 15, the default solid is a black square, not nothing. -->
<solid android:color="@android:color/transparent" />
<padding
android:bottom="1dp"
android:top="1dp"
android:left="1dp"
android:right="1dp"
/>
<stroke
android:color="@color/gray55"
android:width="1dp"
android:height="1dp"
/>
<corners android:radius="0dp" />
</shape>

View file

@ -1,38 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<com.newsblur.view.SquaredRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.newsblur.view.SquaredRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:newsblur="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
newsblur:addedHeight="60"
android:background="@drawable/item_border"
>
<ImageView
android:id="@+id/story_item_thumbnail"
android:layout_width="match_parent"
<View
android:id="@+id/story_item_favicon_borderbar_1"
android:layout_width="4dp"
android:layout_height="match_parent"
/>
<View
android:id="@+id/story_item_favicon_borderbar_2"
android:layout_width="4dp"
android:layout_height="match_parent"
android:layout_marginTop="1dp"
android:layout_marginBottom="1dp"
android:layout_marginLeft="1dp"
android:layout_marginRight="1dp"
android:layout_toRightOf="@id/story_item_favicon_borderbar_1"
/>
<TextView
android:id="@+id/story_item_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="2dp"
android:layout_marginRight="4dp"
android:singleLine="true"
style="?storyDateText"
/>
<ImageView
android:id="@+id/story_item_feedicon"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="4dp"
android:layout_marginLeft="4dp"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_toRightOf="@id/story_item_favicon_borderbar_2"
android:layout_above="@id/story_item_date"
android:layout_marginTop="5dp"
android:layout_marginLeft="18dp"
android:layout_marginBottom="2dp"
/>
<TextView
android:id="@+id/story_item_feedtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_toRightOf="@id/story_item_feedicon"
android:layout_above="@id/story_item_date"
android:layout_marginLeft="6dp"
android:layout_marginRight="2dp"
android:layout_marginBottom="2dp"
android:ellipsize="end"
android:singleLine="true"
style="?storyFeedTitleText"
/>
<ImageView
android:id="@+id/story_item_saved_icon"
android:src="@drawable/clock"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_above="@id/story_item_feedtitle"
android:layout_alignParentRight="true"
android:layout_marginTop="2dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:visibility="gone"
/>
<ImageView
android:id="@+id/story_item_shared_icon"
android:src="@drawable/ic_shared"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_above="@id/story_item_feedtitle"
android:layout_toLeftOf="@id/story_item_saved_icon"
android:layout_alignWithParentIfMissing="true"
android:layout_marginTop="2dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:visibility="gone"
/>
<TextView
android:id="@+id/story_item_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/row_item_feedicon"
android:layout_marginLeft="4dp"
android:paddingTop="4dp"
android:layout_above="@id/story_item_feedtitle"
android:layout_toLeftOf="@id/story_item_shared_icon"
android:layout_marginLeft="26dp"
android:layout_marginRight="2dp"
android:layout_marginBottom="2dp"
android:maxLines="2"
android:ellipsize="end"
/>
<ImageView
android:id="@+id/story_item_inteldot"
android:layout_width="9dp"
android:layout_height="match_parent"
android:layout_alignTop="@id/story_item_title"
android:layout_alignBottom="@id/story_item_title"
android:layout_toRightOf="@id/story_item_favicon_borderbar_2"
android:layout_marginLeft="4dp"
/>
<ImageView
android:id="@+id/story_item_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/story_item_title"
android:layout_marginBottom="2dp"
android:layout_marginLeft="10dp"
android:scaleType="centerCrop"
/>
</com.newsblur.view.SquaredRelativeLayout>

View file

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="flow" format="string" />
<attr name="imageViewSize" format="integer" />
<attr name="selectorFolderBackground" format="string" />
<attr name="selectorFeedBackground" format="string" />
<attr name="feedRowNeutCountText" format="string" />
@ -41,8 +39,15 @@
<attr name="selectorOverlayBackgroundText" format="string" />
<attr name="muteicon" format="string" />
<attr name="flow" format="string" />
<attr name="imageViewSize" format="integer" />
<declare-styleable name="FlowLayout">
<attr name="flow" />
<attr name="imageViewSize" />
</declare-styleable>
<attr name="addedHeight" format="integer" />
<declare-styleable name="SquaredRelativeLayout">
<attr name="addedHeight" />
</declare-styleable>
</resources>

View file

@ -59,7 +59,7 @@
<color name="dark_story_background_selected">#4C4C4C</color>
<color name="story_feed_title_text">#606060</color>
<color name="dark_story_feed_title_text">#F7F8F5</color>
<color name="dark_story_feed_title_text">@color/gray55</color>
<color name="story_date_text">#424242</color>
<color name="dark_story_date_text">#BDBDBD</color>
<color name="story_content_text">#404040</color>

View file

@ -265,32 +265,35 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
}
fs.setSearchQuery(q);
if (!TextUtils.equals(q, oldQuery)) {
NBSyncService.resetReadingSession();
FeedUtils.prepareReadingSession(fs);
triggerSync();
itemSetFragment.resetEmptyState();
itemSetFragment.hasUpdated();
itemSetFragment.scrollToTop();
NBSyncService.resetReadingSession();
NBSyncService.resetFetchState(fs);
}
}
@Override
public void storyOrderChanged(StoryOrder newValue) {
updateStoryOrderPreference(newValue);
itemSetFragment.resetEmptyState();
itemSetFragment.hasUpdated();
itemSetFragment.scrollToTop();
NBSyncService.resetFetchState(fs);
triggerSync();
restartReadingSession();
}
@Override
public void readFilterChanged(ReadFilter newValue) {
updateReadFilterPreference(newValue);
restartReadingSession();
}
private void restartReadingSession() {
NBSyncService.resetFetchState(fs);
NBSyncService.resetReadingSession();
FeedUtils.prepareReadingSession(fs);
triggerSync();
itemSetFragment.resetEmptyState();
itemSetFragment.hasUpdated();
itemSetFragment.scrollToTop();
NBSyncService.resetFetchState(fs);
triggerSync();
}
// NB: this callback is for the text size slider

View file

@ -1125,6 +1125,7 @@ public class BlurDatabaseHelper {
}
public void clearStorySession() {
com.newsblur.util.Log.i(this, "reading session reset");
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.READING_SESSION_TABLE, null, null);}
}

View file

@ -44,7 +44,9 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
public final static int VIEW_TYPE_STORY = 1;
public final static int VIEW_TYPE_FOOTER = 2;
private final static float defaultTextSize_story_item_feedtitle = 13f;
private final static float defaultTextSize_story_item_title = 14f;
private final static float defaultTextSize_story_item_date = 12f;
private final static float READ_STORY_ALPHA = 0.4f;
private final static int READ_STORY_ALPHA_B255 = (int) (255f * READ_STORY_ALPHA);
@ -84,6 +86,10 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
setHasStableIds(true);
}
public void updateFeedSet(FeedSet fs) {
this.fs = fs;
}
public synchronized void addFooterView(View v) {
footerViews.add(v);
}
@ -93,7 +99,7 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
return (getStoryCount() + footerViews.size());
}
private int getStoryCount() {
public int getStoryCount() {
if (showNone || (cursor == null)) {
return 0;
} else {
@ -145,12 +151,30 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
this.textSize = textSize;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType == VIEW_TYPE_STORY) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_story_tile, viewGroup, false);
return new StoryViewHolder(v);
} else {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_footer_tile, viewGroup, false);
return new FooterViewHolder(v);
}
}
public class StoryViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener {
@Bind(R.id.story_item_favicon_borderbar_1) View leftBarOne;
@Bind(R.id.story_item_favicon_borderbar_2) View leftBarTwo;
@Bind(R.id.story_item_inteldot) ImageView intelDot;
@Bind(R.id.story_item_thumbnail) ImageView thumbView;
@Bind(R.id.story_item_feedicon) ImageView feedIconView;
@Bind(R.id.story_item_feedtitle) TextView feedTitleView;
@Bind(R.id.story_item_title) TextView storyTitleView;
@Bind(R.id.story_item_date) TextView storyDate;
@Bind(R.id.story_item_saved_icon) View savedView;
@Bind(R.id.story_item_shared_icon) View sharedView;
Story story;
ImageLoader.PhotoToLoad thumbLoader;
@ -170,7 +194,6 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
com.newsblur.util.Log.d(this, "INFLATE: " + story.storyHash);
MenuInflater inflater = new MenuInflater(context);
UIUtils.inflateStoryContextMenu(menu, inflater, context, fs, story);
for (int i=0; i<menu.size(); i++) {
@ -185,27 +208,6 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
}
}
public class FooterViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.footer_view_inner) FrameLayout innerView;
public FooterViewHolder(View view) {
super(view);
ButterKnife.bind(FooterViewHolder.this, view);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType == VIEW_TYPE_STORY) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_story_tile, viewGroup, false);
return new StoryViewHolder(v);
} else {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_footer_tile, viewGroup, false);
return new FooterViewHolder(v);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof StoryViewHolder) {
@ -216,46 +218,60 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
Story story = Story.fromCursor(cursor);
vh.story = story;
//com.newsblur.util.Log.d(this, "BINDING: " + story.storyHash);
// when first created, tiles' views tend to not yet have their dimensions calculated, but
// upon being recycled they will often have a known size, which lets us give a max size to
// the image loader, which in turn can massively optimise loading. the image loader will
// reject nonsene values
int thumbSizeGuess = vh.thumbView.getMeasuredHeight();
// there is a not-unlikely chance that the recycler will re-use a tile for a story with the
// same thumbnail. only load it if it is different.
if (!TextUtils.equals(story.thumbnailUrl, vh.lastThumbUrl)) {
vh.lastThumbUrl = story.thumbnailUrl;
// the view will display a stale, recycled thumb before the new one loads if the old is not cleared
vh.thumbView.setImageDrawable(null);
vh.lastThumbUrl = story.thumbnailUrl;
vh.thumbLoader = FeedUtils.thumbnailLoader.displayImage(story.thumbnailUrl, vh.thumbView, 0, true, thumbSizeGuess);
}
vh.thumbLoader = FeedUtils.thumbnailLoader.displayImage(story.thumbnailUrl, vh.thumbView, 0, true, thumbSizeGuess);
String feedColor = cursor.getString(cursor.getColumnIndex(DatabaseConstants.FEED_FAVICON_COLOR));
String feedFade = cursor.getString(cursor.getColumnIndex(DatabaseConstants.FEED_FAVICON_FADE));
vh.leftBarOne.setBackgroundColor(UIUtils.decodeColourValue(feedColor, Color.GRAY));
vh.leftBarTwo.setBackgroundColor(UIUtils.decodeColourValue(feedFade, Color.LTGRAY));
if (! ignoreIntel) {
int score = cursor.getInt(cursor.getColumnIndex(DatabaseConstants.STORY_INTELLIGENCE_TOTAL));
if (score > 0) {
vh.intelDot.setImageResource(R.drawable.g_icn_focus);
} else if (score == 0) {
vh.intelDot.setImageResource(R.drawable.g_icn_unread);
} else {
vh.intelDot.setImageResource(R.drawable.g_icn_hidden);
}
} else {
vh.intelDot.setImageResource(android.R.color.transparent);
}
vh.storyTitleView.setText(UIUtils.fromHtml(story.title));
vh.storyDate.setText(StoryUtils.formatShortDate(context, new Date(story.timestamp)));
// lists with mixed feeds get added info, but single feeds do not
if (!singleFeed) {
String faviconUrl = cursor.getString(cursor.getColumnIndex(DatabaseConstants.FEED_FAVICON_URL));
FeedUtils.iconLoader.displayImage(faviconUrl, vh.feedIconView, 0, false);
vh.feedTitleView.setText(cursor.getString(cursor.getColumnIndex(DatabaseConstants.FEED_TITLE)));
vh.feedIconView.setVisibility(View.VISIBLE);
vh.feedTitleView.setVisibility(View.VISIBLE);
} else {
vh.feedIconView.setVisibility(View.GONE);
vh.feedTitleView.setVisibility(View.GONE);
}
// dynamic text sizing
vh.storyTitleView.setTextSize(textSize * defaultTextSize_story_item_title);
// read/unread fading
if (this.ignoreReadStatus || (! story.read)) {
vh.thumbView.setImageAlpha(255);
vh.feedIconView.setImageAlpha(255);
vh.storyTitleView.setAlpha(1.0f);
vh.storyTitleView.setTypeface(null, Typeface.BOLD);
if (vh.story.starred) {
vh.savedView.setVisibility(View.VISIBLE);
} else {
vh.thumbView.setImageAlpha(READ_STORY_ALPHA_B255);
vh.feedIconView.setImageAlpha(READ_STORY_ALPHA_B255);
vh.storyTitleView.setAlpha(READ_STORY_ALPHA);
vh.storyTitleView.setTypeface(null, Typeface.NORMAL);
vh.savedView.setVisibility(View.GONE);
}
/*
boolean shared = false;
findshareloop: for (String userId : story.sharedUserIds) {
if (TextUtils.equals(userId, user.id)) {
@ -263,7 +279,38 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
break findshareloop;
}
}
*/
if (shared) {
vh.sharedView.setVisibility(View.VISIBLE);
} else {
vh.sharedView.setVisibility(View.GONE);
}
// dynamic text sizing
vh.feedTitleView.setTextSize(textSize * defaultTextSize_story_item_feedtitle);
vh.storyTitleView.setTextSize(textSize * defaultTextSize_story_item_title);
vh.storyDate.setTextSize(textSize * defaultTextSize_story_item_date);
// read/unread fading
if (this.ignoreReadStatus || (! story.read)) {
vh.leftBarOne.getBackground().setAlpha(255);
vh.leftBarTwo.getBackground().setAlpha(255);
vh.intelDot.setImageAlpha(255);
vh.thumbView.setImageAlpha(255);
vh.feedIconView.setImageAlpha(255);
vh.feedTitleView.setAlpha(1.0f);
vh.storyTitleView.setAlpha(1.0f);
vh.storyDate.setAlpha(1.0f);
} else {
vh.leftBarOne.getBackground().setAlpha(READ_STORY_ALPHA_B255);
vh.leftBarTwo.getBackground().setAlpha(READ_STORY_ALPHA_B255);
vh.intelDot.setImageAlpha(READ_STORY_ALPHA_B255);
vh.thumbView.setImageAlpha(READ_STORY_ALPHA_B255);
vh.feedIconView.setImageAlpha(READ_STORY_ALPHA_B255);
vh.feedTitleView.setAlpha(READ_STORY_ALPHA);
vh.storyTitleView.setAlpha(READ_STORY_ALPHA);
vh.storyDate.setAlpha(READ_STORY_ALPHA);
}
} else {
FooterViewHolder vh = (FooterViewHolder) viewHolder;
vh.innerView.removeAllViews();
@ -275,6 +322,16 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
}
public class FooterViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.footer_view_inner) FrameLayout innerView;
public FooterViewHolder(View view) {
super(view);
ButterKnife.bind(FooterViewHolder.this, view);
}
}
@Override
public void onViewRecycled(RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof StoryViewHolder) {

View file

@ -167,7 +167,7 @@ public class ItemGridFragment extends ItemSetFragment {
} else {
topProgressView.setVisibility(View.INVISIBLE);
bottomProgressView.setVisibility(View.INVISIBLE);
if (cursorSeenYet && NBSyncService.isFeedSetExhausted(getFeedSet())) {
if (cursorSeenYet && NBSyncService.isFeedSetExhausted(getFeedSet()) && (adapter.getStoryCount() > 0)) {
fleuronFooter.setVisibility(View.VISIBLE);
}
}
@ -210,11 +210,11 @@ public class ItemGridFragment extends ItemSetFragment {
int totalCount = layoutManager.getItemCount();
int visibleCount = layoutManager.getChildCount();
int lastVisible = layoutManager.findLastVisibleItemPosition();
//com.newsblur.util.Log.d(this, String.format("SCROLL total:%d bound:%d last%d", totalCount, visibleCount, lastVisible));
// load an extra page or two worth of stories past the viewport
int desiredStoryCount = lastVisible + (visibleCount*2) + 1;
// load an extra page worth of stories past the viewport plus at least two rows to prime the height calc
int desiredStoryCount = lastVisible + (visibleCount*2) + (GRID_COLUMN_COUNT*2);
triggerRefresh(desiredStoryCount, totalCount);
//com.newsblur.util.Log.d(this, String.format(" total:%d bound:%d last%d desire:%d", totalCount, visibleCount, lastVisible, desiredStoryCount));
// TODO: mark on scroll?
}
@ -233,6 +233,7 @@ public class ItemGridFragment extends ItemSetFragment {
@Override
protected void updateAdapter(Cursor cursor) {
adapter.swapCursor(cursor);
adapter.updateFeedSet(getFeedSet());
adapter.notifyDataSetChanged();
if (cursor.getCount() > 0) {
emptyView.setVisibility(View.INVISIBLE);
@ -245,10 +246,6 @@ public class ItemGridFragment extends ItemSetFragment {
ensureSufficientStories();
}
@Override
protected void resetAdapter() {
}
@Override
protected void setShowNone(boolean showNone) {
adapter.setShowNone(showNone);

View file

@ -247,11 +247,6 @@ public class ItemListFragment extends ItemSetFragment implements OnScrollListene
adapter.swapCursor(cursor);
}
@Override
protected void resetAdapter() {
//if (adapter != null) adapter.notifyDataSetInvalidated();
}
@Override
protected void setShowNone(boolean showNone) {
adapter.setShowNone(showNone);

View file

@ -84,9 +84,8 @@ public abstract class ItemSetFragment extends NbFragment implements LoaderManage
* Indicate that the DB was cleared.
*/
public void resetEmptyState() {
resetAdapter();
setShowNone(true);
cursorSeenYet = false;
FeedUtils.dbHelper.clearStorySession();
}
public abstract void setLoading(boolean isLoading);
@ -162,13 +161,11 @@ public abstract class ItemSetFragment extends NbFragment implements LoaderManage
protected abstract void updateAdapter(Cursor cursor);
protected abstract void resetAdapter();
protected abstract void setShowNone(boolean showNone);
@Override
public void onLoaderReset(Loader<Cursor> loader) {
resetAdapter();
;
}
public abstract void setTextSize(Float size);

View file

@ -118,6 +118,8 @@ public class NBSyncService extends Service {
/** Feed to reset to zero-state, so it is fetched fresh, presumably with new filters. */
private static FeedSet ResetFeed;
private static final Object MUTEX_ResetFeed = new Object();
/** Actions that may need to be double-checked locally due to overlapping API calls. */
private static List<ReadingAction> FollowupActions;
static { FollowupActions = new ArrayList<ReadingAction>(); }
@ -657,21 +659,24 @@ public class NBSyncService extends Service {
FeedSet fs = PendingFeed;
try {
// see if we need to quickly reset fetch state for a feed. we
// do this before the loop to prevent-mid loop state corruption
synchronized (MUTEX_ResetFeed) {
if (ResetFeed != null) {
com.newsblur.util.Log.i(this.getClass().getName(), "Resetting state for feed set: " + ResetFeed);
ExhaustedFeeds.remove(ResetFeed);
FeedStoriesSeen.remove(ResetFeed);
FeedPagesSeen.remove(ResetFeed);
ResetFeed = null;
}
}
if (fs == null) {
return;
}
prepareReadingSession(dbHelper, fs);
// see if we need to quickly reset fetch state for a feed. we
// do this before the loop to prevent-mid loop state corruption
if (ResetFeed != null) {
ExhaustedFeeds.remove(ResetFeed);
FeedStoriesSeen.remove(ResetFeed);
FeedPagesSeen.remove(ResetFeed);
ResetFeed = null;
}
LastFeedSet = fs;
if (ExhaustedFeeds.contains(fs)) {
@ -1040,7 +1045,7 @@ public class NBSyncService extends Service {
PendingFeed = fs;
PendingFeedTarget = desiredStoryCount;
if (AppConstants.VERBOSE_LOG) Log.d(NBSyncService.class.getName(), "callerhas: " + callerSeen + " have:" + alreadySeen + " want:" + desiredStoryCount + " pending:" + alreadyPending);
//if (AppConstants.VERBOSE_LOG) Log.d(NBSyncService.class.getName(), "callerhas: " + callerSeen + " have:" + alreadySeen + " want:" + desiredStoryCount + " pending:" + alreadyPending);
if (!fs.equals(LastFeedSet)) {
return true;
@ -1095,8 +1100,10 @@ public class NBSyncService extends Service {
* Reset the API pagniation state for the given feedset, presumably because the order or filter changed.
*/
public static void resetFetchState(FeedSet fs) {
com.newsblur.util.Log.d(NBSyncService.class.getName(), "requesting feed fetch state reset");
ResetFeed = fs;
synchronized (MUTEX_ResetFeed) {
com.newsblur.util.Log.d(NBSyncService.class.getName(), "requesting feed fetch state reset");
ResetFeed = fs;
}
}
public static void addRecountCandidates(FeedSet fs) {

View file

@ -24,6 +24,7 @@ import android.util.Log;
import android.util.TypedValue;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.ContextMenu;
import android.view.MenuInflater;
@ -528,4 +529,16 @@ public class UIUtils {
}
}
public static int decodeColourValue(String val, int defaultVal) {
int result = defaultVal;
if (val == null) return result;
if (TextUtils.equals(val, "null")) return result;
try {
result = Color.parseColor("#" + val);
} catch (NumberFormatException nfe) {
com.newsblur.util.Log.e(UIUtils.class.getName(), "feed supplied bad color info: " + nfe.getMessage());
}
return result;
}
}

View file

@ -1,29 +1,45 @@
package com.newsblur.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import com.newsblur.R;
import com.newsblur.util.UIUtils;
public class SquaredRelativeLayout extends RelativeLayout {
private int addedHeightPx;
public SquaredRelativeLayout(Context context) {
super(context);
addedHeightPx = 0;
}
public SquaredRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
bindAttrs(context, attrs);
}
public SquaredRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
bindAttrs(context, attrs);
}
private void bindAttrs(Context context, AttributeSet attrs) {
TypedArray styledAttributes = context.obtainStyledAttributes(attrs, R.styleable.SquaredRelativeLayout);
int addedHeightAttributeDp = styledAttributes.getInt(R.styleable.SquaredRelativeLayout_addedHeight, 0);
addedHeightPx = UIUtils.dp2px(context, addedHeightAttributeDp);
styledAttributes.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (heightMeasureSpec > widthMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
super.onMeasure(widthMeasureSpec, widthMeasureSpec + addedHeightPx);
} else {
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
super.onMeasure(heightMeasureSpec, heightMeasureSpec + addedHeightPx);
}
}
}