From e0c40e5fb8b9c9ca72a5bb306593565c22e1f804 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Wed, 23 Nov 2011 13:55:05 +0300 Subject: implement headlines view --- src/org/fox/ttrss/FeedsFragment.java | 176 +++++++++++++++++++++++++++++-- src/org/fox/ttrss/HeadlinesFragment.java | 176 +++++++++++++++++++++++++++++-- src/org/fox/ttrss/MainActivity.java | 65 ++++++------ 3 files changed, 366 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/org/fox/ttrss/FeedsFragment.java b/src/org/fox/ttrss/FeedsFragment.java index 30173a6c..56c42de0 100644 --- a/src/org/fox/ttrss/FeedsFragment.java +++ b/src/org/fox/ttrss/FeedsFragment.java @@ -1,40 +1,54 @@ package org.fox.ttrss; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + import android.app.Activity; import android.app.Fragment; -import android.app.FragmentTransaction; +import android.app.FragmentManager; import android.content.Context; import android.content.SharedPreferences; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.preference.PreferenceManager; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; import android.widget.ListView; -import android.widget.SimpleCursorAdapter; +import android.widget.TextView; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; public class FeedsFragment extends Fragment implements OnItemClickListener { private final String TAG = this.getClass().getSimpleName(); private SharedPreferences m_prefs; private String m_sessionId; + private FeedListAdapter m_adapter; + private List m_feeds = new ArrayList(); @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (savedInstanceState != null) { + m_sessionId = savedInstanceState.getString("sessionId"); //m_activeFeedId = savedInstanceState.getInt("activeFeedId"); } View view = inflater.inflate(R.layout.feeds_fragment, container, false); - - + ListView list = (ListView)view.findViewById(R.id.feeds); + m_adapter = new FeedListAdapter(getActivity(), R.layout.feeds_row, (ArrayList)m_feeds); + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + return view; } @@ -49,15 +63,27 @@ public class FeedsFragment extends Fragment implements OnItemClickListener { m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); } - @Override + @Override public void onSaveInstanceState (Bundle out) { super.onSaveInstanceState(out); - //out.putInt("activeFeedId", m_activeFeedId); + out.putString("sessionId", m_sessionId); } @Override public void onItemClick(AdapterView av, View view, int position, long id) { + ListView list = (ListView)av; + + if (list != null) { + Feed feed = (Feed)list.getItemAtPosition(position); + + FragmentManager fm = getFragmentManager(); + HeadlinesFragment hf = (HeadlinesFragment) fm.findFragmentById(R.id.headlines_fragment); + + if (hf != null) { + hf.initialize(m_sessionId, feed.id); + } + } } public void initialize(String sessionId) { @@ -67,8 +93,138 @@ public class FeedsFragment extends Fragment implements OnItemClickListener { } public void refresh() { + FeedsRequest fr = new FeedsRequest(); + fr.setApi(m_prefs.getString("ttrss_url", null)); + + HashMap map = new HashMap() { + { + put("op", "getFeeds"); + put("sid", m_sessionId); + put("cat_id", "-3"); + put("unread_only", "true"); + } + }; + + fr.execute(map); + } + + public void setLoadingStatus(int status, boolean showProgress) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + View pb = getView().findViewById(R.id.loading_progress); + + if (pb != null) { + pb.setVisibility(showProgress ? View.VISIBLE : View.GONE); + } + } + + private class FeedsRequest extends ApiRequest { + + protected void onPostExecute(JsonElement result) { + if (result != null) { + try { + JsonObject rv = result.getAsJsonObject(); + Gson gson = new Gson(); + + int status = rv.get("status").getAsInt(); + + if (status == 0) { + JsonArray content = rv.get("content").getAsJsonArray(); + if (content != null) { + Type listType = new TypeToken>() {}.getType(); + final List feeds = gson.fromJson(content, listType); + + getActivity().runOnUiThread(new Runnable() { + public void run() { + m_feeds.clear(); + + for (Feed f : feeds) + m_feeds.add(f); + + m_adapter.notifyDataSetInvalidated(); + + View v = getView().findViewById(R.id.loading_container); + v.setVisibility(View.GONE); + } + }); + } + } else { + JsonObject content = rv.get("content").getAsJsonObject(); + + if (content != null) { + String error = content.get("error").getAsString(); + + /* m_sessionId = null; + + if (error.equals("LOGIN_ERROR")) { + setLoadingStatus(R.string.login_wrong_password, false); + } else if (error.equals("API_DISABLED")) { + setLoadingStatus(R.string.login_api_disabled, false); + } else { + setLoadingStatus(R.string.login_failed, false); + } */ + + // TODO report error back to MainActivity + } + } + } catch (Exception e) { + e.printStackTrace(); + + MainActivity ma = (MainActivity)getActivity(); + ma.toast("Error parsing feedlist: incorrect format"); + } + } else { + MainActivity ma = (MainActivity)getActivity(); + ma.toast("Error parsing feedlist: null object."); + } + + return; + + } + } + + private class FeedListAdapter extends ArrayAdapter { + private ArrayList items; + + public FeedListAdapter(Context context, int textViewResourceId, ArrayList items) { + super(context, textViewResourceId, items); + this.items = items; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + View v = convertView; + + Feed feed = items.get(position); + + if (v == null) { + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(R.layout.feeds_row, null); + } + + TextView tt = (TextView) v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(feed.title); + //tt.setTextAppearance(getContext(), R.style.Connection); + } + + TextView tu = (TextView) v.findViewById(R.id.unread_counter); + + if (tu != null) { + tu.setText(String.valueOf(feed.unread)); + tu.setVisibility((feed.unread > 0) ? View.VISIBLE : View.INVISIBLE); + } + + return v; + } } + } diff --git a/src/org/fox/ttrss/HeadlinesFragment.java b/src/org/fox/ttrss/HeadlinesFragment.java index 9eb54c5f..6d14d55b 100644 --- a/src/org/fox/ttrss/HeadlinesFragment.java +++ b/src/org/fox/ttrss/HeadlinesFragment.java @@ -1,32 +1,58 @@ package org.fox.ttrss; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.jsoup.Jsoup; + import android.app.Activity; import android.app.Fragment; -import android.app.FragmentTransaction; +import android.content.Context; import android.content.SharedPreferences; -import android.database.Cursor; import android.os.Bundle; import android.preference.PreferenceManager; -import android.provider.OpenableColumns; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; import android.widget.ListView; -import android.widget.SimpleCursorAdapter; +import android.widget.TextView; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; public class HeadlinesFragment extends Fragment implements OnItemClickListener { private final String TAG = this.getClass().getSimpleName(); protected SharedPreferences m_prefs; + private String m_sessionId; + private int m_feedId; + + private ArticleListAdapter m_adapter; + private List
m_articles = new ArrayList
(); + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (savedInstanceState != null) { + m_sessionId = savedInstanceState.getString("sessionId"); + m_feedId = savedInstanceState.getInt("feedId"); + } + View view = inflater.inflate(R.layout.headlines_fragment, container, false); + ListView list = (ListView)view.findViewById(R.id.headlines); + m_adapter = new ArticleListAdapter(getActivity(), R.layout.headlines_row, (ArrayList
)m_articles); + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + return view; } @@ -39,13 +65,149 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { @Override public void onItemClick(AdapterView av, View view, int position, long id) { + + } + + public void initialize(String sessionId, int feedId) { + m_sessionId = sessionId; + m_feedId = feedId; + refresh(); + } + + public void refresh() { + HeadlinesRequest req = new HeadlinesRequest(); + req.setApi(m_prefs.getString("ttrss_url", null)); + + HashMap map = new HashMap() { + { + put("op", "getHeadlines"); + put("sid", m_sessionId); + put("feed_id", String.valueOf(m_feedId)); + put("show_content", "true"); + put("limit", String.valueOf(30)); + put("offset", String.valueOf(0)); + put("view_mode", "adaptive"); + } + }; + + req.execute(map); } @Override - public void onSaveInstanceState (Bundle out) { + public void onSaveInstanceState (Bundle out) { super.onSaveInstanceState(out); + out.putString("sessionId", m_sessionId); + out.putInt("feedId", m_feedId); + } + + private class HeadlinesRequest extends ApiRequest { + + protected void onPostExecute(JsonElement result) { + if (result != null) { + try { + JsonObject rv = result.getAsJsonObject(); + + Gson gson = new Gson(); + + int status = rv.get("status").getAsInt(); + + if (status == 0) { + JsonArray content = rv.get("content").getAsJsonArray(); + if (content != null) { + Type listType = new TypeToken>() {}.getType(); + final List
articles = gson.fromJson(content, listType); + + getActivity().runOnUiThread(new Runnable() { + public void run() { + m_articles.clear(); + + for (Article f : articles) + m_articles.add(f); + + m_adapter.notifyDataSetInvalidated(); + + View v = getView().findViewById(R.id.loading_container); + v.setVisibility(View.GONE); + } + }); + } + } else { + JsonObject content = rv.get("content").getAsJsonObject(); + + if (content != null) { + String error = content.get("error").getAsString(); + + /* m_sessionId = null; + + if (error.equals("LOGIN_ERROR")) { + setLoadingStatus(R.string.login_wrong_password, false); + } else if (error.equals("API_DISABLED")) { + setLoadingStatus(R.string.login_api_disabled, false); + } else { + setLoadingStatus(R.string.login_failed, false); + } */ + + // TODO report error back to MainActivity + } + } + } catch (Exception e) { + e.printStackTrace(); + + MainActivity ma = (MainActivity)getActivity(); + ma.toast("Error parsing headlines: incorrect format"); + } + } else { + MainActivity ma = (MainActivity)getActivity(); + ma.toast("Error parsing headlines: null object."); + } + + return; + + } + } + + private class ArticleListAdapter extends ArrayAdapter
{ + private ArrayList
items; + + public ArticleListAdapter(Context context, int textViewResourceId, ArrayList
items) { + super(context, textViewResourceId, items); + this.items = items; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + View v = convertView; + + Article article = items.get(position); + + if (v == null) { + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(R.layout.headlines_row, null); + } + + TextView tt = (TextView) v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(article.title); + //tt.setTextAppearance(getContext(), R.style.Connection); + } + + TextView te = (TextView) v.findViewById(R.id.excerpt); + + if (te != null) { + String excerpt = Jsoup.parse(article.content).text(); + + if (excerpt.length() > 250) + excerpt = excerpt.substring(0, 250) + "..."; + + te.setText(excerpt); + } + + return v; + } } } diff --git a/src/org/fox/ttrss/MainActivity.java b/src/org/fox/ttrss/MainActivity.java index 0429fc47..1606033c 100644 --- a/src/org/fox/ttrss/MainActivity.java +++ b/src/org/fox/ttrss/MainActivity.java @@ -1,38 +1,25 @@ package org.fox.ttrss; -import java.lang.reflect.Type; import java.util.HashMap; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import org.jsoup.Jsoup; - -import android.animation.LayoutTransition; import android.app.Activity; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Intent; import android.content.SharedPreferences; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteStatement; import android.os.Bundle; import android.preference.PreferenceManager; -import android.provider.BaseColumns; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import android.widget.ViewFlipper; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.reflect.TypeToken; public class MainActivity extends Activity { private final String TAG = this.getClass().getSimpleName(); @@ -49,6 +36,11 @@ public class MainActivity extends Activity { /** Called when the activity is first created. */ + public void toast(String message) { + Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT); + toast.show(); + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -66,13 +58,31 @@ public class MainActivity extends Activity { if (savedInstanceState != null) { m_sessionId = savedInstanceState.getString("sessionId"); } - + setContentView(R.layout.main); - + + /* HeadlinesFragment hf = new HeadlinesFragment(); + FeedsFragment ff = new FeedsFragment(); + ArticleFragment af = new ArticleFragment(); + + FragmentTransaction ft = getFragmentManager().beginTransaction(); + + ft.add(R.id.main, ff); + ft.add(R.id.main, hf); + ft.add(R.id.main, af); + ft.hide(hf); + ft.hide(af); + ft.commit(); */ + + FragmentTransaction ft = getFragmentManager().beginTransaction(); + //ft.hide(getFragmentManager().findFragmentById(R.id.headlines_fragment)); + ft.hide(getFragmentManager().findFragmentById(R.id.article_fragment)); + ft.commit(); + LoginRequest ar = new LoginRequest(); ar.setApi(m_prefs.getString("ttrss_url", null)); - HashMap loginMap = new HashMap() { + HashMap map = new HashMap() { { put("op", "login"); put("user", m_prefs.getString("login", null)); @@ -80,7 +90,7 @@ public class MainActivity extends Activity { } }; - ar.execute(loginMap); + ar.execute(map); setLoadingStatus(R.string.login_in_progress, true); @@ -88,19 +98,8 @@ public class MainActivity extends Activity { if (vf != null) { vf.showNext(); - } + } */ - HeadlinesFragment hf = new HeadlinesFragment(); - FeedsFragment ff = new FeedsFragment(); - ArticleFragment af = new ArticleFragment(); - - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.add(R.id.main, ff); - ft.add(R.id.main, hf); - ft.add(R.id.main, af); - ft.hide(hf); - ft.hide(af); - ft.commit(); */ } public void setLoadingStatus(int status, boolean showProgress) { @@ -175,13 +174,11 @@ public class MainActivity extends Activity { if (content != null) { m_sessionId = content.get("session_id").getAsString(); - Log.d(TAG, "<<< Authentified, sessionId=" + m_sessionId); - setLoadingStatus(R.string.loading_message, true); FragmentManager fm = getFragmentManager(); - FeedsFragment ff = (FeedsFragment) fm.findFragmentById(R.id.feeds); - + FeedsFragment ff = (FeedsFragment) fm.findFragmentById(R.id.feeds_fragment); + if (ff != null) { ff.initialize(m_sessionId); } -- cgit v1.2.3-54-g00ecf