Merge remote-tracking branch 'upstream/master' into mute

This commit is contained in:
Mark Anderson 2016-11-03 22:53:31 +00:00
commit 5de3e8c2b4
39 changed files with 326 additions and 167 deletions

View file

@ -1493,6 +1493,7 @@ class Feed(models.Model):
stories_db = MStory.objects(story_hash__in=story_ids)
stories = cls.format_stories(stories_db)
for story in stories:
story['story_permalink'] = story['story_permalink'][:250]
if story['story_authors'] not in feed['authors']:
feed['authors'][story['story_authors']] = {
'name': story['story_authors'],
@ -1571,8 +1572,8 @@ class Feed(models.Model):
worksheet.write(0, col, 'Feed', bold)
worksheet.write(0, col+1, 'Feed URL', bold)
worksheet.write(0, col+2, '# Subs', bold)
worksheet.write(0, col+3, 'Reach score', bold)
worksheet.write(0, col+4, '# Readers', bold)
worksheet.write(0, col+3, 'Reach score', bold)
worksheet.write(0, col+5, 'Read %', bold)
worksheet.write(0, col+6, '# stories 30d', bold)
worksheet.write(0, col+7, 'Author', bold)
@ -1601,8 +1602,8 @@ class Feed(models.Model):
worksheet.write(row, col+0, feed['feed_title'])
worksheet.write_url(row, col+1, feed['feed_url'])
worksheet.write(row, col+2, feed['num_subscribers'])
worksheet.write(row, col+3, feed['reach_score'])
worksheet.write(row, col+4, feed['reader_count'])
worksheet.write(row, col+3, feed['reach_score'])
worksheet.write(row, col+5, feed['read_pct'])
worksheet.write(row, col+6, feed['story_count'])
worksheet.conditional_format(row, col+3, row, col+6, {'type': 'cell',

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<gradient
android:angle= "270"
android:type= "linear"
android:startColor="@color/dark_feed_background_start"
android:endColor= "@color/dark_feed_background_end" />
</shape>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@color/feed_background" />
</shape>
<solid android:color="@color/gray96" />
</shape>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<gradient
android:angle= "270"
android:type= "linear"
android:startColor="@color/feed_background_start"
android:endColor= "@color/feed_background_end" />
</shape>

View file

@ -44,7 +44,6 @@
android:id="@+id/itemlistfragment_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="?divider"
android:dividerHeight="1dp" />
android:divider="@null" />
</RelativeLayout>

View file

@ -17,8 +17,7 @@
android:layout_width="match_parent"
android:minHeight="6dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
style="?rowItemFeedHeader">
android:paddingBottom="4dp" >
<ImageView
android:id="@+id/reading_feed_icon"

View file

@ -42,12 +42,10 @@
android:gravity="center"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:paddingTop="1dp"
android:paddingBottom="2dp"
android:shadowColor="@color/neutral_drop_shadow"
android:shadowDy="1"
android:shadowRadius="1"
android:textColor="@color/white"
style="?feedRowNeutCountText"
android:textSize="14sp"
android:textStyle="bold" />
@ -84,13 +82,13 @@
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentTop="true"
style="?folderBorderTop" />
style="?rowBorderTop" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
style="?folderBorderBottom" />
style="?rowBorderBottom" />
</RelativeLayout>

View file

@ -28,13 +28,13 @@
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentTop="true"
style="?folderBorderTop" />
style="?rowBorderTop" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
style="?folderBorderBottom" />
style="?rowBorderBottom" />
</RelativeLayout>

View file

@ -87,14 +87,14 @@
android:ellipsize="end" />
<View
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_width="match_parent"
style="?folderBorderTop"
style="?rowBorderTop"
android:layout_alignParentTop="true" />
<View
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_width="match_parent"
style="?folderBorderBottom"
style="?rowBorderBottom"
android:layout_alignParentBottom="true" />
</RelativeLayout>

View file

@ -28,13 +28,13 @@
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentTop="true"
style="?folderBorderTop" />
style="?rowBorderTop" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
style="?folderBorderBottom" />
style="?rowBorderBottom" />
</RelativeLayout>

View file

@ -28,13 +28,13 @@
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentTop="true"
style="?folderBorderTop" />
style="?rowBorderTop" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
style="?folderBorderBottom" />
style="?rowBorderBottom" />
</RelativeLayout>

View file

@ -58,13 +58,13 @@
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentTop="true"
style="?folderBorderTop" />
style="?rowBorderTop" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
style="?folderBorderBottom" />
style="?rowBorderBottom" />
</RelativeLayout>

View file

@ -125,6 +125,17 @@
android:singleLine="true"
android:textColor="@color/story_author_text" />
<View
android:layout_height="0.5dp"
android:layout_width="match_parent"
style="?rowBorderTop"
android:layout_alignParentTop="true" />
<View
android:layout_height="0.5dp"
android:layout_width="match_parent"
style="?rowBorderBottom"
android:layout_alignParentBottom="true" />
</RelativeLayout>
</LinearLayout>

View file

@ -16,7 +16,6 @@
<attr name="storyFeedTitleText" format="string" />
<attr name="selectorStoryBackground" format="string" />
<attr name="rowItemHeaderBackground" format="string" />
<attr name="rowItemFeedHeader" format="string" />
<attr name="readingItemMetadata" format="string" />
<attr name="tag" format="string" />
<attr name="actionButtons" format="string" />
@ -24,8 +23,8 @@
<attr name="shareBarBackground" format="string" />
<attr name="shareBarText" format="string" />
<attr name="commentsHeader" format="string" />
<attr name="folderBorderTop" format="string" />
<attr name="folderBorderBottom" format="string" />
<attr name="rowBorderTop" format="string" />
<attr name="rowBorderBottom" format="string" />
<attr name="divider" format="string" />
<attr name="profileCount" format="string" />
<attr name="profileActivityList" format="string" />

View file

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="white">#FFF</color>
<color name="black">#000000</color>
<color name="gray07">#121212</color>
<color name="gray10">#1A1A1A</color>
<color name="gray13">#212121</color>
<color name="gray20">#333333</color>
<color name="gray30">#4D4D4D</color>
@ -11,10 +13,13 @@
<color name="gray75">#BFBFBF</color>
<color name="gray80">#CCCCCC</color>
<color name="gray90">#E6E6E6</color>
<color name="black">#000000</color>
<color name="gray96">#F4F4F4</color>
<color name="white">#FFF</color>
<color name="transparent">#00000000</color>
<color name="bar_background">@color/gray90</color>
<color name="nb_green_gray91">#E4E7E1</color>
<color name="bar_background">@color/nb_green_gray91</color>
<color name="dark_bar_background">@color/gray13</color>
<color name="text">@color/gray20</color>
@ -29,28 +34,23 @@
<color name="folder_background_end">#E9EBE4</color>
<color name="folder_background_start">#DDE0D7</color>
<color name="dark_folder_background_end">#1A1A1A</color>
<color name="dark_folder_background_start">#212121</color>
<color name="dark_folder_background_end">@color/gray07</color>
<color name="dark_folder_background_start">@color/gray13</color>
<color name="folder_background_selected_end">#D9DBD4</color>
<color name="folder_background_selected_start">#CDD0C7</color>
<color name="dark_folder_background_selected_end">#4C4C4C</color>
<color name="dark_folder_background_selected_start">#1A1A1A</color>
<color name="folder_border_top">#FDFDFD</color>
<color name="folder_border_bottom">#B7BBAA</color>
<color name="dark_folder_border_top">#434343</color>
<color name="dark_folder_border_bottom">#3B3B3B</color>
<color name="feed_background">#F7F8F5</color>
<color name="feed_background_end">#303030</color>
<color name="feed_background_start">#505050</color>
<color name="dark_feed_background_end">#303030</color>
<color name="dark_feed_background_start">#505050</color>
<color name="row_border_top">@color/white</color>
<color name="row_border_bottom">@color/gray80</color>
<color name="dark_row_border_top">@color/gray20</color>
<color name="dark_row_border_bottom">@color/gray13</color>
<color name="feed_background_selected_end">#FFFFD2</color>
<color name="feed_background_selected_start">#E3D0AE</color>
<color name="dark_feed_background_selected_end">#4C4C4C</color>
<color name="dark_feed_background_selected_start">#1A1A1A</color>
<color name="story_background">#F4F4F4</color>
<color name="story_background">@color/gray96</color>
<color name="story_background_selected">#FFFDEF</color>
<color name="dark_story_background">#1A1A1A</color>
<color name="dark_story_background">@color/gray07</color>
<color name="dark_story_background_selected">#4C4C4C</color>
<color name="story_feed_title_text">#606060</color>

View file

@ -263,6 +263,8 @@
</string-array>
<string name="default_theme_value">light</string>
<string name="settings_gestures">Gestures</string>
<string name="sync_status_housekeeping">Tidying up...</string>
<string name="sync_status_actions">Catching up %d reading actions...</string>
<string name="sync_status_recounts">Catching up reading actions...</string>
@ -305,4 +307,43 @@
<item>NONE</item>
</string-array>
<string name="confirm_mark_all_read_value">FOLDER_ONLY</string>
<string name="settings_ltr_gesture_action">Rightward Swipe on Story Title</string>
<string name="gest_action_none">No Action</string>
<string name="gest_action_markread">Mark Story Read</string>
<string name="gest_action_markunread">Mark Story Unread</string>
<string name="gest_action_save">Save Story</string>
<string name="gest_action_unsave">Unsave Story</string>
<string-array name="ltr_gesture_action_entries">
<item>@string/gest_action_none</item>
<item>@string/gest_action_markread</item>
<item>@string/gest_action_markunread</item>
<item>@string/gest_action_save</item>
<item>@string/gest_action_unsave</item>
</string-array>
<string-array name="ltr_gesture_action_values">
<item>GEST_ACTION_NONE</item>
<item>GEST_ACTION_MARKREAD</item>
<item>GEST_ACTION_MARKUNREAD</item>
<item>GEST_ACTION_SAVE</item>
<item>GEST_ACTION_UNSAVE</item>
</string-array>
<string name="ltr_gesture_action_value">GEST_ACTION_MARKREAD</string>
<string name="settings_rtl_gesture_action">Leftward Swipe on Story Title</string>
<string-array name="rtl_gesture_action_entries">
<item>@string/gest_action_none</item>
<item>@string/gest_action_markread</item>
<item>@string/gest_action_markunread</item>
<item>@string/gest_action_save</item>
<item>@string/gest_action_unsave</item>
</string-array>
<string-array name="rtl_gesture_action_values">
<item>GEST_ACTION_NONE</item>
<item>GEST_ACTION_MARKREAD</item>
<item>GEST_ACTION_MARKUNREAD</item>
<item>GEST_ACTION_SAVE</item>
<item>GEST_ACTION_UNSAVE</item>
</string-array>
<string name="rtl_gesture_action_value">GEST_ACTION_MARKUNREAD</string>
</resources>

View file

@ -137,13 +137,6 @@
<item name="android:background">@drawable/dark_row_item_header_background</item>
</style>
<style name="rowItemFeedHeader">
<item name="android:background">@drawable/row_item_feed_header</item>
</style>
<style name="rowItemFeedHeader.dark">
<item name="android:background">@drawable/dark_row_item_feed_header</item>
</style>
<style name="readingItemMetadata">
<item name="android:textColor">@color/half_darkgray</item>
</style>
@ -227,25 +220,18 @@
<item name="android:textColor">@color/dark_text</item>
</style>
<style name="folderBorderTop">
<item name="android:background">@color/folder_border_top</item>
<style name="rowBorderTop">
<item name="android:background">@color/row_border_top</item>
</style>
<style name="folderBorderTop.dark">
<item name="android:background">@color/dark_folder_border_top</item>
<style name="rowBorderTop.dark">
<item name="android:background">@color/dark_row_border_top</item>
</style>
<style name="folderBorderBottom">
<item name="android:background">@color/folder_border_bottom</item>
<style name="rowBorderBottom">
<item name="android:background">@color/row_border_bottom</item>
</style>
<style name="folderBorderBottom.dark">
<item name="android:background">@color/dark_folder_border_bottom</item>
</style>
<style name="divider">
<item name="android:divider">@drawable/divider_light</item>
</style>
<style name="divider.dark">
<item name="android:divider">@drawable/divider_dark</item>
<style name="rowBorderBottom.dark">
<item name="android:background">@color/dark_row_border_bottom</item>
</style>
<style name="profileCount">

View file

@ -17,7 +17,6 @@
<item name="storyFeedTitleText">@style/storyFeedTitleText</item>
<item name="selectorStoryBackground">@style/selectorStoryBackground</item>
<item name="rowItemHeaderBackground">@style/rowItemHeaderBackground</item>
<item name="rowItemFeedHeader">@style/rowItemFeedHeader</item>
<item name="readingItemMetadata">@style/readingItemMetadata</item>
<item name="tag">@style/tag</item>
<item name="actionButtons">@style/actionButtons</item>
@ -25,9 +24,8 @@
<item name="shareBarBackground">@style/shareBarBackground</item>
<item name="shareBarText">@style/shareBarText</item>
<item name="commentsHeader">@style/commentsHeader</item>
<item name="folderBorderTop">@style/folderBorderTop</item>
<item name="folderBorderBottom">@style/folderBorderBottom</item>
<item name="divider">@style/divider</item>
<item name="rowBorderTop">@style/rowBorderTop</item>
<item name="rowBorderBottom">@style/rowBorderBottom</item>
<item name="profileCount">@style/profileCount</item>
<item name="profileActivityList">@style/profileActivityList</item>
<item name="itemHeaderDivider">@style/itemHeaderDivider</item>
@ -60,7 +58,6 @@
<item name="storyFeedTitleText">@style/storyFeedTitleText.dark</item>
<item name="selectorStoryBackground">@style/selectorStoryBackground.dark</item>
<item name="rowItemHeaderBackground">@style/rowItemHeaderBackground.dark</item>
<item name="rowItemFeedHeader">@style/rowItemFeedHeader.dark</item>
<item name="readingItemMetadata">@style/readingItemMetadata.dark</item>
<item name="tag">@style/tag.dark</item>
<item name="actionButtons">@style/actionButtons.dark</item>
@ -68,9 +65,8 @@
<item name="shareBarBackground">@style/shareBarBackground.dark</item>
<item name="shareBarText">@style/shareBarText.dark</item>
<item name="commentsHeader">@style/commentsHeader.dark</item>
<item name="folderBorderTop">@style/folderBorderTop.dark</item>
<item name="folderBorderBottom">@style/folderBorderBottom.dark</item>
<item name="divider">@style/divider.dark</item>
<item name="rowBorderTop">@style/rowBorderTop.dark</item>
<item name="rowBorderBottom">@style/rowBorderBottom.dark</item>
<item name="profileCount">@style/profileCount.dark</item>
<item name="profileActivityList">@style/profileActivityList.dark</item>
<item name="itemHeaderDivider">@style/itemHeaderDivider.dark</item>

View file

@ -61,7 +61,7 @@
android:key="pref_show_content_preview"
android:title="@string/settings_show_content_preview" />
<CheckBoxPreference
android:defaultValue="false"
android:defaultValue="true"
android:key="pref_show_thumbnails"
android:title="@string/settings_show_thumbnails" />
</PreferenceCategory>
@ -103,4 +103,22 @@
android:defaultValue="@string/default_theme_value" />
</PreferenceCategory>
<PreferenceCategory
android:title="@string/settings_gestures">
<ListPreference
android:key="ltr_gesture_action"
android:title="@string/settings_ltr_gesture_action"
android:dialogTitle="@string/settings_ltr_gesture_action"
android:entries="@array/ltr_gesture_action_entries"
android:entryValues="@array/ltr_gesture_action_values"
android:defaultValue="@string/ltr_gesture_action_value" />
<ListPreference
android:key="rtl_gesture_action"
android:title="@string/settings_rtl_gesture_action"
android:dialogTitle="@string/settings_rtl_gesture_action"
android:entries="@array/rtl_gesture_action_entries"
android:entryValues="@array/rtl_gesture_action_values"
android:defaultValue="@string/rtl_gesture_action_value" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -183,7 +183,8 @@ public class StoryItemsAdapter extends SimpleCursorAdapter {
thumbnailView.setVisibility(View.VISIBLE);
FeedUtils.thumbnailLoader.displayImage(story.thumbnailUrl, thumbnailView, 0, true);
} else {
thumbnailView.setVisibility(View.INVISIBLE);
// to GONE rather than INVIS makes start titles misalign on the right side, but this is by design
thumbnailView.setVisibility(View.GONE);
}
} else {
thumbnailView.setVisibility(View.GONE);

View file

@ -37,6 +37,7 @@ import com.newsblur.service.NBSyncService;
import com.newsblur.util.DefaultFeedView;
import com.newsblur.util.FeedSet;
import com.newsblur.util.FeedUtils;
import com.newsblur.util.GestureAction;
import com.newsblur.util.PrefsUtils;
import com.newsblur.util.ReadFilter;
import com.newsblur.util.StoryOrder;
@ -64,11 +65,20 @@ public abstract class ItemListFragment extends NbFragment implements OnScrollLis
private View fleuronFooter;
// row index of the last story to get a LTR gesture or -1 if none
private int gestureLeftToRightFlag = -1;
// row index of the last story to get a RTL gesture or -1 if none
private int gestureRightToLeftFlag = -1;
// flag indicating a gesture just occurred so we can ignore spurious story taps right after
private boolean gestureDebounce = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
defaultFeedView = (DefaultFeedView)getArguments().getSerializable("defaultFeedView");
activity = (ItemsList) getActivity();
// tell the sync service to discard the reading session at the start of the next sync, just in case
NBSyncService.resetReadingSession();
}
@Override
@ -92,7 +102,6 @@ public abstract class ItemListFragment extends NbFragment implements OnScrollLis
UIUtils.getColor(getActivity(), R.color.refresh_3),
UIUtils.getColor(getActivity(), R.color.refresh_4));
itemList.addHeaderView(headerView, null, false);
itemList.setHeaderDividersEnabled(false);
View footerView = inflater.inflate(R.layout.row_loading_throbber, null);
footerProgressView = (ProgressThrobber) footerView.findViewById(R.id.itemlist_loading_throb);
@ -102,14 +111,13 @@ public abstract class ItemListFragment extends NbFragment implements OnScrollLis
UIUtils.getColor(getActivity(), R.color.refresh_3),
UIUtils.getColor(getActivity(), R.color.refresh_4));
itemList.addFooterView(footerView, null, false);
itemList.setFooterDividersEnabled(false);
fleuronFooter = inflater.inflate(R.layout.row_fleuron, null);
fleuronFooter.setVisibility(View.GONE);
itemList.addFooterView(fleuronFooter, null, false);
itemList.setEmptyView(v.findViewById(R.id.empty_view));
setupBezelSwipeDetector(itemList);
setupGestureDetector(itemList);
itemList.setOnScrollListener(this);
itemList.setOnItemClickListener(this);
itemList.setOnCreateContextMenuListener(this);
@ -294,6 +302,10 @@ public abstract class ItemListFragment extends NbFragment implements OnScrollLis
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
// context menu like to get accidentally triggered by the ListView event handler right after
// we detect a gesure. if so, let the gesture happen rather than popping up the menu
if ((gestureLeftToRightFlag > -1) || (gestureRightToLeftFlag > -1)) return;
MenuInflater inflater = getActivity().getMenuInflater();
if (PrefsUtils.getStoryOrder(activity, getFeedSet()) == StoryOrder.NEWEST) {
inflater.inflate(R.menu.context_story_newest, menu);
@ -367,6 +379,14 @@ public abstract class ItemListFragment extends NbFragment implements OnScrollLis
@Override
public synchronized void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// clicks like to get accidentally triggered by the ListView event handler right after we detect
// a gesture. if so, let the gesture happen rather than popping up the menu
if (gestureDebounce){
gestureDebounce = false;
return;
}
if ((gestureLeftToRightFlag > -1) || (gestureRightToLeftFlag > -1)) return;
int truePosition = position - 1;
Story story = adapter.getStory(truePosition);
if (getActivity().isFinishing()) return;
@ -378,36 +398,92 @@ public abstract class ItemListFragment extends NbFragment implements OnScrollLis
adapter.setTextSize(size);
adapter.notifyDataSetChanged();
}
}
protected void setupBezelSwipeDetector(View v) {
final GestureDetector gestureDetector = new GestureDetector(getActivity(), new BezelSwipeDetector());
protected void setupGestureDetector(View v) {
final GestureDetector gestureDetector = new GestureDetector(getActivity(), new ItemListGestureDetector());
v.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
boolean result = gestureDetector.onTouchEvent(event);
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
ItemListFragment.this.flushGesture();
}
return result;
}
});
}
/**
* A gesture detector that captures bezel swipes and finishes the activity,
* to simulate a 'back' gesture.
*
* NB: pretty much all Views still try to process on-tap events despite
* returning true, so be sure to check isFinishing() on all other
* tap handlers.
*/
class BezelSwipeDetector extends GestureDetector.SimpleOnGestureListener {
protected void gestureLeftToRight(float x, float y) {
int index = itemList.pointToPosition((int) x, (int) y);
gestureLeftToRightFlag = index;
}
protected void gestureRightToLeft(float x, float y) {
int index = itemList.pointToPosition((int) x, (int) y);
gestureRightToLeftFlag = index;
}
// the above gesture* methods will trigger more than once while being performed. it is not until
// the up-event that we look to see if any happened, and if so, take action and flush.
protected void flushGesture() {
int index = -1;
GestureAction action = GestureAction.GEST_ACTION_NONE;
if (gestureLeftToRightFlag > -1) {
index = gestureLeftToRightFlag;
action = PrefsUtils.getLeftToRightGestureAction(getActivity());
gestureLeftToRightFlag = -1;
gestureDebounce = true;
}
if (gestureRightToLeftFlag > -1) {
index = gestureRightToLeftFlag;
action = PrefsUtils.getRightToLeftGestureAction(getActivity());
gestureRightToLeftFlag = -1;
gestureDebounce = true;
}
if (index <= -1) return;
Story story = adapter.getStory(index-1);
switch (action) {
case GEST_ACTION_MARKREAD:
FeedUtils.markStoryAsRead(story, getActivity());;
break;
case GEST_ACTION_MARKUNREAD:
FeedUtils.markStoryUnread(story, getActivity());;
break;
case GEST_ACTION_SAVE:
FeedUtils.setStorySaved(story, true, getActivity());;
break;
case GEST_ACTION_UNSAVE:
FeedUtils.setStorySaved(story, false, getActivity());;
break;
case GEST_ACTION_NONE:
default:
}
}
class ItemListGestureDetector extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if((e1.getX() < 75f) && // the gesture should start from the left bezel and
((e2.getX()-e1.getX()) > 90f) && // move horizontally to the right and
(Math.abs(e1.getY()-e2.getY()) < 40f) // have minimal vertical travel, so we don't capture scrolling gestures
) {
if ((e1.getX() < 75f) && // the gesture should start from the left bezel and
((e2.getX()-e1.getX()) > 90f) && // move horizontally to the right and
(Math.abs(e1.getY()-e2.getY()) < 40f) // have minimal vertical travel, so we don't capture scrolling gestures
) {
ItemListFragment.this.getActivity().finish();
return true;
}
if ((e1.getX() > 75f) && // the gesture should not start from the left bezel and
((e2.getX()-e1.getX()) > 120f) && // move horizontally to the right and
(Math.abs(e1.getY()-e2.getY()) < 40f) // have minimal vertical travel, so we don't capture scrolling gestures
) {
ItemListFragment.this.gestureLeftToRight(e1.getX(), e1.getY());
return true;
}
if ((e1.getX() > 75f) && // the gesture should not start from the left bezel and
((e1.getX()-e2.getX()) > 120f) && // move horizontally to the left and
(Math.abs(e1.getY()-e2.getY()) < 40f) // have minimal vertical travel, so we don't capture scrolling gestures
) {
ItemListFragment.this.gestureRightToLeft(e1.getX(), e1.getY());
return true;
}
return false;
}
}

