#1812 Scroll the stories list to the last user read story once reading session ends

This commit is contained in:
sictiru 2023-09-26 18:07:18 -07:00
parent ae720e9947
commit bea1140ea2
7 changed files with 107 additions and 14 deletions

View file

@ -21,7 +21,7 @@ public class AllStoriesItemsList extends ItemsList {
setIntent(intent);
if (getIntent().getBooleanExtra(EXTRA_WIDGET_STORY, false)) {
String hash = (String) getIntent().getSerializableExtra(EXTRA_STORY_HASH);
UIUtils.startReadingActivity(fs, hash, this);
UIUtils.startReadingActivity(this, fs, hash, readingActivityLaunch);
}
}

View file

@ -4,8 +4,13 @@ import static com.newsblur.service.NBSyncReceiver.UPDATE_REBUILD;
import static com.newsblur.service.NBSyncReceiver.UPDATE_STATUS;
import static com.newsblur.service.NBSyncReceiver.UPDATE_STORY;
import android.content.Intent;
import android.os.Bundle;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
@ -29,6 +34,7 @@ import com.newsblur.service.NBSyncService;
import com.newsblur.util.AppConstants;
import com.newsblur.util.FeedSet;
import com.newsblur.util.FeedUtils;
import com.newsblur.util.Log;
import com.newsblur.util.ReadingActionListener;
import com.newsblur.util.PrefsUtils;
import com.newsblur.util.Session;
@ -65,8 +71,13 @@ public abstract class ItemsList extends NbActivity implements ReadingActionListe
private ItemListContextMenuDelegate contextMenuDelegate;
@Nullable
private SessionDataSource sessionDataSource;
@Override
@NonNull
protected ActivityResultLauncher<Intent> readingActivityLaunch = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), this::handleReadingActivityResult
);
@Override
protected void onCreate(Bundle bundle) {
Trace.beginSection("ItemsListOnCreate");
super.onCreate(bundle);
@ -84,11 +95,11 @@ public abstract class ItemsList extends NbActivity implements ReadingActionListe
feedUtils.prepareReadingSession(this, fs, false);
if (getIntent().getBooleanExtra(EXTRA_WIDGET_STORY, false)) {
String hash = (String) getIntent().getSerializableExtra(EXTRA_STORY_HASH);
UIUtils.startReadingActivity(fs, hash, this);
UIUtils.startReadingActivity(this, fs, hash, readingActivityLaunch);
} else if (PrefsUtils.isAutoOpenFirstUnread(this)) {
StateFilter intelState = PrefsUtils.getStateFilter(this);
if (dbHelper.getUnreadCount(fs, intelState) > 0) {
UIUtils.startReadingActivity(fs, Reading.FIND_FIRST_UNREAD, this);
UIUtils.startReadingActivity(this, fs, Reading.FIND_FIRST_UNREAD, readingActivityLaunch);
}
}
@ -285,6 +296,20 @@ public abstract class ItemsList extends NbActivity implements ReadingActionListe
itemSetFragment.scrollToTop();
}
public void startReadingActivity(FeedSet feedSet, String storyHash) {
UIUtils.startReadingActivity(this, feedSet, storyHash, readingActivityLaunch);
}
private void handleReadingActivityResult(ActivityResult result) {
if (result.getData() != null) {
int lastReadingPosition = result.getData().getIntExtra(Reading.LAST_READING_POS, -1);
if (lastReadingPosition > 1) {
Log.d(this.getClass().getName(), "Scrolling to last reading position " + lastReadingPosition);
itemSetFragment.scrollToPosition(lastReadingPosition);
}
}
}
@Override
public void finish() {
super.finish();

View file

@ -1,5 +1,6 @@
package com.newsblur.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
@ -10,6 +11,7 @@ import android.view.KeyEvent
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.commit
import androidx.lifecycle.ViewModelProvider
@ -32,8 +34,20 @@ import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_REBUILD
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_STATUS
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_STORY
import com.newsblur.service.NBSyncService
import com.newsblur.util.*
import com.newsblur.util.AppConstants
import com.newsblur.util.CursorFilters
import com.newsblur.util.DefaultFeedView
import com.newsblur.util.FeedSet
import com.newsblur.util.FeedUtils
import com.newsblur.util.ImageLoader
import com.newsblur.util.MarkStoryReadBehavior
import com.newsblur.util.PrefConstants.ThemeValue
import com.newsblur.util.PrefsUtils
import com.newsblur.util.StateFilter
import com.newsblur.util.UIUtils
import com.newsblur.util.ViewUtils
import com.newsblur.util.VolumeKeyNavigation
import com.newsblur.util.executeAsyncTask
import com.newsblur.view.ReadingScrollView.ScrollChangeListener
import com.newsblur.viewModel.StoriesViewModel
import dagger.hilt.android.AndroidEntryPoint
@ -42,7 +56,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.lang.Runnable
import javax.inject.Inject
import kotlin.math.abs
@ -142,6 +155,7 @@ abstract class Reading : NbActivity(), OnPageChangeListener, ScrollChangeListene
setupViews()
setupListeners()
setupObservers()
setupOnBackPressed()
getActiveStoriesCursor(this, true)
}
@ -226,6 +240,17 @@ abstract class Reading : NbActivity(), OnPageChangeListener, ScrollChangeListene
}
}
/**
* Overrides on back pressed to use overridden [Reading.finish] method
*/
private fun setupOnBackPressed() {
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(enabled = true) {
override fun handleOnBackPressed() {
finish()
}
})
}
private fun getActiveStoriesCursor(context: Context, finishOnInvalidFs: Boolean = false) {
fs?.let {
val cursorFilters = CursorFilters(context, it)
@ -843,6 +868,20 @@ abstract class Reading : NbActivity(), OnPageChangeListener, ScrollChangeListene
}
}
/**
* Overrides the [Reading] finish method and
* passes back the last read item position from the pager
*/
override fun finish() {
setResult(Activity.RESULT_OK, Intent().apply {
pager?.currentItem?.let { position ->
com.newsblur.util.Log.d(this@Reading.javaClass.name, "Finish reading at position $position")
putExtra(LAST_READING_POS, position)
}
})
super.finish()
}
companion object {
const val EXTRA_FEEDSET = "feed_set"
const val EXTRA_STORY_HASH = "story_hash"
@ -857,5 +896,7 @@ abstract class Reading : NbActivity(), OnPageChangeListener, ScrollChangeListene
/** The minimum screen width (in DP) needed to show all the overlay controls. */
private const val OVERLAY_MIN_WIDTH_DP = 355
const val LAST_READING_POS = "last_reading_pos"
}
}

