/*
* Copyright (c) 2015, Nils Braden
*
* This file is part of ttrss-reader-fork. This program is free software; you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation;
* either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. You should have received a
* copy of the GNU General Public License along with this program; If
* not, see http://www.gnu.org/licenses/.
*/
package org.ttrssreader.gui;
import org.ttrssreader.R;
import org.ttrssreader.controllers.Controller;
import org.ttrssreader.controllers.Data;
import org.ttrssreader.gui.fragments.ArticleFragment;
import org.ttrssreader.gui.fragments.FeedHeadlineListFragment;
import org.ttrssreader.gui.fragments.FeedListFragment;
import org.ttrssreader.gui.fragments.MainListFragment;
import org.ttrssreader.utils.AsyncTask;
import org.ttrssreader.utils.Utils;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import java.util.List;
public class FeedHeadlineActivity extends MenuActivity {
@SuppressWarnings("unused")
private static final String TAG = FeedHeadlineActivity.class.getSimpleName();
public static final int FEED_NO_ID = 37846914;
private int categoryId = Integer.MIN_VALUE;
private int feedId = Integer.MIN_VALUE;
private boolean selectArticlesForCategory = false;
private FeedHeadlineUpdater headlineUpdater = null;
private int articleId = Integer.MIN_VALUE;
@Override
protected void onCreate(Bundle instance) {
super.onCreate(instance);
Bundle extras = getIntent().getExtras();
if (instance != null) {
categoryId = instance.getInt(FeedHeadlineListFragment.FEED_CAT_ID);
feedId = instance.getInt(FeedHeadlineListFragment.FEED_ID);
selectArticlesForCategory = instance.getBoolean(FeedHeadlineListFragment.FEED_SELECT_ARTICLES);
articleId = instance.getInt(FeedHeadlineListFragment.ARTICLE_ID, Integer.MIN_VALUE);
} else if (extras != null) {
categoryId = extras.getInt(FeedHeadlineListFragment.FEED_CAT_ID);
feedId = extras.getInt(FeedHeadlineListFragment.FEED_ID);
selectArticlesForCategory = extras.getBoolean(FeedHeadlineListFragment.FEED_SELECT_ARTICLES);
articleId = extras.getInt(FeedHeadlineListFragment.ARTICLE_ID, Integer.MIN_VALUE);
}
FragmentManager fm = getFragmentManager();
FeedListFragment feedFragment = (FeedListFragment) fm.findFragmentByTag(FeedListFragment.FRAGMENT);
if (feedFragment == null) {
feedFragment = FeedListFragment.newInstance(categoryId);
fm.beginTransaction().add(R.id.frame_invisible, feedFragment, FeedListFragment.FRAGMENT).commit();
}
FeedHeadlineListFragment headlineFragment = (FeedHeadlineListFragment) fm
.findFragmentByTag(FeedHeadlineListFragment.FRAGMENT);
if (headlineFragment == null) {
displayFeed(feedId, 0);
}
}
@Override
protected int getLayoutResource() {
return R.layout.main;
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(FeedHeadlineListFragment.FEED_CAT_ID, categoryId);
outState.putInt(FeedHeadlineListFragment.FEED_ID, feedId);
outState.putBoolean(FeedHeadlineListFragment.FEED_SELECT_ARTICLES, selectArticlesForCategory);
outState.putInt(FeedHeadlineListFragment.ARTICLE_ID, articleId);
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle instance) {
categoryId = instance.getInt(FeedHeadlineListFragment.FEED_CAT_ID);
feedId = instance.getInt(FeedHeadlineListFragment.FEED_ID);
selectArticlesForCategory = instance.getBoolean(FeedHeadlineListFragment.FEED_SELECT_ARTICLES);
articleId = instance.getInt(FeedHeadlineListFragment.ARTICLE_ID, Integer.MIN_VALUE);
super.onRestoreInstanceState(instance);
}
@Override
public void dataLoadingFinished() {
setTitleAndUnread();
}
@Override
protected void doRefresh() {
super.doRefresh();
FeedHeadlineListFragment headlineFragment = (FeedHeadlineListFragment) getFragmentManager()
.findFragmentByTag(FeedHeadlineListFragment.FRAGMENT);
if (headlineFragment != null) headlineFragment.doRefresh();
setTitleAndUnread();
}
private void setTitleAndUnread() {
// Title and unread information:
FeedHeadlineListFragment headlineFragment = (FeedHeadlineListFragment) getFragmentManager()
.findFragmentByTag(FeedHeadlineListFragment.FRAGMENT);
if (headlineFragment != null) {
setTitle(headlineFragment.getTitle());
setUnread(headlineFragment.getUnread());
}
}
@Override
protected void onResume() {
super.onResume();
showBackArrow();
}
@Override
protected void doUpdate(boolean forceUpdate) {
// Only update if no headlineUpdater already running
if (headlineUpdater != null) {
if (headlineUpdater.getStatus().equals(AsyncTask.Status.FINISHED)) {
headlineUpdater = null;
} else {
return;
}
}
if (Data.getInstance().isConnected()) {
if (!isCacherRunning()) {
headlineUpdater = new FeedHeadlineUpdater(forceUpdate);
headlineUpdater.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (articleId != Integer.MIN_VALUE) {
getMenuInflater().inflate(R.menu.article, menu);
if (Controller.isTablet) super.onCreateOptionsMenu(menu);
} else {
super.onCreateOptionsMenu(menu);
}
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.removeItem(R.id.Menu_MarkAllRead);
menu.removeItem(R.id.Menu_MarkFeedsRead);
return super.onPrepareOptionsMenu(menu);
}
@Override
public final boolean onOptionsItemSelected(final MenuItem item) {
if (super.onOptionsItemSelected(item)) return true;
switch (item.getItemId()) {
case R.id.Menu_Refresh: {
doUpdate(true);
return true;
}
default:
return false;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (Controller.getInstance().useVolumeKeys()) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_N) {
openNextFragment(-1);
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_B) {
openNextFragment(1);
return true;
}
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (Controller.getInstance().useVolumeKeys()) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP
|| keyCode == KeyEvent.KEYCODE_N || keyCode == KeyEvent.KEYCODE_B) {
return true;
}
}
return super.onKeyUp(keyCode, event);
}
private void openNextFragment(int direction) {
if (articleId != Integer.MIN_VALUE) {
openNextArticle(direction);
} else {
openNextFeed(direction);
}
}
public void openNextFeed(int direction) {
FeedListFragment feedFragment = (FeedListFragment) getFragmentManager()
.findFragmentByTag(FeedListFragment.FRAGMENT);
int newId = findNext(feedFragment.getFeedIds(), feedId, direction);
if (newId == Integer.MIN_VALUE) {
Utils.alert(this, true);
return;
}
displayFeed(newId, direction);
}
public void openNextArticle(int direction) {
FeedHeadlineListFragment headlineFragment = (FeedHeadlineListFragment) getFragmentManager()
.findFragmentByTag(FeedHeadlineListFragment.FRAGMENT);
int newId = findNext(headlineFragment.getArticleIds(), articleId, direction);
if (newId == Integer.MIN_VALUE) {
Utils.alert(this, true);
return;
}
displayArticle(newId, direction);
}
protected static int findNext(List<Integer> list, int current, int direction) {
int[] ids = getNextPrevIds(list, current);
return (direction < 0) ? ids[0] : ids[1];
}
protected static int[] getNextPrevIds(List<Integer> list, Integer search) {
int index = list.indexOf(search);
if (index < 0) return new int[] {Integer.MIN_VALUE, Integer.MIN_VALUE};
int prev = 0 <= (index - 1) ? list.get(index - 1) : Integer.MIN_VALUE;
int next = list.size() > (index + 1) ? list.get(index + 1) : Integer.MIN_VALUE;
return new int[] {prev, next};
}
/**
* Updates all articles from the selected feed.
*/
private class FeedHeadlineUpdater extends ActivityUpdater {
private static final int DEFAULT_TASK_COUNT = 1;
private FeedHeadlineUpdater(boolean forceUpdate) {
super(forceUpdate);
}
@Override
protected Void doInBackground(Void... params) {
taskCount = DEFAULT_TASK_COUNT;
boolean displayUnread = Controller.getInstance().onlyUnread();
int progress = 0;
publishProgress(progress);
if (selectArticlesForCategory) {
Data.getInstance().updateArticles(categoryId, displayUnread, true, false, forceUpdate);
} else {
Data.getInstance().updateArticles(feedId, displayUnread, false, false, forceUpdate);
}
publishProgress(++progress);
Data.getInstance().calculateCounters();
Data.getInstance().notifyListeners();
publishProgress(Integer.MAX_VALUE); // Move progress forward to 100%
return null;
}
}
@Override
public void itemSelected(MainListFragment source, int selectedId) {
switch (source.getType()) {
case FEEDHEADLINE:
displayArticle(selectedId, 0);
break;
}
}
private void displayFeed(int newFeedId, int direction) {
if (mOnSaveInstanceStateCalled) {
Log.w(TAG, "displayFeed() has been called after onSaveInstanceState(), this call has been supressed!");
Toast.makeText(this,
"displayFeed() has been called after onSaveInstanceState(), this call has been supressed!",
Toast.LENGTH_SHORT).show();
return;
}
feedId = newFeedId;
FeedHeadlineListFragment headlineFragment = FeedHeadlineListFragment
.newInstance(feedId, categoryId, selectArticlesForCategory);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
setAnimationForDirection(ft, direction);
ft.setTransition(FragmentTransaction.TRANSIT_NONE);
if (direction == 0) ft.add(R.id.frame_main, headlineFragment, FeedHeadlineListFragment.FRAGMENT).commit();
else ft.replace(R.id.frame_main, headlineFragment, FeedHeadlineListFragment.FRAGMENT).commit();
// Check if a next feed in this direction exists
if (direction != 0) {
FeedListFragment feedFragment = (FeedListFragment) fm.findFragmentByTag(FeedListFragment.FRAGMENT);
if (findNext(feedFragment.getFeedIds(), feedId, direction) == Integer.MIN_VALUE) {
Utils.alert(this);
}
}
}
private void displayArticle(int newArticleId, int direction) {
if (mOnSaveInstanceStateCalled) {
Log.w(TAG, "displayArticle() has been called after onSaveInstanceState(), this call has been supressed!");
Toast.makeText(this,
"displayArticle() has been called after onSaveInstanceState(), this call has been supressed!",
Toast.LENGTH_SHORT).show();
return;
}
articleId = newArticleId;
FeedHeadlineListFragment headlineFragment = (FeedHeadlineListFragment) getFragmentManager()
.findFragmentByTag(FeedHeadlineListFragment.FRAGMENT);
headlineFragment.setSelectedId(articleId);
FragmentManager fm = getFragmentManager();
// Clear back stack
Controller.sFragmentAnimationDirection = direction;
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
ArticleFragment articleFragment = ArticleFragment
.newInstance(articleId, feedId, categoryId, selectArticlesForCategory, direction);
FragmentTransaction ft = fm.beginTransaction();
if (!Controller.isTablet) ft.addToBackStack(null);
setAnimationForDirection(ft, direction);
ft.setTransition(FragmentTransaction.TRANSIT_NONE);
ft.replace(R.id.frame_sub, articleFragment, ArticleFragment.FRAGMENT).commit();
// Check if a next feed in this direction exists
if (direction != 0) {
if (findNext(headlineFragment.getArticleIds(), articleId, direction) == Integer.MIN_VALUE) {
Utils.alert(this);
}
}
}
private static FragmentTransaction setAnimationForDirection(final FragmentTransaction ft, final int direction) {
if (Controller.getInstance().animations()) {
if (direction >= 0) ft.setCustomAnimations(R.animator.slide_in_right, R.animator.slide_out_left);
else ft.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right);
}
return ft;
}
@Override
public void onBackPressed() {
articleId = Integer.MIN_VALUE;
/* Back button automatically finishes the activity since Lollipop so we have to work around by checking the
backstack before */
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
public int getCategoryId() {
return categoryId;
}
public int getFeedId() {
return feedId;
}
}