View file

@ -244,14 +244,14 @@ public class NBSyncService extends Service {
syncMetadata(startId);
checkRecounts();
unreadsService.start(startId);
imagePrefetchService.start(startId);
finishActions();
checkRecounts();
if (AppConstants.VERBOSE_LOG) Log.d(this.getClass().getName(), "finishing primary sync");
} catch (Exception e) {
@ -637,17 +637,21 @@ public class NBSyncService extends Service {
StoryOrder order = PrefsUtils.getStoryOrder(this, fs);
ReadFilter filter = PrefsUtils.getReadFilter(this, fs);
boolean doReset = false;
synchronized (PENDING_FEED_MUTEX) {
if (ResetSession) {
// the next fetch will be the start of a new reading session; clear it so it
// will be re-primed
dbHelper.clearStorySession();
// don't just rely on the auto-prepare code when fetching stories, it might be called
// after we insert our first page and not trigger
dbHelper.prepareReadingSession(fs);
doReset = true;
ResetSession = false;
}
}
if (doReset) {
// the next fetch will be the start of a new reading session; clear it so it
// will be re-primed
dbHelper.clearStorySession();
// don't just rely on the auto-prepare code when fetching stories, it might be called
// after we insert our first page and not trigger
dbHelper.prepareReadingSession(fs);
}
while (totalStoriesSeen < PendingFeedTarget) {
if (stopSync()) return;

View file

@ -158,9 +158,6 @@ public class FeedUtils {
}
public static void markFeedsRead(final FeedSet fs, final Long olderThan, final Long newerThan, final Context context) {
dbHelper.markStoriesRead(fs, olderThan, newerThan);
dbHelper.updateLocalFeedCounts(fs);
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA | NbActivity.UPDATE_STORY);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... arg) {
@ -186,8 +183,10 @@ public class FeedUtils {
if (ra != null) {
dbHelper.enqueueAction(ra);
ra.doLocal(dbHelper);
}
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA | NbActivity.UPDATE_STORY);
triggerSync(context);
return null;
}

View file

@ -0,0 +1,11 @@
package com.newsblur.util;
public enum GestureAction {
GEST_ACTION_NONE,
GEST_ACTION_MARKREAD,
GEST_ACTION_MARKUNREAD,
GEST_ACTION_SAVE,
GEST_ACTION_UNSAVE;
}

View file

@ -15,7 +15,7 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Process;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import com.newsblur.R;
@ -28,25 +28,27 @@ public class ImageLoader {
private final ExecutorService executorService;
private final int emptyRID;
private final int minImgHeight;
private final boolean hideMissing;
// some image loads can happen after the imageview in question is already reused for some other image. keep
// track of what image each view wants so that when it comes time to load them, they aren't stale
private final Map<ImageView, String> imageViewMappings = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
private ImageLoader(FileCache fileCache, int emptyRID, int minImgHeight, long memoryCacheSize) {
private ImageLoader(FileCache fileCache, int emptyRID, int minImgHeight, boolean hideMissing, long memoryCacheSize) {
this.memoryCache = new MemoryCache(memoryCacheSize);
this.fileCache = fileCache;
executorService = Executors.newFixedThreadPool(3);
this.emptyRID = emptyRID;
this.minImgHeight = minImgHeight;
this.hideMissing = hideMissing;
}
public static ImageLoader asIconLoader(Context context) {
return new ImageLoader(FileCache.asIconCache(context), R.drawable.world, 2, (Runtime.getRuntime().maxMemory()/20));
return new ImageLoader(FileCache.asIconCache(context), R.drawable.world, 2, false, (Runtime.getRuntime().maxMemory()/20));
}
public static ImageLoader asThumbnailLoader(Context context) {
return new ImageLoader(FileCache.asThumbnailCache(context), android.R.color.transparent, 32, (Runtime.getRuntime().maxMemory()/5));
return new ImageLoader(FileCache.asThumbnailCache(context), android.R.color.transparent, 32, true, (Runtime.getRuntime().maxMemory()/5));
}
public void displayImage(String url, ImageView imageView, float roundRadius, boolean cropSquare) {
@ -108,14 +110,12 @@ public class ImageLoader {
if (bitmap != null) {
memoryCache.put(photoToLoad.url, bitmap);
setViewImage(bitmap, photoToLoad);
}
setViewImage(bitmap, photoToLoad);
}
}
private void setViewImage(Bitmap bitmap, PhotoToLoad photoToLoad) {
if (bitmap == null) return;
if (bitmap.getHeight() < minImgHeight) return;
BitmapDisplayer bitmapDisplayer = new BitmapDisplayer(bitmap, photoToLoad);
Activity a = (Activity) photoToLoad.imageView.getContext();
a.runOnUiThread(bitmapDisplayer);
@ -133,11 +133,16 @@ public class ImageLoader {
// ensure this imageview even still wants this image
String latestMappedUrl = imageViewMappings.get(photoToLoad.imageView);
if (latestMappedUrl == null || !latestMappedUrl.equals(photoToLoad.url)) return;
if (bitmap != null) {
if ((bitmap == null) || (bitmap.getHeight() < minImgHeight)) {
if (hideMissing) {
photoToLoad.imageView.setVisibility(View.GONE);
} else {
photoToLoad.imageView.setImageResource(emptyRID);
}
} else {
bitmap = UIUtils.clipAndRound(bitmap, photoToLoad.roundRadius, photoToLoad.cropSquare);
photoToLoad.imageView.setImageBitmap(bitmap);
} else {
photoToLoad.imageView.setImageResource(emptyRID);
}
}
}

View file

@ -72,4 +72,7 @@ public class PrefConstants {
public static final String VOLUME_KEY_NAVIGATION = "volume_key_navigation";
public static final String MARK_ALL_READ_CONFIRMATION = "pref_confirm_mark_all_read";
public static final String LTR_GESTURE_ACTION = "ltr_gesture_action";
public static final String RTL_GESTURE_ACTION = "rtl_gesture_action";
}

View file

@ -97,6 +97,7 @@ public class PrefsUtils {
}
s.append("%0Aprefetch: ").append(isOfflineEnabled(context) ? "yes" : "no");
s.append("%0Akeepread: ").append(isKeepOldStories(context) ? "yes" : "no");
s.append("%0Athumbs: ").append(isShowThumbnails(context) ? "yes" : "no");
return s.toString();
}
@ -598,4 +599,14 @@ public class PrefsUtils {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
return MarkAllReadConfirmation.valueOf(prefs.getString(PrefConstants.MARK_ALL_READ_CONFIRMATION, MarkAllReadConfirmation.FOLDER_ONLY.toString()));
}
public static GestureAction getLeftToRightGestureAction(Context context) {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
return GestureAction.valueOf(prefs.getString(PrefConstants.LTR_GESTURE_ACTION, GestureAction.GEST_ACTION_MARKREAD.toString()));
}
public static GestureAction getRightToLeftGestureAction(Context context) {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
return GestureAction.valueOf(prefs.getString(PrefConstants.RTL_GESTURE_ACTION, GestureAction.GEST_ACTION_MARKUNREAD.toString()));
}
}

View file

@ -304,6 +304,7 @@ public class ReadingAction {
dbHelper.setStoryReadState(storyHash, true);
} else if (feedSet != null) {
dbHelper.markStoriesRead(feedSet, olderThan, newerThan);
dbHelper.updateLocalFeedCounts(feedSet);
}
impact |= NbActivity.UPDATE_METADATA;
break;

View file

@ -2124,6 +2124,7 @@ heightForHeaderInSection:(NSInteger)section {
self.notifier.title = @"Counting is difficult...";
[self.notifier setProgress:0];
[self.notifier show];
[self finishRefresh];
}
- (void)showSyncingNotifier {
@ -2131,6 +2132,7 @@ heightForHeaderInSection:(NSInteger)section {
self.notifier.title = @"Syncing stories...";
[self.notifier setProgress:0];
[self.notifier show];
[self finishRefresh];
}
- (void)showDoneNotifier {

View file

@ -2176,6 +2176,11 @@ shouldStartLoadWithRequest:(NSURLRequest *)request
}
- (void)changeWebViewWidth {
// Don't do this in the background, to avoid scrolling to the top unnecessarily
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
return;
}
// [webView setNeedsLayout];
// [webView layoutIfNeeded];

View file

@ -368,7 +368,9 @@
// NSLog(@"---> Story page control did re-orient: %@ / %@", NSStringFromCGSize(self.view.bounds.size), NSStringFromCGSize(size));
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
[self refreshPages];
// This causes the story to reload on rotation (or when going to the background), but doesn't seem necessary?
// [self refreshPages];
}];
}

View file

@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>6.1.0</string>
<string>6.1.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@ -58,7 +58,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>67</string>
<string>68</string>
<key>FacebookAppID</key>
<string>230426707030569</string>
<key>ITSAppUsesNonExemptEncryption</key>

View file

@ -2431,12 +2431,12 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0810;
ORGANIZATIONNAME = NewsBlur;
TargetAttributes = {
1D6058900D05DD3D006BFB54 = {
DevelopmentTeam = HR7P97SD72;
ProvisioningStyle = Manual;
ProvisioningStyle = Automatic;
};
};
};
@ -3051,9 +3051,9 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEVELOPMENT_TEAM = HR7P97SD72;
DEVELOPMENT_TEAM = "";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
@ -3081,8 +3081,8 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.newsblur.NewsBlur;
PRODUCT_NAME = NewsBlur;
PROVISIONING_PROFILE = "a33bf1f3-82b0-4761-a144-cb612ef478e9";
PROVISIONING_PROFILE_SPECIFIER = "NewsBlur App Store";
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
STRIP_INSTALLED_PRODUCT = NO;
TARGETED_DEVICE_FAMILY = "1,2";
"WARNING_CFLAGS[arch=*]" = "-Wall";
@ -3096,9 +3096,9 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEVELOPMENT_TEAM = HR7P97SD72;
DEVELOPMENT_TEAM = "";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
@ -3124,8 +3124,8 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.newsblur.NewsBlur;
PRODUCT_NAME = NewsBlur;
PROVISIONING_PROFILE = "a33bf1f3-82b0-4761-a144-cb612ef478e9";
PROVISIONING_PROFILE_SPECIFIER = "NewsBlur App Store";
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};