View file

@ -80,6 +80,7 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
private final ExecutorService executorService;
private final NbActivity context;
private final ItemSetFragment fragment;
private final OnStoryClickListener listener;
private FeedSet fs;
private StoryListStyle listStyle;
private boolean ignoreReadStatus;
@ -96,7 +97,8 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
StoryListStyle listStyle,
ImageLoader iconLoader,
ImageLoader thumbnailLoader,
FeedUtils feedUtils) {
FeedUtils feedUtils,
OnStoryClickListener listener) {
this.context = context;
this.fragment = fragment;
this.fs = fs;
@ -104,6 +106,7 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
this.iconLoader = iconLoader;
this.thumbnailLoader = thumbnailLoader;
this.feedUtils = feedUtils;
this.listener = listener;
if (fs.isGlobalShared()) {ignoreReadStatus = false; ignoreIntel = true; singleFeed = false;}
if (fs.isAllSocial()) {ignoreReadStatus = false; ignoreIntel = false; singleFeed = false;}
@ -392,7 +395,7 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
return;
}
if (gestureL2R || gestureR2L) return;
UIUtils.startReadingActivity(fs, story.storyHash, context);
listener.onStoryClicked(fs, story.storyHash);
}
@Override
@ -817,4 +820,8 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
notifyItemRangeChanged(0, getItemCount());
}
public interface OnStoryClickListener {
void onStoryClicked(FeedSet feedSet, String storyHash);
}
}

