implement feedlist serialization and proper restoring of

feedlist/login status on orientation change
This commit is contained in:
Andrew Dolgov 2011-11-25 13:13:10 +03:00
parent 44147c17aa
commit ccb6b1cb5f
6 changed files with 163 additions and 115 deletions

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="x"
android:valueType="floatType"
android:valueFrom="1280"
android:valueTo="0"
android:duration="500"/>
</set>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="x"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="1280"
android:duration="500"/>
</set>

View File

@ -1,6 +1,9 @@
package org.fox.ttrss; package org.fox.ttrss;
public class Feed implements Comparable<Feed> { import android.os.Parcel;
import android.os.Parcelable;
public class Feed implements Comparable<Feed>, Parcelable {
String feed_url; String feed_url;
String title; String title;
int id; int id;
@ -16,4 +19,30 @@ public class Feed implements Comparable<Feed> {
else else
return this.title.compareTo(feed.title); return this.title.compareTo(feed.title);
} }
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(feed_url);
out.writeString(title);
out.writeInt(id);
out.writeInt(unread);
out.writeInt(has_icon ? 1 : 0);
out.writeInt(cat_id);
out.writeInt(last_updated);
}
public void readFromParcel(Parcel in) {
feed_url = in.readString();
title = in.readString();
id = in.readInt();
unread = in.readInt();
has_icon = in.readInt() == 1;
cat_id = in.readInt();
last_updated = in.readInt();
}
} }

View File

@ -11,7 +11,10 @@ import android.app.Fragment;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -31,10 +34,36 @@ public class FeedsFragment extends Fragment implements OnItemClickListener {
private final String TAG = this.getClass().getSimpleName(); private final String TAG = this.getClass().getSimpleName();
private SharedPreferences m_prefs; private SharedPreferences m_prefs;
private FeedListAdapter m_adapter; private FeedListAdapter m_adapter;
private List<Feed> m_feeds = new ArrayList<Feed>(); private FeedList m_feeds = new FeedList();
private OnFeedSelectedListener m_feedSelectedListener; private OnFeedSelectedListener m_feedSelectedListener;
private int m_selectedFeedId; private int m_selectedFeedId;
private class FeedList extends ArrayList<Feed> implements Parcelable {
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(this.size());
for (Feed feed : this) {
out.writeParcelable(feed, flags);
}
}
public void readFromParcel(Parcel in) {
int length = in.readInt();
for (int i = 0; i < length; i++) {
Feed feed = in.readParcelable(Feed.class.getClassLoader());
this.add(feed);
}
}
}
public interface OnFeedSelectedListener { public interface OnFeedSelectedListener {
public void onFeedSelected(Feed feed); public void onFeedSelected(Feed feed);
} }
@ -54,8 +83,8 @@ public class FeedsFragment extends Fragment implements OnItemClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (savedInstanceState != null) { if (savedInstanceState != null) {
//m_sessionId = savedInstanceState.getString("sessionId"); m_selectedFeedId = savedInstanceState.getInt("selectedFeedId");
//m_activeFeedId = savedInstanceState.getInt("activeFeedId"); m_feeds = savedInstanceState.getParcelable("feeds");
} }
View view = inflater.inflate(R.layout.feeds_fragment, container, false); View view = inflater.inflate(R.layout.feeds_fragment, container, false);
@ -63,11 +92,12 @@ public class FeedsFragment extends Fragment implements OnItemClickListener {
ListView list = (ListView)view.findViewById(R.id.feeds); ListView list = (ListView)view.findViewById(R.id.feeds);
m_adapter = new FeedListAdapter(getActivity(), R.layout.feeds_row, (ArrayList<Feed>)m_feeds); m_adapter = new FeedListAdapter(getActivity(), R.layout.feeds_row, (ArrayList<Feed>)m_feeds);
list.setAdapter(m_adapter); list.setAdapter(m_adapter);
//list.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
list.setOnItemClickListener(this); list.setOnItemClickListener(this);
//if (m_sessionId != null) if (m_feeds == null || m_feeds.size() == 0)
refresh(); refresh();
else
view.findViewById(R.id.loading_container).setVisibility(View.GONE);
return view; return view;
} }
@ -83,17 +113,14 @@ public class FeedsFragment extends Fragment implements OnItemClickListener {
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
m_feedSelectedListener = (OnFeedSelectedListener) activity; m_feedSelectedListener = (OnFeedSelectedListener) activity;
//m_sessionId = ((MainActivity)activity).getSessionId();
} }
@Override @Override
public void onSaveInstanceState (Bundle out) { public void onSaveInstanceState (Bundle out) {
super.onSaveInstanceState(out); super.onSaveInstanceState(out);
//out.putString("sessionId", m_sessionId); out.putInt("selectedFeedId", m_selectedFeedId);
//out.putInt("activeFeedId", m_activeFeedId); out.putParcelable("feeds", m_feeds);
} }
@Override @Override
@ -187,13 +214,10 @@ public class FeedsFragment extends Fragment implements OnItemClickListener {
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
// report invalid object received
MainActivity ma = (MainActivity)getActivity();
ma.toast("Error parsing feedlist: incorrect format");
} }
} else { } else {
MainActivity ma = (MainActivity)getActivity(); // report null object received
ma.toast("Error parsing feedlist: null object.");
} }
return; return;

