394 lines
16 KiB
Java
394 lines
16 KiB
Java
package de.danoeh.antennapod.ui.screen.subscriptions;
|
|
|
|
import android.content.Context;
|
|
import android.content.SharedPreferences;
|
|
import android.os.Bundle;
|
|
import android.util.Log;
|
|
import android.view.ContextMenu;
|
|
import android.view.LayoutInflater;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.ProgressBar;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.fragment.app.Fragment;
|
|
import androidx.recyclerview.widget.GridLayoutManager;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|
|
|
import com.google.android.material.appbar.MaterialToolbar;
|
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|
import com.leinardi.android.speeddial.SpeedDialView;
|
|
|
|
import de.danoeh.antennapod.ui.screen.AddFeedFragment;
|
|
import de.danoeh.antennapod.ui.screen.SearchFragment;
|
|
import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
|
|
import org.greenrobot.eventbus.EventBus;
|
|
import org.greenrobot.eventbus.Subscribe;
|
|
import org.greenrobot.eventbus.ThreadMode;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
|
|
import de.danoeh.antennapod.R;
|
|
import de.danoeh.antennapod.activity.MainActivity;
|
|
import de.danoeh.antennapod.ui.MenuItemUtils;
|
|
import de.danoeh.antennapod.storage.database.DBReader;
|
|
import de.danoeh.antennapod.storage.database.NavDrawerData;
|
|
import de.danoeh.antennapod.ui.screen.feed.RenameFeedDialog;
|
|
import de.danoeh.antennapod.event.FeedListUpdateEvent;
|
|
import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
|
|
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
|
|
import de.danoeh.antennapod.model.feed.Feed;
|
|
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
|
import de.danoeh.antennapod.ui.statistics.StatisticsFragment;
|
|
import de.danoeh.antennapod.ui.view.EmptyViewHandler;
|
|
import de.danoeh.antennapod.ui.view.LiftOnScrollListener;
|
|
import io.reactivex.Observable;
|
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
import io.reactivex.disposables.Disposable;
|
|
import io.reactivex.schedulers.Schedulers;
|
|
|
|
/**
|
|
* Fragment for displaying feed subscriptions
|
|
*/
|
|
public class SubscriptionFragment extends Fragment
|
|
implements MaterialToolbar.OnMenuItemClickListener,
|
|
SubscriptionsRecyclerAdapter.OnSelectModeListener {
|
|
public static final String TAG = "SubscriptionFragment";
|
|
private static final String PREFS = "SubscriptionFragment";
|
|
private static final String PREF_NUM_COLUMNS = "columns";
|
|
private static final String KEY_UP_ARROW = "up_arrow";
|
|
private static final String ARGUMENT_FOLDER = "folder";
|
|
|
|
private static final int MIN_NUM_COLUMNS = 1;
|
|
private static final int[] COLUMN_CHECKBOX_IDS = {
|
|
R.id.subscription_display_list,
|
|
R.id.subscription_num_columns_2,
|
|
R.id.subscription_num_columns_3,
|
|
R.id.subscription_num_columns_4,
|
|
R.id.subscription_num_columns_5};
|
|
|
|
private RecyclerView subscriptionRecycler;
|
|
private SubscriptionsRecyclerAdapter subscriptionAdapter;
|
|
private EmptyViewHandler emptyView;
|
|
private LinearLayout feedsFilteredMsg;
|
|
private MaterialToolbar toolbar;
|
|
private SwipeRefreshLayout swipeRefreshLayout;
|
|
private ProgressBar progressBar;
|
|
private String displayedFolder = null;
|
|
private boolean displayUpArrow;
|
|
|
|
private Disposable disposable;
|
|
private SharedPreferences prefs;
|
|
|
|
private FloatingActionButton subscriptionAddButton;
|
|
private SpeedDialView speedDialView;
|
|
private RecyclerView.ItemDecoration itemDecoration;
|
|
private List<NavDrawerData.DrawerItem> listItems;
|
|
|
|
public static SubscriptionFragment newInstance(String folderTitle) {
|
|
SubscriptionFragment fragment = new SubscriptionFragment();
|
|
Bundle args = new Bundle();
|
|
args.putString(ARGUMENT_FOLDER, folderTitle);
|
|
fragment.setArguments(args);
|
|
return fragment;
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
prefs = requireActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
|
}
|
|
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
Bundle savedInstanceState) {
|
|
View root = inflater.inflate(R.layout.fragment_subscriptions, container, false);
|
|
toolbar = root.findViewById(R.id.toolbar);
|
|
toolbar.setOnMenuItemClickListener(this);
|
|
toolbar.setOnLongClickListener(v -> {
|
|
subscriptionRecycler.scrollToPosition(5);
|
|
subscriptionRecycler.post(() -> subscriptionRecycler.smoothScrollToPosition(0));
|
|
return false;
|
|
});
|
|
displayUpArrow = getParentFragmentManager().getBackStackEntryCount() != 0;
|
|
if (savedInstanceState != null) {
|
|
displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW);
|
|
}
|
|
((MainActivity) getActivity()).setupToolbarToggle(toolbar, displayUpArrow);
|
|
toolbar.inflateMenu(R.menu.subscriptions);
|
|
for (int i = 1; i < COLUMN_CHECKBOX_IDS.length; i++) {
|
|
// Do this in Java to localize numbers
|
|
toolbar.getMenu().findItem(COLUMN_CHECKBOX_IDS[i])
|
|
.setTitle(String.format(Locale.getDefault(), "%d", i + MIN_NUM_COLUMNS));
|
|
}
|
|
refreshToolbarState();
|
|
|
|
if (getArguments() != null) {
|
|
displayedFolder = getArguments().getString(ARGUMENT_FOLDER, null);
|
|
if (displayedFolder != null) {
|
|
toolbar.setTitle(displayedFolder);
|
|
}
|
|
}
|
|
|
|
subscriptionRecycler = root.findViewById(R.id.subscriptions_grid);
|
|
registerForContextMenu(subscriptionRecycler);
|
|
subscriptionRecycler.addOnScrollListener(new LiftOnScrollListener(root.findViewById(R.id.appbar)));
|
|
subscriptionAdapter = new SubscriptionsRecyclerAdapter((MainActivity) getActivity()) {
|
|
@Override
|
|
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
|
super.onCreateContextMenu(menu, v, menuInfo);
|
|
MenuItemUtils.setOnClickListeners(menu, SubscriptionFragment.this::onContextItemSelected);
|
|
}
|
|
};
|
|
setColumnNumber(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()));
|
|
subscriptionAdapter.setOnSelectModeListener(this);
|
|
subscriptionRecycler.setAdapter(subscriptionAdapter);
|
|
setupEmptyView();
|
|
|
|
progressBar = root.findViewById(R.id.progressBar);
|
|
progressBar.setVisibility(View.VISIBLE);
|
|
|
|
subscriptionAddButton = root.findViewById(R.id.subscriptions_add);
|
|
subscriptionAddButton.setOnClickListener(view -> {
|
|
if (getActivity() instanceof MainActivity) {
|
|
((MainActivity) getActivity()).loadChildFragment(new AddFeedFragment());
|
|
}
|
|
});
|
|
|
|
feedsFilteredMsg = root.findViewById(R.id.feeds_filtered_message);
|
|
feedsFilteredMsg.setOnClickListener((l) ->
|
|
new SubscriptionsFilterDialog().show(getChildFragmentManager(), "filter"));
|
|
|
|
swipeRefreshLayout = root.findViewById(R.id.swipeRefresh);
|
|
swipeRefreshLayout.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance));
|
|
swipeRefreshLayout.setOnRefreshListener(() -> FeedUpdateManager.getInstance().runOnceOrAsk(requireContext()));
|
|
|
|
speedDialView = root.findViewById(R.id.fabSD);
|
|
speedDialView.setOverlayLayout(root.findViewById(R.id.fabSDOverlay));
|
|
speedDialView.inflate(R.menu.nav_feed_action_speeddial);
|
|
speedDialView.setOnActionSelectedListener(actionItem -> {
|
|
new FeedMultiSelectActionHandler((MainActivity) getActivity(), subscriptionAdapter.getSelectedItems())
|
|
.handleAction(actionItem.getId());
|
|
return true;
|
|
});
|
|
|
|
return root;
|
|
}
|
|
|
|
@Override
|
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
|
outState.putBoolean(KEY_UP_ARROW, displayUpArrow);
|
|
super.onSaveInstanceState(outState);
|
|
}
|
|
|
|
private void refreshToolbarState() {
|
|
int columns = prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns());
|
|
toolbar.getMenu().findItem(COLUMN_CHECKBOX_IDS[columns - MIN_NUM_COLUMNS]).setChecked(true);
|
|
toolbar.getMenu().findItem(R.id.pref_show_subscription_title).setVisible(columns > 1);
|
|
toolbar.getMenu().findItem(R.id.pref_show_subscription_title)
|
|
.setChecked(UserPreferences.shouldShowSubscriptionTitle());
|
|
}
|
|
|
|
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
|
|
public void onEventMainThread(FeedUpdateRunningEvent event) {
|
|
swipeRefreshLayout.setRefreshing(event.isFeedUpdateRunning);
|
|
}
|
|
|
|
@Override
|
|
public boolean onMenuItemClick(MenuItem item) {
|
|
final int itemId = item.getItemId();
|
|
if (itemId == R.id.refresh_item) {
|
|
FeedUpdateManager.getInstance().runOnceOrAsk(requireContext());
|
|
return true;
|
|
} else if (itemId == R.id.subscriptions_filter) {
|
|
new SubscriptionsFilterDialog().show(getChildFragmentManager(), "filter");
|
|
return true;
|
|
} else if (itemId == R.id.subscriptions_sort) {
|
|
FeedSortDialog.showDialog(requireContext());
|
|
return true;
|
|
} else if (itemId == R.id.subscription_display_list) {
|
|
setColumnNumber(1);
|
|
return true;
|
|
} else if (itemId == R.id.subscription_num_columns_2) {
|
|
setColumnNumber(2);
|
|
return true;
|
|
} else if (itemId == R.id.subscription_num_columns_3) {
|
|
setColumnNumber(3);
|
|
return true;
|
|
} else if (itemId == R.id.subscription_num_columns_4) {
|
|
setColumnNumber(4);
|
|
return true;
|
|
} else if (itemId == R.id.subscription_num_columns_5) {
|
|
setColumnNumber(5);
|
|
return true;
|
|
} else if (itemId == R.id.action_search) {
|
|
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance());
|
|
return true;
|
|
} else if (itemId == R.id.action_statistics) {
|
|
((MainActivity) getActivity()).loadChildFragment(new StatisticsFragment());
|
|
return true;
|
|
} else if (itemId == R.id.pref_show_subscription_title) {
|
|
item.setChecked(!item.isChecked());
|
|
UserPreferences.setShouldShowSubscriptionTitle(item.isChecked());
|
|
subscriptionAdapter.notifyDataSetChanged();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void setColumnNumber(int columns) {
|
|
if (itemDecoration != null) {
|
|
subscriptionRecycler.removeItemDecoration(itemDecoration);
|
|
itemDecoration = null;
|
|
}
|
|
RecyclerView.LayoutManager layoutManager;
|
|
if (columns == 1 && getDefaultNumOfColumns() == 5) { // Tablet
|
|
layoutManager = new GridLayoutManager(getContext(), 2, RecyclerView.VERTICAL, false);
|
|
} else if (columns == 1) {
|
|
layoutManager = new GridLayoutManager(getContext(), 1, RecyclerView.VERTICAL, false);
|
|
} else {
|
|
layoutManager = new GridLayoutManager(getContext(), columns, RecyclerView.VERTICAL, false);
|
|
itemDecoration = new SubscriptionsRecyclerAdapter.GridDividerItemDecorator();
|
|
subscriptionRecycler.addItemDecoration(itemDecoration);
|
|
}
|
|
subscriptionAdapter.setColumnCount(columns);
|
|
subscriptionRecycler.setLayoutManager(layoutManager);
|
|
prefs.edit().putInt(PREF_NUM_COLUMNS, columns).apply();
|
|
refreshToolbarState();
|
|
}
|
|
|
|
private void setupEmptyView() {
|
|
emptyView = new EmptyViewHandler(getContext());
|
|
emptyView.setIcon(R.drawable.ic_subscriptions);
|
|
emptyView.setTitle(R.string.no_subscriptions_head_label);
|
|
emptyView.setMessage(R.string.no_subscriptions_label);
|
|
emptyView.attachToRecyclerView(subscriptionRecycler);
|
|
}
|
|
|
|
@Override
|
|
public void onStart() {
|
|
super.onStart();
|
|
EventBus.getDefault().register(this);
|
|
loadSubscriptions();
|
|
}
|
|
|
|
@Override
|
|
public void onStop() {
|
|
super.onStop();
|
|
EventBus.getDefault().unregister(this);
|
|
if (disposable != null) {
|
|
disposable.dispose();
|
|
}
|
|
if (subscriptionAdapter != null) {
|
|
subscriptionAdapter.endSelectMode();
|
|
}
|
|
}
|
|
|
|
private void loadSubscriptions() {
|
|
if (disposable != null) {
|
|
disposable.dispose();
|
|
}
|
|
emptyView.hide();
|
|
disposable = Observable.fromCallable(
|
|
() -> {
|
|
NavDrawerData data = DBReader.getNavDrawerData(UserPreferences.getSubscriptionsFilter(),
|
|
UserPreferences.getFeedOrder(), UserPreferences.getFeedCounterSetting());
|
|
List<NavDrawerData.DrawerItem> items = data.items;
|
|
for (NavDrawerData.DrawerItem item : items) {
|
|
if (item.type == NavDrawerData.DrawerItem.Type.TAG
|
|
&& item.getTitle().equals(displayedFolder)) {
|
|
return ((NavDrawerData.TagDrawerItem) item).getChildren();
|
|
}
|
|
}
|
|
return items;
|
|
})
|
|
.subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(
|
|
result -> {
|
|
if (listItems != null && listItems.size() > result.size()) {
|
|
// We have fewer items. This can result in items being selected that are no longer visible.
|
|
subscriptionAdapter.endSelectMode();
|
|
}
|
|
listItems = result;
|
|
progressBar.setVisibility(View.GONE);
|
|
subscriptionAdapter.setItems(result);
|
|
emptyView.updateVisibility();
|
|
}, error -> {
|
|
Log.e(TAG, Log.getStackTraceString(error));
|
|
});
|
|
|
|
updateFilterVisibility();
|
|
}
|
|
|
|
private void updateFilterVisibility() {
|
|
if (subscriptionAdapter.inActionMode()) {
|
|
feedsFilteredMsg.setVisibility(View.INVISIBLE);
|
|
} else if (UserPreferences.getSubscriptionsFilter().isEnabled()) {
|
|
feedsFilteredMsg.setVisibility(View.VISIBLE);
|
|
} else {
|
|
feedsFilteredMsg.setVisibility(View.GONE);
|
|
}
|
|
}
|
|
|
|
private int getDefaultNumOfColumns() {
|
|
return getResources().getInteger(R.integer.subscriptions_default_num_of_columns);
|
|
}
|
|
|
|
@Override
|
|
public boolean onContextItemSelected(MenuItem item) {
|
|
NavDrawerData.DrawerItem drawerItem = subscriptionAdapter.getSelectedItem();
|
|
if (drawerItem == null) {
|
|
return false;
|
|
}
|
|
int itemId = item.getItemId();
|
|
if (drawerItem.type == NavDrawerData.DrawerItem.Type.TAG && itemId == R.id.rename_folder_item) {
|
|
new RenameFeedDialog(getActivity(), drawerItem).show();
|
|
return true;
|
|
}
|
|
|
|
Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
|
|
if (itemId == R.id.multi_select) {
|
|
return subscriptionAdapter.onContextItemSelected(item);
|
|
}
|
|
return FeedMenuHandler.onMenuItemClicked(this, item.getItemId(), feed, this::loadSubscriptions);
|
|
}
|
|
|
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
|
public void onFeedListChanged(FeedListUpdateEvent event) {
|
|
loadSubscriptions();
|
|
}
|
|
|
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
|
public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
|
|
loadSubscriptions();
|
|
}
|
|
|
|
@Override
|
|
public void onEndSelectMode() {
|
|
speedDialView.close();
|
|
speedDialView.setVisibility(View.GONE);
|
|
subscriptionAddButton.setVisibility(View.VISIBLE);
|
|
subscriptionAdapter.setItems(listItems);
|
|
updateFilterVisibility();
|
|
}
|
|
|
|
@Override
|
|
public void onStartSelectMode() {
|
|
List<NavDrawerData.DrawerItem> feedsOnly = new ArrayList<>();
|
|
for (NavDrawerData.DrawerItem item : listItems) {
|
|
if (item.type == NavDrawerData.DrawerItem.Type.FEED) {
|
|
feedsOnly.add(item);
|
|
}
|
|
}
|
|
subscriptionAdapter.setItems(feedsOnly);
|
|
speedDialView.setVisibility(View.VISIBLE);
|
|
subscriptionAddButton.setVisibility(View.GONE);
|
|
updateFilterVisibility();
|
|
}
|
|
}
|