View file

@ -185,7 +185,7 @@ public class ItemSetFragment extends NbFragment {
}
});
adapter = new StoryViewAdapter(((NbActivity) getActivity()), this, getFeedSet(), listStyle, iconLoader, thumbnailLoader, feedUtils);
adapter = new StoryViewAdapter(((NbActivity) getActivity()), this, getFeedSet(), listStyle, iconLoader, thumbnailLoader, feedUtils, getOnStoryClickListener());
adapter.addFooterView(footerView);
adapter.addFooterView(fleuronBinding.getRoot());
binding.itemgridfragmentGrid.setAdapter(adapter);
@ -261,6 +261,13 @@ public class ItemSetFragment extends NbFragment {
layoutManager.scrollToPositionWithOffset(0, 0);
}
public void scrollToPosition(int position) {
int layoutTotalPositions = layoutManager.getItemCount() - 1;
if (position > 0 && position <= layoutTotalPositions) {
layoutManager.scrollToPosition(position);
}
}
protected FeedSet getFeedSet() {
return ((ItemsList) getActivity()).getFeedSet();
}
@ -546,6 +553,13 @@ public class ItemSetFragment extends NbFragment {
fleuronBinding.getRoot().setLayoutParams(newLayout);
}
private StoryViewAdapter.OnStoryClickListener getOnStoryClickListener() {
return (feedSet, storyHash) -> {
ItemsList activity = ((ItemsList) getActivity());
if (activity != null) activity.startReadingActivity(feedSet, storyHash);
};
}
@Override
public void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);

View file

@ -135,7 +135,7 @@ abstract class ProfileActivityDetailsFragment : Fragment(), OnItemClickListener
//context.startActivity(intent);
}
} else if (activity.category == ActivityDetails.Category.STAR) {
UIUtils.startReadingActivity(FeedSet.allSaved(), activity.storyHash, context)
UIUtils.startReadingActivity(context, FeedSet.allSaved(), activity.storyHash)
} else if (isSocialFeedCategory(activity)) {
// Strip the social: prefix from feedId
val socialFeedId = activity.feedId.substring(7)
@ -143,7 +143,7 @@ abstract class ProfileActivityDetailsFragment : Fragment(), OnItemClickListener
if (feed == null) {
Toast.makeText(context, R.string.profile_do_not_follow, Toast.LENGTH_SHORT).show()
} else {
UIUtils.startReadingActivity(FeedSet.singleSocialFeed(feed.userId, feed.username), activity.storyHash, context)
UIUtils.startReadingActivity(context, FeedSet.singleSocialFeed(feed.userId, feed.username), activity.storyHash)
}
}
}

View file

@ -36,6 +36,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@ -265,7 +266,11 @@ public class UIUtils {
});
}
public static void startReadingActivity(FeedSet fs, String startingHash, Context context) {
public static void startReadingActivity(Context context, FeedSet fs, String startingHash) {
startReadingActivity(context, fs, startingHash, null);
}
public static void startReadingActivity(Context context, FeedSet fs, String startingHash, @Nullable ActivityResultLauncher<Intent> readingActivityLauncher) {
Class activityClass;
if (fs.isAllSaved()) {
activityClass = SavedStoriesReading.class;
@ -294,7 +299,8 @@ public class UIUtils {
Intent i = new Intent(context, activityClass);
i.putExtra(Reading.EXTRA_FEEDSET, fs);
i.putExtra(Reading.EXTRA_STORY_HASH, startingHash);
context.startActivity(i);
if (readingActivityLauncher != null) readingActivityLauncher.launch(i);
else context.startActivity(i);
}
public static String getMemoryUsageDebug(Context context) {