View File

@ -59,7 +59,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener {
if (savedInstanceState != null) { if (savedInstanceState != null) {
//m_sessionId = savedInstanceState.getString("sessionId"); //m_sessionId = savedInstanceState.getString("sessionId");
//m_feedId = savedInstanceState.getInt("feedId");
m_feed = savedInstanceState.getParcelable("feed");
//m_activeArticleId = savedInstanceState.getInt("activeArticleId"); //m_activeArticleId = savedInstanceState.getInt("activeArticleId");
} }
@ -70,6 +71,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener {
list.setAdapter(m_adapter); list.setAdapter(m_adapter);
list.setOnItemClickListener(this); list.setOnItemClickListener(this);
Log.d(TAG, "onCreateView, feed=" + m_feed);
if (m_feed != null) if (m_feed != null)
refresh(); refresh();
else else
@ -140,6 +143,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener {
public void onSaveInstanceState (Bundle out) { public void onSaveInstanceState (Bundle out) {
super.onSaveInstanceState(out); super.onSaveInstanceState(out);
out.putParcelable("feed", m_feed);
//out.putString("sessionId", m_sessionId); //out.putString("sessionId", m_sessionId);
//out.putInt("feedId", m_feedId); //out.putInt("feedId", m_feedId);
//out.putInt("activeArticleId", m_activeArticleId); //out.putInt("activeArticleId", m_activeArticleId);
@ -182,13 +187,10 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener {
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
// report invalid object
MainActivity ma = (MainActivity)getActivity();
ma.toast("Error parsing headlines: incorrect format");
} }
} else { } else {
MainActivity ma = (MainActivity)getActivity(); // report null object
ma.toast("Error parsing headlines: null object.");
} }
return; return;

View File

@ -11,6 +11,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.method.HideReturnsTransformationMethod;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
@ -41,15 +42,15 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
@Override @Override
public void run() { public void run() {
Log.d(TAG, "Refreshing feeds...");
refreshFeeds(); refreshFeeds();
} }
} }
public synchronized void refreshFeeds() { public synchronized void refreshFeeds() {
FeedsFragment frag = (FeedsFragment) getFragmentManager().findFragmentById(R.id.feeds_fragment); FeedsFragment frag = (FeedsFragment) getFragmentManager().findFragmentById(R.id.feeds_fragment);
Log.d(TAG, "Refreshing feeds..." + frag);
if (frag != null) { if (frag != null) {
frag.refresh(); frag.refresh();
} }
@ -72,11 +73,6 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
/** Called when the activity is first created. */ /** Called when the activity is first created. */
public void toast(String message) {
Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT);
toast.show();
}
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -93,6 +89,8 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
if (savedInstanceState != null) { if (savedInstanceState != null) {
m_sessionId = savedInstanceState.getString("sessionId"); m_sessionId = savedInstanceState.getString("sessionId");
m_unreadOnly = savedInstanceState.getBoolean("unreadOnly");
m_activeFeed = savedInstanceState.getParcelable("activeFeed");
} }
setContentView(R.layout.main); setContentView(R.layout.main);
@ -101,19 +99,14 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
LinearLayout layout = (LinearLayout)findViewById(R.id.main); LinearLayout layout = (LinearLayout)findViewById(R.id.main);
layout.setLayoutTransition(transitioner); layout.setLayoutTransition(transitioner);
HeadlinesFragment hf = new HeadlinesFragment();
ArticleFragment af = new ArticleFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
ft.replace(R.id.feeds_fragment, new FeedsFragment());
ft.replace(R.id.headlines_fragment, hf);
ft.replace(R.id.article_fragment, af);
ft.commit();
findViewById(R.id.article_fragment).setVisibility(View.GONE); findViewById(R.id.article_fragment).setVisibility(View.GONE);
login(); if (m_sessionId != null) {
// restarting, TODO set update timers here?
loginSuccess();
} else {
login();
}
} }
@ -136,6 +129,9 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
super.onSaveInstanceState(out); super.onSaveInstanceState(out);
out.putString("sessionId", m_sessionId); out.putString("sessionId", m_sessionId);
out.putBoolean("unreadOnly", m_unreadOnly);
out.putParcelable("activeFeed", m_activeFeed);
} }
@Override @Override
@ -170,6 +166,8 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
inflater.inflate(R.menu.main_menu, menu); inflater.inflate(R.menu.main_menu, menu);
m_menu = menu; m_menu = menu;
initMainMenu();
return true; return true;
} }
@ -240,6 +238,52 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
m_selectedArticle = null; m_selectedArticle = null;
} }
private void initMainMenu() {
if (m_menu != null) {
if (m_sessionId != null) {
m_menu.findItem(R.id.login).setVisible(false);
m_menu.findItem(R.id.logout).setVisible(true);
m_menu.findItem(R.id.update_feeds).setEnabled(true);
m_menu.findItem(R.id.show_feeds).setEnabled(true);
} else {
m_menu.findItem(R.id.login).setVisible(true);
m_menu.findItem(R.id.logout).setVisible(false);
m_menu.findItem(R.id.close_article).setVisible(false);
m_menu.findItem(R.id.share_article).setVisible(false);
m_menu.findItem(R.id.update_feeds).setEnabled(false);
m_menu.findItem(R.id.show_feeds).setEnabled(false);
}
}
}
private void loginSuccess() {
findViewById(R.id.loading_container).setVisibility(View.INVISIBLE);
findViewById(R.id.main).setVisibility(View.VISIBLE);
initMainMenu();
if (m_refreshTask != null) {
m_refreshTask.cancel();
m_refreshTask = null;
}
if (m_refreshTimer != null) {
m_refreshTimer.cancel();
m_refreshTimer = null;
}
m_refreshTask = new RefreshTask();
m_refreshTimer = new Timer("Refresh");
m_refreshTimer.schedule(m_refreshTask, 60*1000L, 60*1000L);
}
private class LoginRequest extends ApiRequest { private class LoginRequest extends ApiRequest {
@ -255,39 +299,18 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
if (content != null) { if (content != null) {
m_sessionId = content.get("session_id").getAsString(); m_sessionId = content.get("session_id").getAsString();
Log.d(TAG, "Authenticated!");
setLoadingStatus(R.string.loading_message, true); setLoadingStatus(R.string.loading_message, true);
findViewById(R.id.loading_container).setVisibility(View.INVISIBLE);
findViewById(R.id.main).setVisibility(View.VISIBLE);
FeedsFragment frag = new FeedsFragment(); FeedsFragment frag = new FeedsFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction(); FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.feeds_fragment, frag); ft.replace(R.id.feeds_fragment, frag);
ft.show(frag);
ft.commit(); ft.commit();
m_menu.findItem(R.id.login).setVisible(false); loginSuccess();
m_menu.findItem(R.id.logout).setVisible(true);
m_menu.findItem(R.id.update_feeds).setEnabled(true);
m_menu.findItem(R.id.show_feeds).setEnabled(true);
if (m_refreshTask != null) {
m_refreshTask.cancel();
m_refreshTask = null;
}
if (m_refreshTimer != null) {
m_refreshTimer.cancel();
m_refreshTimer = null;
}
m_refreshTask = new RefreshTask();
m_refreshTimer = new Timer("Refresh");
m_refreshTimer.schedule(m_refreshTask, 60*1000L, 60*1000L);
} }
} else { } else {
JsonObject content = rv.get("content").getAsJsonObject(); JsonObject content = rv.get("content").getAsJsonObject();
@ -318,37 +341,30 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
@Override @Override
public void onFeedSelected(Feed feed) { public void onFeedSelected(Feed feed) {
Log.d(TAG, "Selected feed: " + feed.toString()); Log.d(TAG, "Selected feed: " + feed.toString());
viewFeed(feed);
m_activeFeed = feed;
HeadlinesFragment hf = new HeadlinesFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
//ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
ft.show(getFragmentManager().findFragmentById(R.id.headlines_fragment));
ft.replace(R.id.headlines_fragment, hf);
ft.addToBackStack(null);
ft.commit();
} }
public Article getSelectedArticle() { public Article getSelectedArticle() {
return m_selectedArticle; return m_selectedArticle;
} }
@Override public void viewFeed(Feed feed) {
public void onArticleSelected(Article article) { m_activeFeed = feed;
Log.d(TAG, "Selected article: " + article.toString());
HeadlinesFragment hf = new HeadlinesFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.headlines_fragment, hf);
ft.commit();
}
public void openArticle(Article article) {
m_selectedArticle = article; m_selectedArticle = article;
ArticleFragment frag = new ArticleFragment(); ArticleFragment frag = new ArticleFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction(); FragmentTransaction ft = getFragmentManager().beginTransaction();
//ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
//ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
ft.show(getFragmentManager().findFragmentById(R.id.article_fragment));
ft.replace(R.id.article_fragment, frag); ft.replace(R.id.article_fragment, frag);
ft.addToBackStack(null);
ft.commit(); ft.commit();
findViewById(R.id.feeds_fragment).setVisibility(View.GONE); findViewById(R.id.feeds_fragment).setVisibility(View.GONE);
@ -358,7 +374,11 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
m_menu.findItem(R.id.close_article).setVisible(true); m_menu.findItem(R.id.close_article).setVisible(true);
m_menu.findItem(R.id.share_article).setVisible(true); m_menu.findItem(R.id.share_article).setVisible(true);
} }
}
@Override
public void onArticleSelected(Article article) {
openArticle(article);
} }
public Feed getActiveFeed() { public Feed getActiveFeed() {
@ -368,17 +388,8 @@ public class MainActivity extends Activity implements FeedsFragment.OnFeedSelect
public void logout() { public void logout() {
findViewById(R.id.loading_container).setVisibility(View.VISIBLE); findViewById(R.id.loading_container).setVisibility(View.VISIBLE);
findViewById(R.id.main).setVisibility(View.INVISIBLE); findViewById(R.id.main).setVisibility(View.INVISIBLE);
if (m_menu != null) { initMainMenu();
m_menu.findItem(R.id.login).setVisible(true);
m_menu.findItem(R.id.logout).setVisible(false);
m_menu.findItem(R.id.close_article).setVisible(false);
m_menu.findItem(R.id.share_article).setVisible(false);
m_menu.findItem(R.id.update_feeds).setEnabled(false);
m_menu.findItem(R.id.show_feeds).setEnabled(false);
}
if (m_refreshTask != null) { if (m_refreshTask != null) {
m_refreshTask.cancel(); m_refreshTask.cancel();