diff --git a/app/src/main/assets/changelog b/app/src/main/assets/changelog
index 97baff42..ee1c204c 100644
--- a/app/src/main/assets/changelog
+++ b/app/src/main/assets/changelog
@@ -1,6 +1,7 @@
xx/xx/xxxx 0.60
- Night mode support
+ - Allow marking items as read while scrolling
- Better indication when the anonymous account is used on startup
25/03/2020 0.59
diff --git a/app/src/main/java/com/indieweb/indigenous/Indigenous.java b/app/src/main/java/com/indieweb/indigenous/Indigenous.java
index ff9ef9c2..257b33b7 100644
--- a/app/src/main/java/com/indieweb/indigenous/Indigenous.java
+++ b/app/src/main/java/com/indieweb/indigenous/Indigenous.java
@@ -19,6 +19,8 @@ public class Indigenous extends Application {
public static Contact contactItem;
+ public static boolean refreshChannels;
+
public static Indigenous getInstance(){
return singleton;
}
@@ -33,6 +35,14 @@ public String getDebug() {
return debug;
}
+ public void setRefreshChannels(boolean refresh) {
+ refreshChannels = refresh;
+ }
+
+ public boolean isRefreshChannels() {
+ return refreshChannels;
+ }
+
public void setTimelineItem(TimelineItem item) {
timelineItem = item;
}
diff --git a/app/src/main/java/com/indieweb/indigenous/microsub/channel/ChannelFragment.java b/app/src/main/java/com/indieweb/indigenous/microsub/channel/ChannelFragment.java
index 5478cedf..dd85e843 100644
--- a/app/src/main/java/com/indieweb/indigenous/microsub/channel/ChannelFragment.java
+++ b/app/src/main/java/com/indieweb/indigenous/microsub/channel/ChannelFragment.java
@@ -85,6 +85,15 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
}
}
+ @Override
+ public void onResume() {
+ super.onResume();
+ Indigenous app = Indigenous.getInstance();
+ if (app.isRefreshChannels()) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+
@Override
public void onRefresh() {
setShowRefreshedMessage(true);
diff --git a/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineActivity.java b/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineActivity.java
index e0feb17e..d8cdfdfa 100644
--- a/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineActivity.java
+++ b/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineActivity.java
@@ -12,6 +12,7 @@
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -96,6 +97,7 @@ public class TimelineActivity extends AppCompatActivity implements SwipeRefreshL
public static int MARK_READ_CHANNEL_CLICK = 1;
public static int MARK_READ_MANUAL = 2;
+ public static int MARK_READ_SCROLL = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -156,23 +158,29 @@ else if (isSearch) {
DatabaseHelper db = new DatabaseHelper(TimelineActivity.this);
style = db.getTimelineStyle(channelId);
- // Autoload more posts.
- if (Preferences.getPreference(TimelineActivity.this, "pref_key_timeline_autoload_more", false)) {
+ // Autoload more posts or mark while scrolling.
+ final boolean autoload = Preferences.getPreference(TimelineActivity.this, "pref_key_timeline_autoload_more", false);
+ final boolean markReadScroll = Preferences.getPreference(getApplicationContext(), "pref_key_mark_read", MARK_READ_CHANNEL_CLICK) == MARK_READ_SCROLL && !readLater.equals(channelId);
+ if (autoload || markReadScroll) {
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
- if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE
+ if (autoload && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE
&& (listView.getLastVisiblePosition() - listView.getHeaderViewsCount() -
listView.getFooterViewsCount()) >= (adapter.getCount() - 1)) {
if (!loadMoreClicked && loadMoreButtonAdded) {
loadMoreItems();
}
}
+
+ if (markReadScroll && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
+ markItemsReadWhileScrolling();
+ }
}
@Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { }
});
}
@@ -907,6 +915,50 @@ private void loadMoreItems() {
getTimeLineItems(olderItems[0]);
}
+ /**
+ * Mark items read while scrolling.
+ */
+ private void markItemsReadWhileScrolling() {
+ try {
+ // Determine the position to where we have to check. Switch to the last if the user has
+ // scrolled to the end.
+ int position = listView.getFirstVisiblePosition();
+ //Log.d("indigenous_debug", "First visible: " + position + " - last visible: " + listView.getLastVisiblePosition());
+ if (listView.getLastVisiblePosition() == (adapter.getCount() - 1)) {
+ position = listView.getLastVisiblePosition();
+ //Log.d("indigenous_debug", "Count: " + adapter.getCount() + " - Last position: " + listView.getLastVisiblePosition());
+ }
+ //Log.d("indigenous_debug", "position: " + position);
+
+ int counter = 0;
+ TimelineItem item;
+ int itemPosition = 0;
+ List readEntries = new ArrayList<>();
+ while (itemPosition <= position) {
+ item = adapter.getItem(itemPosition);
+ //Log.d("indigenous_debug", "Position:" + itemPosition + " - " + item.getName());
+ //noinspection ConstantConditions
+ if (item != null && !item.isRead()) {
+ //Log.d("indigenous_debug", "Marking as read: " + item.getName());
+ readEntries.add(item.getId());
+ item.setRead(true);
+ TimelineItems.set(itemPosition, item);
+ counter -= 1;
+ }
+ itemPosition++;
+ }
+
+ if (readEntries.size() > 0) {
+ //Log.d("indigenous_debug", "Counter: " + counter);
+ new MicrosubAction(getApplicationContext(), user, layout).markRead(channelId, readEntries, false, false);
+ Utility.notifyChannels(channelId, counter);
+ }
+ }
+ catch (Exception e) {
+ Log.d("indigenous_debug", "Exception marking read: " + e.getMessage());
+ }
+ }
+
/**
* Returns the reference content.
* @param object
diff --git a/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineDetailActivity.java b/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineDetailActivity.java
index 086d2d90..9bdea157 100644
--- a/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineDetailActivity.java
+++ b/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineDetailActivity.java
@@ -650,11 +650,13 @@ public void onClick(DialogInterface dialog, int which) {
case R.id.timeline_entry_mark_unread:
List unreadEntries = new ArrayList<>();
new MicrosubAction(TimelineDetailActivity.this, user, layout).markUnread(entry.getChannelId(), unreadEntries, true);
+ Utility.notifyChannels(entry.getChannelId(), 1);
break;
case R.id.timeline_entry_mark_read:
List readEntries = new ArrayList<>();
new MicrosubAction(TimelineDetailActivity.this, user, layout).markRead(entry.getChannelId(), readEntries, false, true);
+ Utility.notifyChannels(entry.getChannelId(), -1);
break;
case R.id.timeline_entry_debug:
diff --git a/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineListAdapter.java b/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineListAdapter.java
index 25990270..ee1a132e 100644
--- a/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineListAdapter.java
+++ b/app/src/main/java/com/indieweb/indigenous/microsub/timeline/TimelineListAdapter.java
@@ -1110,6 +1110,8 @@ public void onClick(DialogInterface dialog, int which) {
displayValues.add(channel.getName());
}
}
+
+ @SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument")
final CharSequence[] channelItems = displayValues.toArray(new CharSequence[displayValues.size()]);
builder.setTitle(context.getString(R.string.select_channel_move));
@@ -1136,6 +1138,7 @@ public void onClick(DialogInterface dialog, int which) {
ms.markUnread(channel.getUid(), unreadEntries, false);
}
items.remove(position);
+ Utility.notifyChannels(channelId, -1);
notifyDataSetChanged();
break;
}
@@ -1151,6 +1154,7 @@ public void onClick(DialogInterface dialog, int which) {
unreadEntries.add(entry.getId());
entry.setRead(false);
new MicrosubAction(context, user, layout).markUnread(channelId, unreadEntries, true);
+ Utility.notifyChannels(channelId, 1);
break;
case R.id.timeline_entry_mark_read:
@@ -1158,6 +1162,7 @@ public void onClick(DialogInterface dialog, int which) {
readEntries.add(entry.getId());
entry.setRead(true);
new MicrosubAction(context, user, layout).markRead(channelId, readEntries, false, true);
+ Utility.notifyChannels(channelId, -1);
break;
case R.id.timeline_entry_debug:
diff --git a/app/src/main/java/com/indieweb/indigenous/util/Utility.java b/app/src/main/java/com/indieweb/indigenous/util/Utility.java
index 905b381b..304eea3e 100644
--- a/app/src/main/java/com/indieweb/indigenous/util/Utility.java
+++ b/app/src/main/java/com/indieweb/indigenous/util/Utility.java
@@ -24,6 +24,7 @@
import com.indieweb.indigenous.db.DatabaseHelper;
import com.indieweb.indigenous.general.DebugActivity;
import com.indieweb.indigenous.model.Cache;
+import com.indieweb.indigenous.model.Channel;
import java.net.MalformedURLException;
import java.net.URI;
@@ -132,6 +133,30 @@ public static void showDebugInfo(Context context, String debug) {
context.startActivity(i);
}
+ /**
+ * Notify channels the counter is changed.
+ *
+ * @param channelId
+ * The channel id.
+ * @param count
+ * How many items to count up or down.
+ */
+ public static void notifyChannels(String channelId, int count) {
+ try {
+ Indigenous app = Indigenous.getInstance();
+ app.setRefreshChannels(true);
+ for (Channel c: app.getChannelsList()) {
+ if (c.getUid().equals(channelId)) {
+ if (c.getUnread() != -1) {
+ c.setUnread(c.getUnread() + count);
+ break;
+ }
+ }
+ }
+ }
+ catch (Exception ignored) { }
+ }
+
/**
* Copy to clipboard.
*
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1067fb59..1a5bf53b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -382,7 +382,7 @@
Image preview on compact
Show the first image per post in the compact style. The images are always visible on the full detail of the post.
Mark items read
- Either automatically mark all items read when viewing a channel (per page), or manually with a "Mark all read" button per channel and "Mark read" action in the item menu.
+ Configure how items are marked as read.\n1: mark all items read when viewing a channel, which is per page.\n2: manually with a "Mark all read" button per channel (only shows up in case there are more than 20 items) and "Mark read" action in the item menu.\n3: mark read while scrolling.
Channel search
Allows to search in a channel for posts
Global search
@@ -473,11 +473,13 @@
- Channel per page
- Mark manually
+ - Mark read while scrolling
- 1
- 2
+ - 3