basic configurable story title gestures (#496)

This commit is contained in:
dosiecki 2016-11-03 08:10:17 -07:00
parent 8abd460d18
commit 0063742689
6 changed files with 159 additions and 18 deletions

View file

@ -258,6 +258,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>
@ -300,4 +302,33 @@
<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-array name="ltr_gesture_action_entries">
<item>@string/gest_action_none</item>
<item>@string/gest_action_markread</item>
<item>@string/gest_action_markunread</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>
</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>
</string-array>
<string-array name="rtl_gesture_action_values">
<item>GEST_ACTION_NONE</item>
<item>GEST_ACTION_MARKREAD</item>
<item>GEST_ACTION_MARKUNREAD</item>
</string-array>
<string name="rtl_gesture_action_value">GEST_ACTION_MARKUNREAD</string>
</resources>

View file

@ -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

@ -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,6 +65,13 @@ 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);
@ -109,7 +117,7 @@ public abstract class ItemListFragment extends NbFragment implements OnScrollLis
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);
@ -280,6 +288,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);
@ -353,6 +365,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;
@ -364,36 +384,86 @@ 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_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

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

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

@ -599,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()));
}
}