View file

@ -85,6 +85,6 @@ verbose = true
#source = slave.example.com
# in replica set configuration, specify the name of the replica set
replSet = nbset
# replSet = nbset
journal = true

View file

@ -8,7 +8,7 @@
dbpath=/var/lib/mongodb
#where to log
logpath=/var/log/mongodb/mongodb.log
logpath=/var/log/mongod/mongod.log
logappend=true
@ -18,7 +18,7 @@ slowms=100
syncdelay=5
rest = true
#rest = true
#profile = 2
# Enables periodic logging of CPU utilization and I/O wait
#cpu = true

14
fabfile.py vendored
View file

@ -978,17 +978,21 @@ def copy_postgres_to_standby(master='db01'):
put('config/postgresql_recovery.conf', '/var/lib/postgresql/9.4/main/recovery.conf', use_sudo=True)
def setup_mongo():
MONGODB_VERSION = "2.6.12"
sudo('apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10')
# sudo('echo "deb http://downloads.mongodb.org/distros/ubuntu 10.10 10gen" >> /etc/apt/sources.list.d/10gen.list')
sudo('echo "\ndeb http://downloads-distro.mongodb.org/repo/debian-sysvinit dist 10gen" | sudo tee -a /etc/apt/sources.list')
sudo('echo "deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen" | sudo tee /etc/apt/sources.list.d/mongodb.list')
# sudo('echo "\ndeb http://downloads-distro.mongodb.org/repo/debian-sysvinit dist 10gen" | sudo tee -a /etc/apt/sources.list')
sudo('apt-get update')
sudo('apt-get -y install mongodb-10gen')
sudo('apt-get install -y mongodb-org=%s mongodb-org-server=%s mongodb-org-shell=%s mongodb-org-mongos=%s mongodb-org-tools=%s' %
(MONGODB_VERSION, MONGODB_VERSION, MONGODB_VERSION, MONGODB_VERSION, MONGODB_VERSION))
put('config/mongodb.%s.conf' % ('prod' if env.user != 'ubuntu' else 'ec2'),
'/etc/mongodb.conf', use_sudo=True)
run('echo "ulimit -n 100000" > mongodb.defaults')
sudo('mv mongodb.defaults /etc/default/mongodb')
sudo('/etc/init.d/mongodb restart')
put('config/logrotate.mongo.conf', '/etc/logrotate.d/mongodb', use_sudo=True)
sudo('cp mongodb.defaults /etc/default/mongod')
sudo('/etc/init.d/mongod restart')
put('config/logrotate.mongo.conf', '/etc/logrotate.d/mongod', use_sudo=True)
# Reclaim 5% disk space used for root logs. Set to 1%.
with settings(warn_only=True):

