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

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