summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dolgov <fox@fakecake.org>2025-05-17 10:35:09 +0300
committerAndrew Dolgov <fox@fakecake.org>2025-05-17 10:35:40 +0300
commit4715cc93f9e4b0dde090288aac6fa7abf834636c (patch)
treeadc6ed538cb4ce2d569f0510ab6df8ef100b4e1f
parent334379d21bf9ac24bed68665bcc06b1c49d8f109 (diff)
switch to viewmodel for feeds/cats
-rwxr-xr-xorg.fox.ttrss/src/main/java/org/fox/ttrss/ApiLoader.java84
-rwxr-xr-xorg.fox.ttrss/src/main/java/org/fox/ttrss/Application.java3
-rw-r--r--org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleModel.java18
-rwxr-xr-xorg.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java223
-rw-r--r--org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsModel.java160
-rwxr-xr-xorg.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java5
-rwxr-xr-xorg.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java4
-rwxr-xr-xorg.fox.ttrss/src/main/java/org/fox/ttrss/RootCategoriesFragment.java90
8 files changed, 311 insertions, 276 deletions
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiLoader.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiLoader.java
deleted file mode 100755
index 5cba0ed1..00000000
--- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiLoader.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.fox.ttrss;
-
-import android.content.Context;
-
-import androidx.loader.content.AsyncTaskLoader;
-
-import com.google.gson.JsonElement;
-
-import org.fox.ttrss.ApiCommon.ApiError;
-
-import java.util.HashMap;
-
-public class ApiLoader extends AsyncTaskLoader<JsonElement> implements ApiCommon.ApiCaller {
- private final String TAG = this.getClass().getSimpleName();
-
- private final int m_responseCode = 0;
- protected String m_responseMessage;
- private int m_apiStatusCode = 0;
-
- private final Context m_context;
- private String m_lastErrorMessage;
- private ApiError m_lastError;
- private final HashMap<String,String> m_params;
- private JsonElement m_data;
-
- ApiLoader(Context context, HashMap<String, String> params) {
- super(context);
-
- m_context = context;
- m_lastError = ApiError.UNKNOWN_ERROR;
- m_params = params;
- }
-
- @Override
- protected void onStartLoading() {
- if (m_data != null) {
- deliverResult(m_data);
- } else {
- forceLoad();
- }
- }
-
- @Override
- public void deliverResult(JsonElement data) {
- m_data = data;
-
- super.deliverResult(data);
- }
-
- public int getErrorMessage() {
- return ApiCommon.getErrorMessage(m_lastError);
- }
-
- ApiError getLastError() {
- return m_lastError;
- }
-
- String getLastErrorMessage() {
- return m_lastErrorMessage;
- }
-
- @Override
- public JsonElement loadInBackground() {
- return ApiCommon.performRequest(m_context, m_params, this);
- }
-
- @Override
- public void setStatusCode(int statusCode) {
- m_apiStatusCode = statusCode;
- }
-
- @Override
- public void setLastError(ApiError lastError) {
- m_lastError = lastError;
- }
-
- @Override
- public void setLastErrorMessage(String message) {
- m_lastErrorMessage = message;
- }
-
- @Override
- public void notifyProgress(int progress) { }
-}
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/Application.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/Application.java
index 75542e3c..11e32bcf 100755
--- a/org.fox.ttrss/src/main/java/org/fox/ttrss/Application.java
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/Application.java
@@ -11,9 +11,6 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
public class Application extends android.app.Application {
- public static final int LOADER_HEADLINES = 0;
- public static final int LOADER_FEEDS = 1;
- public static final int LOADER_CATS = 2;
private static Application m_singleton;
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleModel.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleModel.java
index f4deb372..2a6b4b3e 100644
--- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleModel.java
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ArticleModel.java
@@ -47,7 +47,7 @@ public class ArticleModel extends AndroidViewModel implements ApiCommon.ApiCalle
private int m_resizeWidth;
private boolean m_append;
private boolean m_lazyLoadEnabled = true;
- private boolean m_loadingInProgress;
+ private MutableLiveData<Boolean> m_isLoading = new MutableLiveData<>(Boolean.valueOf(false));
private ExecutorService m_executor;
private Handler m_mainHandler = new Handler(Looper.getMainLooper());
private MutableLiveData<Long> m_lastUpdate = new MutableLiveData<>(Long.valueOf(0));
@@ -91,7 +91,7 @@ public class ArticleModel extends AndroidViewModel implements ApiCommon.ApiCalle
m_feed = feed;
loadInBackground();
- } else if (feed != m_feed || m_lazyLoadEnabled && !m_loadingInProgress) {
+ } else if (feed != m_feed || m_lazyLoadEnabled || !m_isLoading.getValue()) {
m_append = true;
m_feed = feed;
@@ -106,7 +106,7 @@ public class ArticleModel extends AndroidViewModel implements ApiCommon.ApiCalle
ArticleList articlesWork = new ArticleList(m_articles.getValue());
- m_loadingInProgress = true;
+ m_isLoading.postValue(true);
final int skip = getSkip(m_append, articlesWork);
final boolean allowForceUpdate = org.fox.ttrss.Application.getInstance().getApiLevel() >= 9 &&
@@ -212,7 +212,7 @@ public class ArticleModel extends AndroidViewModel implements ApiCommon.ApiCalle
}
m_offset += m_amountLoaded;
- m_loadingInProgress = false;
+ m_isLoading.postValue(false);
Log.d(TAG, this + " loaded headlines=" + m_amountLoaded + " resultingLocalSize=" + articlesWork.size());
}
@@ -227,7 +227,7 @@ public class ArticleModel extends AndroidViewModel implements ApiCommon.ApiCalle
});
});
- m_loadingInProgress = false;
+ m_isLoading.postValue(false);
}
@@ -299,7 +299,7 @@ public class ArticleModel extends AndroidViewModel implements ApiCommon.ApiCalle
return m_offset;
}
- public boolean lazyLoadEnabled() {
+ public boolean isLazyLoadEnabled() {
return m_lazyLoadEnabled;
}
@@ -316,7 +316,11 @@ public class ArticleModel extends AndroidViewModel implements ApiCommon.ApiCalle
}
public boolean isLoading() {
- return m_loadingInProgress;
+ return m_isLoading.getValue();
+ }
+
+ public LiveData<Boolean> getIsLoading() {
+ return m_isLoading;
}
public LiveData<Integer> getLoadingProgress() {
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java
index 513eaeb7..6fe2144a 100755
--- a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java
@@ -21,6 +21,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.preference.PreferenceManager;
@@ -51,8 +52,7 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
-public class FeedsFragment extends Fragment implements OnSharedPreferenceChangeListener,
- LoaderManager.LoaderCallbacks<JsonElement> {
+public class FeedsFragment extends Fragment implements OnSharedPreferenceChangeListener {
private final String TAG = this.getClass().getSimpleName();
protected SharedPreferences m_prefs;
protected MasterActivity m_activity;
@@ -71,88 +71,6 @@ public class FeedsFragment extends Fragment implements OnSharedPreferenceChangeL
m_enableParentBtn = enableParentBtn;
}
- @NonNull
- @Override
- public Loader<JsonElement> onCreateLoader(int id, Bundle args) {
-
- if (m_swipeLayout != null)
- m_swipeLayout.setRefreshing(true);
-
- HashMap<String,String> params = new HashMap<>();
- params.put("op", "getFeeds");
- params.put("sid", m_activity.getSessionId());
- params.put("include_nested", "true");
- params.put("cat_id", String.valueOf(m_rootFeed.id));
-
- return new ApiLoader(getContext(), params);
- }
-
- @Override
- public void onLoadFinished(@NonNull Loader<JsonElement> loader, JsonElement result) {
- if (m_swipeLayout != null) m_swipeLayout.setRefreshing(false);
-
- if (result != null) {
- try {
- JsonArray content = result.getAsJsonArray();
- if (content != null) {
-
- Type listType = new TypeToken<List<Feed>>() {}.getType();
- List<Feed> feedsJson = new Gson().fromJson(content, listType);
- List<Feed> feeds = new ArrayList<>();
-
- if (m_activity.getUnreadOnly() && m_rootFeed.id != Feed.CAT_SPECIAL)
- feedsJson = feedsJson.stream()
- .filter(f -> f.unread > 0)
- .collect(Collectors.toList());
-
- sortFeeds(feedsJson, m_rootFeed);
-
- if (m_enableParentBtn) {
- feeds.add(0, new Feed(Feed.TYPE_GOBACK));
-
- if (m_rootFeed.id >= 0 && !feedsJson.isEmpty()) {
- Feed feed = new Feed(m_rootFeed.id, m_rootFeed.title, true);
-
- feed.unread = feedsJson.stream().map(a -> a.unread).reduce(0, Integer::sum);
- feed.always_open_headlines = true;
-
- feeds.add(1, feed);
- }
- }
-
- feeds.addAll(feedsJson);
-
- feeds.add(new Feed(Feed.TYPE_DIVIDER));
- feeds.add(new Feed(Feed.TYPE_TOGGLE_UNREAD, getString(R.string.unread_only), true));
-
- m_adapter.submitList(feeds);
-
- return;
- }
-
- } catch (Exception e) {
- m_activity.toast(e.getMessage());
- }
- }
-
- ApiLoader apiLoader = (ApiLoader) loader;
-
- if (apiLoader.getLastError() != null && apiLoader.getLastError() != ApiCommon.ApiError.SUCCESS) {
- if (apiLoader.getLastError() == ApiCommon.ApiError.LOGIN_FAILED) {
- m_activity.login(true);
- } else {
- if (apiLoader.getLastErrorMessage() != null) {
- m_activity.toast(getString(apiLoader.getErrorMessage()) + "\n" + apiLoader.getLastErrorMessage());
- } else {
- m_activity.toast(apiLoader.getErrorMessage());
- }
- }
- }
- }
-
- @Override
- public void onLoaderReset(Loader<JsonElement> loader) { }
-
@SuppressLint("DefaultLocale")
static class FeedUnreadComparator implements Comparator<Feed> {
@@ -165,7 +83,6 @@ public class FeedsFragment extends Fragment implements OnSharedPreferenceChangeL
}
}
-
@SuppressLint("DefaultLocale")
static class FeedTitleComparator implements Comparator<Feed> {
@@ -230,39 +147,48 @@ public class FeedsFragment extends Fragment implements OnSharedPreferenceChangeL
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item
.getMenuInfo();
- final Feed feed = m_adapter.getCurrentList().get(info.position);
-
- Log.d(TAG, "context for feed=" + feed.id);
-
- int itemId = item.getItemId();
- if (itemId == R.id.browse_headlines) {
- Feed tmpFeed = new Feed(feed);
+ // all onContextItemSelected are invoked in sequence so we might get a context menu for headlines, etc
+ // TODO context menu ids defined here should be unique to feedsfragment
+ try {
+ if (info != null) {
+ final Feed feed = m_adapter.getCurrentList().get(info.position);
- if (!neverOpenHeadlines(feed))
- tmpFeed.always_open_headlines = true;
+ Log.d(TAG, "context for feed=" + feed.id);
- m_activity.onFeedSelected(tmpFeed);
- return true;
- } else if (itemId == R.id.browse_feeds) {
- m_activity.onFeedSelected(feed);
- return true;
- } else if (itemId == R.id.unsubscribe_feed) {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext())
- .setMessage(getString(R.string.unsubscribe_from_prompt, feed.title))
- .setPositiveButton(R.string.unsubscribe,
- (dialog, which) -> m_activity.unsubscribeFeed(feed))
- .setNegativeButton(R.string.dialog_cancel,
- (dialog, which) -> {
+ int itemId = item.getItemId();
+ if (itemId == R.id.browse_headlines) {
+ Feed tmpFeed = new Feed(feed);
- });
+ if (!neverOpenHeadlines(feed))
+ tmpFeed.always_open_headlines = true;
- Dialog dlg = builder.create();
- dlg.show();
+ m_activity.onFeedSelected(tmpFeed);
+ return true;
+ } else if (itemId == R.id.browse_feeds) {
+ m_activity.onFeedSelected(feed);
+ return true;
+ } else if (itemId == R.id.unsubscribe_feed) {
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext())
+ .setMessage(getString(R.string.unsubscribe_from_prompt, feed.title))
+ .setPositiveButton(R.string.unsubscribe,
+ (dialog, which) -> m_activity.unsubscribeFeed(feed))
+ .setNegativeButton(R.string.dialog_cancel,
+ (dialog, which) -> {
+
+ });
+
+ Dialog dlg = builder.create();
+ dlg.show();
+
+ return true;
+ } else if (itemId == R.id.catchup_feed) {
+ m_activity.catchupDialog(feed);
+ return true;
+ }
+ }
- return true;
- } else if (itemId == R.id.catchup_feed) {
- m_activity.catchupDialog(feed);
- return true;
+ } catch (IndexOutOfBoundsException e) {
+ e.printStackTrace();
}
Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
@@ -360,9 +286,73 @@ public class FeedsFragment extends Fragment implements OnSharedPreferenceChangeL
});
}
+ FeedsModel model = new ViewModelProvider(this).get(FeedsModel.class);
+
+ model.getUpdatesData().observe(getActivity(), lastUpdate -> {
+ Log.d(TAG, "observed update=" + lastUpdate);
+ });
+
+ model.getIsLoading().observe(getActivity(), isLoading -> {
+ Log.d(TAG, "observed isLoading=" + isLoading);
+
+ if (isAdded() && m_swipeLayout != null)
+ m_swipeLayout.setRefreshing(isLoading);
+ });
+
+ model.getFeeds().observe(getActivity(), feeds -> {
+ Log.d(TAG, "observed feeds=" + feeds);
+
+ if (isAdded()) {
+ onFeedsLoaded(feeds);
+
+ if (model.getLastError() != null && model.getLastError() != ApiCommon.ApiError.SUCCESS) {
+ if (model.getLastError() == ApiCommon.ApiError.LOGIN_FAILED) {
+ m_activity.login(true);
+ } else {
+ if (model.getLastErrorMessage() != null) {
+ m_activity.toast(getString(model.getErrorMessage()) + "\n" + model.getLastErrorMessage());
+ } else {
+ m_activity.toast(model.getErrorMessage());
+ }
+ }
+ }
+ }
+ });
+
return view;
}
+ protected void onFeedsLoaded(List<Feed> loadedFeeds) {
+ List<Feed> feedsWork = new ArrayList<>();
+
+ if (m_activity.getUnreadOnly() && m_rootFeed.id != Feed.CAT_SPECIAL)
+ loadedFeeds = loadedFeeds.stream()
+ .filter(f -> f.unread > 0)
+ .collect(Collectors.toList());
+
+ sortFeeds(loadedFeeds, m_rootFeed);
+
+ if (m_enableParentBtn) {
+ feedsWork.add(0, new Feed(Feed.TYPE_GOBACK));
+
+ if (m_rootFeed.id >= 0 && !loadedFeeds.isEmpty()) {
+ Feed feed = new Feed(m_rootFeed.id, m_rootFeed.title, true);
+
+ feed.unread = loadedFeeds.stream().map(a -> a.unread).reduce(0, Integer::sum);
+ feed.always_open_headlines = true;
+
+ feedsWork.add(1, feed);
+ }
+ }
+
+ feedsWork.addAll(loadedFeeds);
+
+ feedsWork.add(new Feed(Feed.TYPE_DIVIDER));
+ feedsWork.add(new Feed(Feed.TYPE_TOGGLE_UNREAD, getString(R.string.unread_only), true));
+
+ m_adapter.submitList(feedsWork);
+ }
+
@Override
public void onDestroy() {
super.onDestroy();
@@ -395,11 +385,8 @@ public class FeedsFragment extends Fragment implements OnSharedPreferenceChangeL
if (!isAdded())
return;
- if (m_swipeLayout != null) {
- m_swipeLayout.setRefreshing(true);
- }
-
- LoaderManager.getInstance(this).restartLoader(Application.LOADER_FEEDS, null, this).forceLoad();
+ FeedsModel model = new ViewModelProvider(this).get(FeedsModel.class);
+ model.startLoading(m_rootFeed, false);
}
private class FeedViewHolder extends RecyclerView.ViewHolder {
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsModel.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsModel.java
new file mode 100644
index 00000000..bd6ca21f
--- /dev/null
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsModel.java
@@ -0,0 +1,160 @@
+package org.fox.ttrss;
+
+import android.app.Application;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.reflect.TypeToken;
+
+import org.fox.ttrss.types.ArticleList;
+import org.fox.ttrss.types.Feed;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class FeedsModel extends AndroidViewModel implements ApiCommon.ApiCaller {
+ private final String TAG = this.getClass().getSimpleName();
+ private MutableLiveData<List<Feed>> m_feeds = new MutableLiveData<>(new ArrayList<>());
+ private MutableLiveData<Integer> m_loadingProgress = new MutableLiveData<>(Integer.valueOf(0));
+ private MutableLiveData<Long> m_lastUpdate = new MutableLiveData<>(Long.valueOf(0));
+ private MutableLiveData<Boolean> m_isLoading = new MutableLiveData<>(Boolean.valueOf(false));
+
+ private Feed m_feed;
+
+ private ExecutorService m_executor;
+ private Handler m_mainHandler = new Handler(Looper.getMainLooper());
+
+ private final int m_responseCode = 0;
+ protected String m_responseMessage;
+ private int m_apiStatusCode = 0;
+ private String m_lastErrorMessage;
+ private ApiCommon.ApiError m_lastError;
+ private boolean m_rootMode;
+
+ public FeedsModel(@NonNull Application application) {
+ super(application);
+
+ // do we need concurrency or not?
+ m_executor = Executors.newSingleThreadExecutor();
+
+ Log.d(TAG, this + " created");
+ }
+
+ @Override
+ public void setStatusCode(int statusCode) {
+ m_apiStatusCode = statusCode;
+ }
+
+ @Override
+ public void setLastError(ApiCommon.ApiError lastError) {
+ m_lastError = lastError;
+ }
+
+ @Override
+ public void setLastErrorMessage(String message) {
+ m_lastErrorMessage = message;
+ }
+
+ public void startLoading(Feed feed, boolean rootMode) {
+ Log.d(TAG, "startLoading feed id=" + feed.id + " cat=" + feed.is_cat);
+
+ m_feed = feed;
+ m_rootMode = rootMode;
+
+ loadInBackground();
+ }
+
+ @Override
+ public void notifyProgress(int progress) {
+ m_loadingProgress.postValue(progress);
+ }
+
+ protected HashMap<String,String> constructParams() {
+ HashMap<String,String> params = new HashMap<>();
+
+ if (m_rootMode) {
+ params.put("op", "getCategories");
+
+ // this confusingly named option means "return top level categories only"
+ params.put("enable_nested", "true");
+ } else {
+ params.put("op", "getFeeds");
+ params.put("cat_id", String.valueOf(m_feed.id));
+ params.put("include_nested", "true");
+ }
+
+ params.put("sid", ((org.fox.ttrss.Application)getApplication()).getSessionId());
+
+ return params;
+ }
+
+ private void loadInBackground() {
+ Log.d(TAG, this + " loadInBackground");
+
+ m_isLoading.postValue(true);
+
+ HashMap<String,String> params = constructParams();
+
+ m_executor.execute(() -> {
+ JsonElement result = ApiCommon.performRequest(getApplication(), params, this);
+
+ Log.d(TAG, "got result=" + result);
+
+ try {
+ JsonArray content = result.getAsJsonArray();
+ if (content != null) {
+
+ Type listType = new TypeToken<List<Feed>>() {
+ }.getType();
+ List<Feed> feeds = new Gson().fromJson(content, listType);
+
+ m_feeds.postValue(feeds);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ m_isLoading.postValue(false);
+ });
+ }
+
+ public LiveData<Integer> getLoadingProgress() {
+ return m_loadingProgress;
+ }
+
+ public LiveData<Long> getUpdatesData() {
+ return m_lastUpdate;
+ }
+
+ public LiveData<Boolean> getIsLoading() { return m_isLoading; }
+
+ public LiveData<List<Feed>> getFeeds() {
+ return m_feeds;
+ }
+
+ public int getErrorMessage() {
+ return ApiCommon.getErrorMessage(m_lastError);
+ }
+
+ ApiCommon.ApiError getLastError() {
+ return m_lastError;
+ }
+
+ String getLastErrorMessage() {
+ return m_lastErrorMessage;
+ }
+
+} \ No newline at end of file
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java
index 099afc60..dba0ac47 100755
--- a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java
@@ -217,12 +217,12 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment {
}
}
+ // all onContextItemSelected are invoked in sequence so we might get a context menu for headlines, etc
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
if (info != null) {
-
try {
Article article = Application.getArticles().get(info.position);
@@ -233,6 +233,7 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment {
}
}
+ Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
return super.onContextItemSelected(item);
}
@@ -459,7 +460,7 @@ public class HeadlinesFragment extends androidx.fragment.app.Fragment {
ArticleModel model = Application.getArticlesModel();
- if (dy > 0 && !m_isLazyLoading && !model.isLoading() && model.lazyLoadEnabled() &&
+ if (dy > 0 && !m_isLazyLoading && !model.isLoading() && model.isLazyLoadEnabled() &&
lastVisibleItem >= Application.getArticles().size() - 5) {
Log.d(TAG, "attempting to lazy load more articles...");
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java
index 643f859c..bdbac8ff 100755
--- a/org.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/MasterActivity.java
@@ -165,6 +165,10 @@ public class MasterActivity extends OnlineActivity implements HeadlinesEventList
fc.initialize(new Feed(-1, getString(R.string.cat_special), true), false);
ft.replace(R.id.feeds_fragment, fc, FRAG_FEEDS);
+ /* FeedsFragment ff = new FeedsFragment();
+ ff.initialize(new Feed(12, "Technology", true), true);
+ ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS); */
+
// allow overriding feed to open on startup in non-shortcut mode, default to
// open_on_startup prefs setting and not-category
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/RootCategoriesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/RootCategoriesFragment.java
index b61a2736..55c23226 100755
--- a/org.fox.ttrss/src/main/java/org/fox/ttrss/RootCategoriesFragment.java
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/RootCategoriesFragment.java
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
import android.os.Bundle;
import androidx.annotation.NonNull;
+import androidx.lifecycle.ViewModelProvider;
import androidx.loader.content.Loader;
import com.google.gson.Gson;
@@ -23,19 +24,6 @@ import java.util.stream.Collectors;
public class RootCategoriesFragment extends FeedsFragment {
private final String TAG = this.getClass().getSimpleName();
- @Override
- @NonNull
- public Loader<JsonElement> onCreateLoader(int id, Bundle args) {
- HashMap<String, String> params = new HashMap<>();
- params.put("op", "getCategories");
- params.put("sid", m_activity.getSessionId());
-
- // this confusingly named option means "return top level categories only"
- params.put("enable_nested", "true");
-
- return new ApiLoader(getContext(), params);
- }
-
@SuppressLint("DefaultLocale")
static class CatOrderComparator implements Comparator<Feed> {
@@ -74,65 +62,43 @@ public class RootCategoriesFragment extends FeedsFragment {
}
@Override
- public void onLoadFinished(@NonNull Loader<JsonElement> loader, JsonElement result) {
- if (m_swipeLayout != null) m_swipeLayout.setRefreshing(false);
-
- if (result != null) {
- try {
- JsonArray content = result.getAsJsonArray();
- if (content != null) {
-
- Type listType = new TypeToken<List<Feed>>() {}.getType();
- List<Feed> feedsJson = new Gson().fromJson(content, listType);
+ public void refresh() {
+ if (!isAdded())
+ return;
- List<Feed> feeds = new ArrayList<>();
-
- sortFeeds(feedsJson, m_rootFeed);
+ FeedsModel model = new ViewModelProvider(this).get(FeedsModel.class);
+ model.startLoading(m_rootFeed, true);
+ }
- // virtual cats implemented in getCategories since api level 1
- if (m_activity.getApiLevel() == 0) {
- feeds.add(0, new Feed(-2, getString(R.string.cat_labels), true));
- feeds.add(1, new Feed(-1, getString(R.string.cat_special), true));
- feeds.add(new Feed(0, getString(R.string.cat_uncategorized), true));
- }
+ @Override
+ protected void onFeedsLoaded(List<Feed> loadedFeeds) {
+ List<Feed> feedsWork = new ArrayList<>();
- if (m_activity.getUnreadOnly())
- feedsJson = feedsJson.stream()
- .filter(f -> f.id == Feed.CAT_SPECIAL || f.unread > 0)
- .collect(Collectors.toList());
+ sortFeeds(loadedFeeds, m_rootFeed);
- feedsJson = feedsJson.stream()
- .peek(f -> f.is_cat = true)
- .collect(Collectors.toList());
+ // virtual cats implemented in getCategories since api level 1
+ if (m_activity.getApiLevel() == 0) {
+ feedsWork.add(0, new Feed(-2, getString(R.string.cat_labels), true));
+ feedsWork.add(1, new Feed(-1, getString(R.string.cat_special), true));
+ feedsWork.add(new Feed(0, getString(R.string.cat_uncategorized), true));
+ }
- feeds.addAll(feedsJson);
+ if (m_activity.getUnreadOnly())
+ loadedFeeds = loadedFeeds.stream()
+ .filter(f -> f.id == Feed.CAT_SPECIAL || f.unread > 0)
+ .collect(Collectors.toList());
- feeds.add(new Feed(Feed.TYPE_DIVIDER));
- feeds.add(new Feed(Feed.TYPE_TOGGLE_UNREAD, getString(R.string.unread_only), true));
+ loadedFeeds = loadedFeeds.stream()
+ .peek(f -> f.is_cat = true)
+ .collect(Collectors.toList());
- m_adapter.submitList(feeds);
+ feedsWork.addAll(loadedFeeds);
- return;
- }
+ feedsWork.add(new Feed(Feed.TYPE_DIVIDER));
+ feedsWork.add(new Feed(Feed.TYPE_TOGGLE_UNREAD, getString(R.string.unread_only), true));
- } catch (Exception e) {
- m_activity.toast(e.getMessage());
- }
- }
+ m_adapter.submitList(feedsWork);
- ApiLoader apiLoader = (ApiLoader) loader;
-
- if (apiLoader.getLastError() != null && apiLoader.getLastError() != ApiCommon.ApiError.SUCCESS) {
- if (apiLoader.getLastError() == ApiCommon.ApiError.LOGIN_FAILED) {
- m_activity.login(true);
- } else {
- if (apiLoader.getLastErrorMessage() != null) {
- m_activity.toast(getString(apiLoader.getErrorMessage()) + "\n" + apiLoader.getLastErrorMessage());
- } else {
- m_activity.toast(apiLoader.getErrorMessage());
- }
- }
- }
}
}