View file

@ -2,7 +2,7 @@
{% load utils_tags %}
{% block body %}
<p style="font-size: 24px; color:#555555; margin-top: 18px;margin-bottom: 10px;padding-top:6px;">Introducing <img src="https://turntouch.com/static/images/logos/TT Logo - 64.png" style="width: 32px; height: 32px; vertical-align: bottom;padding-right: 4px;">Turn Touch</p>
<p style="font-size: 24px; color:#555555; margin-top: 18px;margin-bottom: 10px;padding-top:6px;">Introducing <img src="https://turntouch.com/static/images/logos/turntouch-icon-64.png" style="width: 32px; height: 32px; vertical-align: bottom;padding-right: 4px;">Turn Touch</p>
<img src="https://turntouch.com/static/images/home/home-still-mahogany.jpg" style="width:650px;height:433px;" alt="">
<p style="line-height: 20px;"><a href="https://turntouch.com/kickstarter">Turn Touch</a> is a solid wood remote... for NewsBlur.</p>
<p style="line-height: 20px;">Your favorite RSS news reader just dropped a gorgeous new piece of hardware on the world and it's built just for you. The you that would enjoy a new way of reading the news. </p>

View file

@ -85,7 +85,7 @@
<img src="/media/img/logo_512.png" class="logo">
<h1>NewsBlur is in <span class="error404">maintenance mode</span></h1>
<div class="description">
<p>Moving to a new primary MongoDB database server. This server has been the cause of all the 1 minute downtimes over the past couple days. This should take 5 minutes max.</p>
<p>Moving to a new primary MongoDB database server. This server has been the cause of the slowdowns over the past couple days. This should take 5 minutes max.</p>
<p>To pass the time, <a href="http://mlkshk.com/popular">check out what's popular on MLKSHK</a>.</p>
</div>
</div>

View file

@ -97,7 +97,10 @@ def read_streams(streams):
if not data:
streams.remove(stream)
break
combination_message = "[%-6s] %s" % (stream.name[:6], data)
try:
combination_message = "[%-6s] %s" % (stream.name[:6], data)
except UnicodeDecodeError:
continue
sys.stdout.write(combination_message)
break