diff options
Diffstat (limited to 'src')
44 files changed, 11371 insertions, 11378 deletions
diff --git a/src/org/fox/ttrss/ApiRequest.java b/src/org/fox/ttrss/ApiRequest.java index 95d72385..12aaae9f 100644 --- a/src/org/fox/ttrss/ApiRequest.java +++ b/src/org/fox/ttrss/ApiRequest.java @@ -1,341 +1,341 @@ -package org.fox.ttrss;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.preference.PreferenceManager;
-import android.util.Base64;
-import android.util.Log;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-
-public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonElement> {
- private final String TAG = this.getClass().getSimpleName();
-
- public enum ApiError { NO_ERROR, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, HTTP_NOT_FOUND,
- HTTP_SERVER_ERROR, HTTP_OTHER_ERROR, SSL_REJECTED, SSL_HOSTNAME_REJECTED, PARSE_ERROR, IO_ERROR, OTHER_ERROR, API_DISABLED,
- API_UNKNOWN, LOGIN_FAILED, INVALID_URL, API_INCORRECT_USAGE, NETWORK_UNAVAILABLE, API_UNKNOWN_METHOD };
-
- public static final int API_STATUS_OK = 0;
- public static final int API_STATUS_ERR = 1;
-
- private String m_api;
- private boolean m_transportDebugging = false;
- protected int m_responseCode = 0;
- protected String m_responseMessage;
- protected int m_apiStatusCode = 0;
- protected boolean m_canUseProgress = false;
- protected Context m_context;
- private SharedPreferences m_prefs;
-
- protected ApiError m_lastError;
-
- public ApiRequest(Context context) {
- m_context = context;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(m_context);
-
- m_api = m_prefs.getString("ttrss_url", null).trim();
- m_transportDebugging = m_prefs.getBoolean("transport_debugging", false);
- m_lastError = ApiError.NO_ERROR;
-
- }
-
- protected int getErrorMessage() {
- switch (m_lastError) {
- case NO_ERROR:
- return R.string.error_unknown;
- case HTTP_UNAUTHORIZED:
- return R.string.error_http_unauthorized;
- case HTTP_FORBIDDEN:
- return R.string.error_http_forbidden;
- case HTTP_NOT_FOUND:
- return R.string.error_http_not_found;
- case HTTP_SERVER_ERROR:
- return R.string.error_http_server_error;
- case HTTP_OTHER_ERROR:
- return R.string.error_http_other_error;
- case SSL_REJECTED:
- return R.string.error_ssl_rejected;
- case SSL_HOSTNAME_REJECTED:
- return R.string.error_ssl_hostname_rejected;
- case PARSE_ERROR:
- return R.string.error_parse_error;
- case IO_ERROR:
- return R.string.error_io_error;
- case OTHER_ERROR:
- return R.string.error_other_error;
- case API_DISABLED:
- return R.string.error_api_disabled;
- case API_UNKNOWN:
- return R.string.error_api_unknown;
- case API_UNKNOWN_METHOD:
- return R.string.error_api_unknown_method;
- case LOGIN_FAILED:
- return R.string.error_login_failed;
- case INVALID_URL:
- return R.string.error_invalid_api_url;
- case API_INCORRECT_USAGE:
- return R.string.error_api_incorrect_usage;
- case NETWORK_UNAVAILABLE:
- return R.string.error_network_unavailable;
- default:
- Log.d(TAG, "getErrorMessage: unknown error code=" + m_lastError);
- return R.string.error_unknown;
- }
- }
-
- @Override
- protected JsonElement doInBackground(HashMap<String, String>... params) {
-
- if (!isNetworkAvailable()) {
- m_lastError = ApiError.NETWORK_UNAVAILABLE;
- return null;
- }
-
- Gson gson = new Gson();
-
- String requestStr = gson.toJson(new HashMap<String,String>(params[0]));
- byte[] postData = null;
-
- try {
- postData = requestStr.getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- m_lastError = ApiError.OTHER_ERROR;
- e.printStackTrace();
- return null;
- }
-
- /* disableConnectionReuseIfNecessary(); */
-
- if (m_transportDebugging) Log.d(TAG, ">>> (" + requestStr + ") " + m_api);
-
- /* ApiRequest.trustAllHosts(m_prefs.getBoolean("ssl_trust_any", false),
- m_prefs.getBoolean("ssl_trust_any_host", false)); */
-
- URL url;
-
- try {
- url = new URL(m_api + "/api/");
- } catch (Exception e) {
- m_lastError = ApiError.INVALID_URL;
- e.printStackTrace();
- return null;
- }
-
- try {
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-
- String httpLogin = m_prefs.getString("http_login", "").trim();
- String httpPassword = m_prefs.getString("http_password", "").trim();
-
- if (httpLogin.length() > 0) {
- if (m_transportDebugging) Log.d(TAG, "Using HTTP Basic authentication.");
-
- conn.setRequestProperty("Authorization", "Basic " +
- Base64.encodeToString((httpLogin + ":" + httpPassword).getBytes("UTF-8"), Base64.NO_WRAP));
- }
-
- conn.setDoInput(true);
- conn.setDoOutput(true);
- conn.setUseCaches(false);
- conn.setRequestMethod("POST");
- conn.setRequestProperty("Content-Length", Integer.toString(postData.length));
-
- OutputStream out = conn.getOutputStream();
- out.write(postData);
- out.close();
-
- m_responseCode = conn.getResponseCode();
- m_responseMessage = conn.getResponseMessage();
-
- switch (m_responseCode) {
- case HttpURLConnection.HTTP_OK:
- StringBuffer response = new StringBuffer();
- InputStreamReader in = new InputStreamReader(conn.getInputStream(), "UTF-8");
- char[] buf = new char[256];
- int read = 0;
- int total = 0;
-
- int contentLength = conn.getHeaderFieldInt("Api-Content-Length", -1);
-
- m_canUseProgress = (contentLength != -1);
-
- while ((read = in.read(buf)) >= 0) {
- response.append(buf, 0, read);
- total += read;
- publishProgress(Integer.valueOf(total), Integer.valueOf(contentLength));
- }
-
- if (m_transportDebugging) Log.d(TAG, "<<< " + response);
-
- JsonParser parser = new JsonParser();
-
- JsonElement result = parser.parse(response.toString());
- JsonObject resultObj = result.getAsJsonObject();
-
- m_apiStatusCode = resultObj.get("status").getAsInt();
-
- conn.disconnect();
-
- switch (m_apiStatusCode) {
- case API_STATUS_OK:
- return result.getAsJsonObject().get("content");
- case API_STATUS_ERR:
- JsonObject contentObj = resultObj.get("content").getAsJsonObject();
- String error = contentObj.get("error").getAsString();
-
- if (error.equals("LOGIN_ERROR")) {
- m_lastError = ApiError.LOGIN_FAILED;
- } else if (error.equals("API_DISABLED")) {
- m_lastError = ApiError.API_DISABLED;
- } else if (error.equals("NOT_LOGGED_IN")) {
- m_lastError = ApiError.LOGIN_FAILED;
- } else if (error.equals("INCORRECT_USAGE")) {
- m_lastError = ApiError.API_INCORRECT_USAGE;
- } else if (error.equals("UNKNOWN_METHOD")) {
- m_lastError = ApiError.API_UNKNOWN_METHOD;
- } else {
- Log.d(TAG, "Unknown API error: " + error);
- m_lastError = ApiError.API_UNKNOWN;
- }
- }
-
- return null;
- case HttpURLConnection.HTTP_UNAUTHORIZED:
- m_lastError = ApiError.HTTP_UNAUTHORIZED;
- break;
- case HttpURLConnection.HTTP_FORBIDDEN:
- m_lastError = ApiError.HTTP_FORBIDDEN;
- break;
- case HttpURLConnection.HTTP_NOT_FOUND:
- m_lastError = ApiError.HTTP_NOT_FOUND;
- break;
- case HttpURLConnection.HTTP_INTERNAL_ERROR:
- m_lastError = ApiError.HTTP_SERVER_ERROR;
- break;
- default:
- Log.d(TAG, "HTTP response code: " + m_responseCode + "(" + m_responseMessage + ")");
- m_lastError = ApiError.HTTP_OTHER_ERROR;
- break;
- }
-
- conn.disconnect();
- return null;
- } catch (javax.net.ssl.SSLPeerUnverifiedException e) {
- m_lastError = ApiError.SSL_REJECTED;
- e.printStackTrace();
- } catch (IOException e) {
- m_lastError = ApiError.IO_ERROR;
-
- if (e.getMessage() != null) {
- if (e.getMessage().matches("Hostname [^ ]+ was not verified")) {
- m_lastError = ApiError.SSL_HOSTNAME_REJECTED;
- }
- }
-
- e.printStackTrace();
- } catch (com.google.gson.JsonSyntaxException e) {
- m_lastError = ApiError.PARSE_ERROR;
- e.printStackTrace();
- } catch (Exception e) {
- m_lastError = ApiError.OTHER_ERROR;
- e.printStackTrace();
- }
-
- return null;
- }
-
- protected static void trustAllHosts(boolean trustAnyCert, boolean trustAnyHost) {
- try {
- if (trustAnyCert) {
- X509TrustManager easyTrustManager = new X509TrustManager() {
-
- public void checkClientTrusted(
- X509Certificate[] chain,
- String authType) throws CertificateException {
- // Oh, I am easy!
- }
-
- public void checkServerTrusted(
- X509Certificate[] chain,
- String authType) throws CertificateException {
- // Oh, I am easy!
- }
-
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
-
- };
-
- // Create a trust manager that does not validate certificate chains
- TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager};
-
- // Install the all-trusting trust manager
-
- SSLContext sc = SSLContext.getInstance("TLS");
-
- sc.init(null, trustAllCerts, new java.security.SecureRandom());
-
- HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
- }
-
- if (trustAnyHost) {
- HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
- @Override
- public boolean verify(String hostname, SSLSession session) {
- return true;
- }
- });
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- @SuppressWarnings("deprecation")
- protected static void disableConnectionReuseIfNecessary() {
- // HTTP connection reuse which was buggy pre-froyo
- if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
- System.setProperty("http.keepAlive", "false");
- }
- }
-
- protected boolean isNetworkAvailable() {
- ConnectivityManager cm = (ConnectivityManager)
- m_context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = cm.getActiveNetworkInfo();
-
- // if no network is available networkInfo will be null
- // otherwise check if we are connected
- if (networkInfo != null && networkInfo.isConnected()) {
- return true;
- }
- return false;
- }
-}
+package org.fox.ttrss; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.HashMap; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import android.content.Context; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.AsyncTask; +import android.os.Build; +import android.preference.PreferenceManager; +import android.util.Base64; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonElement> { + private final String TAG = this.getClass().getSimpleName(); + + public enum ApiError { NO_ERROR, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, HTTP_NOT_FOUND, + HTTP_SERVER_ERROR, HTTP_OTHER_ERROR, SSL_REJECTED, SSL_HOSTNAME_REJECTED, PARSE_ERROR, IO_ERROR, OTHER_ERROR, API_DISABLED, + API_UNKNOWN, LOGIN_FAILED, INVALID_URL, API_INCORRECT_USAGE, NETWORK_UNAVAILABLE, API_UNKNOWN_METHOD }; + + public static final int API_STATUS_OK = 0; + public static final int API_STATUS_ERR = 1; + + private String m_api; + private boolean m_transportDebugging = false; + protected int m_responseCode = 0; + protected String m_responseMessage; + protected int m_apiStatusCode = 0; + protected boolean m_canUseProgress = false; + protected Context m_context; + private SharedPreferences m_prefs; + + protected ApiError m_lastError; + + public ApiRequest(Context context) { + m_context = context; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(m_context); + + m_api = m_prefs.getString("ttrss_url", null).trim(); + m_transportDebugging = m_prefs.getBoolean("transport_debugging", false); + m_lastError = ApiError.NO_ERROR; + + } + + protected int getErrorMessage() { + switch (m_lastError) { + case NO_ERROR: + return R.string.error_unknown; + case HTTP_UNAUTHORIZED: + return R.string.error_http_unauthorized; + case HTTP_FORBIDDEN: + return R.string.error_http_forbidden; + case HTTP_NOT_FOUND: + return R.string.error_http_not_found; + case HTTP_SERVER_ERROR: + return R.string.error_http_server_error; + case HTTP_OTHER_ERROR: + return R.string.error_http_other_error; + case SSL_REJECTED: + return R.string.error_ssl_rejected; + case SSL_HOSTNAME_REJECTED: + return R.string.error_ssl_hostname_rejected; + case PARSE_ERROR: + return R.string.error_parse_error; + case IO_ERROR: + return R.string.error_io_error; + case OTHER_ERROR: + return R.string.error_other_error; + case API_DISABLED: + return R.string.error_api_disabled; + case API_UNKNOWN: + return R.string.error_api_unknown; + case API_UNKNOWN_METHOD: + return R.string.error_api_unknown_method; + case LOGIN_FAILED: + return R.string.error_login_failed; + case INVALID_URL: + return R.string.error_invalid_api_url; + case API_INCORRECT_USAGE: + return R.string.error_api_incorrect_usage; + case NETWORK_UNAVAILABLE: + return R.string.error_network_unavailable; + default: + Log.d(TAG, "getErrorMessage: unknown error code=" + m_lastError); + return R.string.error_unknown; + } + } + + @Override + protected JsonElement doInBackground(HashMap<String, String>... params) { + + if (!isNetworkAvailable()) { + m_lastError = ApiError.NETWORK_UNAVAILABLE; + return null; + } + + Gson gson = new Gson(); + + String requestStr = gson.toJson(new HashMap<String,String>(params[0])); + byte[] postData = null; + + try { + postData = requestStr.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + m_lastError = ApiError.OTHER_ERROR; + e.printStackTrace(); + return null; + } + + /* disableConnectionReuseIfNecessary(); */ + + if (m_transportDebugging) Log.d(TAG, ">>> (" + requestStr + ") " + m_api); + + /* ApiRequest.trustAllHosts(m_prefs.getBoolean("ssl_trust_any", false), + m_prefs.getBoolean("ssl_trust_any_host", false)); */ + + URL url; + + try { + url = new URL(m_api + "/api/"); + } catch (Exception e) { + m_lastError = ApiError.INVALID_URL; + e.printStackTrace(); + return null; + } + + try { + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + String httpLogin = m_prefs.getString("http_login", "").trim(); + String httpPassword = m_prefs.getString("http_password", "").trim(); + + if (httpLogin.length() > 0) { + if (m_transportDebugging) Log.d(TAG, "Using HTTP Basic authentication."); + + conn.setRequestProperty("Authorization", "Basic " + + Base64.encodeToString((httpLogin + ":" + httpPassword).getBytes("UTF-8"), Base64.NO_WRAP)); + } + + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Length", Integer.toString(postData.length)); + + OutputStream out = conn.getOutputStream(); + out.write(postData); + out.close(); + + m_responseCode = conn.getResponseCode(); + m_responseMessage = conn.getResponseMessage(); + + switch (m_responseCode) { + case HttpURLConnection.HTTP_OK: + StringBuffer response = new StringBuffer(); + InputStreamReader in = new InputStreamReader(conn.getInputStream(), "UTF-8"); + char[] buf = new char[256]; + int read = 0; + int total = 0; + + int contentLength = conn.getHeaderFieldInt("Api-Content-Length", -1); + + m_canUseProgress = (contentLength != -1); + + while ((read = in.read(buf)) >= 0) { + response.append(buf, 0, read); + total += read; + publishProgress(Integer.valueOf(total), Integer.valueOf(contentLength)); + } + + if (m_transportDebugging) Log.d(TAG, "<<< " + response); + + JsonParser parser = new JsonParser(); + + JsonElement result = parser.parse(response.toString()); + JsonObject resultObj = result.getAsJsonObject(); + + m_apiStatusCode = resultObj.get("status").getAsInt(); + + conn.disconnect(); + + switch (m_apiStatusCode) { + case API_STATUS_OK: + return result.getAsJsonObject().get("content"); + case API_STATUS_ERR: + JsonObject contentObj = resultObj.get("content").getAsJsonObject(); + String error = contentObj.get("error").getAsString(); + + if (error.equals("LOGIN_ERROR")) { + m_lastError = ApiError.LOGIN_FAILED; + } else if (error.equals("API_DISABLED")) { + m_lastError = ApiError.API_DISABLED; + } else if (error.equals("NOT_LOGGED_IN")) { + m_lastError = ApiError.LOGIN_FAILED; + } else if (error.equals("INCORRECT_USAGE")) { + m_lastError = ApiError.API_INCORRECT_USAGE; + } else if (error.equals("UNKNOWN_METHOD")) { + m_lastError = ApiError.API_UNKNOWN_METHOD; + } else { + Log.d(TAG, "Unknown API error: " + error); + m_lastError = ApiError.API_UNKNOWN; + } + } + + return null; + case HttpURLConnection.HTTP_UNAUTHORIZED: + m_lastError = ApiError.HTTP_UNAUTHORIZED; + break; + case HttpURLConnection.HTTP_FORBIDDEN: + m_lastError = ApiError.HTTP_FORBIDDEN; + break; + case HttpURLConnection.HTTP_NOT_FOUND: + m_lastError = ApiError.HTTP_NOT_FOUND; + break; + case HttpURLConnection.HTTP_INTERNAL_ERROR: + m_lastError = ApiError.HTTP_SERVER_ERROR; + break; + default: + Log.d(TAG, "HTTP response code: " + m_responseCode + "(" + m_responseMessage + ")"); + m_lastError = ApiError.HTTP_OTHER_ERROR; + break; + } + + conn.disconnect(); + return null; + } catch (javax.net.ssl.SSLPeerUnverifiedException e) { + m_lastError = ApiError.SSL_REJECTED; + e.printStackTrace(); + } catch (IOException e) { + m_lastError = ApiError.IO_ERROR; + + if (e.getMessage() != null) { + if (e.getMessage().matches("Hostname [^ ]+ was not verified")) { + m_lastError = ApiError.SSL_HOSTNAME_REJECTED; + } + } + + e.printStackTrace(); + } catch (com.google.gson.JsonSyntaxException e) { + m_lastError = ApiError.PARSE_ERROR; + e.printStackTrace(); + } catch (Exception e) { + m_lastError = ApiError.OTHER_ERROR; + e.printStackTrace(); + } + + return null; + } + + protected static void trustAllHosts(boolean trustAnyCert, boolean trustAnyHost) { + try { + if (trustAnyCert) { + X509TrustManager easyTrustManager = new X509TrustManager() { + + public void checkClientTrusted( + X509Certificate[] chain, + String authType) throws CertificateException { + // Oh, I am easy! + } + + public void checkServerTrusted( + X509Certificate[] chain, + String authType) throws CertificateException { + // Oh, I am easy! + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + }; + + // Create a trust manager that does not validate certificate chains + TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager}; + + // Install the all-trusting trust manager + + SSLContext sc = SSLContext.getInstance("TLS"); + + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } + + if (trustAnyHost) { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("deprecation") + protected static void disableConnectionReuseIfNecessary() { + // HTTP connection reuse which was buggy pre-froyo + if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) { + System.setProperty("http.keepAlive", "false"); + } + } + + protected boolean isNetworkAvailable() { + ConnectivityManager cm = (ConnectivityManager) + m_context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + + // if no network is available networkInfo will be null + // otherwise check if we are connected + if (networkInfo != null && networkInfo.isConnected()) { + return true; + } + return false; + } +} diff --git a/src/org/fox/ttrss/ArticleFragment.java b/src/org/fox/ttrss/ArticleFragment.java index 1fa76bcc..ccf7829f 100644 --- a/src/org/fox/ttrss/ArticleFragment.java +++ b/src/org/fox/ttrss/ArticleFragment.java @@ -1,450 +1,450 @@ -package org.fox.ttrss;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.Attachment;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.Typeface;
-import android.net.Uri;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.text.Html;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.GestureDetector;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebSettings.LayoutAlgorithm;
-import android.webkit.WebView;
-import android.webkit.WebView.HitTestResult;
-import android.widget.TextView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-
-public class ArticleFragment extends Fragment implements GestureDetector.OnDoubleTapListener {
- private final String TAG = this.getClass().getSimpleName();
-
- private SharedPreferences m_prefs;
- private Article m_article;
- private OnlineActivity m_activity;
- private GestureDetector m_detector;
-
- public ArticleFragment() {
- super();
- }
-
- public ArticleFragment(Article article) {
- super();
-
- m_article = article;
- }
-
- private View.OnTouchListener m_gestureListener;
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- if (v.getId() == R.id.content) {
- HitTestResult result = ((WebView)v).getHitTestResult();
-
- if (result != null && (result.getType() == HitTestResult.IMAGE_TYPE || result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE)) {
- menu.setHeaderTitle(result.getExtra());
- getActivity().getMenuInflater().inflate(R.menu.article_content_img_context_menu, menu);
-
- /* FIXME I have no idea how to do this correctly ;( */
-
- m_activity.setLastContentImageHitTestUrl(result.getExtra());
-
- } else {
- menu.setHeaderTitle(m_article.title);
- getActivity().getMenuInflater().inflate(R.menu.article_link_context_menu, menu);
- }
- } else {
- menu.setHeaderTitle(m_article.title);
- getActivity().getMenuInflater().inflate(R.menu.article_link_context_menu, menu);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- @SuppressLint("NewApi")
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- m_activity.setProgressBarVisibility(true);
-
- if (savedInstanceState != null) {
- m_article = savedInstanceState.getParcelable("article");
- }
-
- View view = inflater.inflate(R.layout.article_fragment, container, false);
-
- if (m_article != null) {
-
- TextView title = (TextView)view.findViewById(R.id.title);
-
- if (title != null) {
-
- String titleStr;
-
- if (m_article.title.length() > 200)
- titleStr = m_article.title.substring(0, 200) + "...";
- else
- titleStr = m_article.title;
-
-
- title.setTypeface(null, m_article.unread ? Typeface.BOLD : Typeface.NORMAL);
- title.setText(Html.fromHtml(titleStr));
- //title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
- title.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW,
- Uri.parse(m_article.link.trim()));
- startActivity(intent);
- } catch (Exception e) {
- e.printStackTrace();
- m_activity.toast(R.string.error_other_error);
- }
- }
- });
-
- registerForContextMenu(title);
- }
-
- TextView comments = (TextView)view.findViewById(R.id.comments);
-
- if (comments != null) {
- if (m_activity.getApiLevel() >= 4 && m_article.comments_count > 0) {
- String commentsTitle = getString(R.string.article_comments, m_article.comments_count);
- comments.setText(commentsTitle);
- //comments.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
- comments.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- try {
- String link = (m_article.comments_link != null && m_article.comments_link.length() > 0) ?
- m_article.comments_link : m_article.link;
-
- Intent intent = new Intent(Intent.ACTION_VIEW,
- Uri.parse(link.trim()));
- startActivity(intent);
- } catch (Exception e) {
- e.printStackTrace();
- m_activity.toast(R.string.error_other_error);
- }
- }
- });
-
- } else {
- comments.setVisibility(View.GONE);
- }
- }
-
- WebView web = (WebView)view.findViewById(R.id.content);
-
- if (web != null) {
- registerForContextMenu(web);
-
- web.setWebChromeClient(new WebChromeClient() {
- @Override
- public void onProgressChanged(WebView view, int progress) {
- m_activity.setProgress(Math.round(((float)progress / 100f) * 10000));
- if (progress == 100) {
- m_activity.setProgressBarVisibility(false);
- }
- }
- });
-
- web.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- return m_detector.onTouchEvent(event);
- }
- });
-
- String content;
- String cssOverride = "";
-
- WebSettings ws = web.getSettings();
- ws.setSupportZoom(true);
- ws.setBuiltInZoomControls(false);
-
- web.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
-
- TypedValue tv = new TypedValue();
- getActivity().getTheme().resolveAttribute(R.attr.linkColor, tv, true);
-
- // prevent flicker in ics
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- web.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
-
- if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) {
- cssOverride = "body { background : transparent; color : #e0e0e0}";
- } else if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK_GRAY")) {
- cssOverride = "body { background : transparent; color : #e0e0e0}";
- } else {
- cssOverride = "body { background : transparent; }";
- }
- web.setBackgroundColor(getResources().getColor(android.R.color.transparent));
-
- String hexColor = String.format("#%06X", (0xFFFFFF & tv.data));
- cssOverride += " a:link {color: "+hexColor+";} a:visited { color: "+hexColor+";}";
-
- String articleContent = m_article.content != null ? m_article.content : "";
-
- Document doc = Jsoup.parse(articleContent);
-
- if (doc != null) {
- // thanks webview for crashing on <video> tag
- Elements videos = doc.select("video");
-
- for (Element video : videos)
- video.remove();
-
- articleContent = doc.toString();
- }
-
- String align = m_prefs.getBoolean("justify_article_text", true) ? "text-align : justify;" : "";
-
- switch (Integer.parseInt(m_prefs.getString("font_size", "0"))) {
- case 0:
- cssOverride += "body { "+align+" font-size : 14px; } ";
- break;
- case 1:
- cssOverride += "body { "+align+" font-size : 18px; } ";
- break;
- case 2:
- cssOverride += "body { "+align+" font-size : 21px; } ";
- break;
- }
-
- content =
- "<html>" +
- "<head>" +
- "<meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\">" +
- "<style type=\"text/css\">" +
- "body { padding : 0px; margin : 0px; }" +
- cssOverride +
- /* "img { max-width : 98%; height : auto; }" + */
- "</style>" +
- "</head>" +
- "<body>" + articleContent;
-
- if (m_article.attachments != null && m_article.attachments.size() != 0) {
- String flatContent = articleContent.replaceAll("[\r\n]", "");
- boolean hasImages = flatContent.matches(".*?<img[^>+].*?");
-
- for (Attachment a : m_article.attachments) {
- if (a.content_type != null && a.content_url != null) {
- try {
- if (a.content_type.indexOf("image") != -1 &&
- (!hasImages || m_article.always_display_attachments)) {
-
- URL url = new URL(a.content_url.trim());
- String strUrl = url.toString().trim();
-
- content += "<p><img src=\"" + strUrl.replace("\"", "\\\"") + "\"></p>";
- }
-
- } catch (MalformedURLException e) {
- //
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- content += "<p> </p><p> </p></body></html>";
-
- try {
- web.loadDataWithBaseURL(null, content, "text/html", "utf-8", null);
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
-
- if (m_activity.isSmallScreen())
- web.setOnTouchListener(m_gestureListener);
- }
-
- TextView dv = (TextView)view.findViewById(R.id.date);
-
- if (dv != null) {
- Date d = new Date(m_article.updated * 1000L);
- SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy, HH:mm");
- dv.setText(df.format(d));
- }
-
- TextView tagv = (TextView)view.findViewById(R.id.tags);
-
- if (tagv != null) {
- if (m_article.feed_title != null) {
- tagv.setText(m_article.feed_title);
- } else if (m_article.tags != null) {
- String tagsStr = "";
-
- for (String tag : m_article.tags)
- tagsStr += tag + ", ";
-
- tagsStr = tagsStr.replaceAll(", $", "");
-
- tagv.setText(tagsStr);
- } else {
- tagv.setVisibility(View.GONE);
- }
- }
-
- TextView author = (TextView)view.findViewById(R.id.author);
-
- if (author != null) {
- if (m_article.author != null && m_article.author.length() > 0) {
- author.setText(m_article.author);
- } else {
- author.setVisibility(View.GONE);
- }
- }
- }
-
- return view;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putParcelable("article", m_article);
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- m_activity = (OnlineActivity)activity;
- //m_article = m_onlineServices.getSelectedArticle();
-
- m_detector = new GestureDetector(m_activity, new GestureDetector.OnGestureListener() {
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- m_activity.openContextMenu(getView());
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- // TODO Auto-generated method stub
- return false;
- }
- });
-
- m_detector.setOnDoubleTapListener(this);
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent arg0) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent arg0) {
- // TODO Auto-generated method stub
- return false;
- }
-
- private void onLeftSideTapped() {
- ArticlePager ap = (ArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- ap.selectArticle(false);
- }
- }
-
- private void onRightSideTapped() {
- ArticlePager ap = (ArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- ap.selectArticle(true);
- }
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
-
- int width = getView().getWidth();
- int x = Math.round(e.getX());
-
- if (x <= width/15) {
- onLeftSideTapped();
- return true;
- } else if (x >= width-(width/15)) {
- onRightSideTapped();
- return true;
- } /* else if (!m_activity.isCompatMode()) {
- ActionBar bar = m_activity.getActionBar();
-
- if (bar.isShowing()) {
- bar.hide();
- } else {
- bar.show();
- }
- } */
- return false;
- }
-
-}
+package org.fox.ttrss; + +import java.net.MalformedURLException; +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.Attachment; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.text.Html; +import android.util.Log; +import android.util.TypedValue; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.GestureDetector; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebSettings.LayoutAlgorithm; +import android.webkit.WebView; +import android.webkit.WebView.HitTestResult; +import android.widget.TextView; +import android.widget.AdapterView.AdapterContextMenuInfo; + +public class ArticleFragment extends Fragment implements GestureDetector.OnDoubleTapListener { + private final String TAG = this.getClass().getSimpleName(); + + private SharedPreferences m_prefs; + private Article m_article; + private OnlineActivity m_activity; + private GestureDetector m_detector; + + public ArticleFragment() { + super(); + } + + public ArticleFragment(Article article) { + super(); + + m_article = article; + } + + private View.OnTouchListener m_gestureListener; + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + if (v.getId() == R.id.content) { + HitTestResult result = ((WebView)v).getHitTestResult(); + + if (result != null && (result.getType() == HitTestResult.IMAGE_TYPE || result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE)) { + menu.setHeaderTitle(result.getExtra()); + getActivity().getMenuInflater().inflate(R.menu.article_content_img_context_menu, menu); + + /* FIXME I have no idea how to do this correctly ;( */ + + m_activity.setLastContentImageHitTestUrl(result.getExtra()); + + } else { + menu.setHeaderTitle(m_article.title); + getActivity().getMenuInflater().inflate(R.menu.article_link_context_menu, menu); + } + } else { + menu.setHeaderTitle(m_article.title); + getActivity().getMenuInflater().inflate(R.menu.article_link_context_menu, menu); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + @SuppressLint("NewApi") + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + m_activity.setProgressBarVisibility(true); + + if (savedInstanceState != null) { + m_article = savedInstanceState.getParcelable("article"); + } + + View view = inflater.inflate(R.layout.article_fragment, container, false); + + if (m_article != null) { + + TextView title = (TextView)view.findViewById(R.id.title); + + if (title != null) { + + String titleStr; + + if (m_article.title.length() > 200) + titleStr = m_article.title.substring(0, 200) + "..."; + else + titleStr = m_article.title; + + + title.setTypeface(null, m_article.unread ? Typeface.BOLD : Typeface.NORMAL); + title.setText(Html.fromHtml(titleStr)); + //title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); + title.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse(m_article.link.trim())); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + m_activity.toast(R.string.error_other_error); + } + } + }); + + registerForContextMenu(title); + } + + TextView comments = (TextView)view.findViewById(R.id.comments); + + if (comments != null) { + if (m_activity.getApiLevel() >= 4 && m_article.comments_count > 0) { + String commentsTitle = getString(R.string.article_comments, m_article.comments_count); + comments.setText(commentsTitle); + //comments.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); + comments.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + try { + String link = (m_article.comments_link != null && m_article.comments_link.length() > 0) ? + m_article.comments_link : m_article.link; + + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse(link.trim())); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + m_activity.toast(R.string.error_other_error); + } + } + }); + + } else { + comments.setVisibility(View.GONE); + } + } + + WebView web = (WebView)view.findViewById(R.id.content); + + if (web != null) { + registerForContextMenu(web); + + web.setWebChromeClient(new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int progress) { + m_activity.setProgress(Math.round(((float)progress / 100f) * 10000)); + if (progress == 100) { + m_activity.setProgressBarVisibility(false); + } + } + }); + + web.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return m_detector.onTouchEvent(event); + } + }); + + String content; + String cssOverride = ""; + + WebSettings ws = web.getSettings(); + ws.setSupportZoom(true); + ws.setBuiltInZoomControls(false); + + web.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); + + TypedValue tv = new TypedValue(); + getActivity().getTheme().resolveAttribute(R.attr.linkColor, tv, true); + + // prevent flicker in ics + if (android.os.Build.VERSION.SDK_INT >= 11) { + web.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + + if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) { + cssOverride = "body { background : transparent; color : #e0e0e0}"; + } else if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK_GRAY")) { + cssOverride = "body { background : transparent; color : #e0e0e0}"; + } else { + cssOverride = "body { background : transparent; }"; + } + web.setBackgroundColor(getResources().getColor(android.R.color.transparent)); + + String hexColor = String.format("#%06X", (0xFFFFFF & tv.data)); + cssOverride += " a:link {color: "+hexColor+";} a:visited { color: "+hexColor+";}"; + + String articleContent = m_article.content != null ? m_article.content : ""; + + Document doc = Jsoup.parse(articleContent); + + if (doc != null) { + // thanks webview for crashing on <video> tag + Elements videos = doc.select("video"); + + for (Element video : videos) + video.remove(); + + articleContent = doc.toString(); + } + + String align = m_prefs.getBoolean("justify_article_text", true) ? "text-align : justify;" : ""; + + switch (Integer.parseInt(m_prefs.getString("font_size", "0"))) { + case 0: + cssOverride += "body { "+align+" font-size : 14px; } "; + break; + case 1: + cssOverride += "body { "+align+" font-size : 18px; } "; + break; + case 2: + cssOverride += "body { "+align+" font-size : 21px; } "; + break; + } + + content = + "<html>" + + "<head>" + + "<meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\">" + + "<style type=\"text/css\">" + + "body { padding : 0px; margin : 0px; }" + + cssOverride + + /* "img { max-width : 98%; height : auto; }" + */ + "</style>" + + "</head>" + + "<body>" + articleContent; + + if (m_article.attachments != null && m_article.attachments.size() != 0) { + String flatContent = articleContent.replaceAll("[\r\n]", ""); + boolean hasImages = flatContent.matches(".*?<img[^>+].*?"); + + for (Attachment a : m_article.attachments) { + if (a.content_type != null && a.content_url != null) { + try { + if (a.content_type.indexOf("image") != -1 && + (!hasImages || m_article.always_display_attachments)) { + + URL url = new URL(a.content_url.trim()); + String strUrl = url.toString().trim(); + + content += "<p><img src=\"" + strUrl.replace("\"", "\\\"") + "\"></p>"; + } + + } catch (MalformedURLException e) { + // + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + content += "<p> </p><p> </p></body></html>"; + + try { + web.loadDataWithBaseURL(null, content, "text/html", "utf-8", null); + } catch (RuntimeException e) { + e.printStackTrace(); + } + + if (m_activity.isSmallScreen()) + web.setOnTouchListener(m_gestureListener); + } + + TextView dv = (TextView)view.findViewById(R.id.date); + + if (dv != null) { + Date d = new Date(m_article.updated * 1000L); + SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy, HH:mm"); + dv.setText(df.format(d)); + } + + TextView tagv = (TextView)view.findViewById(R.id.tags); + + if (tagv != null) { + if (m_article.feed_title != null) { + tagv.setText(m_article.feed_title); + } else if (m_article.tags != null) { + String tagsStr = ""; + + for (String tag : m_article.tags) + tagsStr += tag + ", "; + + tagsStr = tagsStr.replaceAll(", $", ""); + + tagv.setText(tagsStr); + } else { + tagv.setVisibility(View.GONE); + } + } + + TextView author = (TextView)view.findViewById(R.id.author); + + if (author != null) { + if (m_article.author != null && m_article.author.length() > 0) { + author.setText(m_article.author); + } else { + author.setVisibility(View.GONE); + } + } + } + + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putParcelable("article", m_article); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + m_activity = (OnlineActivity)activity; + //m_article = m_onlineServices.getSelectedArticle(); + + m_detector = new GestureDetector(m_activity, new GestureDetector.OnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onShowPress(MotionEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, + float distanceY) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onLongPress(MotionEvent e) { + m_activity.openContextMenu(getView()); + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onDown(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + }); + + m_detector.setOnDoubleTapListener(this); + } + + @Override + public boolean onDoubleTap(MotionEvent arg0) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent arg0) { + // TODO Auto-generated method stub + return false; + } + + private void onLeftSideTapped() { + ArticlePager ap = (ArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + ap.selectArticle(false); + } + } + + private void onRightSideTapped() { + ArticlePager ap = (ArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + ap.selectArticle(true); + } + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + + int width = getView().getWidth(); + int x = Math.round(e.getX()); + + if (x <= width/15) { + onLeftSideTapped(); + return true; + } else if (x >= width-(width/15)) { + onRightSideTapped(); + return true; + } /* else if (!m_activity.isCompatMode()) { + ActionBar bar = m_activity.getSupportActionBar(); + + if (bar.isShowing()) { + bar.hide(); + } else { + bar.show(); + } + } */ + return false; + } + +} diff --git a/src/org/fox/ttrss/ArticlePager.java b/src/org/fox/ttrss/ArticlePager.java index 258c41b8..aa6e0c44 100644 --- a/src/org/fox/ttrss/ArticlePager.java +++ b/src/org/fox/ttrss/ArticlePager.java @@ -1,330 +1,330 @@ -package org.fox.ttrss;
-
-import java.util.HashMap;
-
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.ArticleList;
-import org.fox.ttrss.types.Feed;
-import org.fox.ttrss.util.HeadlinesRequest;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.SharedPreferences;
-import android.os.BadParcelableException;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-
-import com.google.gson.JsonElement;
-import com.viewpagerindicator.TitlePageIndicator;
-import com.viewpagerindicator.UnderlinePageIndicator;
-
-public class ArticlePager extends Fragment {
-
- private final String TAG = "ArticlePager";
- private PagerAdapter m_adapter;
- private HeadlinesEventListener m_listener;
- private Article m_article;
- private ArticleList m_articles = GlobalState.getInstance().m_loadedArticles;
- private OnlineActivity m_activity;
- private String m_searchQuery = "";
- private Feed m_feed;
- private SharedPreferences m_prefs;
-
- private class PagerAdapter extends FragmentStatePagerAdapter {
-
- public PagerAdapter(FragmentManager fm) {
- super(fm);
- }
-
- @Override
- public Fragment getItem(int position) {
- Article article = m_articles.get(position);
-
- if (article != null) {
- ArticleFragment af = new ArticleFragment(article);
-
- if (m_prefs.getBoolean("dim_status_bar", false) && getView() != null && !m_activity.isCompatMode()) {
- getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
- }
-
- return af;
- }
- return null;
- }
-
- @Override
- public int getCount() {
- return m_articles.size();
- }
-
- }
-
- public ArticlePager() {
- super();
- }
-
- public ArticlePager(Article article, Feed feed) {
- super();
-
- m_article = article;
- m_feed = feed;
- }
-
- public void setSearchQuery(String searchQuery) {
- m_searchQuery = searchQuery;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.article_pager, container, false);
-
- if (savedInstanceState != null) {
- m_article = savedInstanceState.getParcelable("article");
- m_feed = savedInstanceState.getParcelable("feed");
- }
-
- m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager());
-
- ViewPager pager = (ViewPager) view.findViewById(R.id.article_pager);
-
- int position = m_articles.indexOf(m_article);
-
- m_listener.onArticleSelected(m_article, false);
-
- m_activity.setProgressBarVisibility(true);
-
- pager.setAdapter(m_adapter);
-
- UnderlinePageIndicator indicator = (UnderlinePageIndicator)view.findViewById(R.id.article_titles);
- indicator.setViewPager(pager);
-
- pager.setCurrentItem(position);
-
- indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
-
- @Override
- public void onPageScrollStateChanged(int arg0) {
- }
-
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {
- }
-
- @Override
- public void onPageSelected(int position) {
- Article article = m_articles.get(position);
-
- if (article != null) {
- m_article = article;
-
- /* if (article.unread) {
- article.unread = false;
- m_activity.saveArticleUnread(article);
- } */
-
- m_listener.onArticleSelected(article, false);
-
- //Log.d(TAG, "Page #" + position + "/" + m_adapter.getCount());
-
- if ((m_activity.isSmallScreen() || m_activity.isPortrait()) && position == m_adapter.getCount() - 5) {
- Log.d(TAG, "loading more articles...");
- refresh(true);
- }
- }
- }
- });
-
- return view;
- }
-
- @SuppressWarnings({ "unchecked", "serial" })
- protected void refresh(boolean append) {
- m_activity.setLoadingStatus(R.string.blank, true);
-
- m_activity.setProgressBarVisibility(true);
-
- if (!m_feed.equals(GlobalState.getInstance().m_activeFeed)) {
- append = false;
- }
-
- HeadlinesRequest req = new HeadlinesRequest(getActivity().getApplicationContext(), m_activity) {
- @Override
- protected void onProgressUpdate(Integer... progress) {
- m_activity.setProgress(progress[0] / progress[1] * 10000);
- }
-
- @Override
- protected void onPostExecute(JsonElement result) {
- if (isDetached()) return;
-
- m_activity.setProgressBarVisibility(false);
-
- super.onPostExecute(result);
-
- if (result != null) {
- try {
- m_adapter.notifyDataSetChanged();
- } catch (BadParcelableException e) {
- if (getActivity() != null) {
- getActivity().finish();
- return;
- }
- }
-
- if (m_article.id == 0 || m_articles.indexOf(m_article) == -1) {
- if (m_articles.size() > 0) {
- m_article = m_articles.get(0);
- m_listener.onArticleSelected(m_article, false);
- }
- }
-
- } else {
- if (m_lastError == ApiError.LOGIN_FAILED) {
- m_activity.login(true);
- } else {
- m_activity.toast(getErrorMessage());
- //setLoadingStatus(getErrorMessage(), false);
- }
- }
- }
- };
-
- final Feed feed = m_feed;
-
- final String sessionId = m_activity.getSessionId();
- int skip = 0;
-
- if (append) {
- for (Article a : m_articles) {
- if (a.unread) ++skip;
- }
-
- if (skip == 0) skip = m_articles.size();
- }
-
- final int fskip = skip;
-
- req.setOffset(skip);
-
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getHeadlines");
- put("sid", sessionId);
- put("feed_id", String.valueOf(feed.id));
- put("show_content", "true");
- put("include_attachments", "true");
- put("limit", String.valueOf(HeadlinesFragment.HEADLINES_REQUEST_SIZE));
- put("offset", String.valueOf(0));
- put("view_mode", m_activity.getViewMode());
- put("skip", String.valueOf(fskip));
- put("include_nested", "true");
- put("order_by", m_prefs.getBoolean("oldest_first", false) ? "date_reverse" : "");
-
- if (feed.is_cat) put("is_cat", "true");
-
- if (m_searchQuery != null && m_searchQuery.length() != 0) {
- put("search", m_searchQuery);
- put("search_mode", "");
- put("match_on", "both");
- }
- }
- };
-
- req.execute(map);
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putParcelable("article", m_article);
- out.putParcelable("feed", m_feed);
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_listener = (HeadlinesEventListener)activity;
- m_activity = (OnlineActivity)activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- }
-
- @SuppressLint("NewApi")
- @Override
- public void onResume() {
- super.onResume();
-
- if (m_articles.size() == 0 || !m_feed.equals(GlobalState.getInstance().m_activeFeed)) {
- refresh(false);
- GlobalState.getInstance().m_activeFeed = m_feed;
- }
-
- m_activity.initMenu();
-
- if (!m_activity.isCompatMode() && m_prefs.getBoolean("dim_status_bar", false)) {
- getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
- }
-
- if (m_prefs.getBoolean("full_screen_mode", false)) {
- m_activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
-
- /* if (!m_activity.isCompatMode()) {
- m_activity.getActionBar().hide();
- } */
- }
- }
-
- public Article getSelectedArticle() {
- return m_article;
- }
-
- public void setActiveArticle(Article article) {
- if (m_article != article) {
- m_article = article;
-
- int position = m_articles.indexOf(m_article);
-
- ViewPager pager = (ViewPager) getView().findViewById(R.id.article_pager);
-
- pager.setCurrentItem(position);
- }
- }
-
- public void selectArticle(boolean next) {
- if (m_article != null) {
- int position = m_articles.indexOf(m_article);
-
- if (next)
- position++;
- else
- position--;
-
- try {
- Article tmp = m_articles.get(position);
-
- if (tmp != null) {
- setActiveArticle(tmp);
- }
-
- } catch (IndexOutOfBoundsException e) {
- // do nothing
- }
- }
- }
-
- public void notifyUpdated() {
- m_adapter.notifyDataSetChanged();
- }
-}
+package org.fox.ttrss; + +import java.util.HashMap; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; +import org.fox.ttrss.types.Feed; +import org.fox.ttrss.util.HeadlinesRequest; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.SharedPreferences; +import android.os.BadParcelableException; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.view.ViewPager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +import com.google.gson.JsonElement; +import com.viewpagerindicator.TitlePageIndicator; +import com.viewpagerindicator.UnderlinePageIndicator; + +public class ArticlePager extends Fragment { + + private final String TAG = "ArticlePager"; + private PagerAdapter m_adapter; + private HeadlinesEventListener m_listener; + private Article m_article; + private ArticleList m_articles = GlobalState.getInstance().m_loadedArticles; + private OnlineActivity m_activity; + private String m_searchQuery = ""; + private Feed m_feed; + private SharedPreferences m_prefs; + + private class PagerAdapter extends FragmentStatePagerAdapter { + + public PagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + Article article = m_articles.get(position); + + if (article != null) { + ArticleFragment af = new ArticleFragment(article); + + if (m_prefs.getBoolean("dim_status_bar", false) && getView() != null && !m_activity.isCompatMode()) { + getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + + return af; + } + return null; + } + + @Override + public int getCount() { + return m_articles.size(); + } + + } + + public ArticlePager() { + super(); + } + + public ArticlePager(Article article, Feed feed) { + super(); + + m_article = article; + m_feed = feed; + } + + public void setSearchQuery(String searchQuery) { + m_searchQuery = searchQuery; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.article_pager, container, false); + + if (savedInstanceState != null) { + m_article = savedInstanceState.getParcelable("article"); + m_feed = savedInstanceState.getParcelable("feed"); + } + + m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager()); + + ViewPager pager = (ViewPager) view.findViewById(R.id.article_pager); + + int position = m_articles.indexOf(m_article); + + m_listener.onArticleSelected(m_article, false); + + m_activity.setProgressBarVisibility(true); + + pager.setAdapter(m_adapter); + + UnderlinePageIndicator indicator = (UnderlinePageIndicator)view.findViewById(R.id.article_titles); + indicator.setViewPager(pager); + + pager.setCurrentItem(position); + + indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + + @Override + public void onPageScrollStateChanged(int arg0) { + } + + @Override + public void onPageScrolled(int arg0, float arg1, int arg2) { + } + + @Override + public void onPageSelected(int position) { + Article article = m_articles.get(position); + + if (article != null) { + m_article = article; + + /* if (article.unread) { + article.unread = false; + m_activity.saveArticleUnread(article); + } */ + + m_listener.onArticleSelected(article, false); + + //Log.d(TAG, "Page #" + position + "/" + m_adapter.getCount()); + + if ((m_activity.isSmallScreen() || m_activity.isPortrait()) && position == m_adapter.getCount() - 5) { + Log.d(TAG, "loading more articles..."); + refresh(true); + } + } + } + }); + + return view; + } + + @SuppressWarnings({ "unchecked", "serial" }) + protected void refresh(boolean append) { + m_activity.setLoadingStatus(R.string.blank, true); + + m_activity.setProgressBarVisibility(true); + + if (!m_feed.equals(GlobalState.getInstance().m_activeFeed)) { + append = false; + } + + HeadlinesRequest req = new HeadlinesRequest(getActivity().getApplicationContext(), m_activity) { + @Override + protected void onProgressUpdate(Integer... progress) { + m_activity.setProgress(progress[0] / progress[1] * 10000); + } + + @Override + protected void onPostExecute(JsonElement result) { + if (isDetached()) return; + + m_activity.setProgressBarVisibility(false); + + super.onPostExecute(result); + + if (result != null) { + try { + m_adapter.notifyDataSetChanged(); + } catch (BadParcelableException e) { + if (getActivity() != null) { + getActivity().finish(); + return; + } + } + + if (m_article.id == 0 || m_articles.indexOf(m_article) == -1) { + if (m_articles.size() > 0) { + m_article = m_articles.get(0); + m_listener.onArticleSelected(m_article, false); + } + } + + } else { + if (m_lastError == ApiError.LOGIN_FAILED) { + m_activity.login(true); + } else { + m_activity.toast(getErrorMessage()); + //setLoadingStatus(getErrorMessage(), false); + } + } + } + }; + + final Feed feed = m_feed; + + final String sessionId = m_activity.getSessionId(); + int skip = 0; + + if (append) { + for (Article a : m_articles) { + if (a.unread) ++skip; + } + + if (skip == 0) skip = m_articles.size(); + } + + final int fskip = skip; + + req.setOffset(skip); + + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getHeadlines"); + put("sid", sessionId); + put("feed_id", String.valueOf(feed.id)); + put("show_content", "true"); + put("include_attachments", "true"); + put("limit", String.valueOf(HeadlinesFragment.HEADLINES_REQUEST_SIZE)); + put("offset", String.valueOf(0)); + put("view_mode", m_activity.getViewMode()); + put("skip", String.valueOf(fskip)); + put("include_nested", "true"); + put("order_by", m_prefs.getBoolean("oldest_first", false) ? "date_reverse" : ""); + + if (feed.is_cat) put("is_cat", "true"); + + if (m_searchQuery != null && m_searchQuery.length() != 0) { + put("search", m_searchQuery); + put("search_mode", ""); + put("match_on", "both"); + } + } + }; + + req.execute(map); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putParcelable("article", m_article); + out.putParcelable("feed", m_feed); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_listener = (HeadlinesEventListener)activity; + m_activity = (OnlineActivity)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + } + + @SuppressLint("NewApi") + @Override + public void onResume() { + super.onResume(); + + if (m_articles.size() == 0 || !m_feed.equals(GlobalState.getInstance().m_activeFeed)) { + refresh(false); + GlobalState.getInstance().m_activeFeed = m_feed; + } + + m_activity.initMenu(); + + if (!m_activity.isCompatMode() && m_prefs.getBoolean("dim_status_bar", false)) { + getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + + if (m_prefs.getBoolean("full_screen_mode", false)) { + m_activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + + /* if (!m_activity.isCompatMode()) { + m_activity.getSupportActionBar().hide(); + } */ + } + } + + public Article getSelectedArticle() { + return m_article; + } + + public void setActiveArticle(Article article) { + if (m_article != article) { + m_article = article; + + int position = m_articles.indexOf(m_article); + + ViewPager pager = (ViewPager) getView().findViewById(R.id.article_pager); + + pager.setCurrentItem(position); + } + } + + public void selectArticle(boolean next) { + if (m_article != null) { + int position = m_articles.indexOf(m_article); + + if (next) + position++; + else + position--; + + try { + Article tmp = m_articles.get(position); + + if (tmp != null) { + setActiveArticle(tmp); + } + + } catch (IndexOutOfBoundsException e) { + // do nothing + } + } + } + + public void notifyUpdated() { + m_adapter.notifyDataSetChanged(); + } +} diff --git a/src/org/fox/ttrss/CommonActivity.java b/src/org/fox/ttrss/CommonActivity.java index 3db70fdf..58e1f882 100644 --- a/src/org/fox/ttrss/CommonActivity.java +++ b/src/org/fox/ttrss/CommonActivity.java @@ -1,160 +1,155 @@ -package org.fox.ttrss;
-
-import org.fox.ttrss.util.DatabaseHelper;
-
-import android.annotation.SuppressLint;
-import android.content.SharedPreferences;
-import android.database.sqlite.SQLiteDatabase;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.app.FragmentActivity;
-import android.util.Log;
-import android.view.Display;
-import android.view.View;
-import android.widget.TextView;
-import android.widget.Toast;
-
-public class CommonActivity extends FragmentActivity {
- private final String TAG = this.getClass().getSimpleName();
-
- public final static String FRAG_HEADLINES = "headlines";
- public final static String FRAG_ARTICLE = "article";
- public final static String FRAG_FEEDS = "feeds";
- public final static String FRAG_CATS = "cats";
-
- private SQLiteDatabase m_readableDb;
- private SQLiteDatabase m_writableDb;
-
- private boolean m_smallScreenMode = true;
- private boolean m_compatMode = false;
-
- protected SharedPreferences m_prefs;
-
- protected void setSmallScreen(boolean smallScreen) {
- Log.d(TAG, "m_smallScreenMode=" + smallScreen);
- m_smallScreenMode = smallScreen;
- }
-
- public boolean getUnreadOnly() {
- return m_prefs.getBoolean("show_unread_only", true);
- }
-
- public void setUnreadOnly(boolean unread) {
- SharedPreferences.Editor editor = m_prefs.edit();
- editor.putBoolean("show_unread_only", unread);
- editor.commit();
- }
-
- public void setLoadingStatus(int status, boolean showProgress) {
- TextView tv = (TextView) findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
-
- findViewById(R.id.loading_container).setVisibility(status == R.string.blank ? View.GONE : View.VISIBLE);
-
- setProgressBarIndeterminateVisibility(showProgress);
- }
-
- public void toast(int msgId) {
- Toast toast = Toast.makeText(CommonActivity.this, msgId, Toast.LENGTH_SHORT);
- toast.show();
- }
-
- public void toast(String msg) {
- Toast toast = Toast.makeText(CommonActivity.this, msg, Toast.LENGTH_SHORT);
- toast.show();
- }
-
- private void initDatabase() {
- DatabaseHelper dh = new DatabaseHelper(getApplicationContext());
-
- m_writableDb = dh.getWritableDatabase();
- m_readableDb = dh.getReadableDatabase();
- }
-
- public synchronized SQLiteDatabase getReadableDb() {
- return m_readableDb;
- }
-
- public synchronized SQLiteDatabase getWritableDb() {
- return m_writableDb;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- m_readableDb.close();
- m_writableDb.close();
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- initDatabase();
-
- m_compatMode = android.os.Build.VERSION.SDK_INT <= 10;
-
- Log.d(TAG, "m_compatMode=" + m_compatMode);
-
- super.onCreate(savedInstanceState);
- }
-
- public boolean isSmallScreen() {
- return m_smallScreenMode;
- }
-
- public boolean isCompatMode() {
- return m_compatMode;
- }
-
- @SuppressWarnings("deprecation")
- public boolean isPortrait() {
- Display display = getWindowManager().getDefaultDisplay();
-
- int width = display.getWidth();
- int height = display.getHeight();
-
- return width < height;
- }
-
- @SuppressLint("NewApi")
- @SuppressWarnings("deprecation")
- public void copyToClipboard(String str) {
- if (android.os.Build.VERSION.SDK_INT < 11) {
- android.text.ClipboardManager clipboard = (android.text.ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
- clipboard.setText(str);
- } else {
- android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
- clipboard.setText(str);
- }
-
- Toast toast = Toast.makeText(this, R.string.text_copied_to_clipboard, Toast.LENGTH_SHORT);
- toast.show();
- }
-
- protected void setAppTheme(SharedPreferences prefs) {
- String defaultTheme = "THEME_DARK";
-
- if (prefs.getString("theme", defaultTheme).equals("THEME_DARK")) {
- setTheme(R.style.DarkTheme);
- } else if (prefs.getString("theme", defaultTheme).equals("THEME_SEPIA")) {
- setTheme(R.style.SepiaTheme);
- } else if (prefs.getString("theme", defaultTheme).equals("THEME_DARK_GRAY")) {
- setTheme(R.style.DarkGrayTheme);
- } else {
- // LightTheme is not supported on honeycomb
-
- if (android.os.Build.VERSION.SDK_INT >= 11 && android.os.Build.VERSION.SDK_INT < 14) {
- toast(R.string.light_theme_is_not_supported_on_honeycomb);
- setTheme(R.style.DarkTheme);
- } else {
- setTheme(R.style.LightTheme);
- }
- }
- }
-}
+package org.fox.ttrss; + +import org.fox.ttrss.util.DatabaseHelper; + +import com.actionbarsherlock.app.SherlockFragmentActivity; + +import android.annotation.SuppressLint; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.FragmentActivity; +import android.util.Log; +import android.view.Display; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +public class CommonActivity extends SherlockFragmentActivity { + private final String TAG = this.getClass().getSimpleName(); + + public final static String FRAG_HEADLINES = "headlines"; + public final static String FRAG_ARTICLE = "article"; + public final static String FRAG_FEEDS = "feeds"; + public final static String FRAG_CATS = "cats"; + + private SQLiteDatabase m_readableDb; + private SQLiteDatabase m_writableDb; + + private boolean m_smallScreenMode = true; + private boolean m_compatMode = false; + + protected SharedPreferences m_prefs; + + protected void setSmallScreen(boolean smallScreen) { + Log.d(TAG, "m_smallScreenMode=" + smallScreen); + m_smallScreenMode = smallScreen; + } + + public boolean getUnreadOnly() { + return m_prefs.getBoolean("show_unread_only", true); + } + + public void setUnreadOnly(boolean unread) { + SharedPreferences.Editor editor = m_prefs.edit(); + editor.putBoolean("show_unread_only", unread); + editor.commit(); + } + + public void setLoadingStatus(int status, boolean showProgress) { + TextView tv = (TextView) findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + + findViewById(R.id.loading_container).setVisibility(status == R.string.blank ? View.GONE : View.VISIBLE); + + setProgressBarIndeterminateVisibility(showProgress); + } + + public void toast(int msgId) { + Toast toast = Toast.makeText(CommonActivity.this, msgId, Toast.LENGTH_SHORT); + toast.show(); + } + + public void toast(String msg) { + Toast toast = Toast.makeText(CommonActivity.this, msg, Toast.LENGTH_SHORT); + toast.show(); + } + + private void initDatabase() { + DatabaseHelper dh = new DatabaseHelper(getApplicationContext()); + + m_writableDb = dh.getWritableDatabase(); + m_readableDb = dh.getReadableDatabase(); + } + + public synchronized SQLiteDatabase getReadableDb() { + return m_readableDb; + } + + public synchronized SQLiteDatabase getWritableDb() { + return m_writableDb; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + m_readableDb.close(); + m_writableDb.close(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + initDatabase(); + + m_compatMode = android.os.Build.VERSION.SDK_INT <= 10; + + Log.d(TAG, "m_compatMode=" + m_compatMode); + + super.onCreate(savedInstanceState); + } + + public boolean isSmallScreen() { + return m_smallScreenMode; + } + + public boolean isCompatMode() { + return m_compatMode; + } + + @SuppressWarnings("deprecation") + public boolean isPortrait() { + Display display = getWindowManager().getDefaultDisplay(); + + int width = display.getWidth(); + int height = display.getHeight(); + + return width < height; + } + + @SuppressLint("NewApi") + @SuppressWarnings("deprecation") + public void copyToClipboard(String str) { + if (android.os.Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + clipboard.setText(str); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + clipboard.setText(str); + } + + Toast toast = Toast.makeText(this, R.string.text_copied_to_clipboard, Toast.LENGTH_SHORT); + toast.show(); + } + + protected void setAppTheme(SharedPreferences prefs) { + String defaultTheme = "THEME_DARK"; + + if (prefs.getString("theme", defaultTheme).equals("THEME_DARK")) { + setTheme(R.style.DarkTheme); + } else if (prefs.getString("theme", defaultTheme).equals("THEME_SEPIA")) { + setTheme(R.style.SepiaTheme); + } else if (prefs.getString("theme", defaultTheme).equals("THEME_DARK_GRAY")) { + setTheme(R.style.DarkGrayTheme); + } else { + setTheme(R.style.LightTheme); + } + } +} diff --git a/src/org/fox/ttrss/DummyFragment.java b/src/org/fox/ttrss/DummyFragment.java index 7fd0f03e..7bf799a9 100644 --- a/src/org/fox/ttrss/DummyFragment.java +++ b/src/org/fox/ttrss/DummyFragment.java @@ -1,17 +1,17 @@ -package org.fox.ttrss;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-public class DummyFragment extends Fragment {
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- View view = inflater.inflate(R.layout.dummy_fragment, container, false);
-
- return view;
- }
-}
+package org.fox.ttrss; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class DummyFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + View view = inflater.inflate(R.layout.dummy_fragment, container, false); + + return view; + } +} diff --git a/src/org/fox/ttrss/FeedCategoriesFragment.java b/src/org/fox/ttrss/FeedCategoriesFragment.java index 1dfda7f2..1cf7d4e6 100644 --- a/src/org/fox/ttrss/FeedCategoriesFragment.java +++ b/src/org/fox/ttrss/FeedCategoriesFragment.java @@ -1,452 +1,452 @@ -package org.fox.ttrss;
-
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-
-import org.fox.ttrss.types.Feed;
-import org.fox.ttrss.types.FeedCategory;
-import org.fox.ttrss.types.FeedCategoryList;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.reflect.TypeToken;
-
-public class FeedCategoriesFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener {
- private final String TAG = this.getClass().getSimpleName();
- private SharedPreferences m_prefs;
- private FeedCategoryListAdapter m_adapter;
- private FeedCategoryList m_cats = new FeedCategoryList();
- private FeedCategory m_selectedCat;
- private FeedsActivity m_activity;
-
- class CatUnreadComparator implements Comparator<FeedCategory> {
- @Override
- public int compare(FeedCategory a, FeedCategory b) {
- if (a.unread != b.unread)
- return b.unread - a.unread;
- else
- return a.title.compareTo(b.title);
- }
- }
-
-
- class CatTitleComparator implements Comparator<FeedCategory> {
-
- @Override
- public int compare(FeedCategory a, FeedCategory b) {
- if (a.id >= 0 && b.id >= 0)
- return a.title.compareTo(b.title);
- else
- return a.id - b.id;
- }
-
- }
-
- class CatOrderComparator implements Comparator<FeedCategory> {
-
- @Override
- public int compare(FeedCategory a, FeedCategory b) {
- if (a.id >= 0 && b.id >= 0)
- if (a.order_id != 0 && b.order_id != 0)
- return a.order_id - b.order_id;
- else
- return a.title.compareTo(b.title);
- else
- return a.id - b.id;
- }
-
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
-
- switch (item.getItemId()) {
- case R.id.browse_articles:
- if (true) {
- FeedCategory cat = getCategoryAtPosition(info.position);
- if (cat != null) {
- m_activity.openFeedArticles(new Feed(cat.id, cat.title, true));
- //setSelectedCategory(cat);
- }
- }
- return true;
- case R.id.browse_headlines:
- if (true) {
- FeedCategory cat = getCategoryAtPosition(info.position);
- if (cat != null) {
- m_activity.onCatSelected(cat, true);
- //setSelectedCategory(cat);
- }
- }
- return true;
- case R.id.browse_feeds:
- if (true) {
- FeedCategory cat = getCategoryAtPosition(info.position);
- if (cat != null) {
- m_activity.onCatSelected(cat, false);
- //cf.setSelectedCategory(cat);
- }
- }
- return true;
- case R.id.catchup_category:
- if (true) {
- FeedCategory cat = getCategoryAtPosition(info.position);
- if (cat != null) {
- m_activity.catchupFeed(new Feed(cat.id, cat.title, true));
- }
- }
- return true;
-
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- m_activity.getMenuInflater().inflate(R.menu.category_menu, menu);
-
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
- FeedCategory cat = m_adapter.getItem(info.position);
-
- if (cat != null)
- menu.setHeaderTitle(cat.title);
-
- if (!m_activity.isSmallScreen()) {
- menu.findItem(R.id.browse_articles).setVisible(false);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- public FeedCategory getCategoryAtPosition(int position) {
- return m_adapter.getItem(position);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- if (savedInstanceState != null) {
- m_selectedCat = savedInstanceState.getParcelable("selectedCat");
- m_cats = savedInstanceState.getParcelable("cats");
- }
-
- View view = inflater.inflate(R.layout.cats_fragment, container, false);
-
- ListView list = (ListView)view.findViewById(R.id.feeds);
- m_adapter = new FeedCategoryListAdapter(getActivity(), R.layout.feeds_row, (ArrayList<FeedCategory>)m_cats);
- list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- registerForContextMenu(list);
-
- return view;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_activity = (FeedsActivity)activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- m_prefs.registerOnSharedPreferenceChangeListener(this);
-
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- refresh(false);
-
- m_activity.initMenu();
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putParcelable("selectedCat", m_selectedCat);
- out.putParcelable("cats", m_cats);
- }
-
- /* private void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- m_activity.setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- @SuppressWarnings("unchecked")
- public void refresh(boolean background) {
- CatsRequest req = new CatsRequest(getActivity().getApplicationContext());
-
- final String sessionId = m_activity.getSessionId();
- final boolean unreadOnly = m_activity.getUnreadOnly();
-
- if (sessionId != null) {
- m_activity.setLoadingStatus(R.string.blank, true);
- m_activity.setProgressBarVisibility(true);
-
- @SuppressWarnings("serial")
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getCategories");
- put("sid", sessionId);
- put("enable_nested", "true");
- if (unreadOnly) {
- put("unread_only", String.valueOf(unreadOnly));
- }
- }
- };
-
- req.execute(map);
- }
- }
-
- private class CatsRequest extends ApiRequest {
-
- public CatsRequest(Context context) {
- super(context);
- }
-
- @Override
- protected void onProgressUpdate(Integer... progress) {
- m_activity.setProgress(Math.round((((float)progress[0] / (float)progress[1]) * 10000)));
- }
-
- @Override
- protected void onPostExecute(JsonElement result) {
- if (isDetached()) return;
-
- m_activity.setProgressBarVisibility(false);
-
- if (getView() != null) {
- ListView list = (ListView)getView().findViewById(R.id.feeds);
-
- if (list != null) {
- list.setEmptyView(getView().findViewById(R.id.no_feeds));
- }
- }
-
- if (result != null) {
- try {
- JsonArray content = result.getAsJsonArray();
- if (content != null) {
- Type listType = new TypeToken<List<FeedCategory>>() {}.getType();
- final List<FeedCategory> cats = new Gson().fromJson(content, listType);
-
- m_cats.clear();
-
- int apiLevel = m_activity.getApiLevel();
-
- // virtual cats implemented in getCategories since api level 1
- if (apiLevel == 0) {
- m_cats.add(new FeedCategory(-1, "Special", 0));
- m_cats.add(new FeedCategory(-2, "Labels", 0));
- m_cats.add(new FeedCategory(0, "Uncategorized", 0));
- }
-
- for (FeedCategory c : cats)
- m_cats.add(c);
-
- sortCats();
-
- /* if (m_cats.size() == 0)
- setLoadingStatus(R.string.no_feeds_to_display, false);
- else */
-
- //m_adapter.notifyDataSetChanged(); (done by sortCats)
- m_activity.setLoadingStatus(R.string.blank, false);
-
- return;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- if (m_lastError == ApiError.LOGIN_FAILED) {
- m_activity.login(true);
- } else {
- m_activity.setLoadingStatus(getErrorMessage(), false);
- }
- }
-
- }
-
- public void sortCats() {
- Comparator<FeedCategory> cmp;
-
- if (m_prefs.getBoolean("sort_feeds_by_unread", false)) {
- cmp = new CatUnreadComparator();
- } else {
- if (m_activity.getApiLevel() >= 3) {
- cmp = new CatOrderComparator();
- } else {
- cmp = new CatTitleComparator();
- }
- }
-
- Collections.sort(m_cats, cmp);
- try {
- m_adapter.notifyDataSetChanged();
- } catch (NullPointerException e) {
- // adapter missing
- }
-
- }
-
- private class FeedCategoryListAdapter extends ArrayAdapter<FeedCategory> {
- private ArrayList<FeedCategory> items;
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_SELECTED = 1;
-
- public static final int VIEW_COUNT = VIEW_SELECTED+1;
-
- public FeedCategoryListAdapter(Context context, int textViewResourceId, ArrayList<FeedCategory> items) {
- super(context, textViewResourceId, items);
- this.items = items;
- }
-
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- FeedCategory cat = items.get(position);
-
- if (!m_activity.isSmallScreen() && m_selectedCat != null && cat.id == m_selectedCat.id) {
- return VIEW_SELECTED;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
-
- FeedCategory cat = items.get(position);
-
- if (v == null) {
- int layoutId = R.layout.feeds_row;
-
- switch (getItemViewType(position)) {
- case VIEW_SELECTED:
- layoutId = R.layout.feeds_row_selected;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- }
-
- TextView tt = (TextView) v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(cat.title);
- }
-
- TextView tu = (TextView) v.findViewById(R.id.unread_counter);
-
- if (tu != null) {
- tu.setText(String.valueOf(cat.unread));
- tu.setVisibility((cat.unread > 0) ? View.VISIBLE : View.INVISIBLE);
- }
-
- ImageView icon = (ImageView)v.findViewById(R.id.icon);
-
- if (icon != null) {
- icon.setImageResource(cat.unread > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- return v;
- }
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
-
- sortCats();
-
- }
-
- @Override
- public void onItemClick(AdapterView<?> av, View view, int position, long id) {
- ListView list = (ListView)av;
-
- if (list != null) {
- FeedCategory cat = (FeedCategory)list.getItemAtPosition(position);
-
- if (cat.id < 0) {
- m_activity.onCatSelected(cat, false);
- } else {
- if ("ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES")) &&
- m_prefs.getBoolean("browse_cats_like_feeds", false)) {
-
- m_activity.openFeedArticles(new Feed(cat.id, cat.title, true));
-
- } else {
- m_activity.onCatSelected(cat);
- }
- }
-
- if (!m_activity.isSmallScreen())
- m_selectedCat = cat;
-
- m_adapter.notifyDataSetChanged();
- }
- }
-
- public void setSelectedCategory(FeedCategory cat) {
- m_selectedCat = cat;
- m_adapter.notifyDataSetChanged();
- }
-
- public FeedCategory getSelectedCategory() {
- return m_selectedCat;
- }
-}
+package org.fox.ttrss; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +import org.fox.ttrss.types.Feed; +import org.fox.ttrss.types.FeedCategory; +import org.fox.ttrss.types.FeedCategoryList; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +public class FeedCategoriesFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener { + private final String TAG = this.getClass().getSimpleName(); + private SharedPreferences m_prefs; + private FeedCategoryListAdapter m_adapter; + private FeedCategoryList m_cats = new FeedCategoryList(); + private FeedCategory m_selectedCat; + private FeedsActivity m_activity; + + class CatUnreadComparator implements Comparator<FeedCategory> { + @Override + public int compare(FeedCategory a, FeedCategory b) { + if (a.unread != b.unread) + return b.unread - a.unread; + else + return a.title.compareTo(b.title); + } + } + + + class CatTitleComparator implements Comparator<FeedCategory> { + + @Override + public int compare(FeedCategory a, FeedCategory b) { + if (a.id >= 0 && b.id >= 0) + return a.title.compareTo(b.title); + else + return a.id - b.id; + } + + } + + class CatOrderComparator implements Comparator<FeedCategory> { + + @Override + public int compare(FeedCategory a, FeedCategory b) { + if (a.id >= 0 && b.id >= 0) + if (a.order_id != 0 && b.order_id != 0) + return a.order_id - b.order_id; + else + return a.title.compareTo(b.title); + else + return a.id - b.id; + } + + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + + switch (item.getItemId()) { + case R.id.browse_articles: + if (true) { + FeedCategory cat = getCategoryAtPosition(info.position); + if (cat != null) { + m_activity.openFeedArticles(new Feed(cat.id, cat.title, true)); + //setSelectedCategory(cat); + } + } + return true; + case R.id.browse_headlines: + if (true) { + FeedCategory cat = getCategoryAtPosition(info.position); + if (cat != null) { + m_activity.onCatSelected(cat, true); + //setSelectedCategory(cat); + } + } + return true; + case R.id.browse_feeds: + if (true) { + FeedCategory cat = getCategoryAtPosition(info.position); + if (cat != null) { + m_activity.onCatSelected(cat, false); + //cf.setSelectedCategory(cat); + } + } + return true; + case R.id.catchup_category: + if (true) { + FeedCategory cat = getCategoryAtPosition(info.position); + if (cat != null) { + m_activity.catchupFeed(new Feed(cat.id, cat.title, true)); + } + } + return true; + + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + m_activity.getMenuInflater().inflate(R.menu.category_menu, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + FeedCategory cat = m_adapter.getItem(info.position); + + if (cat != null) + menu.setHeaderTitle(cat.title); + + if (!m_activity.isSmallScreen()) { + menu.findItem(R.id.browse_articles).setVisible(false); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + public FeedCategory getCategoryAtPosition(int position) { + return m_adapter.getItem(position); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (savedInstanceState != null) { + m_selectedCat = savedInstanceState.getParcelable("selectedCat"); + m_cats = savedInstanceState.getParcelable("cats"); + } + + View view = inflater.inflate(R.layout.cats_fragment, container, false); + + ListView list = (ListView)view.findViewById(R.id.feeds); + m_adapter = new FeedCategoryListAdapter(getActivity(), R.layout.feeds_row, (ArrayList<FeedCategory>)m_cats); + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + registerForContextMenu(list); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (FeedsActivity)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + m_prefs.registerOnSharedPreferenceChangeListener(this); + + } + + @Override + public void onResume() { + super.onResume(); + + refresh(false); + + m_activity.initMenu(); + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putParcelable("selectedCat", m_selectedCat); + out.putParcelable("cats", m_cats); + } + + /* private void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + m_activity.setProgressBarIndeterminateVisibility(showProgress); + } */ + + @SuppressWarnings("unchecked") + public void refresh(boolean background) { + CatsRequest req = new CatsRequest(getActivity().getApplicationContext()); + + final String sessionId = m_activity.getSessionId(); + final boolean unreadOnly = m_activity.getUnreadOnly(); + + if (sessionId != null) { + m_activity.setLoadingStatus(R.string.blank, true); + m_activity.setProgressBarVisibility(true); + + @SuppressWarnings("serial") + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getCategories"); + put("sid", sessionId); + put("enable_nested", "true"); + if (unreadOnly) { + put("unread_only", String.valueOf(unreadOnly)); + } + } + }; + + req.execute(map); + } + } + + private class CatsRequest extends ApiRequest { + + public CatsRequest(Context context) { + super(context); + } + + @Override + protected void onProgressUpdate(Integer... progress) { + m_activity.setProgress(Math.round((((float)progress[0] / (float)progress[1]) * 10000))); + } + + @Override + protected void onPostExecute(JsonElement result) { + if (isDetached()) return; + + m_activity.setProgressBarVisibility(false); + + if (getView() != null) { + ListView list = (ListView)getView().findViewById(R.id.feeds); + + if (list != null) { + list.setEmptyView(getView().findViewById(R.id.no_feeds)); + } + } + + if (result != null) { + try { + JsonArray content = result.getAsJsonArray(); + if (content != null) { + Type listType = new TypeToken<List<FeedCategory>>() {}.getType(); + final List<FeedCategory> cats = new Gson().fromJson(content, listType); + + m_cats.clear(); + + int apiLevel = m_activity.getApiLevel(); + + // virtual cats implemented in getCategories since api level 1 + if (apiLevel == 0) { + m_cats.add(new FeedCategory(-1, "Special", 0)); + m_cats.add(new FeedCategory(-2, "Labels", 0)); + m_cats.add(new FeedCategory(0, "Uncategorized", 0)); + } + + for (FeedCategory c : cats) + m_cats.add(c); + + sortCats(); + + /* if (m_cats.size() == 0) + setLoadingStatus(R.string.no_feeds_to_display, false); + else */ + + //m_adapter.notifyDataSetChanged(); (done by sortCats) + m_activity.setLoadingStatus(R.string.blank, false); + + return; + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (m_lastError == ApiError.LOGIN_FAILED) { + m_activity.login(true); + } else { + m_activity.setLoadingStatus(getErrorMessage(), false); + } + } + + } + + public void sortCats() { + Comparator<FeedCategory> cmp; + + if (m_prefs.getBoolean("sort_feeds_by_unread", false)) { + cmp = new CatUnreadComparator(); + } else { + if (m_activity.getApiLevel() >= 3) { + cmp = new CatOrderComparator(); + } else { + cmp = new CatTitleComparator(); + } + } + + Collections.sort(m_cats, cmp); + try { + m_adapter.notifyDataSetChanged(); + } catch (NullPointerException e) { + // adapter missing + } + + } + + private class FeedCategoryListAdapter extends ArrayAdapter<FeedCategory> { + private ArrayList<FeedCategory> items; + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_SELECTED = 1; + + public static final int VIEW_COUNT = VIEW_SELECTED+1; + + public FeedCategoryListAdapter(Context context, int textViewResourceId, ArrayList<FeedCategory> items) { + super(context, textViewResourceId, items); + this.items = items; + } + + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + FeedCategory cat = items.get(position); + + if (!m_activity.isSmallScreen() && m_selectedCat != null && cat.id == m_selectedCat.id) { + return VIEW_SELECTED; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + + FeedCategory cat = items.get(position); + + if (v == null) { + int layoutId = R.layout.feeds_row; + + switch (getItemViewType(position)) { + case VIEW_SELECTED: + layoutId = R.layout.feeds_row_selected; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + } + + TextView tt = (TextView) v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(cat.title); + } + + TextView tu = (TextView) v.findViewById(R.id.unread_counter); + + if (tu != null) { + tu.setText(String.valueOf(cat.unread)); + tu.setVisibility((cat.unread > 0) ? View.VISIBLE : View.INVISIBLE); + } + + ImageView icon = (ImageView)v.findViewById(R.id.icon); + + if (icon != null) { + icon.setImageResource(cat.unread > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + return v; + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + + sortCats(); + + } + + @Override + public void onItemClick(AdapterView<?> av, View view, int position, long id) { + ListView list = (ListView)av; + + if (list != null) { + FeedCategory cat = (FeedCategory)list.getItemAtPosition(position); + + if (cat.id < 0) { + m_activity.onCatSelected(cat, false); + } else { + if ("ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES")) && + m_prefs.getBoolean("browse_cats_like_feeds", false)) { + + m_activity.openFeedArticles(new Feed(cat.id, cat.title, true)); + + } else { + m_activity.onCatSelected(cat); + } + } + + if (!m_activity.isSmallScreen()) + m_selectedCat = cat; + + m_adapter.notifyDataSetChanged(); + } + } + + public void setSelectedCategory(FeedCategory cat) { + m_selectedCat = cat; + m_adapter.notifyDataSetChanged(); + } + + public FeedCategory getSelectedCategory() { + return m_selectedCat; + } +} diff --git a/src/org/fox/ttrss/FeedsActivity.java b/src/org/fox/ttrss/FeedsActivity.java index 8904d4cb..510d756a 100644 --- a/src/org/fox/ttrss/FeedsActivity.java +++ b/src/org/fox/ttrss/FeedsActivity.java @@ -1,391 +1,391 @@ -package org.fox.ttrss;
-
-import java.util.Date;
-
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.ArticleList;
-import org.fox.ttrss.types.Feed;
-import org.fox.ttrss.types.FeedCategory;
-import org.fox.ttrss.util.AppRater;
-
-import android.view.ViewGroup;
-import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.LinearLayout;
-
-public class FeedsActivity extends OnlineActivity implements HeadlinesEventListener {
- private final String TAG = this.getClass().getSimpleName();
-
- private static final int HEADLINES_REQUEST = 1;
-
- protected SharedPreferences m_prefs;
- protected long m_lastRefresh = 0;
-
- private boolean m_actionbarUpEnabled = false;
-
- @SuppressLint("NewApi")
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.feeds);
-
- setSmallScreen(findViewById(R.id.headlines_fragment) == null);
-
- GlobalState.getInstance().load(savedInstanceState);
-
- Intent intent = getIntent();
-
- if (savedInstanceState == null) {
-
- if (intent.getParcelableExtra("feed") != null || intent.getParcelableExtra("category") != null ||
- intent.getParcelableExtra("article") != null) {
-
- if (!isCompatMode()) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- m_actionbarUpEnabled = true;
- }
-
- Feed feed = (Feed) intent.getParcelableExtra("feed");
- FeedCategory cat = (FeedCategory) intent.getParcelableExtra("category");
- Article article = (Article) intent.getParcelableExtra("article");
-
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- if (article != null) {
- Article original = GlobalState.getInstance().m_loadedArticles.findById(article.id);
-
- ArticlePager ap = new ArticlePager(original != null ? original : article, feed);
- ft.replace(R.id.feeds_fragment, ap, FRAG_ARTICLE);
-
- ap.setSearchQuery(intent.getStringExtra("searchQuery"));
-
- setTitle(feed.title);
- } else {
- if (feed != null) {
- HeadlinesFragment hf = new HeadlinesFragment(feed);
- ft.replace(R.id.feeds_fragment, hf, FRAG_HEADLINES);
-
- setTitle(feed.title);
- }
-
- if (cat != null) {
- FeedsFragment ff = new FeedsFragment(cat);
- ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS);
-
- setTitle(cat.title);
- }
- }
-
- ft.commit();
-
- } else {
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- if (m_prefs.getBoolean("enable_cats", false)) {
- ft.replace(R.id.feeds_fragment, new FeedCategoriesFragment(), FRAG_CATS);
- } else {
- ft.replace(R.id.feeds_fragment, new FeedsFragment(), FRAG_FEEDS);
- }
-
- /* if (!isSmallScreen()) {
- ft.replace(R.id.headlines_fragment, new HeadlinesFragment(new Feed(-3, "Fresh articles", false)));
- } */
-
- ft.commit();
-
- AppRater.appLaunched(this);
- checkTrial(true);
- }
- } else { // savedInstanceState != null
- m_actionbarUpEnabled = savedInstanceState.getBoolean("actionbarUpEnabled");
-
- if (!isSmallScreen()) {
- // temporary hack because FeedsActivity doesn't track whether active feed is open
- LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container);
- container.setWeightSum(3f);
- }
-
- if (!isCompatMode() && m_actionbarUpEnabled) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- }
- }
-
- if (!isCompatMode() && !isSmallScreen()) {
- ((ViewGroup)findViewById(R.id.headlines_fragment)).setLayoutTransition(new LayoutTransition());
- ((ViewGroup)findViewById(R.id.feeds_fragment)).setLayoutTransition(new LayoutTransition());
- }
-
- }
-
- @Override
- protected void initMenu() {
- super.initMenu();
-
- if (m_menu != null && getSessionId() != null) {
- Fragment ff = getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS);
- Fragment cf = getSupportFragmentManager().findFragmentByTag(FRAG_CATS);
- ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
- HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- m_menu.setGroupVisible(R.id.menu_group_feeds, (ff != null && ff.isAdded()) || (cf != null && cf.isAdded()));
-
- m_menu.setGroupVisible(R.id.menu_group_article, af != null && af.isAdded());
-
- m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded() && hf.getSelectedArticles().size() == 0);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.isAdded() && hf.getSelectedArticles().size() != 0);
-
- if (isSmallScreen()) {
- m_menu.findItem(R.id.update_headlines).setVisible(hf != null && hf.isAdded());
- } else {
- m_menu.findItem(R.id.update_headlines).setVisible(false);
- }
-
- if (af != null) {
- if (af.getSelectedArticle() != null && af.getSelectedArticle().attachments != null && af.getSelectedArticle().attachments.size() > 0) {
- if (!isCompatMode()) {
- m_menu.findItem(R.id.toggle_attachments).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- }
- m_menu.findItem(R.id.toggle_attachments).setVisible(true);
- } else {
- if (!isCompatMode()) {
- m_menu.findItem(R.id.toggle_attachments).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- }
- m_menu.findItem(R.id.toggle_attachments).setVisible(false);
- }
- }
-
- MenuItem item = m_menu.findItem(R.id.show_feeds);
-
- if (getUnreadOnly()) {
- item.setTitle(R.string.menu_all_feeds);
- } else {
- item.setTitle(R.string.menu_unread_feeds);
- }
- }
- }
-
- public void onFeedSelected(Feed feed) {
- GlobalState.getInstance().m_loadedArticles.clear();
-
- if (isSmallScreen()) {
- Intent intent = new Intent(FeedsActivity.this, FeedsActivity.class);
- intent.putExtra("feed", feed);
-
- startActivityForResult(intent, 0);
- } else {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- ft.replace(R.id.headlines_fragment, new LoadingFragment(), null);
- ft.commit();
-
- if (!isCompatMode()) {
- LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container);
- float wSum = container.getWeightSum();
- if (wSum <= 2.0f) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(container, "weightSum", wSum, 3.0f);
- anim.setDuration(200);
- anim.start();
- }
- }
-
- final Feed fFeed = feed;
-
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- HeadlinesFragment hf = new HeadlinesFragment(fFeed);
- ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES);
-
- ft.commit();
- }
- }, 10);
-
-
- Date date = new Date();
-
- if (date.getTime() - m_lastRefresh > 10000) {
- m_lastRefresh = date.getTime();
- refresh(false);
- }
- }
- }
-
- public void onCatSelected(FeedCategory cat, boolean openAsFeed) {
-
- if (!openAsFeed) {
-
- if (isSmallScreen()) {
-
- Intent intent = new Intent(FeedsActivity.this, FeedsActivity.class);
- intent.putExtra("category", cat);
-
- startActivityForResult(intent, 0);
-
- } else {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- FeedsFragment ff = new FeedsFragment(cat);
- ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS);
-
- ft.addToBackStack(null);
- ft.commit();
- }
- } else {
- Feed feed = new Feed(cat.id, cat.title, true);
- onFeedSelected(feed);
- }
- }
-
- public void onCatSelected(FeedCategory cat) {
- onCatSelected(cat, m_prefs.getBoolean("browse_cats_like_feeds", false));
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.show_feeds:
- setUnreadOnly(!getUnreadOnly());
- initMenu();
- refresh();
- return true;
- case R.id.update_feeds:
- refresh();
- return true;
- default:
- Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- protected void loginSuccess(boolean refresh) {
- setLoadingStatus(R.string.blank, false);
- findViewById(R.id.loading_container).setVisibility(View.GONE);
- initMenu();
-
- if (refresh) refresh();
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putBoolean("actionbarUpEnabled", m_actionbarUpEnabled);
-
- GlobalState.getInstance().save(out);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- initMenu();
- }
-
- @Override
- public void onArticleListSelectionChange(ArticleList m_selectedArticles) {
- initMenu();
- }
-
- public void openFeedArticles(Feed feed) {
- if (isSmallScreen()) {
- Intent intent = new Intent(FeedsActivity.this, FeedsActivity.class);
-
- GlobalState.getInstance().m_activeFeed = feed;
- GlobalState.getInstance().m_loadedArticles.clear();
-
- intent.putExtra("feed", feed);
- intent.putExtra("article", new Article());
- startActivityForResult(intent, 0);
- } else {
- GlobalState.getInstance().m_loadedArticles.clear();
-
- Intent intent = new Intent(FeedsActivity.this, HeadlinesActivity.class);
- intent.putExtra("feed", feed);
- intent.putExtra("article", (Article)null);
- intent.putExtra("searchQuery", (String)null);
-
- startActivityForResult(intent, HEADLINES_REQUEST);
- overridePendingTransition(R.anim.right_slide_in, 0);
- }
- }
-
- public void onArticleSelected(Article article, boolean open) {
- if (article.unread) {
- article.unread = false;
- saveArticleUnread(article);
- }
-
- if (open) {
- HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- if (isSmallScreen()) {
-
- //GlobalState.getInstance().m_loadedArticles.clear();
-
- Intent intent = new Intent(FeedsActivity.this, FeedsActivity.class);
- intent.putExtra("feed", hf.getFeed());
- intent.putExtra("article", article);
- intent.putExtra("searchQuery", hf.getSearchQuery());
-
- startActivityForResult(intent, 0);
-
-
- } else {
- Intent intent = new Intent(FeedsActivity.this, HeadlinesActivity.class);
- intent.putExtra("feed", hf.getFeed());
- intent.putExtra("article", article);
- intent.putExtra("searchQuery", hf.getSearchQuery());
-
- startActivityForResult(intent, HEADLINES_REQUEST);
- overridePendingTransition(R.anim.right_slide_in, 0);
- }
- } else {
- initMenu();
- }
- }
-
- @Override
- public void onArticleSelected(Article article) {
- onArticleSelected(article, true);
- }
-
- public void catchupFeed(final Feed feed) {
- super.catchupFeed(feed);
- refresh();
- }
-
- @Override
- public void onHeadlinesLoaded(boolean appended) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == HEADLINES_REQUEST) {
- GlobalState.getInstance().m_activeArticle = null;
- }
- }
-}
+package org.fox.ttrss; + +import java.util.Date; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; +import org.fox.ttrss.types.Feed; +import org.fox.ttrss.types.FeedCategory; +import org.fox.ttrss.util.AppRater; + +import com.actionbarsherlock.view.MenuItem; + +import android.view.ViewGroup; +import android.animation.LayoutTransition; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.View; +import android.widget.LinearLayout; + +public class FeedsActivity extends OnlineActivity implements HeadlinesEventListener { + private final String TAG = this.getClass().getSimpleName(); + + private static final int HEADLINES_REQUEST = 1; + + protected SharedPreferences m_prefs; + protected long m_lastRefresh = 0; + + private boolean m_actionbarUpEnabled = false; + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + setContentView(R.layout.feeds); + + setSmallScreen(findViewById(R.id.headlines_fragment) == null); + + GlobalState.getInstance().load(savedInstanceState); + + Intent intent = getIntent(); + + if (savedInstanceState == null) { + + if (intent.getParcelableExtra("feed") != null || intent.getParcelableExtra("category") != null || + intent.getParcelableExtra("article") != null) { + + if (!isCompatMode()) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + m_actionbarUpEnabled = true; + } + + Feed feed = (Feed) intent.getParcelableExtra("feed"); + FeedCategory cat = (FeedCategory) intent.getParcelableExtra("category"); + Article article = (Article) intent.getParcelableExtra("article"); + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + if (article != null) { + Article original = GlobalState.getInstance().m_loadedArticles.findById(article.id); + + ArticlePager ap = new ArticlePager(original != null ? original : article, feed); + ft.replace(R.id.feeds_fragment, ap, FRAG_ARTICLE); + + ap.setSearchQuery(intent.getStringExtra("searchQuery")); + + setTitle(feed.title); + } else { + if (feed != null) { + HeadlinesFragment hf = new HeadlinesFragment(feed); + ft.replace(R.id.feeds_fragment, hf, FRAG_HEADLINES); + + setTitle(feed.title); + } + + if (cat != null) { + FeedsFragment ff = new FeedsFragment(cat); + ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS); + + setTitle(cat.title); + } + } + + ft.commit(); + + } else { + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + if (m_prefs.getBoolean("enable_cats", false)) { + ft.replace(R.id.feeds_fragment, new FeedCategoriesFragment(), FRAG_CATS); + } else { + ft.replace(R.id.feeds_fragment, new FeedsFragment(), FRAG_FEEDS); + } + + /* if (!isSmallScreen()) { + ft.replace(R.id.headlines_fragment, new HeadlinesFragment(new Feed(-3, "Fresh articles", false))); + } */ + + ft.commit(); + + AppRater.appLaunched(this); + checkTrial(true); + } + } else { // savedInstanceState != null + m_actionbarUpEnabled = savedInstanceState.getBoolean("actionbarUpEnabled"); + + if (!isSmallScreen()) { + // temporary hack because FeedsActivity doesn't track whether active feed is open + LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container); + container.setWeightSum(3f); + } + + if (!isCompatMode() && m_actionbarUpEnabled) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + } + + if (!isCompatMode() && !isSmallScreen()) { + ((ViewGroup)findViewById(R.id.headlines_fragment)).setLayoutTransition(new LayoutTransition()); + ((ViewGroup)findViewById(R.id.feeds_fragment)).setLayoutTransition(new LayoutTransition()); + } + + } + + @Override + protected void initMenu() { + super.initMenu(); + + if (m_menu != null && getSessionId() != null) { + Fragment ff = getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS); + Fragment cf = getSupportFragmentManager().findFragmentByTag(FRAG_CATS); + ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + m_menu.setGroupVisible(R.id.menu_group_feeds, (ff != null && ff.isAdded()) || (cf != null && cf.isAdded())); + + m_menu.setGroupVisible(R.id.menu_group_article, af != null && af.isAdded()); + + m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded()); + + if (isSmallScreen()) { + m_menu.findItem(R.id.update_headlines).setVisible(hf != null && hf.isAdded()); + } else { + m_menu.findItem(R.id.update_headlines).setVisible(false); + } + + if (af != null) { + if (af.getSelectedArticle() != null && af.getSelectedArticle().attachments != null && af.getSelectedArticle().attachments.size() > 0) { + if (!isCompatMode()) { + m_menu.findItem(R.id.toggle_attachments).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + } + m_menu.findItem(R.id.toggle_attachments).setVisible(true); + } else { + if (!isCompatMode()) { + m_menu.findItem(R.id.toggle_attachments).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + } + m_menu.findItem(R.id.toggle_attachments).setVisible(false); + } + } + + MenuItem item = m_menu.findItem(R.id.show_feeds); + + if (getUnreadOnly()) { + item.setTitle(R.string.menu_all_feeds); + } else { + item.setTitle(R.string.menu_unread_feeds); + } + } + } + + public void onFeedSelected(Feed feed) { + GlobalState.getInstance().m_loadedArticles.clear(); + + if (isSmallScreen()) { + Intent intent = new Intent(FeedsActivity.this, FeedsActivity.class); + intent.putExtra("feed", feed); + + startActivityForResult(intent, 0); + } else { + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + ft.replace(R.id.headlines_fragment, new LoadingFragment(), null); + ft.commit(); + + if (!isCompatMode()) { + LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container); + float wSum = container.getWeightSum(); + if (wSum <= 2.0f) { + ObjectAnimator anim = ObjectAnimator.ofFloat(container, "weightSum", wSum, 3.0f); + anim.setDuration(200); + anim.start(); + } + } + + final Feed fFeed = feed; + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + HeadlinesFragment hf = new HeadlinesFragment(fFeed); + ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES); + + ft.commit(); + } + }, 10); + + + Date date = new Date(); + + if (date.getTime() - m_lastRefresh > 10000) { + m_lastRefresh = date.getTime(); + refresh(false); + } + } + } + + public void onCatSelected(FeedCategory cat, boolean openAsFeed) { + + if (!openAsFeed) { + + if (isSmallScreen()) { + + Intent intent = new Intent(FeedsActivity.this, FeedsActivity.class); + intent.putExtra("category", cat); + + startActivityForResult(intent, 0); + + } else { + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + FeedsFragment ff = new FeedsFragment(cat); + ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS); + + ft.addToBackStack(null); + ft.commit(); + } + } else { + Feed feed = new Feed(cat.id, cat.title, true); + onFeedSelected(feed); + } + } + + public void onCatSelected(FeedCategory cat) { + onCatSelected(cat, m_prefs.getBoolean("browse_cats_like_feeds", false)); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.show_feeds: + setUnreadOnly(!getUnreadOnly()); + initMenu(); + refresh(); + return true; + case R.id.update_feeds: + refresh(); + return true; + default: + Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + @Override + protected void loginSuccess(boolean refresh) { + setLoadingStatus(R.string.blank, false); + findViewById(R.id.loading_container).setVisibility(View.GONE); + initMenu(); + + if (refresh) refresh(); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putBoolean("actionbarUpEnabled", m_actionbarUpEnabled); + + GlobalState.getInstance().save(out); + } + + @Override + public void onResume() { + super.onResume(); + initMenu(); + } + + @Override + public void onArticleListSelectionChange(ArticleList m_selectedArticles) { + initMenu(); + } + + public void openFeedArticles(Feed feed) { + if (isSmallScreen()) { + Intent intent = new Intent(FeedsActivity.this, FeedsActivity.class); + + GlobalState.getInstance().m_activeFeed = feed; + GlobalState.getInstance().m_loadedArticles.clear(); + + intent.putExtra("feed", feed); + intent.putExtra("article", new Article()); + startActivityForResult(intent, 0); + } else { + GlobalState.getInstance().m_loadedArticles.clear(); + + Intent intent = new Intent(FeedsActivity.this, HeadlinesActivity.class); + intent.putExtra("feed", feed); + intent.putExtra("article", (Article)null); + intent.putExtra("searchQuery", (String)null); + + startActivityForResult(intent, HEADLINES_REQUEST); + overridePendingTransition(R.anim.right_slide_in, 0); + } + } + + public void onArticleSelected(Article article, boolean open) { + if (article.unread) { + article.unread = false; + saveArticleUnread(article); + } + + if (open) { + HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + if (isSmallScreen()) { + + //GlobalState.getInstance().m_loadedArticles.clear(); + + Intent intent = new Intent(FeedsActivity.this, FeedsActivity.class); + intent.putExtra("feed", hf.getFeed()); + intent.putExtra("article", article); + intent.putExtra("searchQuery", hf.getSearchQuery()); + + startActivityForResult(intent, 0); + + + } else { + Intent intent = new Intent(FeedsActivity.this, HeadlinesActivity.class); + intent.putExtra("feed", hf.getFeed()); + intent.putExtra("article", article); + intent.putExtra("searchQuery", hf.getSearchQuery()); + + startActivityForResult(intent, HEADLINES_REQUEST); + overridePendingTransition(R.anim.right_slide_in, 0); + } + } else { + initMenu(); + } + } + + @Override + public void onArticleSelected(Article article) { + onArticleSelected(article, true); + } + + public void catchupFeed(final Feed feed) { + super.catchupFeed(feed); + refresh(); + } + + @Override + public void onHeadlinesLoaded(boolean appended) { + // TODO Auto-generated method stub + + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == HEADLINES_REQUEST) { + GlobalState.getInstance().m_activeArticle = null; + } + } +} diff --git a/src/org/fox/ttrss/FeedsFragment.java b/src/org/fox/ttrss/FeedsFragment.java index 9d76a367..1a649c61 100644 --- a/src/org/fox/ttrss/FeedsFragment.java +++ b/src/org/fox/ttrss/FeedsFragment.java @@ -1,670 +1,670 @@ -package org.fox.ttrss;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.lang.reflect.Type;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-
-import org.fox.ttrss.types.Feed;
-import org.fox.ttrss.types.FeedCategory;
-import org.fox.ttrss.types.FeedList;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.http.AndroidHttpClient;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Environment;
-import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.util.Base64;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.reflect.TypeToken;
-
-public class FeedsFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener {
- private final String TAG = this.getClass().getSimpleName();
- private SharedPreferences m_prefs;
- private FeedListAdapter m_adapter;
- private FeedList m_feeds = new FeedList();
- private FeedsActivity m_activity;
- private Feed m_selectedFeed;
- private FeedCategory m_activeCategory;
- private static final String ICON_PATH = "/icons/";
- private boolean m_enableFeedIcons;
- private boolean m_feedIconsChecked = false;
-
- public FeedsFragment() {
-
-
- }
-
- public FeedsFragment(FeedCategory cat) {
- m_activeCategory = cat;
- }
-
- class FeedUnreadComparator implements Comparator<Feed> {
-
- @Override
- public int compare(Feed a, Feed b) {
- if (a.unread != b.unread)
- return b.unread - a.unread;
- else
- return a.title.compareTo(b.title);
- }
-
- }
-
-
- class FeedTitleComparator implements Comparator<Feed> {
-
- @Override
- public int compare(Feed a, Feed b) {
- if (a.is_cat && b.is_cat)
- return a.title.compareTo(b.title);
- else if (a.is_cat && !b.is_cat)
- return -1;
- else if (!a.is_cat && b.is_cat)
- return 1;
- else if (a.id >= 0 && b.id >= 0)
- return a.title.compareTo(b.title);
- else
- return a.id - b.id;
- }
-
- }
-
- class FeedOrderComparator implements Comparator<Feed> {
-
- @Override
- public int compare(Feed a, Feed b) {
- if (a.id >= 0 && b.id >= 0)
- if (a.is_cat && b.is_cat)
- return a.title.compareTo(b.title);
- else if (a.is_cat && !b.is_cat)
- return -1;
- else if (!a.is_cat && b.is_cat)
- return 1;
- else if (a.order_id != 0 && b.order_id != 0)
- return a.order_id - b.order_id;
- else
- return a.title.compareTo(b.title);
- else
- return a.id - b.id;
- }
-
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
- switch (item.getItemId()) {
- case R.id.browse_articles:
- if (true) {
- Feed feed = getFeedAtPosition(info.position);
- if (feed != null) {
- m_activity.openFeedArticles(feed);
- }
- }
- return true;
- case R.id.browse_headlines:
- if (true) {
- Feed feed = getFeedAtPosition(info.position);
- if (feed != null) {
- m_activity.onFeedSelected(feed);
- }
- }
- return true;
- case R.id.browse_feeds:
- if (true) {
- Feed feed = getFeedAtPosition(info.position);
- if (feed != null) {
- m_activity.onCatSelected(new FeedCategory(feed.id, feed.title, feed.unread), false);
- }
- }
- return true;
- case R.id.catchup_feed:
- if (true) {
- Feed feed = getFeedAtPosition(info.position);
- if (feed != null) {
- m_activity.catchupFeed(feed);
- }
- }
- return true;
-
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.feed_menu, menu);
-
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
- Feed feed = m_adapter.getItem(info.position);
-
- if (feed != null)
- menu.setHeaderTitle(feed.title);
-
- if (!m_activity.isSmallScreen()) {
- menu.findItem(R.id.browse_articles).setVisible(false);
- }
-
- if (!feed.is_cat) {
- menu.findItem(R.id.browse_feeds).setVisible(false);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_selectedFeed = savedInstanceState.getParcelable("selectedFeed");
- m_feeds = savedInstanceState.getParcelable("feeds");
- m_feedIconsChecked = savedInstanceState.getBoolean("feedIconsChecked");
- m_activeCategory = savedInstanceState.getParcelable("activeCat");
- }
-
- 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<Feed>)m_feeds);
- list.setAdapter(m_adapter);
- //list.setEmptyView(view.findViewById(R.id.no_feeds));
- list.setOnItemClickListener(this);
-
- registerForContextMenu(list);
-
- m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false);
-
- return view;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- m_prefs.registerOnSharedPreferenceChangeListener(this);
-
- m_activity = (FeedsActivity)activity;
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- refresh(false);
-
- m_activity.initMenu();
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putParcelable("selectedFeed", m_selectedFeed);
- out.putParcelable("feeds", m_feeds);
- out.putBoolean("feedIconsChecked", m_feedIconsChecked);
- out.putParcelable("activeCat", m_activeCategory);
- }
-
- @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);
-
- if (feed.is_cat) {
- if (m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES")) &&
- m_prefs.getBoolean("browse_cats_like_feeds", false)) {
-
- m_activity.openFeedArticles(feed);
-
- } else {
- m_activity.onCatSelected(new FeedCategory(feed.id, feed.title, feed.unread));
- }
- } else {
- if ("ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES"))) {
- m_activity.openFeedArticles(feed);
- } else {
- m_activity.onFeedSelected(feed);
- }
- }
-
- if (!m_activity.isSmallScreen())
- m_selectedFeed = feed;
-
- m_adapter.notifyDataSetChanged();
- }
- }
-
- @SuppressWarnings({ "unchecked", "serial" })
- public void refresh(boolean background) {
- //FeedCategory cat = m_onlineServices.getActiveCategory();
-
- m_activity.setProgressBarVisibility(true);
-
- final int catId = (m_activeCategory != null) ? m_activeCategory.id : -4;
-
- final String sessionId = m_activity.getSessionId();
- final boolean unreadOnly = m_activity.getUnreadOnly();
-
- FeedsRequest req = new FeedsRequest(getActivity().getApplicationContext(), catId);
-
- if (sessionId != null) {
- m_activity.setLoadingStatus(R.string.blank, true);
-
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getFeeds");
- put("sid", sessionId);
- put("include_nested", "true");
- put("cat_id", String.valueOf(catId));
- if (unreadOnly) {
- put("unread_only", String.valueOf(unreadOnly));
- }
- }
- };
-
- req.execute(map);
-
- }
- }
-
- /* private void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- if (getActivity() != null)
- getActivity().setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- @SuppressWarnings({ "unchecked", "serial" })
- public void getFeedIcons() {
-
- ApiRequest req = new ApiRequest(getActivity().getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- if (isDetached()) return;
-
- if (result != null) {
-
- try {
- JsonElement iconsUrl = result.getAsJsonObject().get("icons_dir");
-
- if (iconsUrl != null) {
- String iconsStr = iconsUrl.getAsString();
- String baseUrl = "";
-
- if (!iconsStr.contains("://")) {
- baseUrl = m_prefs.getString("ttrss_url", "") + "/" + iconsStr;
- } else {
- baseUrl = iconsStr;
- }
-
- GetIconsTask git = new GetIconsTask(baseUrl);
- git.execute(m_feeds);
-
- m_feedIconsChecked = true;
- }
- } catch (Exception e) {
- Log.d(TAG, "Error receiving icons configuration");
- e.printStackTrace();
- }
-
- }
- }
- };
-
- final String sessionId = m_activity.getSessionId();
-
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("sid", sessionId);
- put("op", "getConfig");
- }
- };
-
- req.execute(map);
- }
-
- private class FeedsRequest extends ApiRequest {
- private int m_catId;
-
- public FeedsRequest(Context context, int catId) {
- super(context);
- m_catId = catId;
- }
-
- @Override
- protected void onProgressUpdate(Integer... progress) {
- m_activity.setProgress(Math.round((((float)progress[0] / (float)progress[1]) * 10000)));
- }
-
- @Override
- protected void onPostExecute(JsonElement result) {
- if (isDetached()) return;
-
- if (getView() != null) {
- ListView list = (ListView)getView().findViewById(R.id.feeds);
-
- if (list != null) {
- list.setEmptyView(getView().findViewById(R.id.no_feeds));
- }
- }
-
- m_activity.setProgressBarVisibility(false);
-
- if (result != null) {
- try {
- JsonArray content = result.getAsJsonArray();
- if (content != null) {
-
- Type listType = new TypeToken<List<Feed>>() {}.getType();
- final List<Feed> feeds = new Gson().fromJson(content, listType);
-
- m_feeds.clear();
-
- for (Feed f : feeds)
- if (f.id > -10 || m_catId != -4) // skip labels for flat feedlist for now
- m_feeds.add(f);
-
- sortFeeds();
-
- /*if (m_feeds.size() == 0)
- setLoadingStatus(R.string.no_feeds_to_display, false);
- else */
-
- m_activity.setLoadingStatus(R.string.blank, false);
- //m_adapter.notifyDataSetChanged(); (done by sortFeeds)
-
- if (m_enableFeedIcons && !m_feedIconsChecked &&
- Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
- getFeedIcons();
-
- return;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- if (m_lastError == ApiError.LOGIN_FAILED) {
- m_activity.login(true);
- } else {
- m_activity.setLoadingStatus(getErrorMessage(), false);
- }
- }
- }
-
- private class FeedListAdapter extends ArrayAdapter<Feed> {
- private ArrayList<Feed> items;
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_SELECTED = 1;
-
- public static final int VIEW_COUNT = VIEW_SELECTED+1;
-
- public FeedListAdapter(Context context, int textViewResourceId, ArrayList<Feed> items) {
- super(context, textViewResourceId, items);
- this.items = items;
- }
-
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- Feed feed = items.get(position);
-
- if (!m_activity.isSmallScreen() && m_selectedFeed != null && feed.id == m_selectedFeed.id) {
- return VIEW_SELECTED;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
-
- Feed feed = items.get(position);
-
- if (v == null) {
- int layoutId = R.layout.feeds_row;
-
- switch (getItemViewType(position)) {
- case VIEW_SELECTED:
- layoutId = R.layout.feeds_row_selected;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- }
-
- TextView tt = (TextView) v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(feed.title);
- }
-
- 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);
- }
-
- ImageView icon = (ImageView)v.findViewById(R.id.icon);
-
- if (icon != null) {
-
- if (m_enableFeedIcons) {
-
- File storage = m_activity.getExternalCacheDir();
-
- File iconFile = new File(storage.getAbsolutePath() + ICON_PATH + feed.id + ".ico");
- if (iconFile.exists()) {
- Bitmap bmpOrig = BitmapFactory.decodeFile(iconFile.getAbsolutePath());
- if (bmpOrig != null) {
- icon.setImageBitmap(bmpOrig);
- }
- } else {
- icon.setImageResource(feed.unread > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- } else {
- icon.setImageResource(feed.unread > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- }
-
- return v;
- }
- }
-
- public void sortFeeds() {
- Comparator<Feed> cmp;
-
- if (m_prefs.getBoolean("sort_feeds_by_unread", false)) {
- cmp = new FeedUnreadComparator();
- } else {
- if (m_activity.getApiLevel() >= 3) {
- cmp = new FeedOrderComparator();
- } else {
- cmp = new FeedTitleComparator();
- }
- }
-
- Collections.sort(m_feeds, cmp);
-
- try {
- m_adapter.notifyDataSetChanged();
- } catch (NullPointerException e) {
- // adapter missing
- }
- }
-
- public class GetIconsTask extends AsyncTask<FeedList, Integer, Integer> {
-
- private String m_baseUrl;
-
- public GetIconsTask(String baseUrl) {
- m_baseUrl = baseUrl;
- }
-
- @Override
- protected Integer doInBackground(FeedList... params) {
-
- try {
- File storage = m_activity.getExternalCacheDir();
- final File iconPath = new File(storage.getAbsolutePath() + ICON_PATH);
- if (!iconPath.exists()) iconPath.mkdirs();
-
- if (iconPath.exists()) {
- for (Feed feed : params[0]) {
- if (feed.id > 0 && feed.has_icon && !feed.is_cat) {
- File outputFile = new File(iconPath.getAbsolutePath() + "/" + feed.id + ".ico");
- String fetchUrl = m_baseUrl + "/" + feed.id + ".ico";
-
- if (!outputFile.exists()) {
- downloadFile(fetchUrl, outputFile.getAbsolutePath());
- Thread.sleep(2000);
- }
- }
- }
- }
- } catch (Exception e) {
- Log.d(TAG, "Error while downloading feed icons");
- e.printStackTrace();
- }
- return null;
- }
-
- protected void downloadFile(String fetchUrl, String outputFile) {
+package org.fox.ttrss; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +import org.fox.ttrss.types.Feed; +import org.fox.ttrss.types.FeedCategory; +import org.fox.ttrss.types.FeedList; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.http.AndroidHttpClient; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.util.Base64; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +public class FeedsFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener { + private final String TAG = this.getClass().getSimpleName(); + private SharedPreferences m_prefs; + private FeedListAdapter m_adapter; + private FeedList m_feeds = new FeedList(); + private FeedsActivity m_activity; + private Feed m_selectedFeed; + private FeedCategory m_activeCategory; + private static final String ICON_PATH = "/icons/"; + private boolean m_enableFeedIcons; + private boolean m_feedIconsChecked = false; + + public FeedsFragment() { + + + } + + public FeedsFragment(FeedCategory cat) { + m_activeCategory = cat; + } + + class FeedUnreadComparator implements Comparator<Feed> { + + @Override + public int compare(Feed a, Feed b) { + if (a.unread != b.unread) + return b.unread - a.unread; + else + return a.title.compareTo(b.title); + } + + } + + + class FeedTitleComparator implements Comparator<Feed> { + + @Override + public int compare(Feed a, Feed b) { + if (a.is_cat && b.is_cat) + return a.title.compareTo(b.title); + else if (a.is_cat && !b.is_cat) + return -1; + else if (!a.is_cat && b.is_cat) + return 1; + else if (a.id >= 0 && b.id >= 0) + return a.title.compareTo(b.title); + else + return a.id - b.id; + } + + } + + class FeedOrderComparator implements Comparator<Feed> { + + @Override + public int compare(Feed a, Feed b) { + if (a.id >= 0 && b.id >= 0) + if (a.is_cat && b.is_cat) + return a.title.compareTo(b.title); + else if (a.is_cat && !b.is_cat) + return -1; + else if (!a.is_cat && b.is_cat) + return 1; + else if (a.order_id != 0 && b.order_id != 0) + return a.order_id - b.order_id; + else + return a.title.compareTo(b.title); + else + return a.id - b.id; + } + + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + switch (item.getItemId()) { + case R.id.browse_articles: + if (true) { + Feed feed = getFeedAtPosition(info.position); + if (feed != null) { + m_activity.openFeedArticles(feed); + } + } + return true; + case R.id.browse_headlines: + if (true) { + Feed feed = getFeedAtPosition(info.position); + if (feed != null) { + m_activity.onFeedSelected(feed); + } + } + return true; + case R.id.browse_feeds: + if (true) { + Feed feed = getFeedAtPosition(info.position); + if (feed != null) { + m_activity.onCatSelected(new FeedCategory(feed.id, feed.title, feed.unread), false); + } + } + return true; + case R.id.catchup_feed: + if (true) { + Feed feed = getFeedAtPosition(info.position); + if (feed != null) { + m_activity.catchupFeed(feed); + } + } + return true; + + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.feed_menu, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + Feed feed = m_adapter.getItem(info.position); + + if (feed != null) + menu.setHeaderTitle(feed.title); + + if (!m_activity.isSmallScreen()) { + menu.findItem(R.id.browse_articles).setVisible(false); + } + + if (!feed.is_cat) { + menu.findItem(R.id.browse_feeds).setVisible(false); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_selectedFeed = savedInstanceState.getParcelable("selectedFeed"); + m_feeds = savedInstanceState.getParcelable("feeds"); + m_feedIconsChecked = savedInstanceState.getBoolean("feedIconsChecked"); + m_activeCategory = savedInstanceState.getParcelable("activeCat"); + } + + 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<Feed>)m_feeds); + list.setAdapter(m_adapter); + //list.setEmptyView(view.findViewById(R.id.no_feeds)); + list.setOnItemClickListener(this); + + registerForContextMenu(list); + + m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false); + + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + m_prefs.registerOnSharedPreferenceChangeListener(this); + + m_activity = (FeedsActivity)activity; + } + + @Override + public void onResume() { + super.onResume(); + + refresh(false); + + m_activity.initMenu(); + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putParcelable("selectedFeed", m_selectedFeed); + out.putParcelable("feeds", m_feeds); + out.putBoolean("feedIconsChecked", m_feedIconsChecked); + out.putParcelable("activeCat", m_activeCategory); + } + + @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); + + if (feed.is_cat) { + if (m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES")) && + m_prefs.getBoolean("browse_cats_like_feeds", false)) { + + m_activity.openFeedArticles(feed); + + } else { + m_activity.onCatSelected(new FeedCategory(feed.id, feed.title, feed.unread)); + } + } else { + if ("ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES"))) { + m_activity.openFeedArticles(feed); + } else { + m_activity.onFeedSelected(feed); + } + } + + if (!m_activity.isSmallScreen()) + m_selectedFeed = feed; + + m_adapter.notifyDataSetChanged(); + } + } + + @SuppressWarnings({ "unchecked", "serial" }) + public void refresh(boolean background) { + //FeedCategory cat = m_onlineServices.getActiveCategory(); + + m_activity.setProgressBarVisibility(true); + + final int catId = (m_activeCategory != null) ? m_activeCategory.id : -4; + + final String sessionId = m_activity.getSessionId(); + final boolean unreadOnly = m_activity.getUnreadOnly(); + + FeedsRequest req = new FeedsRequest(getActivity().getApplicationContext(), catId); + + if (sessionId != null) { + m_activity.setLoadingStatus(R.string.blank, true); + + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getFeeds"); + put("sid", sessionId); + put("include_nested", "true"); + put("cat_id", String.valueOf(catId)); + if (unreadOnly) { + put("unread_only", String.valueOf(unreadOnly)); + } + } + }; + + req.execute(map); + + } + } + + /* private void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + if (getActivity() != null) + getActivity().setProgressBarIndeterminateVisibility(showProgress); + } */ + + @SuppressWarnings({ "unchecked", "serial" }) + public void getFeedIcons() { + + ApiRequest req = new ApiRequest(getActivity().getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + if (isDetached()) return; + + if (result != null) { + + try { + JsonElement iconsUrl = result.getAsJsonObject().get("icons_dir"); + + if (iconsUrl != null) { + String iconsStr = iconsUrl.getAsString(); + String baseUrl = ""; + + if (!iconsStr.contains("://")) { + baseUrl = m_prefs.getString("ttrss_url", "") + "/" + iconsStr; + } else { + baseUrl = iconsStr; + } + + GetIconsTask git = new GetIconsTask(baseUrl); + git.execute(m_feeds); + + m_feedIconsChecked = true; + } + } catch (Exception e) { + Log.d(TAG, "Error receiving icons configuration"); + e.printStackTrace(); + } + + } + } + }; + + final String sessionId = m_activity.getSessionId(); + + HashMap<String,String> map = new HashMap<String,String>() { + { + put("sid", sessionId); + put("op", "getConfig"); + } + }; + + req.execute(map); + } + + private class FeedsRequest extends ApiRequest { + private int m_catId; + + public FeedsRequest(Context context, int catId) { + super(context); + m_catId = catId; + } + + @Override + protected void onProgressUpdate(Integer... progress) { + m_activity.setProgress(Math.round((((float)progress[0] / (float)progress[1]) * 10000))); + } + + @Override + protected void onPostExecute(JsonElement result) { + if (isDetached()) return; + + if (getView() != null) { + ListView list = (ListView)getView().findViewById(R.id.feeds); + + if (list != null) { + list.setEmptyView(getView().findViewById(R.id.no_feeds)); + } + } + + m_activity.setProgressBarVisibility(false); + + if (result != null) { + try { + JsonArray content = result.getAsJsonArray(); + if (content != null) { + + Type listType = new TypeToken<List<Feed>>() {}.getType(); + final List<Feed> feeds = new Gson().fromJson(content, listType); + + m_feeds.clear(); + + for (Feed f : feeds) + if (f.id > -10 || m_catId != -4) // skip labels for flat feedlist for now + m_feeds.add(f); + + sortFeeds(); + + /*if (m_feeds.size() == 0) + setLoadingStatus(R.string.no_feeds_to_display, false); + else */ + + m_activity.setLoadingStatus(R.string.blank, false); + //m_adapter.notifyDataSetChanged(); (done by sortFeeds) + + if (m_enableFeedIcons && !m_feedIconsChecked && + Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) + getFeedIcons(); + + return; + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (m_lastError == ApiError.LOGIN_FAILED) { + m_activity.login(true); + } else { + m_activity.setLoadingStatus(getErrorMessage(), false); + } + } + } + + private class FeedListAdapter extends ArrayAdapter<Feed> { + private ArrayList<Feed> items; + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_SELECTED = 1; + + public static final int VIEW_COUNT = VIEW_SELECTED+1; + + public FeedListAdapter(Context context, int textViewResourceId, ArrayList<Feed> items) { + super(context, textViewResourceId, items); + this.items = items; + } + + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + Feed feed = items.get(position); + + if (!m_activity.isSmallScreen() && m_selectedFeed != null && feed.id == m_selectedFeed.id) { + return VIEW_SELECTED; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + + Feed feed = items.get(position); + + if (v == null) { + int layoutId = R.layout.feeds_row; + + switch (getItemViewType(position)) { + case VIEW_SELECTED: + layoutId = R.layout.feeds_row_selected; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + } + + TextView tt = (TextView) v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(feed.title); + } + + 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); + } + + ImageView icon = (ImageView)v.findViewById(R.id.icon); + + if (icon != null) { + + if (m_enableFeedIcons) { + + File storage = m_activity.getExternalCacheDir(); + + File iconFile = new File(storage.getAbsolutePath() + ICON_PATH + feed.id + ".ico"); + if (iconFile.exists()) { + Bitmap bmpOrig = BitmapFactory.decodeFile(iconFile.getAbsolutePath()); + if (bmpOrig != null) { + icon.setImageBitmap(bmpOrig); + } + } else { + icon.setImageResource(feed.unread > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + } else { + icon.setImageResource(feed.unread > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + } + + return v; + } + } + + public void sortFeeds() { + Comparator<Feed> cmp; + + if (m_prefs.getBoolean("sort_feeds_by_unread", false)) { + cmp = new FeedUnreadComparator(); + } else { + if (m_activity.getApiLevel() >= 3) { + cmp = new FeedOrderComparator(); + } else { + cmp = new FeedTitleComparator(); + } + } + + Collections.sort(m_feeds, cmp); + + try { + m_adapter.notifyDataSetChanged(); + } catch (NullPointerException e) { + // adapter missing + } + } + + public class GetIconsTask extends AsyncTask<FeedList, Integer, Integer> { + + private String m_baseUrl; + + public GetIconsTask(String baseUrl) { + m_baseUrl = baseUrl; + } + + @Override + protected Integer doInBackground(FeedList... params) { + + try { + File storage = m_activity.getExternalCacheDir(); + final File iconPath = new File(storage.getAbsolutePath() + ICON_PATH); + if (!iconPath.exists()) iconPath.mkdirs(); + + if (iconPath.exists()) { + for (Feed feed : params[0]) { + if (feed.id > 0 && feed.has_icon && !feed.is_cat) { + File outputFile = new File(iconPath.getAbsolutePath() + "/" + feed.id + ".ico"); + String fetchUrl = m_baseUrl + "/" + feed.id + ".ico"; + + if (!outputFile.exists()) { + downloadFile(fetchUrl, outputFile.getAbsolutePath()); + Thread.sleep(2000); + } + } + } + } + } catch (Exception e) { + Log.d(TAG, "Error while downloading feed icons"); + e.printStackTrace(); + } + return null; + } + + protected void downloadFile(String fetchUrl, String outputFile) { AndroidHttpClient client = AndroidHttpClient.newInstance("Tiny Tiny RSS"); -
- /* ApiRequest.disableConnectionReuseIfNecessary(); */
-
- /* ApiRequest.trustAllHosts(m_prefs.getBoolean("ssl_trust_any", false),
+ + /* ApiRequest.disableConnectionReuseIfNecessary(); */ + + /* ApiRequest.trustAllHosts(m_prefs.getBoolean("ssl_trust_any", false), m_prefs.getBoolean("ssl_trust_any_host", false)); */ -
- try {
- URL url = new URL(fetchUrl);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-
- String httpLogin = m_prefs.getString("http_login", "");
- String httpPassword = m_prefs.getString("http_password", "");
-
- if (httpLogin.length() > 0) {
- conn.setRequestProperty("Authorization", "Basic " +
- Base64.encodeToString((httpLogin + ":" + httpPassword).getBytes("UTF-8"), Base64.NO_WRAP));
- }
-
- InputStream content = conn.getInputStream();
-
- BufferedInputStream is = new BufferedInputStream(content, 1024);
- FileOutputStream fos = new FileOutputStream(outputFile);
-
- byte[] buffer = new byte[1024];
- int len = 0;
- while ((len = is.read(buffer)) != -1) {
- fos.write(buffer, 0, len);
- }
-
- fos.close();
- is.close();
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- - client.close();
- }
-
- protected void onPostExecute(Integer result) {
- if (isDetached()) return;
-
- m_adapter.notifyDataSetChanged();
- }
-
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
-
- sortFeeds();
- m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false);
-
- }
-
- public Feed getFeedAtPosition(int position) {
- try {
- return m_adapter.getItem(position);
- } catch (IndexOutOfBoundsException e) {
- return null;
- }
- }
-
- public Feed getSelectedFeed() {
- return m_selectedFeed;
- }
-
- public void setSelectedFeed(Feed feed) {
- m_selectedFeed = feed;
- m_adapter.notifyDataSetChanged();
- }
-
-}
+ + try { + URL url = new URL(fetchUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + String httpLogin = m_prefs.getString("http_login", ""); + String httpPassword = m_prefs.getString("http_password", ""); + + if (httpLogin.length() > 0) { + conn.setRequestProperty("Authorization", "Basic " + + Base64.encodeToString((httpLogin + ":" + httpPassword).getBytes("UTF-8"), Base64.NO_WRAP)); + } + + InputStream content = conn.getInputStream(); + + BufferedInputStream is = new BufferedInputStream(content, 1024); + FileOutputStream fos = new FileOutputStream(outputFile); + + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = is.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + + fos.close(); + is.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + + client.close(); + } + + protected void onPostExecute(Integer result) { + if (isDetached()) return; + + m_adapter.notifyDataSetChanged(); + } + + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + + sortFeeds(); + m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false); + + } + + public Feed getFeedAtPosition(int position) { + try { + return m_adapter.getItem(position); + } catch (IndexOutOfBoundsException e) { + return null; + } + } + + public Feed getSelectedFeed() { + return m_selectedFeed; + } + + public void setSelectedFeed(Feed feed) { + m_selectedFeed = feed; + m_adapter.notifyDataSetChanged(); + } + +} diff --git a/src/org/fox/ttrss/GlobalState.java b/src/org/fox/ttrss/GlobalState.java index d997cdc5..830ed6b7 100644 --- a/src/org/fox/ttrss/GlobalState.java +++ b/src/org/fox/ttrss/GlobalState.java @@ -1,61 +1,61 @@ -package org.fox.ttrss;
-
-import java.util.ArrayList;
-
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.ArticleList;
-import org.fox.ttrss.types.Feed;
-
-import android.app.Application;
-import android.os.Bundle;
-import android.os.Parcelable;
-
-public class GlobalState extends Application {
- private static GlobalState m_singleton;
-
- public ArticleList m_loadedArticles = new ArticleList();
- public Feed m_activeFeed;
- public Article m_activeArticle;
- public int m_selectedArticleId;
- public String m_sessionId;
- public int m_apiLevel;
- public boolean m_canUseProgress;
-
- public static GlobalState getInstance(){
- return m_singleton;
- }
-
- @Override
- public final void onCreate() {
- super.onCreate();
- m_singleton = this;
- }
-
- public void save(Bundle out) {
- out.putParcelableArrayList("gs:loadedArticles", m_loadedArticles);
- out.putParcelable("gs:activeFeed", m_activeFeed);
- out.putParcelable("gs:activeArticle", m_activeArticle);
- out.putString("gs:sessionId", m_sessionId);
- out.putInt("gs:apiLevel", m_apiLevel);
- out.putBoolean("gs:canUseProgress", m_canUseProgress);
- out.putInt("gs:selectedArticleId", m_selectedArticleId);
- }
-
- public void load(Bundle in) {
- if (m_loadedArticles.size() == 0 && in != null) {
- ArrayList<Parcelable> list = in.getParcelableArrayList("gs:loadedArticles");
-
- for (Parcelable p : list) {
- m_loadedArticles.add((Article)p);
- }
-
- m_activeFeed = (Feed) in.getParcelable("gs:activeFeed");
- m_activeArticle = (Article) in.getParcelable("gs:activeArticle");
- m_sessionId = in.getString("gs:sessionId");
- m_apiLevel = in.getInt("gs:apiLevel");
- m_canUseProgress = in.getBoolean("gs:canUseProgress");
- m_selectedArticleId = in.getInt("gs:selectedArticleId");
- }
-
- }
-}
+package org.fox.ttrss; + +import java.util.ArrayList; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; +import org.fox.ttrss.types.Feed; + +import android.app.Application; +import android.os.Bundle; +import android.os.Parcelable; + +public class GlobalState extends Application { + private static GlobalState m_singleton; + + public ArticleList m_loadedArticles = new ArticleList(); + public Feed m_activeFeed; + public Article m_activeArticle; + public int m_selectedArticleId; + public String m_sessionId; + public int m_apiLevel; + public boolean m_canUseProgress; + + public static GlobalState getInstance(){ + return m_singleton; + } + + @Override + public final void onCreate() { + super.onCreate(); + m_singleton = this; + } + + public void save(Bundle out) { + out.putParcelableArrayList("gs:loadedArticles", m_loadedArticles); + out.putParcelable("gs:activeFeed", m_activeFeed); + out.putParcelable("gs:activeArticle", m_activeArticle); + out.putString("gs:sessionId", m_sessionId); + out.putInt("gs:apiLevel", m_apiLevel); + out.putBoolean("gs:canUseProgress", m_canUseProgress); + out.putInt("gs:selectedArticleId", m_selectedArticleId); + } + + public void load(Bundle in) { + if (m_loadedArticles.size() == 0 && in != null) { + ArrayList<Parcelable> list = in.getParcelableArrayList("gs:loadedArticles"); + + for (Parcelable p : list) { + m_loadedArticles.add((Article)p); + } + + m_activeFeed = (Feed) in.getParcelable("gs:activeFeed"); + m_activeArticle = (Article) in.getParcelable("gs:activeArticle"); + m_sessionId = in.getString("gs:sessionId"); + m_apiLevel = in.getInt("gs:apiLevel"); + m_canUseProgress = in.getBoolean("gs:canUseProgress"); + m_selectedArticleId = in.getInt("gs:selectedArticleId"); + } + + } +} diff --git a/src/org/fox/ttrss/HeadlinesActivity.java b/src/org/fox/ttrss/HeadlinesActivity.java index bccc9e79..59cd8474 100644 --- a/src/org/fox/ttrss/HeadlinesActivity.java +++ b/src/org/fox/ttrss/HeadlinesActivity.java @@ -1,256 +1,256 @@ -package org.fox.ttrss;
-
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.ArticleList;
-import org.fox.ttrss.types.Feed;
-
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-
-public class HeadlinesActivity extends OnlineActivity implements HeadlinesEventListener {
- private final String TAG = this.getClass().getSimpleName();
-
- protected SharedPreferences m_prefs;
-
- @SuppressLint("NewApi")
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.headlines);
-
- if (!isCompatMode()) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- }
-
- setSmallScreen(findViewById(R.id.headlines_fragment) == null);
-
- GlobalState.getInstance().load(savedInstanceState);
-
- if (isPortrait()) {
- findViewById(R.id.headlines_fragment).setVisibility(View.GONE);
- }
-
- if (savedInstanceState == null) {
- Intent i = getIntent();
-
- if (i.getExtras() != null) {
- final Feed feed = i.getParcelableExtra("feed");
- final Article article = i.getParcelableExtra("article");
- final String searchQuery = i.getStringExtra("searchQuery");
-
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- ft.replace(R.id.headlines_fragment, new LoadingFragment(), null);
- ft.replace(R.id.article_fragment, new LoadingFragment(), null);
-
- ft.commit();
-
- setTitle(feed.title);
-
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- HeadlinesFragment hf = new HeadlinesFragment(feed, article);
- hf.setSearchQuery(searchQuery);
-
- ArticlePager af = new ArticlePager(article != null ? hf.getArticleById(article.id) : new Article(), feed);
- af.setSearchQuery(searchQuery);
-
- ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES);
- ft.replace(R.id.article_fragment, af, FRAG_ARTICLE);
-
- ft.commit();
- }
- }, 25);
-
- }
- }
-
- /* if (!isCompatMode()) {
- ((ViewGroup)findViewById(R.id.headlines_fragment)).setLayoutTransition(new LayoutTransition());
- ((ViewGroup)findViewById(R.id.article_fragment)).setLayoutTransition(new LayoutTransition());
- } */
- }
-
- @Override
- protected void refresh() {
- super.refresh();
-
-
- }
-
- @Override
- protected void loginSuccess(boolean refresh) {
- Log.d(TAG, "loginSuccess");
-
- setLoadingStatus(R.string.blank, false);
- findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- initMenu();
-
- if (refresh) refresh();
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- GlobalState.getInstance().save(out);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- overridePendingTransition(0, R.anim.right_slide_out);
- return true;
- default:
- Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- }
-
- @Override
- protected void initMenu() {
- super.initMenu();
-
- if (m_menu != null && getSessionId() != null) {
- m_menu.setGroupVisible(R.id.menu_group_feeds, false);
-
- HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- m_menu.setGroupVisible(R.id.menu_group_headlines, !isPortrait()&& hf != null && hf.getSelectedArticles().size() == 0);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, !isPortrait() && hf != null && hf.getSelectedArticles().size() != 0);
-
- ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- m_menu.setGroupVisible(R.id.menu_group_article, af != null);
-
- if (af != null) {
- if (af.getSelectedArticle() != null && af.getSelectedArticle().attachments != null && af.getSelectedArticle().attachments.size() > 0) {
- if (!isCompatMode()) {
- m_menu.findItem(R.id.toggle_attachments).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- }
- m_menu.findItem(R.id.toggle_attachments).setVisible(true);
- } else {
- if (!isCompatMode()) {
- m_menu.findItem(R.id.toggle_attachments).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- }
- m_menu.findItem(R.id.toggle_attachments).setVisible(false);
- }
- }
-
- m_menu.findItem(R.id.search).setVisible(false);
- }
- }
-
- @Override
- public void onArticleListSelectionChange(ArticleList m_selectedArticles) {
- initMenu();
- }
-
- @Override
- public void onArticleSelected(Article article) {
- onArticleSelected(article, true);
- }
-
- @Override
- public void onArticleSelected(Article article, boolean open) {
-
- if (article.unread) {
- article.unread = false;
- saveArticleUnread(article);
- }
-
- if (open) {
-
- final Article fArticle = article;
-
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (af != null) {
- af.setActiveArticle(fArticle);
- }
- }
- }, 10);
-
- } else {
- HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
- hf.setActiveArticle(article);
- }
-
- GlobalState.getInstance().m_activeArticle = article;
-
- initMenu();
-
- }
-
- @Override
- public void onHeadlinesLoaded(boolean appended) {
- HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- if (hf != null) {
- Article article = hf.getActiveArticle();
-
- if (article == null && hf.getAllArticles().size() > 0) {
- article = hf.getAllArticles().get(0);
-
- hf.setActiveArticle(article);
-
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- ft.replace(R.id.article_fragment, new LoadingFragment(), null);
-
- ft.commit();
-
- final Article fArticle = article;
- final Feed fFeed = hf.getFeed();
-
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- ArticlePager af = new ArticlePager(fArticle, fFeed);
-
- ft.replace(R.id.article_fragment, af, FRAG_ARTICLE);
- ft.commit();
- }
- }, 10);
- }
- }
- }
-
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- overridePendingTransition(0, R.anim.right_slide_out);
- }
-}
+package org.fox.ttrss; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; +import org.fox.ttrss.types.Feed; + +import com.actionbarsherlock.view.MenuItem; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.View; + +public class HeadlinesActivity extends OnlineActivity implements HeadlinesEventListener { + private final String TAG = this.getClass().getSimpleName(); + + protected SharedPreferences m_prefs; + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + setContentView(R.layout.headlines); + + if (!isCompatMode()) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + setSmallScreen(findViewById(R.id.headlines_fragment) == null); + + GlobalState.getInstance().load(savedInstanceState); + + if (isPortrait()) { + findViewById(R.id.headlines_fragment).setVisibility(View.GONE); + } + + if (savedInstanceState == null) { + Intent i = getIntent(); + + if (i.getExtras() != null) { + final Feed feed = i.getParcelableExtra("feed"); + final Article article = i.getParcelableExtra("article"); + final String searchQuery = i.getStringExtra("searchQuery"); + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + ft.replace(R.id.headlines_fragment, new LoadingFragment(), null); + ft.replace(R.id.article_fragment, new LoadingFragment(), null); + + ft.commit(); + + setTitle(feed.title); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + HeadlinesFragment hf = new HeadlinesFragment(feed, article); + hf.setSearchQuery(searchQuery); + + ArticlePager af = new ArticlePager(article != null ? hf.getArticleById(article.id) : new Article(), feed); + af.setSearchQuery(searchQuery); + + ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES); + ft.replace(R.id.article_fragment, af, FRAG_ARTICLE); + + ft.commit(); + } + }, 25); + + } + } + + /* if (!isCompatMode()) { + ((ViewGroup)findViewById(R.id.headlines_fragment)).setLayoutTransition(new LayoutTransition()); + ((ViewGroup)findViewById(R.id.article_fragment)).setLayoutTransition(new LayoutTransition()); + } */ + } + + @Override + protected void refresh() { + super.refresh(); + + + } + + @Override + protected void loginSuccess(boolean refresh) { + Log.d(TAG, "loginSuccess"); + + setLoadingStatus(R.string.blank, false); + findViewById(R.id.loading_container).setVisibility(View.GONE); + + initMenu(); + + if (refresh) refresh(); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + GlobalState.getInstance().save(out); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + overridePendingTransition(0, R.anim.right_slide_out); + return true; + default: + Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + protected void initMenu() { + super.initMenu(); + + if (m_menu != null && getSessionId() != null) { + m_menu.setGroupVisible(R.id.menu_group_feeds, false); + + HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + m_menu.setGroupVisible(R.id.menu_group_headlines, !isPortrait() && hf != null && hf.isAdded()); + + ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + m_menu.setGroupVisible(R.id.menu_group_article, af != null); + + if (af != null) { + if (af.getSelectedArticle() != null && af.getSelectedArticle().attachments != null && af.getSelectedArticle().attachments.size() > 0) { + if (!isCompatMode()) { + m_menu.findItem(R.id.toggle_attachments).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + } + m_menu.findItem(R.id.toggle_attachments).setVisible(true); + } else { + if (!isCompatMode()) { + m_menu.findItem(R.id.toggle_attachments).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + } + m_menu.findItem(R.id.toggle_attachments).setVisible(false); + } + } + + m_menu.findItem(R.id.search).setVisible(false); + } + } + + @Override + public void onArticleListSelectionChange(ArticleList m_selectedArticles) { + initMenu(); + } + + @Override + public void onArticleSelected(Article article) { + onArticleSelected(article, true); + } + + @Override + public void onArticleSelected(Article article, boolean open) { + + if (article.unread) { + article.unread = false; + saveArticleUnread(article); + } + + if (open) { + + final Article fArticle = article; + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (af != null) { + af.setActiveArticle(fArticle); + } + } + }, 10); + + } else { + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + hf.setActiveArticle(article); + } + + GlobalState.getInstance().m_activeArticle = article; + + initMenu(); + + } + + @Override + public void onHeadlinesLoaded(boolean appended) { + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + if (hf != null) { + Article article = hf.getActiveArticle(); + + if (article == null && hf.getAllArticles().size() > 0) { + article = hf.getAllArticles().get(0); + + hf.setActiveArticle(article); + + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + ft.replace(R.id.article_fragment, new LoadingFragment(), null); + + ft.commit(); + + final Article fArticle = article; + final Feed fFeed = hf.getFeed(); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + ArticlePager af = new ArticlePager(fArticle, fFeed); + + ft.replace(R.id.article_fragment, af, FRAG_ARTICLE); + ft.commit(); + } + }, 10); + } + } + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + overridePendingTransition(0, R.anim.right_slide_out); + } +} diff --git a/src/org/fox/ttrss/HeadlinesEventListener.java b/src/org/fox/ttrss/HeadlinesEventListener.java index 08806c8b..5494bb2b 100644 --- a/src/org/fox/ttrss/HeadlinesEventListener.java +++ b/src/org/fox/ttrss/HeadlinesEventListener.java @@ -1,11 +1,11 @@ -package org.fox.ttrss;
-
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.ArticleList;
-
-public interface HeadlinesEventListener {
- void onArticleListSelectionChange(ArticleList m_selectedArticles);
- void onArticleSelected(Article article);
- void onArticleSelected(Article article, boolean open);
- void onHeadlinesLoaded(boolean appended);
-}
+package org.fox.ttrss; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; + +public interface HeadlinesEventListener { + void onArticleListSelectionChange(ArticleList m_selectedArticles); + void onArticleSelected(Article article); + void onArticleSelected(Article article, boolean open); + void onHeadlinesLoaded(boolean appended); +} diff --git a/src/org/fox/ttrss/HeadlinesFragment.java b/src/org/fox/ttrss/HeadlinesFragment.java index bc31f0d8..3001f071 100644 --- a/src/org/fox/ttrss/HeadlinesFragment.java +++ b/src/org/fox/ttrss/HeadlinesFragment.java @@ -1,852 +1,852 @@ -package org.fox.ttrss;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.TimeZone;
-
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.ArticleList;
-import org.fox.ttrss.types.Feed;
-import org.fox.ttrss.util.HeadlinesRequest;
-import org.jsoup.Jsoup;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.text.Html;
-import android.text.Html.ImageGetter;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.google.gson.JsonElement;
-
-public class HeadlinesFragment extends Fragment implements OnItemClickListener, OnScrollListener {
- public static enum ArticlesSelection { ALL, NONE, UNREAD };
-
- public static final int HEADLINES_REQUEST_SIZE = 30;
- public static final int HEADLINES_BUFFER_MAX = 500;
-
- private final String TAG = this.getClass().getSimpleName();
-
- private Feed m_feed;
- private Article m_activeArticle;
- private String m_searchQuery = "";
- private boolean m_refreshInProgress = false;
-
- private SharedPreferences m_prefs;
-
- private ArticleListAdapter m_adapter;
- private ArticleList m_articles = GlobalState.getInstance().m_loadedArticles;
- private ArticleList m_selectedArticles = new ArticleList();
- private ArticleList m_readArticles = new ArticleList();
- private HeadlinesEventListener m_listener;
- private OnlineActivity m_activity;
-
- private ImageGetter m_dummyGetter = new ImageGetter() {
-
- @SuppressWarnings("deprecation")
- @Override
- public Drawable getDrawable(String source) {
- return new BitmapDrawable();
- }
-
- };
- public ArticleList getSelectedArticles() {
- return m_selectedArticles;
- }
-
- public HeadlinesFragment(Feed feed) {
- m_feed = feed;
- }
-
- public HeadlinesFragment(Feed feed, Article activeArticle) {
- m_feed = feed;
-
- if (activeArticle != null) {
- m_activeArticle = getArticleById(activeArticle.id);
- }
- }
-
- public HeadlinesFragment() {
- //
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
-
- switch (item.getItemId()) {
- case R.id.set_labels:
- if (true) {
- Article article = getArticleAtPosition(info.position);
-
- if (article != null) {
- m_activity.editArticleLabels(article);
- }
- }
- return true;
- case R.id.article_set_note:
- if (true) {
- Article article = getArticleAtPosition(info.position);
-
- if (article != null) {
- m_activity.editArticleNote(article);
- }
- }
- return true;
-
- case R.id.headlines_article_link_copy:
- if (true) {
- Article article = getArticleAtPosition(info.position);
-
- if (article != null) {
- m_activity.copyToClipboard(article.link);
- }
- }
- return true;
- case R.id.selection_toggle_marked:
- if (true) {
- ArticleList selected = getSelectedArticles();
-
- if (selected.size() > 0) {
- for (Article a : selected)
- a.marked = !a.marked;
-
- m_activity.toggleArticlesMarked(selected);
- //updateHeadlines();
- } else {
- Article article = getArticleAtPosition(info.position);
- if (article != null) {
- article.marked = !article.marked;
- m_activity.saveArticleMarked(article);
- //updateHeadlines();
- }
- }
- m_adapter.notifyDataSetChanged();
- }
- return true;
- case R.id.selection_toggle_published:
- if (true) {
- ArticleList selected = getSelectedArticles();
-
- if (selected.size() > 0) {
- for (Article a : selected)
- a.published = !a.published;
-
- m_activity.toggleArticlesPublished(selected);
- //updateHeadlines();
- } else {
- Article article = getArticleAtPosition(info.position);
- if (article != null) {
- article.published = !article.published;
- m_activity.saveArticlePublished(article);
- //updateHeadlines();
- }
- }
- m_adapter.notifyDataSetChanged();
- }
- return true;
- case R.id.selection_toggle_unread:
- if (true) {
- ArticleList selected = getSelectedArticles();
-
- if (selected.size() > 0) {
- for (Article a : selected)
- a.unread = !a.unread;
-
- m_activity.toggleArticlesUnread(selected);
- //updateHeadlines();
- } else {
- Article article = getArticleAtPosition(info.position);
- if (article != null) {
- article.unread = !article.unread;
- m_activity.saveArticleUnread(article);
- //updateHeadlines();
- }
- }
- m_adapter.notifyDataSetChanged();
- }
- return true;
- case R.id.headlines_share_article:
- if (true) {
- Article article = getArticleAtPosition(info.position);
- if (article != null)
- m_activity.shareArticle(article);
- }
- return true;
- case R.id.catchup_above:
- if (true) {
- Article article = getArticleAtPosition(info.position);
- if (article != null) {
- ArticleList articles = getAllArticles();
- ArticleList tmp = new ArticleList();
- for (Article a : articles) {
- if (a.unread) {
- if (article.id == a.id)
- break;
-
- a.unread = false;
- tmp.add(a);
- }
- }
- if (tmp.size() > 0) {
- m_activity.toggleArticlesUnread(tmp);
- //updateHeadlines();
- }
- }
- m_adapter.notifyDataSetChanged();
- }
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.headlines_context_menu, menu);
-
- if (m_selectedArticles.size() > 0) {
- menu.setHeaderTitle(R.string.headline_context_multiple);
- menu.setGroupVisible(R.id.menu_group_single_article, false);
- } else {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
- Article article = getArticleAtPosition(info.position);
- menu.setHeaderTitle(article.title);
- menu.setGroupVisible(R.id.menu_group_single_article, true);
- }
-
- menu.findItem(R.id.set_labels).setEnabled(m_activity.getApiLevel() >= 1);
- menu.findItem(R.id.article_set_note).setEnabled(m_activity.getApiLevel() >= 1);
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_feed = savedInstanceState.getParcelable("feed");
- //m_articles = savedInstanceState.getParcelable("articles");
- m_activeArticle = savedInstanceState.getParcelable("activeArticle");
- m_selectedArticles = savedInstanceState.getParcelable("selectedArticles");
- m_searchQuery = (String) savedInstanceState.getCharSequence("searchQuery");
- }
-
- 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<Article>)m_articles);
- list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- list.setOnScrollListener(this);
- //list.setEmptyView(view.findViewById(R.id.no_headlines));
- registerForContextMenu(list);
-
- if (m_activity.isSmallScreen() || m_activity.isPortrait())
- view.findViewById(R.id.headlines_fragment).setPadding(0, 0, 0, 0);
-
- Log.d(TAG, "onCreateView, feed=" + m_feed);
-
- return view;
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (GlobalState.getInstance().m_activeArticle != null) {
- m_activeArticle = GlobalState.getInstance().m_activeArticle;
- GlobalState.getInstance().m_activeArticle = null;
- }
-
- if (m_activeArticle != null) {
- setActiveArticle(m_activeArticle);
- }
-
- if (m_articles.size() == 0 || !m_feed.equals(GlobalState.getInstance().m_activeFeed)) {
- if (m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE) == null) {
- refresh(false);
- GlobalState.getInstance().m_activeFeed = m_feed;
- }
- } else {
- notifyUpdated();
- }
-
- m_activity.initMenu();
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- m_activity = (OnlineActivity) activity;
- m_listener = (HeadlinesEventListener) activity;
- }
-
- @Override
- public void onItemClick(AdapterView<?> av, View view, int position, long id) {
- ListView list = (ListView)av;
-
- Log.d(TAG, "onItemClick=" + position);
-
- if (list != null) {
- Article article = (Article)list.getItemAtPosition(position);
- if (article.id >= 0) {
- m_listener.onArticleSelected(article);
-
- // only set active article when it makes sense (in HeadlinesActivity)
- if (getActivity().findViewById(R.id.article_fragment) != null) {
- m_activeArticle = article;
- }
-
- m_adapter.notifyDataSetChanged();
- }
- }
- }
-
- @SuppressWarnings({ "unchecked", "serial" })
- public void refresh(boolean append) {
- if (m_activity != null) {
- m_refreshInProgress = true;
-
- m_activity.setProgressBarVisibility(true);
-
- if (!m_feed.equals(GlobalState.getInstance().m_activeFeed)) {
- append = false;
- }
-
- final boolean fappend = append;
- final String sessionId = m_activity.getSessionId();
- final boolean isCat = m_feed.is_cat;
-
- HeadlinesRequest req = new HeadlinesRequest(getActivity().getApplicationContext(), m_activity) {
- @Override
- protected void onProgressUpdate(Integer... progress) {
- m_activity.setProgress(Math.round((((float)progress[0] / (float)progress[1]) * 10000)));
- }
-
- @Override
- protected void onPostExecute(JsonElement result) {
- if (isDetached()) return;
-
- if (getView() != null) {
- ListView list = (ListView)getView().findViewById(R.id.headlines);
-
- if (list != null) {
- list.setEmptyView(getView().findViewById(R.id.no_headlines));
- }
- }
-
- m_activity.setProgressBarVisibility(false);
-
- super.onPostExecute(result);
-
- if (result != null) {
- m_refreshInProgress = false;
-
- if (m_articles.indexOf(m_activeArticle) == -1)
- m_activeArticle = null;
-
- m_adapter.notifyDataSetChanged();
- m_listener.onHeadlinesLoaded(fappend);
- } else {
- if (m_lastError == ApiError.LOGIN_FAILED) {
- m_activity.login();
- } else {
- m_activity.setLoadingStatus(getErrorMessage(), false);
- }
- }
- }
- };
-
- int skip = 0;
-
- if (append) {
- for (Article a : m_articles) {
- if (a.unread) ++skip;
- }
-
- if (skip == 0) skip = m_articles.size();
- } else {
- m_activity.setLoadingStatus(R.string.blank, true);
- }
-
- final int fskip = skip;
-
- req.setOffset(skip);
-
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getHeadlines");
- put("sid", sessionId);
- put("feed_id", String.valueOf(m_feed.id));
- put("show_content", "true");
- put("include_attachments", "true");
- put("view_mode", m_activity.getViewMode());
- put("limit", String.valueOf(HEADLINES_REQUEST_SIZE));
- put("offset", String.valueOf(0));
- put("skip", String.valueOf(fskip));
- put("include_nested", "true");
- put("order_by", m_prefs.getBoolean("oldest_first", false) ? "date_reverse" : "");
-
- if (isCat) put("is_cat", "true");
-
- if (m_searchQuery != null && m_searchQuery.length() != 0) {
- put("search", m_searchQuery);
- put("search_mode", "");
- put("match_on", "both");
- }
- }
- };
-
- req.execute(map);
- }
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putParcelable("feed", m_feed);
- //out.putParcelable("articles", m_articles);
- out.putParcelable("activeArticle", m_activeArticle);
- out.putParcelable("selectedArticles", m_selectedArticles);
- out.putCharSequence("searchQuery", m_searchQuery);
- }
-
- /* private void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- if (getActivity() != null)
- getActivity().setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- /* private class HeadlinesRequest extends ApiRequest {
- int m_offset = 0;
-
- public HeadlinesRequest(Context context) {
- super(context);
- }
-
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- try {
- JsonArray content = result.getAsJsonArray();
- if (content != null) {
- Type listType = new TypeToken<List<Article>>() {}.getType();
- final List<Article> articles = new Gson().fromJson(content, listType);
-
- while (m_articles.size() > HEADLINES_BUFFER_MAX)
- m_articles.remove(0);
-
- if (m_offset == 0)
- m_articles.clear();
- else
- m_articles.remove(m_articles.size()-1); // remove previous placeholder
-
- for (Article f : articles)
- m_articles.add(f);
-
- if (articles.size() == HEADLINES_REQUEST_SIZE) {
- Article placeholder = new Article(-1);
- m_articles.add(placeholder);
-
- m_canLoadMore = true;
- } else {
- m_canLoadMore = false;
- }
-
- m_adapter.notifyDataSetChanged();
-
- if (m_articles.size() == 0)
- setLoadingStatus(R.string.no_headlines_to_display, false);
- else
- setLoadingStatus(R.string.blank, false);
-
- m_refreshInProgress = false;
-
- return;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- if (m_lastError == ApiError.LOGIN_FAILED) {
- m_activity.login();
- } else {
- setLoadingStatus(getErrorMessage(), false);
- }
- m_refreshInProgress = false;
- }
-
- public void setOffset(int skip) {
- m_offset = skip;
- }
- } */
-
- private class ArticleListAdapter extends ArrayAdapter<Article> {
- private ArrayList<Article> items;
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_UNREAD = 1;
- public static final int VIEW_SELECTED = 2;
- public static final int VIEW_SELECTED_UNREAD = 3;
- public static final int VIEW_LOADMORE = 4;
-
- public static final int VIEW_COUNT = VIEW_LOADMORE+1;
-
- public ArticleListAdapter(Context context, int textViewResourceId, ArrayList<Article> items) {
- super(context, textViewResourceId, items);
- this.items = items;
- }
-
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- Article a = items.get(position);
-
- if (a.id == -1) {
- return VIEW_LOADMORE;
- } else if (m_activeArticle != null && a.id == m_activeArticle.id && a.unread) {
- return VIEW_SELECTED_UNREAD;
- } else if (m_activeArticle != null && a.id == m_activeArticle.id) {
- return VIEW_SELECTED;
- } else if (a.unread) {
- return VIEW_UNREAD;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- View v = convertView;
-
- final Article article = items.get(position);
-
- if (v == null) {
- int layoutId = R.layout.headlines_row;
-
- switch (getItemViewType(position)) {
- case VIEW_LOADMORE:
- layoutId = R.layout.headlines_row_loadmore;
- break;
- case VIEW_UNREAD:
- layoutId = R.layout.headlines_row_unread;
- break;
- case VIEW_SELECTED:
- layoutId = R.layout.headlines_row_selected;
- break;
- case VIEW_SELECTED_UNREAD:
- layoutId = R.layout.headlines_row_selected_unread;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- // http://code.google.com/p/android/issues/detail?id=3414
- ((ViewGroup)v).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- }
-
- TextView tt = (TextView)v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(Html.fromHtml(article.title));
- }
-
- TextView ft = (TextView)v.findViewById(R.id.feed_title);
-
- if (ft != null) {
- if (article.feed_title != null && (m_feed.is_cat || m_feed.id < 0)) {
-
- /* if (article.feed_title.length() > 20)
- ft.setText(article.feed_title.substring(0, 20) + "...");
- else */
-
- ft.setText(article.feed_title);
-
- } else {
- ft.setVisibility(View.GONE);
- }
-
- }
-
- ImageView marked = (ImageView)v.findViewById(R.id.marked);
-
- if (marked != null) {
- marked.setImageResource(article.marked ? android.R.drawable.star_on : android.R.drawable.star_off);
-
- marked.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- article.marked = !article.marked;
- m_adapter.notifyDataSetChanged();
-
- m_activity.saveArticleMarked(article);
- }
- });
- }
-
- ImageView published = (ImageView)v.findViewById(R.id.published);
-
- if (published != null) {
- published.setImageResource(article.published ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
-
- published.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- article.published = !article.published;
- m_adapter.notifyDataSetChanged();
-
- m_activity.saveArticlePublished(article);
- }
- });
- }
-
- TextView te = (TextView)v.findViewById(R.id.excerpt);
-
- String articleContent = article.content != null ? article.content : "";
-
- if (te != null) {
- if (!m_prefs.getBoolean("headlines_show_content", true)) {
- te.setVisibility(View.GONE);
- } else {
- String excerpt = Jsoup.parse(articleContent).text();
-
- if (excerpt.length() > 200)
- excerpt = excerpt.substring(0, 200) + "...";
-
- te.setText(excerpt);
- }
- }
-
- String articleAuthor = article.author != null ? article.author : "";
-
- TextView author = (TextView)v.findViewById(R.id.author);
-
- if (author != null) {
- author.setText(articleAuthor);
- }
-
- /* ImageView separator = (ImageView)v.findViewById(R.id.headlines_separator);
-
- if (separator != null && m_onlineServices.isSmallScreen()) {
- separator.setVisibility(View.GONE);
- } */
-
- TextView dv = (TextView) v.findViewById(R.id.date);
-
- if (dv != null) {
- Date d = new Date((long)article.updated * 1000);
- DateFormat df = new SimpleDateFormat("MMM dd, HH:mm");
- df.setTimeZone(TimeZone.getDefault());
- dv.setText(df.format(d));
- }
-
- CheckBox cb = (CheckBox) v.findViewById(R.id.selected);
-
- if (cb != null) {
- cb.setChecked(m_selectedArticles.contains(article));
- cb.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View view) {
- CheckBox cb = (CheckBox)view;
-
- if (cb.isChecked()) {
- if (!m_selectedArticles.contains(article))
- m_selectedArticles.add(article);
- } else {
- m_selectedArticles.remove(article);
- }
-
- m_listener.onArticleListSelectionChange(m_selectedArticles);
-
- Log.d(TAG, "num selected: " + m_selectedArticles.size());
- }
- });
- }
-
- /* ImageButton ib = (ImageButton) v.findViewById(R.id.article_menu_button);
-
- if (ib != null) {
- ib.setVisibility(android.os.Build.VERSION.SDK_INT >= 10 ? View.VISIBLE : View.GONE);
- ib.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- getActivity().openContextMenu(v);
- }
- });
- } */
-
- return v;
- }
- }
-
-
-
- public void notifyUpdated() {
- m_adapter.notifyDataSetChanged();
- }
-
- public ArticleList getAllArticles() {
- return m_articles;
- }
-
- public void setActiveArticle(Article article) {
- if (article != m_activeArticle) {
- m_activeArticle = article;
- m_adapter.notifyDataSetChanged();
-
- ListView list = (ListView)getView().findViewById(R.id.headlines);
-
- if (list != null && article != null) {
- int position = m_adapter.getPosition(article);
- list.setSelection(position);
- }
- }
- }
-
- public void setSelection(ArticlesSelection select) {
- m_selectedArticles.clear();
-
- if (select != ArticlesSelection.NONE) {
- for (Article a : m_articles) {
- if (select == ArticlesSelection.ALL || select == ArticlesSelection.UNREAD && a.unread) {
- m_selectedArticles.add(a);
- }
- }
- }
-
- m_adapter.notifyDataSetChanged();
- }
-
- public Article getArticleAtPosition(int position) {
- try {
- return m_adapter.getItem(position);
- } catch (IndexOutOfBoundsException e) {
- return null;
- } catch (NullPointerException e) {
- return null;
- }
- }
-
- public Article getArticleById(int id) {
- for (Article a : m_articles) {
- if (a.id == id)
- return a;
- }
- return null;
- }
-
- public ArticleList getUnreadArticles() {
- ArticleList tmp = new ArticleList();
- for (Article a : m_articles) {
- if (a.unread) tmp.add(a);
- }
- return tmp;
- }
-
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- if (!m_refreshInProgress && m_articles.findById(-1) != null && firstVisibleItem + visibleItemCount == m_articles.size()) {
- refresh(true);
- }
-
- if (m_prefs.getBoolean("headlines_mark_read_scroll", false) && firstVisibleItem > 0) {
- Article a = m_articles.get(firstVisibleItem - 1);
-
- if (a != null && a.unread) {
- a.unread = false;
- m_readArticles.add(a);
- m_feed.unread--;
- }
- }
- }
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- if (scrollState == SCROLL_STATE_IDLE && m_prefs.getBoolean("headlines_mark_read_scroll", false)) {
- if (!m_readArticles.isEmpty()) {
- m_activity.toggleArticlesUnread(m_readArticles);
- m_activity.refresh(false);
- m_readArticles.clear();
- }
- }
- }
-
- public Article getActiveArticle() {
- return m_activeArticle;
- }
-
- public int getArticlePosition(Article article) {
- try {
- return m_adapter.getPosition(article);
- } catch (NullPointerException e) {
- return -1;
- }
- }
-
- public String getSearchQuery() {
- return m_searchQuery;
- }
-
- public void setSearchQuery(String query) {
- if (!m_searchQuery.equals(query)) {
- m_searchQuery = query;
- refresh(false);
- }
- }
-
- public Feed getFeed() {
- return m_feed;
- }
-
-
-}
+package org.fox.ttrss; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.TimeZone; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; +import org.fox.ttrss.types.Feed; +import org.fox.ttrss.util.HeadlinesRequest; +import org.jsoup.Jsoup; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.text.Html; +import android.text.Html.ImageGetter; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.google.gson.JsonElement; + +public class HeadlinesFragment extends Fragment implements OnItemClickListener, OnScrollListener { + public static enum ArticlesSelection { ALL, NONE, UNREAD }; + + public static final int HEADLINES_REQUEST_SIZE = 30; + public static final int HEADLINES_BUFFER_MAX = 500; + + private final String TAG = this.getClass().getSimpleName(); + + private Feed m_feed; + private Article m_activeArticle; + private String m_searchQuery = ""; + private boolean m_refreshInProgress = false; + + private SharedPreferences m_prefs; + + private ArticleListAdapter m_adapter; + private ArticleList m_articles = GlobalState.getInstance().m_loadedArticles; + private ArticleList m_selectedArticles = new ArticleList(); + private ArticleList m_readArticles = new ArticleList(); + private HeadlinesEventListener m_listener; + private OnlineActivity m_activity; + + private ImageGetter m_dummyGetter = new ImageGetter() { + + @SuppressWarnings("deprecation") + @Override + public Drawable getDrawable(String source) { + return new BitmapDrawable(); + } + + }; + public ArticleList getSelectedArticles() { + return m_selectedArticles; + } + + public HeadlinesFragment(Feed feed) { + m_feed = feed; + } + + public HeadlinesFragment(Feed feed, Article activeArticle) { + m_feed = feed; + + if (activeArticle != null) { + m_activeArticle = getArticleById(activeArticle.id); + } + } + + public HeadlinesFragment() { + // + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + + switch (item.getItemId()) { + case R.id.set_labels: + if (true) { + Article article = getArticleAtPosition(info.position); + + if (article != null) { + m_activity.editArticleLabels(article); + } + } + return true; + case R.id.article_set_note: + if (true) { + Article article = getArticleAtPosition(info.position); + + if (article != null) { + m_activity.editArticleNote(article); + } + } + return true; + + case R.id.headlines_article_link_copy: + if (true) { + Article article = getArticleAtPosition(info.position); + + if (article != null) { + m_activity.copyToClipboard(article.link); + } + } + return true; + case R.id.selection_toggle_marked: + if (true) { + ArticleList selected = getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.marked = !a.marked; + + m_activity.toggleArticlesMarked(selected); + //updateHeadlines(); + } else { + Article article = getArticleAtPosition(info.position); + if (article != null) { + article.marked = !article.marked; + m_activity.saveArticleMarked(article); + //updateHeadlines(); + } + } + m_adapter.notifyDataSetChanged(); + } + return true; + case R.id.selection_toggle_published: + if (true) { + ArticleList selected = getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.published = !a.published; + + m_activity.toggleArticlesPublished(selected); + //updateHeadlines(); + } else { + Article article = getArticleAtPosition(info.position); + if (article != null) { + article.published = !article.published; + m_activity.saveArticlePublished(article); + //updateHeadlines(); + } + } + m_adapter.notifyDataSetChanged(); + } + return true; + case R.id.selection_toggle_unread: + if (true) { + ArticleList selected = getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.unread = !a.unread; + + m_activity.toggleArticlesUnread(selected); + //updateHeadlines(); + } else { + Article article = getArticleAtPosition(info.position); + if (article != null) { + article.unread = !article.unread; + m_activity.saveArticleUnread(article); + //updateHeadlines(); + } + } + m_adapter.notifyDataSetChanged(); + } + return true; + case R.id.headlines_share_article: + if (true) { + Article article = getArticleAtPosition(info.position); + if (article != null) + m_activity.shareArticle(article); + } + return true; + case R.id.catchup_above: + if (true) { + Article article = getArticleAtPosition(info.position); + if (article != null) { + ArticleList articles = getAllArticles(); + ArticleList tmp = new ArticleList(); + for (Article a : articles) { + if (a.unread) { + if (article.id == a.id) + break; + + a.unread = false; + tmp.add(a); + } + } + if (tmp.size() > 0) { + m_activity.toggleArticlesUnread(tmp); + //updateHeadlines(); + } + } + m_adapter.notifyDataSetChanged(); + } + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.headlines_context_menu, menu); + + if (m_selectedArticles.size() > 0) { + menu.setHeaderTitle(R.string.headline_context_multiple); + menu.setGroupVisible(R.id.menu_group_single_article, false); + } else { + AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo; + Article article = getArticleAtPosition(info.position); + menu.setHeaderTitle(article.title); + menu.setGroupVisible(R.id.menu_group_single_article, true); + } + + menu.findItem(R.id.set_labels).setEnabled(m_activity.getApiLevel() >= 1); + menu.findItem(R.id.article_set_note).setEnabled(m_activity.getApiLevel() >= 1); + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_feed = savedInstanceState.getParcelable("feed"); + //m_articles = savedInstanceState.getParcelable("articles"); + m_activeArticle = savedInstanceState.getParcelable("activeArticle"); + m_selectedArticles = savedInstanceState.getParcelable("selectedArticles"); + m_searchQuery = (String) savedInstanceState.getCharSequence("searchQuery"); + } + + 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<Article>)m_articles); + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + list.setOnScrollListener(this); + //list.setEmptyView(view.findViewById(R.id.no_headlines)); + registerForContextMenu(list); + + if (m_activity.isSmallScreen() || m_activity.isPortrait()) + view.findViewById(R.id.headlines_fragment).setPadding(0, 0, 0, 0); + + Log.d(TAG, "onCreateView, feed=" + m_feed); + + return view; + } + + @Override + public void onResume() { + super.onResume(); + + if (GlobalState.getInstance().m_activeArticle != null) { + m_activeArticle = GlobalState.getInstance().m_activeArticle; + GlobalState.getInstance().m_activeArticle = null; + } + + if (m_activeArticle != null) { + setActiveArticle(m_activeArticle); + } + + if (m_articles.size() == 0 || !m_feed.equals(GlobalState.getInstance().m_activeFeed)) { + if (m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE) == null) { + refresh(false); + GlobalState.getInstance().m_activeFeed = m_feed; + } + } else { + notifyUpdated(); + } + + m_activity.initMenu(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + m_activity = (OnlineActivity) activity; + m_listener = (HeadlinesEventListener) activity; + } + + @Override + public void onItemClick(AdapterView<?> av, View view, int position, long id) { + ListView list = (ListView)av; + + Log.d(TAG, "onItemClick=" + position); + + if (list != null) { + Article article = (Article)list.getItemAtPosition(position); + if (article.id >= 0) { + m_listener.onArticleSelected(article); + + // only set active article when it makes sense (in HeadlinesActivity) + if (getActivity().findViewById(R.id.article_fragment) != null) { + m_activeArticle = article; + } + + m_adapter.notifyDataSetChanged(); + } + } + } + + @SuppressWarnings({ "unchecked", "serial" }) + public void refresh(boolean append) { + if (m_activity != null) { + m_refreshInProgress = true; + + m_activity.setProgressBarVisibility(true); + + if (!m_feed.equals(GlobalState.getInstance().m_activeFeed)) { + append = false; + } + + final boolean fappend = append; + final String sessionId = m_activity.getSessionId(); + final boolean isCat = m_feed.is_cat; + + HeadlinesRequest req = new HeadlinesRequest(getActivity().getApplicationContext(), m_activity) { + @Override + protected void onProgressUpdate(Integer... progress) { + m_activity.setProgress(Math.round((((float)progress[0] / (float)progress[1]) * 10000))); + } + + @Override + protected void onPostExecute(JsonElement result) { + if (isDetached()) return; + + if (getView() != null) { + ListView list = (ListView)getView().findViewById(R.id.headlines); + + if (list != null) { + list.setEmptyView(getView().findViewById(R.id.no_headlines)); + } + } + + m_activity.setProgressBarVisibility(false); + + super.onPostExecute(result); + + if (result != null) { + m_refreshInProgress = false; + + if (m_articles.indexOf(m_activeArticle) == -1) + m_activeArticle = null; + + m_adapter.notifyDataSetChanged(); + m_listener.onHeadlinesLoaded(fappend); + } else { + if (m_lastError == ApiError.LOGIN_FAILED) { + m_activity.login(); + } else { + m_activity.setLoadingStatus(getErrorMessage(), false); + } + } + } + }; + + int skip = 0; + + if (append) { + for (Article a : m_articles) { + if (a.unread) ++skip; + } + + if (skip == 0) skip = m_articles.size(); + } else { + m_activity.setLoadingStatus(R.string.blank, true); + } + + final int fskip = skip; + + req.setOffset(skip); + + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getHeadlines"); + put("sid", sessionId); + put("feed_id", String.valueOf(m_feed.id)); + put("show_content", "true"); + put("include_attachments", "true"); + put("view_mode", m_activity.getViewMode()); + put("limit", String.valueOf(HEADLINES_REQUEST_SIZE)); + put("offset", String.valueOf(0)); + put("skip", String.valueOf(fskip)); + put("include_nested", "true"); + put("order_by", m_prefs.getBoolean("oldest_first", false) ? "date_reverse" : ""); + + if (isCat) put("is_cat", "true"); + + if (m_searchQuery != null && m_searchQuery.length() != 0) { + put("search", m_searchQuery); + put("search_mode", ""); + put("match_on", "both"); + } + } + }; + + req.execute(map); + } + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putParcelable("feed", m_feed); + //out.putParcelable("articles", m_articles); + out.putParcelable("activeArticle", m_activeArticle); + out.putParcelable("selectedArticles", m_selectedArticles); + out.putCharSequence("searchQuery", m_searchQuery); + } + + /* private void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + if (getActivity() != null) + getActivity().setProgressBarIndeterminateVisibility(showProgress); + } */ + + /* private class HeadlinesRequest extends ApiRequest { + int m_offset = 0; + + public HeadlinesRequest(Context context) { + super(context); + } + + protected void onPostExecute(JsonElement result) { + if (result != null) { + try { + JsonArray content = result.getAsJsonArray(); + if (content != null) { + Type listType = new TypeToken<List<Article>>() {}.getType(); + final List<Article> articles = new Gson().fromJson(content, listType); + + while (m_articles.size() > HEADLINES_BUFFER_MAX) + m_articles.remove(0); + + if (m_offset == 0) + m_articles.clear(); + else + m_articles.remove(m_articles.size()-1); // remove previous placeholder + + for (Article f : articles) + m_articles.add(f); + + if (articles.size() == HEADLINES_REQUEST_SIZE) { + Article placeholder = new Article(-1); + m_articles.add(placeholder); + + m_canLoadMore = true; + } else { + m_canLoadMore = false; + } + + m_adapter.notifyDataSetChanged(); + + if (m_articles.size() == 0) + setLoadingStatus(R.string.no_headlines_to_display, false); + else + setLoadingStatus(R.string.blank, false); + + m_refreshInProgress = false; + + return; + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (m_lastError == ApiError.LOGIN_FAILED) { + m_activity.login(); + } else { + setLoadingStatus(getErrorMessage(), false); + } + m_refreshInProgress = false; + } + + public void setOffset(int skip) { + m_offset = skip; + } + } */ + + private class ArticleListAdapter extends ArrayAdapter<Article> { + private ArrayList<Article> items; + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_UNREAD = 1; + public static final int VIEW_SELECTED = 2; + public static final int VIEW_SELECTED_UNREAD = 3; + public static final int VIEW_LOADMORE = 4; + + public static final int VIEW_COUNT = VIEW_LOADMORE+1; + + public ArticleListAdapter(Context context, int textViewResourceId, ArrayList<Article> items) { + super(context, textViewResourceId, items); + this.items = items; + } + + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + Article a = items.get(position); + + if (a.id == -1) { + return VIEW_LOADMORE; + } else if (m_activeArticle != null && a.id == m_activeArticle.id && a.unread) { + return VIEW_SELECTED_UNREAD; + } else if (m_activeArticle != null && a.id == m_activeArticle.id) { + return VIEW_SELECTED; + } else if (a.unread) { + return VIEW_UNREAD; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + View v = convertView; + + final Article article = items.get(position); + + if (v == null) { + int layoutId = R.layout.headlines_row; + + switch (getItemViewType(position)) { + case VIEW_LOADMORE: + layoutId = R.layout.headlines_row_loadmore; + break; + case VIEW_UNREAD: + layoutId = R.layout.headlines_row_unread; + break; + case VIEW_SELECTED: + layoutId = R.layout.headlines_row_selected; + break; + case VIEW_SELECTED_UNREAD: + layoutId = R.layout.headlines_row_selected_unread; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + // http://code.google.com/p/android/issues/detail?id=3414 + ((ViewGroup)v).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + } + + TextView tt = (TextView)v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(Html.fromHtml(article.title)); + } + + TextView ft = (TextView)v.findViewById(R.id.feed_title); + + if (ft != null) { + if (article.feed_title != null && (m_feed.is_cat || m_feed.id < 0)) { + + /* if (article.feed_title.length() > 20) + ft.setText(article.feed_title.substring(0, 20) + "..."); + else */ + + ft.setText(article.feed_title); + + } else { + ft.setVisibility(View.GONE); + } + + } + + ImageView marked = (ImageView)v.findViewById(R.id.marked); + + if (marked != null) { + marked.setImageResource(article.marked ? android.R.drawable.star_on : android.R.drawable.star_off); + + marked.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + article.marked = !article.marked; + m_adapter.notifyDataSetChanged(); + + m_activity.saveArticleMarked(article); + } + }); + } + + ImageView published = (ImageView)v.findViewById(R.id.published); + + if (published != null) { + published.setImageResource(article.published ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + + published.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + article.published = !article.published; + m_adapter.notifyDataSetChanged(); + + m_activity.saveArticlePublished(article); + } + }); + } + + TextView te = (TextView)v.findViewById(R.id.excerpt); + + String articleContent = article.content != null ? article.content : ""; + + if (te != null) { + if (!m_prefs.getBoolean("headlines_show_content", true)) { + te.setVisibility(View.GONE); + } else { + String excerpt = Jsoup.parse(articleContent).text(); + + if (excerpt.length() > 200) + excerpt = excerpt.substring(0, 200) + "..."; + + te.setText(excerpt); + } + } + + String articleAuthor = article.author != null ? article.author : ""; + + TextView author = (TextView)v.findViewById(R.id.author); + + if (author != null) { + author.setText(articleAuthor); + } + + /* ImageView separator = (ImageView)v.findViewById(R.id.headlines_separator); + + if (separator != null && m_onlineServices.isSmallScreen()) { + separator.setVisibility(View.GONE); + } */ + + TextView dv = (TextView) v.findViewById(R.id.date); + + if (dv != null) { + Date d = new Date((long)article.updated * 1000); + DateFormat df = new SimpleDateFormat("MMM dd, HH:mm"); + df.setTimeZone(TimeZone.getDefault()); + dv.setText(df.format(d)); + } + + CheckBox cb = (CheckBox) v.findViewById(R.id.selected); + + if (cb != null) { + cb.setChecked(m_selectedArticles.contains(article)); + cb.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View view) { + CheckBox cb = (CheckBox)view; + + if (cb.isChecked()) { + if (!m_selectedArticles.contains(article)) + m_selectedArticles.add(article); + } else { + m_selectedArticles.remove(article); + } + + m_listener.onArticleListSelectionChange(m_selectedArticles); + + Log.d(TAG, "num selected: " + m_selectedArticles.size()); + } + }); + } + + /* ImageButton ib = (ImageButton) v.findViewById(R.id.article_menu_button); + + if (ib != null) { + ib.setVisibility(android.os.Build.VERSION.SDK_INT >= 10 ? View.VISIBLE : View.GONE); + ib.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + getActivity().openContextMenu(v); + } + }); + } */ + + return v; + } + } + + + + public void notifyUpdated() { + m_adapter.notifyDataSetChanged(); + } + + public ArticleList getAllArticles() { + return m_articles; + } + + public void setActiveArticle(Article article) { + if (article != m_activeArticle) { + m_activeArticle = article; + m_adapter.notifyDataSetChanged(); + + ListView list = (ListView)getView().findViewById(R.id.headlines); + + if (list != null && article != null) { + int position = m_adapter.getPosition(article); + list.setSelection(position); + } + } + } + + public void setSelection(ArticlesSelection select) { + m_selectedArticles.clear(); + + if (select != ArticlesSelection.NONE) { + for (Article a : m_articles) { + if (select == ArticlesSelection.ALL || select == ArticlesSelection.UNREAD && a.unread) { + m_selectedArticles.add(a); + } + } + } + + m_adapter.notifyDataSetChanged(); + } + + public Article getArticleAtPosition(int position) { + try { + return m_adapter.getItem(position); + } catch (IndexOutOfBoundsException e) { + return null; + } catch (NullPointerException e) { + return null; + } + } + + public Article getArticleById(int id) { + for (Article a : m_articles) { + if (a.id == id) + return a; + } + return null; + } + + public ArticleList getUnreadArticles() { + ArticleList tmp = new ArticleList(); + for (Article a : m_articles) { + if (a.unread) tmp.add(a); + } + return tmp; + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + if (!m_refreshInProgress && m_articles.findById(-1) != null && firstVisibleItem + visibleItemCount == m_articles.size()) { + refresh(true); + } + + if (m_prefs.getBoolean("headlines_mark_read_scroll", false) && firstVisibleItem > 0) { + Article a = m_articles.get(firstVisibleItem - 1); + + if (a != null && a.unread) { + a.unread = false; + m_readArticles.add(a); + m_feed.unread--; + } + } + } + + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + if (scrollState == SCROLL_STATE_IDLE && m_prefs.getBoolean("headlines_mark_read_scroll", false)) { + if (!m_readArticles.isEmpty()) { + m_activity.toggleArticlesUnread(m_readArticles); + m_activity.refresh(false); + m_readArticles.clear(); + } + } + } + + public Article getActiveArticle() { + return m_activeArticle; + } + + public int getArticlePosition(Article article) { + try { + return m_adapter.getPosition(article); + } catch (NullPointerException e) { + return -1; + } + } + + public String getSearchQuery() { + return m_searchQuery; + } + + public void setSearchQuery(String query) { + if (!m_searchQuery.equals(query)) { + m_searchQuery = query; + refresh(false); + } + } + + public Feed getFeed() { + return m_feed; + } + + +} diff --git a/src/org/fox/ttrss/LoadingFragment.java b/src/org/fox/ttrss/LoadingFragment.java index 2203d66d..f0802b0a 100644 --- a/src/org/fox/ttrss/LoadingFragment.java +++ b/src/org/fox/ttrss/LoadingFragment.java @@ -1,18 +1,18 @@ -package org.fox.ttrss;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-public class LoadingFragment extends Fragment {
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- View view = inflater.inflate(R.layout.loading_fragment, container, false);
-
- return view;
- }
-
-}
+package org.fox.ttrss; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class LoadingFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + View view = inflater.inflate(R.layout.loading_fragment, container, false); + + return view; + } + +} diff --git a/src/org/fox/ttrss/OnlineActivity.java b/src/org/fox/ttrss/OnlineActivity.java index da1a6f17..71c26db1 100644 --- a/src/org/fox/ttrss/OnlineActivity.java +++ b/src/org/fox/ttrss/OnlineActivity.java @@ -1,1679 +1,1676 @@ -package org.fox.ttrss;
-
-import java.lang.reflect.Type;
-import java.util.HashMap;
-import java.util.List;
-
-import org.fox.ttrss.offline.OfflineActivity;
-import org.fox.ttrss.offline.OfflineDownloadService;
-import org.fox.ttrss.offline.OfflineUploadService;
-import org.fox.ttrss.share.SubscribeActivity;
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.ArticleList;
-import org.fox.ttrss.types.Feed;
-import org.fox.ttrss.types.Label;
-
-import android.annotation.TargetApi;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.DialogInterface.OnMultiChoiceClickListener;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.view.ActionMode;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.webkit.WebView;
-import android.webkit.WebView.HitTestResult;
-import android.widget.EditText;
-import android.widget.SearchView;
-import android.widget.ShareActionProvider;
-import android.widget.TextView;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.reflect.TypeToken;
-
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-
-public class OnlineActivity extends CommonActivity {
- private final String TAG = this.getClass().getSimpleName();
-
- private final static int TRIAL_DAYS = 8;
-
- protected SharedPreferences m_prefs;
- protected Menu m_menu;
-
- protected int m_offlineModeStatus = 0;
-
- private ActionMode m_headlinesActionMode;
- private HeadlinesActionModeCallback m_headlinesActionModeCallback;
-
- private String m_lastImageHitTestUrl;
-
- private BroadcastReceiver m_broadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context content, Intent intent) {
-
- if (intent.getAction().equals(OfflineDownloadService.INTENT_ACTION_SUCCESS)) {
-
- m_offlineModeStatus = 2;
-
- switchOffline();
-
- } else if (intent.getAction().equals(OfflineUploadService.INTENT_ACTION_SUCCESS)) {
- Log.d(TAG, "offline upload service reports success");
- toast(R.string.offline_sync_success);
- }
- }
- };
-
-
- @TargetApi(11)
- private class HeadlinesActionModeCallback implements ActionMode.Callback {
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return false;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- if (hf != null) {
- ArticleList selected = hf.getSelectedArticles();
- if (selected.size() > 0) {
- selected.clear();
- initMenu();
- hf.notifyUpdated();
- }
- }
-
- m_headlinesActionMode = null;
- }
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.headlines_action_menu, menu);
-
- return true;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- onOptionsItemSelected(item);
- return false;
- }
- };
-
- protected String getSessionId() {
- return GlobalState.getInstance().m_sessionId;
- }
-
- protected void setSessionId(String sessionId) {
- GlobalState.getInstance().m_sessionId = sessionId;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- ApiRequest.disableConnectionReuseIfNecessary();
-
- // we use that before parent onCreate so let's init locally
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- if (canUseProgress()) {
- requestWindowFeature(Window.FEATURE_PROGRESS);
- } else {
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- }
-
- setProgressBarVisibility(false);
- setProgressBarIndeterminateVisibility(false);
-
-// SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE);
-
- SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE);
-
- boolean isOffline = localPrefs.getBoolean("offline_mode_active", false);
-
- Log.d(TAG, "m_isOffline=" + isOffline);
-
- setContentView(R.layout.login);
-
- if (isOffline) {
- switchOfflineSuccess();
- } else {
- checkTrial(false);
-
- /* if (getIntent().getExtras() != null) {
- Intent i = getIntent();
- } */
-
- if (savedInstanceState != null) {
- m_offlineModeStatus = savedInstanceState.getInt("offlineModeStatus");
- }
-
- if (!isCompatMode()) {
- m_headlinesActionModeCallback = new HeadlinesActionModeCallback();
- }
- }
- }
-
- protected boolean canUseProgress() {
- return GlobalState.getInstance().m_canUseProgress;
- }
-
- private void switchOffline() {
- if (m_offlineModeStatus == 2) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(
- OnlineActivity.this)
- .setMessage(R.string.dialog_offline_success)
- .setPositiveButton(R.string.dialog_offline_go,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
-
- m_offlineModeStatus = 0;
-
- SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = localPrefs.edit();
- editor.putBoolean("offline_mode_active", true);
- editor.commit();
-
- Intent offline = new Intent(
- OnlineActivity.this,
- OfflineActivity.class);
- offline.putExtra("initial", true);
- startActivity(offline);
- finish();
- }
- })
- .setNegativeButton(R.string.dialog_cancel,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
-
- m_offlineModeStatus = 0;
-
- }
- });
-
- AlertDialog dlg = builder.create();
- dlg.show();
-
- } else if (m_offlineModeStatus == 0) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setMessage(R.string.dialog_offline_switch_prompt)
- .setPositiveButton(R.string.dialog_offline_go,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
-
- if (getSessionId() != null) {
- Log.d(TAG, "offline: starting");
-
- m_offlineModeStatus = 1;
-
- Intent intent = new Intent(
- OnlineActivity.this,
- OfflineDownloadService.class);
- intent.putExtra("sessionId", getSessionId());
-
- startService(intent);
- }
- }
- })
- .setNegativeButton(R.string.dialog_cancel,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
- //
- }
- });
-
- AlertDialog dlg = builder.create();
- dlg.show();
- } else if (m_offlineModeStatus == 1) {
- cancelOfflineSync();
- }
- }
-
- private boolean hasPendingOfflineData() {
- try {
- Cursor c = getReadableDb().query("articles",
- new String[] { "COUNT(*)" }, "modified = 1", null, null, null,
- null);
- if (c.moveToFirst()) {
- int modified = c.getInt(0);
- c.close();
-
- return modified > 0;
- }
- } catch (IllegalStateException e) {
- // db is closed? ugh
- }
-
- return false;
- }
-
- private boolean hasOfflineData() {
- try {
- Cursor c = getReadableDb().query("articles",
- new String[] { "COUNT(*)" }, null, null, null, null, null);
- if (c.moveToFirst()) {
- int modified = c.getInt(0);
- c.close();
-
- return modified > 0;
- }
- } catch (IllegalStateException e) {
- // db is closed?
- }
-
- return false;
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- unregisterReceiver(m_broadcastReceiver);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- private void syncOfflineData() {
- Log.d(TAG, "offlineSync: starting");
-
- Intent intent = new Intent(
- OnlineActivity.this,
- OfflineUploadService.class);
-
- intent.putExtra("sessionId", getSessionId());
-
- startService(intent);
- }
-
- private void cancelOfflineSync() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setMessage(R.string.dialog_offline_sync_in_progress)
- .setNegativeButton(R.string.dialog_offline_sync_stop,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
-
- if (getSessionId() != null) {
- Log.d(TAG, "offline: stopping");
-
- m_offlineModeStatus = 0;
-
- Intent intent = new Intent(
- OnlineActivity.this,
- OfflineDownloadService.class);
-
- stopService(intent);
-
- dialog.dismiss();
-
- restart();
- }
- }
- })
- .setPositiveButton(R.string.dialog_offline_sync_continue,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
-
- dialog.dismiss();
-
- restart();
- }
- });
-
- AlertDialog dlg = builder.create();
- dlg.show();
- }
-
- public void restart() {
- Intent refresh = new Intent(OnlineActivity.this, OnlineActivity.class);
- startActivity(refresh);
- finish();
- }
-
- private void switchOfflineSuccess() {
- logout();
- // setLoadingStatus(R.string.blank, false);
-
- SharedPreferences.Editor editor = m_prefs.edit();
- editor.putBoolean("offline_mode_active", true);
- editor.commit();
-
- Intent offline = new Intent(OnlineActivity.this, OfflineActivity.class);
- offline.putExtra("initial", true);
- offline.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-
- startActivityForResult(offline, 0);
-
- finish();
-
- }
-
- public void login() {
- login(false);
- }
-
- public void login(boolean refresh) {
- if (m_prefs.getString("ttrss_url", "").trim().length() == 0) {
-
- setLoadingStatus(R.string.login_need_configure, false);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(R.string.dialog_need_configure_prompt)
- .setCancelable(false)
- .setPositiveButton(R.string.dialog_open_preferences, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- // launch preferences
-
- Intent intent = new Intent(OnlineActivity.this,
- PreferencesActivity.class);
- startActivityForResult(intent, 0);
- }
- })
- .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
-
- } else {
- setLoadingStatus(R.string.login_in_progress, true);
-
- LoginRequest ar = new LoginRequest(getApplicationContext(), refresh);
-
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("op", "login");
- put("user", m_prefs.getString("login", "").trim());
- put("password", m_prefs.getString("password", "").trim());
- }
- };
-
- ar.execute(map);
-
- setLoadingStatus(R.string.login_in_progress, true);
- }
- }
-
- protected void loginSuccess(boolean refresh) {
- setLoadingStatus(R.string.blank, false);
-
- initMenu();
-
- Intent intent = new Intent(OnlineActivity.this, FeedsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-
- startActivityForResult(intent, 0);
- overridePendingTransition(0, 0);
-
- if (hasPendingOfflineData())
- syncOfflineData();
-
- finish();
- }
-
- public void checkTrial(boolean notify) {
- boolean isTrial = getPackageManager().checkSignatures(
- getPackageName(), "org.fox.ttrss.key") != PackageManager.SIGNATURE_MATCH;
-
- if (isTrial) {
- long firstStart = m_prefs.getLong("date_firstlaunch_trial", -1);
-
- if (firstStart == -1) {
- firstStart = System.currentTimeMillis();
-
- SharedPreferences.Editor editor = m_prefs.edit();
- editor.putLong("date_firstlaunch_trial", firstStart);
- editor.commit();
- }
-
- if (!notify && System.currentTimeMillis() > firstStart + (TRIAL_DAYS * 24 * 60 * 60 * 1000)) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(R.string.trial_expired)
- .setMessage(R.string.trial_expired_message)
- .setCancelable(false)
- .setPositiveButton(getString(R.string.trial_purchase),
- new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
-
- openUnlockUrl();
- finish();
-
- }
- })
- .setNegativeButton(getString(R.string.cancel),
- new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
-
- finish();
-
- }
- });
-
- AlertDialog dialog = builder.create();
- dialog.show();
-
- } else {
- long daysLeft = Math.round((firstStart + (TRIAL_DAYS * 24 * 60 * 60 * 1000) - System.currentTimeMillis()) / (24 * 60 * 60 * 1000));
-
- if (notify) {
- toast(getString(R.string.trial_mode_prompt, Long.valueOf(daysLeft)));
- }
- }
- } else if (notify) {
- //toast(R.string.trial_thanks);
- }
- }
-
- private void openUnlockUrl() {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW,
- Uri.parse("market://details?id=org.fox.ttrss.key"));
- startActivity(intent);
- } catch (ActivityNotFoundException ae) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW,
- Uri.parse("https://play.google.com/store/apps/details?id=org.fox.ttrss.key"));
- startActivity(intent);
- } catch (Exception e) {
- e.printStackTrace();
- toast(R.string.error_other_error);
- }
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- /* AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo(); */
-
- final ArticlePager ap = (ArticlePager)getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- switch (item.getItemId()) {
- case R.id.article_img_open:
- if (getLastContentImageHitTestUrl() != null) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW,
- Uri.parse(getLastContentImageHitTestUrl()));
- startActivity(intent);
- } catch (Exception e) {
- e.printStackTrace();
- toast(R.string.error_other_error);
- }
- }
- return true;
- case R.id.article_img_share:
- if (getLastContentImageHitTestUrl() != null) {
- Intent intent = new Intent(Intent.ACTION_SEND);
-
- intent.setType("image/png");
- intent.putExtra(Intent.EXTRA_SUBJECT, getLastContentImageHitTestUrl());
- intent.putExtra(Intent.EXTRA_TEXT, getLastContentImageHitTestUrl());
-
- startActivity(Intent.createChooser(intent, getLastContentImageHitTestUrl()));
- }
- return true;
- case R.id.article_img_view_caption:
- if (getLastContentImageHitTestUrl() != null) {
-
- // Android doesn't give us an easy way to access title tags;
- // we'll use Jsoup on the body text to grab the title text
- // from the first image tag with this url. This will show
- // the wrong text if an image is used multiple times.
- Document doc = Jsoup.parse(ap.getSelectedArticle().content);
- Elements es = doc.getElementsByAttributeValue("src", getLastContentImageHitTestUrl());
- if (es.size() > 0){
- if (es.get(0).hasAttr("title")){
- Dialog dia = new Dialog(this);
- if (es.get(0).hasAttr("alt")){
- dia.setTitle(es.get(0).attr("alt"));
- } else {
- dia.setTitle(es.get(0).attr("title"));
- }
- TextView titleText = new TextView(this);
-
- if (android.os.Build.VERSION.SDK_INT >= 16) {
- titleText.setPaddingRelative(24, 24, 24, 24);
- } else {
- titleText.setPadding(24, 24, 24, 24);
- }
-
- titleText.setTextSize(16);
- titleText.setText(es.get(0).attr("title"));
- dia.setContentView(titleText);
- dia.show();
- } else {
- toast(R.string.no_caption_to_display);
- }
- } else {
- toast(R.string.no_caption_to_display);
- }
- }
- return true;
- case R.id.article_link_share:
- if (ap != null && ap.getSelectedArticle() != null) {
- shareArticle(ap.getSelectedArticle());
- }
- return true;
- case R.id.article_link_copy:
- Log.d(TAG, "article_link_copy");
- if (ap != null && ap.getSelectedArticle() != null) {
- copyToClipboard(ap.getSelectedArticle().link);
- }
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- final HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
- final ArticlePager ap = (ArticlePager)getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- case R.id.subscribe_to_feed:
- Intent subscribe = new Intent(OnlineActivity.this, SubscribeActivity.class);
- startActivityForResult(subscribe, 0);
- return true;
- case R.id.toggle_attachments:
- if (true) {
- Article article = ap.getSelectedArticle();
-
- if (article != null && article.attachments != null && article.attachments.size() > 0) {
- CharSequence[] items = new CharSequence[article.attachments.size()];
- final CharSequence[] itemUrls = new CharSequence[article.attachments.size()];
-
- for (int i = 0; i < article.attachments.size(); i++) {
- items[i] = article.attachments.get(i).title != null ? article.attachments.get(i).content_url :
- article.attachments.get(i).content_url;
-
- itemUrls[i] = article.attachments.get(i).content_url;
- }
-
- Dialog dialog = new Dialog(OnlineActivity.this);
- AlertDialog.Builder builder = new AlertDialog.Builder(OnlineActivity.this)
- .setTitle(R.string.attachments_prompt)
- .setCancelable(true)
- .setSingleChoiceItems(items, 0, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- //
- }
- }).setNeutralButton(R.string.attachment_copy, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- int selectedPosition = ((AlertDialog)dialog).getListView().getCheckedItemPosition();
-
- copyToClipboard((String)itemUrls[selectedPosition]);
- }
- }).setPositiveButton(R.string.attachment_view, new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- int selectedPosition = ((AlertDialog)dialog).getListView().getCheckedItemPosition();
-
- Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse((String)itemUrls[selectedPosition]));
- startActivity(browserIntent);
-
- dialog.cancel();
- }
- }).setNegativeButton(R.string.dialog_cancel, new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
-
- dialog = builder.create();
- dialog.show();
- }
- }
- return true;
- case R.id.donate:
- if (true) {
- openUnlockUrl();
- }
- return true;
- case R.id.logout:
- logout();
- return true;
- case R.id.login:
- login();
- return true;
- case R.id.go_offline:
- switchOffline();
- return true;
- case R.id.article_set_note:
- if (ap != null && ap.getSelectedArticle() != null) {
- editArticleNote(ap.getSelectedArticle());
- }
- return true;
- case R.id.preferences:
- Intent intent = new Intent(OnlineActivity.this,
- PreferencesActivity.class);
- startActivityForResult(intent, 0);
- return true;
- case R.id.search:
- if (hf != null && isCompatMode()) {
- Dialog dialog = new Dialog(this);
-
- final EditText edit = new EditText(this);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(R.string.search)
- .setPositiveButton(getString(R.string.search),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
-
- String query = edit.getText().toString().trim();
-
- hf.setSearchQuery(query);
-
- }
- })
- .setNegativeButton(getString(R.string.cancel),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
-
- //
-
- }
- }).setView(edit);
-
- dialog = builder.create();
- dialog.show();
- }
- return true;
- case R.id.headlines_mark_as_read:
- if (hf != null) {
- ArticleList articles = hf.getUnreadArticles();
-
- for (Article a : articles)
- a.unread = false;
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- if (hf.isAdded()) {
- hf.refresh(false);
- }
- }
- };
-
- final String articleIds = articlesToIdString(articles);
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "updateArticle");
- put("article_ids", articleIds);
- put("mode", "0");
- put("field", "2");
- }
- };
- req.execute(map);
- }
- return true;
- case R.id.headlines_view_mode:
- if (hf != null) {
- Dialog dialog = new Dialog(this);
-
- String viewMode = getViewMode();
-
- //Log.d(TAG, "viewMode:" + getViewMode());
-
- int selectedIndex = 0;
-
- if (viewMode.equals("all_articles")) {
- selectedIndex = 1;
- } else if (viewMode.equals("marked")) {
- selectedIndex = 2;
- } else if (viewMode.equals("published")) {
- selectedIndex = 3;
- } else if (viewMode.equals("unread")) {
- selectedIndex = 4;
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(R.string.headlines_set_view_mode)
- .setSingleChoiceItems(
- new String[] {
- getString(R.string.headlines_adaptive),
- getString(R.string.headlines_all_articles),
- getString(R.string.headlines_starred),
- getString(R.string.headlines_published),
- getString(R.string.headlines_unread) },
- selectedIndex, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- switch (which) {
- case 0:
- setViewMode("adaptive");
- break;
- case 1:
- setViewMode("all_articles");
- break;
- case 2:
- setViewMode("marked");
- break;
- case 3:
- setViewMode("published");
- break;
- case 4:
- setViewMode("unread");
- break;
- }
- dialog.cancel();
-
- refresh();
- }
- });
-
- dialog = builder.create();
- dialog.show();
-
- }
- return true;
- case R.id.headlines_select:
- if (hf != null) {
- Dialog dialog = new Dialog(this);
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(R.string.headlines_select_dialog)
- .setSingleChoiceItems(
- new String[] {
- getString(R.string.headlines_select_all),
- getString(R.string.headlines_select_unread),
- getString(R.string.headlines_select_none) },
- 0, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- switch (which) {
- case 0:
- hf.setSelection(HeadlinesFragment.ArticlesSelection.ALL);
- break;
- case 1:
- hf.setSelection(HeadlinesFragment.ArticlesSelection.UNREAD);
- break;
- case 2:
- hf.setSelection(HeadlinesFragment.ArticlesSelection.NONE);
- break;
- }
- dialog.cancel();
- initMenu();
- }
- });
-
- dialog = builder.create();
- dialog.show();
- }
- return true;
- case R.id.share_article:
- //if (android.os.Build.VERSION.SDK_INT < 14) {
- if (ap != null) {
- shareArticle(ap.getSelectedArticle());
- }
- //}
- return true;
- case R.id.toggle_marked:
- if (ap != null & ap.getSelectedArticle() != null) {
- Article a = ap.getSelectedArticle();
- a.marked = !a.marked;
- saveArticleMarked(a);
- if (hf != null) hf.notifyUpdated();
- }
- return true;
- case R.id.selection_select_none:
- if (hf != null) {
- ArticleList selected = hf.getSelectedArticles();
- if (selected.size() > 0) {
- selected.clear();
- initMenu();
- hf.notifyUpdated();
- }
- }
- return true;
- case R.id.selection_toggle_unread:
- if (hf != null) {
- ArticleList selected = hf.getSelectedArticles();
-
- if (selected.size() > 0) {
- for (Article a : selected)
- a.unread = !a.unread;
-
- toggleArticlesUnread(selected);
- hf.notifyUpdated();
- initMenu();
- }
- }
- return true;
- case R.id.selection_toggle_marked:
- if (hf != null) {
- ArticleList selected = hf.getSelectedArticles();
-
- if (selected.size() > 0) {
- for (Article a : selected)
- a.marked = !a.marked;
-
- toggleArticlesMarked(selected);
- hf.notifyUpdated();
- initMenu();
- }
- }
- return true;
- case R.id.selection_toggle_published:
- if (hf != null) {
- ArticleList selected = hf.getSelectedArticles();
-
- if (selected.size() > 0) {
- for (Article a : selected)
- a.published = !a.published;
-
- toggleArticlesPublished(selected);
- hf.notifyUpdated();
- initMenu();
- }
- }
- return true;
- case R.id.toggle_published:
- if (ap != null && ap.getSelectedArticle() != null) {
- Article a = ap.getSelectedArticle();
- a.published = !a.published;
- saveArticlePublished(a);
- if (hf != null) hf.notifyUpdated();
- }
- return true;
- case R.id.catchup_above:
- if (hf != null) {
- if (ap != null && ap.getSelectedArticle() != null) {
- Article article = ap.getSelectedArticle();
-
- ArticleList articles = hf.getAllArticles();
- ArticleList tmp = new ArticleList();
- for (Article a : articles) {
- a.unread = false;
- tmp.add(a);
- if (article.id == a.id)
- break;
- }
- if (tmp.size() > 0) {
- toggleArticlesUnread(tmp);
- hf.notifyUpdated();
- initMenu();
- }
- }
- }
- return true;
- case R.id.set_unread:
- if (ap != null && ap.getSelectedArticle() != null) {
- Article a = ap.getSelectedArticle();
-
- if (a != null) {
- a.unread = !a.unread;
- saveArticleUnread(a);
- }
-
- if (hf != null) hf.notifyUpdated();
- }
- return true;
- case R.id.set_labels:
- if (ap != null && ap.getSelectedArticle() != null) {
- editArticleLabels(ap.getSelectedArticle());
- }
- return true;
- case R.id.update_headlines:
- if (hf != null) {
- hf.refresh(false);
- }
- return true;
- default:
- Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
- return super.onOptionsItemSelected(item);
- }
- }
-
- public void editArticleNote(final Article article) {
- String note = "";
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(article.title);
- final EditText topicEdit = new EditText(this);
- topicEdit.setText(note);
- builder.setView(topicEdit);
-
- builder.setPositiveButton(R.string.article_set_note, new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- saveArticleNote(article, topicEdit.getText().toString().trim());
- article.published = true;
- saveArticlePublished(article);
-
- HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
- if (hf != null) hf.notifyUpdated();
- }
- });
-
- builder.setNegativeButton(R.string.dialog_cancel, new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- //
- }
- });
-
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- public void editArticleLabels(Article article) {
- final int articleId = article.id;
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- Type listType = new TypeToken<List<Label>>() {}.getType();
- final List<Label> labels = new Gson().fromJson(result, listType);
-
- CharSequence[] items = new CharSequence[labels.size()];
- final int[] itemIds = new int[labels.size()];
- boolean[] checkedItems = new boolean[labels.size()];
-
- for (int i = 0; i < labels.size(); i++) {
- items[i] = labels.get(i).caption;
- itemIds[i] = labels.get(i).id;
- checkedItems[i] = labels.get(i).checked;
- }
-
- Dialog dialog = new Dialog(OnlineActivity.this);
- AlertDialog.Builder builder = new AlertDialog.Builder(OnlineActivity.this)
- .setTitle(R.string.article_set_labels)
- .setMultiChoiceItems(items, checkedItems, new OnMultiChoiceClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which, final boolean isChecked) {
- final int labelId = itemIds[which];
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "setArticleLabel");
- put("label_id", String.valueOf(labelId));
- put("article_ids", String.valueOf(articleId));
- if (isChecked) put("assign", "true");
- }
- };
-
- ApiRequest req = new ApiRequest(m_context);
- req.execute(map);
-
- }
- }).setPositiveButton(R.string.dialog_close, new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
-
- dialog = builder.create();
- dialog.show();
-
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "getLabels");
- put("article_id", String.valueOf(articleId));
- }
- };
-
- req.execute(map);
- }
-
- protected void logout() {
- setSessionId(null);
-
- findViewById(R.id.loading_container).setVisibility(View.VISIBLE);
- setLoadingStatus(R.string.login_ready, false);
-
- initMenu();
- }
-
- protected void loginFailure() {
- setSessionId(null);
- initMenu();
-
- if (hasOfflineData()) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(
- OnlineActivity.this)
- .setMessage(R.string.dialog_offline_prompt)
- .setPositiveButton(R.string.dialog_offline_go,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
- switchOfflineSuccess();
- }
- })
- .setNegativeButton(R.string.dialog_cancel,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
- //
- }
- });
-
- AlertDialog dlg = builder.create();
- dlg.show();
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("offlineModeStatus", m_offlineModeStatus);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- ApiRequest.trustAllHosts(m_prefs.getBoolean("ssl_trust_any", false),
- m_prefs.getBoolean("ssl_trust_any_host", false));
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(OfflineDownloadService.INTENT_ACTION_SUCCESS);
- filter.addAction(OfflineUploadService.INTENT_ACTION_SUCCESS);
- filter.addCategory(Intent.CATEGORY_DEFAULT);
-
- registerReceiver(m_broadcastReceiver, filter);
-
- if (getSessionId() == null) {
- login();
- } else {
- loginSuccess(false);
- }
- }
-
- public Menu getMenu() {
- return m_menu;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main_menu, menu);
-
- m_menu = menu;
-
- initMenu();
-
- List<PackageInfo> pkgs = getPackageManager()
- .getInstalledPackages(0);
-
- for (PackageInfo p : pkgs) {
- if ("org.fox.ttrss.key".equals(p.packageName)) {
- Log.d(TAG, "license apk found");
- menu.findItem(R.id.donate).setVisible(false);
- break;
- }
- }
-
- return true;
- }
-
- protected int getApiLevel() {
- return GlobalState.getInstance().m_apiLevel;
- }
-
- protected void setApiLevel(int apiLevel) {
- GlobalState.getInstance().m_apiLevel = apiLevel;
- }
-
- @SuppressWarnings({ "unchecked", "serial" })
- public void saveArticleUnread(final Article article) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- //toast(R.string.article_set_unread);
- initMenu();
- }
- };
-
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "updateArticle");
- put("article_ids", String.valueOf(article.id));
- put("mode", article.unread ? "1" : "0");
- put("field", "2");
- }
- };
-
- req.execute(map);
- }
-
- @SuppressWarnings({ "unchecked", "serial" })
- public void saveArticleMarked(final Article article) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- //toast(article.marked ? R.string.notify_article_marked : R.string.notify_article_unmarked);
- initMenu();
- }
- };
-
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "updateArticle");
- put("article_ids", String.valueOf(article.id));
- put("mode", article.marked ? "1" : "0");
- put("field", "0");
- }
- };
-
- req.execute(map);
- }
-
- @SuppressWarnings({ "unchecked", "serial" })
- public void saveArticlePublished(final Article article) {
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- //toast(article.published ? R.string.notify_article_published : R.string.notify_article_unpublished);
- initMenu();
- }
- };
-
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "updateArticle");
- put("article_ids", String.valueOf(article.id));
- put("mode", article.published ? "1" : "0");
- put("field", "1");
- }
- };
-
- req.execute(map);
- }
-
- @SuppressWarnings({ "unchecked", "serial" })
- public void saveArticleNote(final Article article, final String note) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- toast(R.string.notify_article_note_set);
- }
- };
-
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "updateArticle");
- put("article_ids", String.valueOf(article.id));
- put("mode", "1");
- put("data", note);
- put("field", "3");
- }
- };
-
- req.execute(map);
- }
-
- public static String articlesToIdString(ArticleList articles) {
- String tmp = "";
-
- for (Article a : articles)
- tmp += String.valueOf(a.id) + ",";
-
- return tmp.replaceAll(",$", "");
- }
-
- public void shareText(String text) {
-
- Intent intent = new Intent(Intent.ACTION_SEND);
-
- intent.setType("text/plain");
- intent.putExtra(Intent.EXTRA_TEXT, text);
-
- startActivity(Intent.createChooser(intent, text));
- }
-
- public void shareArticle(Article article) {
- if (article != null) {
-
- Intent intent = getShareIntent(article);
-
- startActivity(Intent.createChooser(intent,
- getString(R.string.share_article)));
- }
- }
-
- protected Intent getShareIntent(Article article) {
- Intent intent = new Intent(Intent.ACTION_SEND);
-
- intent.setType("text/plain");
- intent.putExtra(Intent.EXTRA_SUBJECT, article.title);
- intent.putExtra(Intent.EXTRA_TEXT, article.link);
-
- return intent;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (m_prefs.getBoolean("use_volume_keys", false)) {
- ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- ap.selectArticle(false);
- return true;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- ap.selectArticle(true);
- return true;
- }
- }
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
- // Handle onKeyUp too to suppress beep
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (m_prefs.getBoolean("use_volume_keys", false)) {
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- return true;
- }
- }
-
- return super.onKeyUp(keyCode, event);
- }
-
- @SuppressWarnings("unchecked")
- public void catchupFeed(final Feed feed) {
- Log.d(TAG, "catchupFeed=" + feed);
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- // refresh?
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "catchupFeed");
- put("feed_id", String.valueOf(feed.id));
- if (feed.is_cat)
- put("is_cat", "1");
- }
- };
-
- req.execute(map);
- }
-
- @SuppressWarnings("unchecked")
- public void toggleArticlesMarked(final ArticleList articles) {
- ApiRequest req = new ApiRequest(getApplicationContext());
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "updateArticle");
- put("article_ids", articlesToIdString(articles));
- put("mode", "2");
- put("field", "0");
- }
- };
-
- req.execute(map);
- }
-
- @SuppressWarnings("unchecked")
- public void toggleArticlesUnread(final ArticleList articles) {
- ApiRequest req = new ApiRequest(getApplicationContext());
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "updateArticle");
- put("article_ids", articlesToIdString(articles));
- put("mode", "2");
- put("field", "2");
- }
- };
-
- req.execute(map);
- //refresh();
- }
-
- @SuppressWarnings("unchecked")
- public void toggleArticlesPublished(final ArticleList articles) {
- ApiRequest req = new ApiRequest(getApplicationContext());
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "updateArticle");
- put("article_ids", articlesToIdString(articles));
- put("mode", "2");
- put("field", "1");
- }
- };
-
- req.execute(map);
- }
-
-
- protected void initMenu() {
- if (m_menu != null) {
- if (getSessionId() != null) {
- m_menu.setGroupVisible(R.id.menu_group_logged_in, true);
- m_menu.setGroupVisible(R.id.menu_group_logged_out, false);
- } else {
- m_menu.setGroupVisible(R.id.menu_group_logged_in, false);
- m_menu.setGroupVisible(R.id.menu_group_logged_out, true);
- }
-
- m_menu.setGroupVisible(R.id.menu_group_headlines, false);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, false);
- m_menu.setGroupVisible(R.id.menu_group_article, false);
- m_menu.setGroupVisible(R.id.menu_group_feeds, false);
-
- m_menu.findItem(R.id.set_labels).setEnabled(getApiLevel() >= 1);
- m_menu.findItem(R.id.article_set_note).setEnabled(getApiLevel() >= 1);
- m_menu.findItem(R.id.subscribe_to_feed).setEnabled(getApiLevel() >= 5);
-
- MenuItem search = m_menu.findItem(R.id.search);
- search.setEnabled(getApiLevel() >= 2);
-
- ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (ap != null) {
- Article article = ap.getSelectedArticle();
-
- if (article != null) {
- m_menu.findItem(R.id.toggle_marked).setIcon(article.marked ? R.drawable.ic_important_light :
- R.drawable.ic_unimportant_light);
-
- m_menu.findItem(R.id.toggle_published).setIcon(article.published ? R.drawable.ic_menu_published_light :
- R.drawable.ic_menu_unpublished_light);
-
- m_menu.findItem(R.id.set_unread).setIcon(article.unread ? R.drawable.ic_unread_light :
- R.drawable.ic_read_light);
- }
- }
-
- /* if (android.os.Build.VERSION.SDK_INT >= 14) {
- ShareActionProvider shareProvider = (ShareActionProvider) m_menu.findItem(R.id.share_article).getActionProvider();
-
- ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (af != null && af.getSelectedArticle() != null) {
- shareProvider.setShareIntent(getShareIntent(af.getSelectedArticle()));
-
- if (!isSmallScreen()) {
- m_menu.findItem(R.id.share_article).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- }
- }
- } */
-
- if (!isCompatMode()) {
- HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- if (hf != null) {
- if (hf.getSelectedArticles().size() > 0 && m_headlinesActionMode == null) {
- m_headlinesActionMode = startActionMode(m_headlinesActionModeCallback);
- } else if (hf.getSelectedArticles().size() == 0 && m_headlinesActionMode != null) {
- m_headlinesActionMode.finish();
- }
- }
-
- SearchView searchView = (SearchView) search.getActionView();
- searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- private String query = "";
-
- @Override
- public boolean onQueryTextSubmit(String query) {
- HeadlinesFragment frag = (HeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- if (frag != null) {
- frag.setSearchQuery(query);
- this.query = query;
- }
-
- return false;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- if (newText.equals("") && !newText.equals(this.query)) {
- HeadlinesFragment frag = (HeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- if (frag != null) {
- frag.setSearchQuery(newText);
- this.query = newText;
- }
- }
-
- return false;
- }
- });
- }
- }
- }
-
- protected void refresh(boolean includeHeadlines) {
- FeedCategoriesFragment cf = (FeedCategoriesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_CATS);
-
- if (cf != null) {
- cf.refresh(false);
- }
-
- FeedsFragment ff = (FeedsFragment) getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS);
-
- if (ff != null) {
- ff.refresh(false);
- }
-
- if (includeHeadlines) {
- HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- if (hf != null) {
- hf.refresh(false);
- }
-
- ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (af != null) {
- af.refresh(false);
- }
- }
- }
-
- protected void refresh() {
- refresh(true);
- }
-
- private class LoginRequest extends ApiRequest {
- boolean m_refreshAfterLogin = false;
-
- public LoginRequest(Context context, boolean refresh) {
- super(context);
- m_refreshAfterLogin = refresh;
- }
-
- @SuppressWarnings("unchecked")
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- try {
- JsonObject content = result.getAsJsonObject();
-
- if (content != null) {
- setSessionId(content.get("session_id").getAsString());
-
- JsonElement apiLevel = content.get("api_level");
-
- GlobalState.getInstance().m_canUseProgress = m_canUseProgress;
-
- Log.d(TAG, "Authenticated! canUseProgress=" + m_canUseProgress);
-
- if (apiLevel != null) {
- setApiLevel(apiLevel.getAsInt());
- Log.d(TAG, "Received API level: " + getApiLevel());
-
- loginSuccess(m_refreshAfterLogin);
-
- } else {
-
- ApiRequest req = new ApiRequest(m_context) {
- protected void onPostExecute(JsonElement result) {
- setApiLevel(0);
-
- if (result != null) {
- try {
- setApiLevel(result.getAsJsonObject().get("level").getAsInt());
- } catch (Exception e) {
- e.printStackTrace();
- }
- } else if (m_lastError != ApiError.API_UNKNOWN_METHOD) {
- // Unknown method means old tt-rss, in that case we assume API 0 and continue
-
- setLoadingStatus(getErrorMessage(), false);
- loginFailure();
- return;
- }
-
- Log.d(TAG, "Received API level: " + getApiLevel());
-
- loginSuccess(m_refreshAfterLogin);
-
- return;
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", getSessionId());
- put("op", "getApiLevel");
- }
- };
-
- req.execute(map);
-
- setLoadingStatus(R.string.loading_message, true);
- }
-
- return;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- setSessionId(null);
- setLoadingStatus(getErrorMessage(), false);
-
- loginFailure();
- }
-
- }
-
- public void setViewMode(String viewMode) {
- SharedPreferences.Editor editor = m_prefs.edit();
- editor.putString("view_mode", viewMode);
- editor.commit();
- }
-
- public String getViewMode() {
- return m_prefs.getString("view_mode", "adaptive");
- }
-
- public void setLastContentImageHitTestUrl(String url) {
- m_lastImageHitTestUrl = url;
- }
-
- public String getLastContentImageHitTestUrl() {
- return m_lastImageHitTestUrl;
- }
-
-}
+package org.fox.ttrss; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; + +import org.fox.ttrss.offline.OfflineActivity; +import org.fox.ttrss.offline.OfflineDownloadService; +import org.fox.ttrss.offline.OfflineUploadService; +import org.fox.ttrss.share.SubscribeActivity; +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; +import org.fox.ttrss.types.Feed; +import org.fox.ttrss.types.Label; + +import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.DialogInterface.OnMultiChoiceClickListener; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.Window; +import android.webkit.WebView; +import android.webkit.WebView.HitTestResult; +import android.widget.EditText; +import android.widget.SearchView; +import android.widget.ShareActionProvider; +import android.widget.TextView; + +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + + +public class OnlineActivity extends CommonActivity { + private final String TAG = this.getClass().getSimpleName(); + + private final static int TRIAL_DAYS = 8; + + protected SharedPreferences m_prefs; + protected Menu m_menu; + + protected int m_offlineModeStatus = 0; + + private ActionMode m_headlinesActionMode; + private HeadlinesActionModeCallback m_headlinesActionModeCallback; + + private String m_lastImageHitTestUrl; + + private BroadcastReceiver m_broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context content, Intent intent) { + + if (intent.getAction().equals(OfflineDownloadService.INTENT_ACTION_SUCCESS)) { + + m_offlineModeStatus = 2; + + switchOffline(); + + } else if (intent.getAction().equals(OfflineUploadService.INTENT_ACTION_SUCCESS)) { + Log.d(TAG, "offline upload service reports success"); + toast(R.string.offline_sync_success); + } + } + }; + + + @TargetApi(11) + private class HeadlinesActionModeCallback implements ActionMode.Callback { + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + m_headlinesActionMode = null; + + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + if (hf != null) { + ArticleList selected = hf.getSelectedArticles(); + if (selected.size() > 0) { + selected.clear(); + initMenu(); + hf.notifyUpdated(); + } + } + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + + MenuInflater inflater = getSupportMenuInflater(); + inflater.inflate(R.menu.headlines_action_menu, menu); + + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + onOptionsItemSelected(item); + return false; + } + }; + + protected String getSessionId() { + return GlobalState.getInstance().m_sessionId; + } + + protected void setSessionId(String sessionId) { + GlobalState.getInstance().m_sessionId = sessionId; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + ApiRequest.disableConnectionReuseIfNecessary(); + + // we use that before parent onCreate so let's init locally + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + if (canUseProgress()) { + requestWindowFeature(Window.FEATURE_PROGRESS); + } else { + requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); + } + + setProgressBarVisibility(false); + setProgressBarIndeterminateVisibility(false); + +// SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); + + SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); + + boolean isOffline = localPrefs.getBoolean("offline_mode_active", false); + + Log.d(TAG, "m_isOffline=" + isOffline); + + setContentView(R.layout.login); + + if (isOffline) { + switchOfflineSuccess(); + } else { + checkTrial(false); + + /* if (getIntent().getExtras() != null) { + Intent i = getIntent(); + } */ + + if (savedInstanceState != null) { + m_offlineModeStatus = savedInstanceState.getInt("offlineModeStatus"); + } + + m_headlinesActionModeCallback = new HeadlinesActionModeCallback(); + } + } + + protected boolean canUseProgress() { + return GlobalState.getInstance().m_canUseProgress; + } + + private void switchOffline() { + if (m_offlineModeStatus == 2) { + + AlertDialog.Builder builder = new AlertDialog.Builder( + OnlineActivity.this) + .setMessage(R.string.dialog_offline_success) + .setPositiveButton(R.string.dialog_offline_go, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + m_offlineModeStatus = 0; + + SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = localPrefs.edit(); + editor.putBoolean("offline_mode_active", true); + editor.commit(); + + Intent offline = new Intent( + OnlineActivity.this, + OfflineActivity.class); + offline.putExtra("initial", true); + startActivity(offline); + finish(); + } + }) + .setNegativeButton(R.string.dialog_cancel, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + m_offlineModeStatus = 0; + + } + }); + + AlertDialog dlg = builder.create(); + dlg.show(); + + } else if (m_offlineModeStatus == 0) { + + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setMessage(R.string.dialog_offline_switch_prompt) + .setPositiveButton(R.string.dialog_offline_go, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + if (getSessionId() != null) { + Log.d(TAG, "offline: starting"); + + m_offlineModeStatus = 1; + + Intent intent = new Intent( + OnlineActivity.this, + OfflineDownloadService.class); + intent.putExtra("sessionId", getSessionId()); + + startService(intent); + } + } + }) + .setNegativeButton(R.string.dialog_cancel, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + // + } + }); + + AlertDialog dlg = builder.create(); + dlg.show(); + } else if (m_offlineModeStatus == 1) { + cancelOfflineSync(); + } + } + + private boolean hasPendingOfflineData() { + try { + Cursor c = getReadableDb().query("articles", + new String[] { "COUNT(*)" }, "modified = 1", null, null, null, + null); + if (c.moveToFirst()) { + int modified = c.getInt(0); + c.close(); + + return modified > 0; + } + } catch (IllegalStateException e) { + // db is closed? ugh + } + + return false; + } + + private boolean hasOfflineData() { + try { + Cursor c = getReadableDb().query("articles", + new String[] { "COUNT(*)" }, null, null, null, null, null); + if (c.moveToFirst()) { + int modified = c.getInt(0); + c.close(); + + return modified > 0; + } + } catch (IllegalStateException e) { + // db is closed? + } + + return false; + } + + @Override + public void onPause() { + super.onPause(); + + unregisterReceiver(m_broadcastReceiver); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + private void syncOfflineData() { + Log.d(TAG, "offlineSync: starting"); + + Intent intent = new Intent( + OnlineActivity.this, + OfflineUploadService.class); + + intent.putExtra("sessionId", getSessionId()); + + startService(intent); + } + + private void cancelOfflineSync() { + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setMessage(R.string.dialog_offline_sync_in_progress) + .setNegativeButton(R.string.dialog_offline_sync_stop, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + if (getSessionId() != null) { + Log.d(TAG, "offline: stopping"); + + m_offlineModeStatus = 0; + + Intent intent = new Intent( + OnlineActivity.this, + OfflineDownloadService.class); + + stopService(intent); + + dialog.dismiss(); + + restart(); + } + } + }) + .setPositiveButton(R.string.dialog_offline_sync_continue, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + dialog.dismiss(); + + restart(); + } + }); + + AlertDialog dlg = builder.create(); + dlg.show(); + } + + public void restart() { + Intent refresh = new Intent(OnlineActivity.this, OnlineActivity.class); + startActivity(refresh); + finish(); + } + + private void switchOfflineSuccess() { + logout(); + // setLoadingStatus(R.string.blank, false); + + SharedPreferences.Editor editor = m_prefs.edit(); + editor.putBoolean("offline_mode_active", true); + editor.commit(); + + Intent offline = new Intent(OnlineActivity.this, OfflineActivity.class); + offline.putExtra("initial", true); + offline.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + + startActivityForResult(offline, 0); + + finish(); + + } + + public void login() { + login(false); + } + + public void login(boolean refresh) { + if (m_prefs.getString("ttrss_url", "").trim().length() == 0) { + + setLoadingStatus(R.string.login_need_configure, false); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.dialog_need_configure_prompt) + .setCancelable(false) + .setPositiveButton(R.string.dialog_open_preferences, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // launch preferences + + Intent intent = new Intent(OnlineActivity.this, + PreferencesActivity.class); + startActivityForResult(intent, 0); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + + } else { + setLoadingStatus(R.string.login_in_progress, true); + + LoginRequest ar = new LoginRequest(getApplicationContext(), refresh); + + HashMap<String, String> map = new HashMap<String, String>() { + { + put("op", "login"); + put("user", m_prefs.getString("login", "").trim()); + put("password", m_prefs.getString("password", "").trim()); + } + }; + + ar.execute(map); + + setLoadingStatus(R.string.login_in_progress, true); + } + } + + protected void loginSuccess(boolean refresh) { + setLoadingStatus(R.string.blank, false); + + initMenu(); + + Intent intent = new Intent(OnlineActivity.this, FeedsActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + + startActivityForResult(intent, 0); + overridePendingTransition(0, 0); + + if (hasPendingOfflineData()) + syncOfflineData(); + + finish(); + } + + public void checkTrial(boolean notify) { + boolean isTrial = getPackageManager().checkSignatures( + getPackageName(), "org.fox.ttrss.key") != PackageManager.SIGNATURE_MATCH; + + if (isTrial) { + long firstStart = m_prefs.getLong("date_firstlaunch_trial", -1); + + if (firstStart == -1) { + firstStart = System.currentTimeMillis(); + + SharedPreferences.Editor editor = m_prefs.edit(); + editor.putLong("date_firstlaunch_trial", firstStart); + editor.commit(); + } + + if (!notify && System.currentTimeMillis() > firstStart + (TRIAL_DAYS * 24 * 60 * 60 * 1000)) { + + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setTitle(R.string.trial_expired) + .setMessage(R.string.trial_expired_message) + .setCancelable(false) + .setPositiveButton(getString(R.string.trial_purchase), + new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int which) { + + openUnlockUrl(); + finish(); + + } + }) + .setNegativeButton(getString(R.string.cancel), + new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int which) { + + finish(); + + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + + } else { + long daysLeft = Math.round((firstStart + (TRIAL_DAYS * 24 * 60 * 60 * 1000) - System.currentTimeMillis()) / (24 * 60 * 60 * 1000)); + + if (notify) { + toast(getString(R.string.trial_mode_prompt, Long.valueOf(daysLeft))); + } + } + } else if (notify) { + //toast(R.string.trial_thanks); + } + } + + private void openUnlockUrl() { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse("market://details?id=org.fox.ttrss.key")); + startActivity(intent); + } catch (ActivityNotFoundException ae) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse("https://play.google.com/store/apps/details?id=org.fox.ttrss.key")); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + toast(R.string.error_other_error); + } + } + } + + @Override + public boolean onContextItemSelected(android.view.MenuItem item) { + /* AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); */ + + final ArticlePager ap = (ArticlePager)getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + switch (item.getItemId()) { + case R.id.article_img_open: + if (getLastContentImageHitTestUrl() != null) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse(getLastContentImageHitTestUrl())); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + toast(R.string.error_other_error); + } + } + return true; + case R.id.article_img_share: + if (getLastContentImageHitTestUrl() != null) { + Intent intent = new Intent(Intent.ACTION_SEND); + + intent.setType("image/png"); + intent.putExtra(Intent.EXTRA_SUBJECT, getLastContentImageHitTestUrl()); + intent.putExtra(Intent.EXTRA_TEXT, getLastContentImageHitTestUrl()); + + startActivity(Intent.createChooser(intent, getLastContentImageHitTestUrl())); + } + return true; + case R.id.article_img_view_caption: + if (getLastContentImageHitTestUrl() != null) { + + // Android doesn't give us an easy way to access title tags; + // we'll use Jsoup on the body text to grab the title text + // from the first image tag with this url. This will show + // the wrong text if an image is used multiple times. + Document doc = Jsoup.parse(ap.getSelectedArticle().content); + Elements es = doc.getElementsByAttributeValue("src", getLastContentImageHitTestUrl()); + if (es.size() > 0){ + if (es.get(0).hasAttr("title")){ + Dialog dia = new Dialog(this); + if (es.get(0).hasAttr("alt")){ + dia.setTitle(es.get(0).attr("alt")); + } else { + dia.setTitle(es.get(0).attr("title")); + } + TextView titleText = new TextView(this); + + if (android.os.Build.VERSION.SDK_INT >= 16) { + titleText.setPaddingRelative(24, 24, 24, 24); + } else { + titleText.setPadding(24, 24, 24, 24); + } + + titleText.setTextSize(16); + titleText.setText(es.get(0).attr("title")); + dia.setContentView(titleText); + dia.show(); + } else { + toast(R.string.no_caption_to_display); + } + } else { + toast(R.string.no_caption_to_display); + } + } + return true; + case R.id.article_link_share: + if (ap != null && ap.getSelectedArticle() != null) { + shareArticle(ap.getSelectedArticle()); + } + return true; + case R.id.article_link_copy: + Log.d(TAG, "article_link_copy"); + if (ap != null && ap.getSelectedArticle() != null) { + copyToClipboard(ap.getSelectedArticle().link); + } + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + final HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + final ArticlePager ap = (ArticlePager)getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + case R.id.subscribe_to_feed: + Intent subscribe = new Intent(OnlineActivity.this, SubscribeActivity.class); + startActivityForResult(subscribe, 0); + return true; + case R.id.toggle_attachments: + if (true) { + Article article = ap.getSelectedArticle(); + + if (article != null && article.attachments != null && article.attachments.size() > 0) { + CharSequence[] items = new CharSequence[article.attachments.size()]; + final CharSequence[] itemUrls = new CharSequence[article.attachments.size()]; + + for (int i = 0; i < article.attachments.size(); i++) { + items[i] = article.attachments.get(i).title != null ? article.attachments.get(i).content_url : + article.attachments.get(i).content_url; + + itemUrls[i] = article.attachments.get(i).content_url; + } + + Dialog dialog = new Dialog(OnlineActivity.this); + AlertDialog.Builder builder = new AlertDialog.Builder(OnlineActivity.this) + .setTitle(R.string.attachments_prompt) + .setCancelable(true) + .setSingleChoiceItems(items, 0, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // + } + }).setNeutralButton(R.string.attachment_copy, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + int selectedPosition = ((AlertDialog)dialog).getListView().getCheckedItemPosition(); + + copyToClipboard((String)itemUrls[selectedPosition]); + } + }).setPositiveButton(R.string.attachment_view, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int id) { + int selectedPosition = ((AlertDialog)dialog).getListView().getCheckedItemPosition(); + + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse((String)itemUrls[selectedPosition])); + startActivity(browserIntent); + + dialog.cancel(); + } + }).setNegativeButton(R.string.dialog_cancel, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + + dialog = builder.create(); + dialog.show(); + } + } + return true; + case R.id.donate: + if (true) { + openUnlockUrl(); + } + return true; + case R.id.logout: + logout(); + return true; + case R.id.login: + login(); + return true; + case R.id.go_offline: + switchOffline(); + return true; + case R.id.article_set_note: + if (ap != null && ap.getSelectedArticle() != null) { + editArticleNote(ap.getSelectedArticle()); + } + return true; + case R.id.preferences: + Intent intent = new Intent(OnlineActivity.this, + PreferencesActivity.class); + startActivityForResult(intent, 0); + return true; + case R.id.search: + if (hf != null && isCompatMode()) { + Dialog dialog = new Dialog(this); + + final EditText edit = new EditText(this); + + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setTitle(R.string.search) + .setPositiveButton(getString(R.string.search), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + + String query = edit.getText().toString().trim(); + + hf.setSearchQuery(query); + + } + }) + .setNegativeButton(getString(R.string.cancel), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + + // + + } + }).setView(edit); + + dialog = builder.create(); + dialog.show(); + } + return true; + case R.id.headlines_mark_as_read: + if (hf != null) { + ArticleList articles = hf.getUnreadArticles(); + + for (Article a : articles) + a.unread = false; + + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + if (hf.isAdded()) { + hf.refresh(false); + } + } + }; + + final String articleIds = articlesToIdString(articles); + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", articleIds); + put("mode", "0"); + put("field", "2"); + } + }; + req.execute(map); + } + return true; + case R.id.headlines_view_mode: + if (hf != null) { + Dialog dialog = new Dialog(this); + + String viewMode = getViewMode(); + + //Log.d(TAG, "viewMode:" + getViewMode()); + + int selectedIndex = 0; + + if (viewMode.equals("all_articles")) { + selectedIndex = 1; + } else if (viewMode.equals("marked")) { + selectedIndex = 2; + } else if (viewMode.equals("published")) { + selectedIndex = 3; + } else if (viewMode.equals("unread")) { + selectedIndex = 4; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setTitle(R.string.headlines_set_view_mode) + .setSingleChoiceItems( + new String[] { + getString(R.string.headlines_adaptive), + getString(R.string.headlines_all_articles), + getString(R.string.headlines_starred), + getString(R.string.headlines_published), + getString(R.string.headlines_unread) }, + selectedIndex, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int which) { + switch (which) { + case 0: + setViewMode("adaptive"); + break; + case 1: + setViewMode("all_articles"); + break; + case 2: + setViewMode("marked"); + break; + case 3: + setViewMode("published"); + break; + case 4: + setViewMode("unread"); + break; + } + dialog.cancel(); + + refresh(); + } + }); + + dialog = builder.create(); + dialog.show(); + + } + return true; + case R.id.headlines_select: + if (hf != null) { + Dialog dialog = new Dialog(this); + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setTitle(R.string.headlines_select_dialog) + .setSingleChoiceItems( + new String[] { + getString(R.string.headlines_select_all), + getString(R.string.headlines_select_unread), + getString(R.string.headlines_select_none) }, + 0, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int which) { + switch (which) { + case 0: + hf.setSelection(HeadlinesFragment.ArticlesSelection.ALL); + break; + case 1: + hf.setSelection(HeadlinesFragment.ArticlesSelection.UNREAD); + break; + case 2: + hf.setSelection(HeadlinesFragment.ArticlesSelection.NONE); + break; + } + dialog.cancel(); + initMenu(); + } + }); + + dialog = builder.create(); + dialog.show(); + } + return true; + case R.id.share_article: + //if (android.os.Build.VERSION.SDK_INT < 14) { + if (ap != null) { + shareArticle(ap.getSelectedArticle()); + } + //} + return true; + case R.id.toggle_marked: + if (ap != null & ap.getSelectedArticle() != null) { + Article a = ap.getSelectedArticle(); + a.marked = !a.marked; + saveArticleMarked(a); + if (hf != null) hf.notifyUpdated(); + } + return true; + /* case R.id.selection_select_none: + if (hf != null) { + ArticleList selected = hf.getSelectedArticles(); + if (selected.size() > 0) { + selected.clear(); + initMenu(); + hf.notifyUpdated(); + } + } + return true; */ + case R.id.selection_toggle_unread: + if (hf != null) { + ArticleList selected = hf.getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.unread = !a.unread; + + toggleArticlesUnread(selected); + hf.notifyUpdated(); + initMenu(); + } + } + return true; + case R.id.selection_toggle_marked: + if (hf != null) { + ArticleList selected = hf.getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.marked = !a.marked; + + toggleArticlesMarked(selected); + hf.notifyUpdated(); + initMenu(); + } + } + return true; + case R.id.selection_toggle_published: + if (hf != null) { + ArticleList selected = hf.getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.published = !a.published; + + toggleArticlesPublished(selected); + hf.notifyUpdated(); + initMenu(); + } + } + return true; + case R.id.toggle_published: + if (ap != null && ap.getSelectedArticle() != null) { + Article a = ap.getSelectedArticle(); + a.published = !a.published; + saveArticlePublished(a); + if (hf != null) hf.notifyUpdated(); + } + return true; + case R.id.catchup_above: + if (hf != null) { + if (ap != null && ap.getSelectedArticle() != null) { + Article article = ap.getSelectedArticle(); + + ArticleList articles = hf.getAllArticles(); + ArticleList tmp = new ArticleList(); + for (Article a : articles) { + a.unread = false; + tmp.add(a); + if (article.id == a.id) + break; + } + if (tmp.size() > 0) { + toggleArticlesUnread(tmp); + hf.notifyUpdated(); + initMenu(); + } + } + } + return true; + case R.id.set_unread: + if (ap != null && ap.getSelectedArticle() != null) { + Article a = ap.getSelectedArticle(); + + if (a != null) { + a.unread = !a.unread; + saveArticleUnread(a); + } + + if (hf != null) hf.notifyUpdated(); + } + return true; + case R.id.set_labels: + if (ap != null && ap.getSelectedArticle() != null) { + editArticleLabels(ap.getSelectedArticle()); + } + return true; + case R.id.update_headlines: + if (hf != null) { + hf.refresh(false); + } + return true; + default: + Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + public void editArticleNote(final Article article) { + String note = ""; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(article.title); + final EditText topicEdit = new EditText(this); + topicEdit.setText(note); + builder.setView(topicEdit); + + builder.setPositiveButton(R.string.article_set_note, new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + saveArticleNote(article, topicEdit.getText().toString().trim()); + article.published = true; + saveArticlePublished(article); + + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + if (hf != null) hf.notifyUpdated(); + } + }); + + builder.setNegativeButton(R.string.dialog_cancel, new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + public void editArticleLabels(Article article) { + final int articleId = article.id; + + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + Type listType = new TypeToken<List<Label>>() {}.getType(); + final List<Label> labels = new Gson().fromJson(result, listType); + + CharSequence[] items = new CharSequence[labels.size()]; + final int[] itemIds = new int[labels.size()]; + boolean[] checkedItems = new boolean[labels.size()]; + + for (int i = 0; i < labels.size(); i++) { + items[i] = labels.get(i).caption; + itemIds[i] = labels.get(i).id; + checkedItems[i] = labels.get(i).checked; + } + + Dialog dialog = new Dialog(OnlineActivity.this); + AlertDialog.Builder builder = new AlertDialog.Builder(OnlineActivity.this) + .setTitle(R.string.article_set_labels) + .setMultiChoiceItems(items, checkedItems, new OnMultiChoiceClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which, final boolean isChecked) { + final int labelId = itemIds[which]; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "setArticleLabel"); + put("label_id", String.valueOf(labelId)); + put("article_ids", String.valueOf(articleId)); + if (isChecked) put("assign", "true"); + } + }; + + ApiRequest req = new ApiRequest(m_context); + req.execute(map); + + } + }).setPositiveButton(R.string.dialog_close, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + dialog = builder.create(); + dialog.show(); + + } + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "getLabels"); + put("article_id", String.valueOf(articleId)); + } + }; + + req.execute(map); + } + + protected void logout() { + setSessionId(null); + + findViewById(R.id.loading_container).setVisibility(View.VISIBLE); + setLoadingStatus(R.string.login_ready, false); + + initMenu(); + } + + protected void loginFailure() { + setSessionId(null); + initMenu(); + + if (hasOfflineData()) { + + AlertDialog.Builder builder = new AlertDialog.Builder( + OnlineActivity.this) + .setMessage(R.string.dialog_offline_prompt) + .setPositiveButton(R.string.dialog_offline_go, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + switchOfflineSuccess(); + } + }) + .setNegativeButton(R.string.dialog_cancel, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + // + } + }); + + AlertDialog dlg = builder.create(); + dlg.show(); + } + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("offlineModeStatus", m_offlineModeStatus); + } + + @Override + public void onResume() { + super.onResume(); + + ApiRequest.trustAllHosts(m_prefs.getBoolean("ssl_trust_any", false), + m_prefs.getBoolean("ssl_trust_any_host", false)); + + IntentFilter filter = new IntentFilter(); + filter.addAction(OfflineDownloadService.INTENT_ACTION_SUCCESS); + filter.addAction(OfflineUploadService.INTENT_ACTION_SUCCESS); + filter.addCategory(Intent.CATEGORY_DEFAULT); + + registerReceiver(m_broadcastReceiver, filter); + + if (getSessionId() == null) { + login(); + } else { + loginSuccess(false); + } + } + + public Menu getMenu() { + return m_menu; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getSupportMenuInflater(); + inflater.inflate(R.menu.main_menu, menu); + + m_menu = menu; + + initMenu(); + + List<PackageInfo> pkgs = getPackageManager() + .getInstalledPackages(0); + + for (PackageInfo p : pkgs) { + if ("org.fox.ttrss.key".equals(p.packageName)) { + Log.d(TAG, "license apk found"); + menu.findItem(R.id.donate).setVisible(false); + break; + } + } + + return true; + } + + protected int getApiLevel() { + return GlobalState.getInstance().m_apiLevel; + } + + protected void setApiLevel(int apiLevel) { + GlobalState.getInstance().m_apiLevel = apiLevel; + } + + @SuppressWarnings({ "unchecked", "serial" }) + public void saveArticleUnread(final Article article) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + //toast(R.string.article_set_unread); + initMenu(); + } + }; + + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", String.valueOf(article.id)); + put("mode", article.unread ? "1" : "0"); + put("field", "2"); + } + }; + + req.execute(map); + } + + @SuppressWarnings({ "unchecked", "serial" }) + public void saveArticleMarked(final Article article) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + //toast(article.marked ? R.string.notify_article_marked : R.string.notify_article_unmarked); + initMenu(); + } + }; + + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", String.valueOf(article.id)); + put("mode", article.marked ? "1" : "0"); + put("field", "0"); + } + }; + + req.execute(map); + } + + @SuppressWarnings({ "unchecked", "serial" }) + public void saveArticlePublished(final Article article) { + + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + //toast(article.published ? R.string.notify_article_published : R.string.notify_article_unpublished); + initMenu(); + } + }; + + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", String.valueOf(article.id)); + put("mode", article.published ? "1" : "0"); + put("field", "1"); + } + }; + + req.execute(map); + } + + @SuppressWarnings({ "unchecked", "serial" }) + public void saveArticleNote(final Article article, final String note) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + toast(R.string.notify_article_note_set); + } + }; + + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", String.valueOf(article.id)); + put("mode", "1"); + put("data", note); + put("field", "3"); + } + }; + + req.execute(map); + } + + public static String articlesToIdString(ArticleList articles) { + String tmp = ""; + + for (Article a : articles) + tmp += String.valueOf(a.id) + ","; + + return tmp.replaceAll(",$", ""); + } + + public void shareText(String text) { + + Intent intent = new Intent(Intent.ACTION_SEND); + + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, text); + + startActivity(Intent.createChooser(intent, text)); + } + + public void shareArticle(Article article) { + if (article != null) { + + Intent intent = getShareIntent(article); + + startActivity(Intent.createChooser(intent, + getString(R.string.share_article))); + } + } + + protected Intent getShareIntent(Article article) { + Intent intent = new Intent(Intent.ACTION_SEND); + + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, article.title); + intent.putExtra(Intent.EXTRA_TEXT, article.link); + + return intent; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (m_prefs.getBoolean("use_volume_keys", false)) { + ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + ap.selectArticle(false); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + ap.selectArticle(true); + return true; + } + } + } + + return super.onKeyDown(keyCode, event); + } + + // Handle onKeyUp too to suppress beep + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (m_prefs.getBoolean("use_volume_keys", false)) { + + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + return true; + } + } + + return super.onKeyUp(keyCode, event); + } + + @SuppressWarnings("unchecked") + public void catchupFeed(final Feed feed) { + Log.d(TAG, "catchupFeed=" + feed); + + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + // refresh? + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "catchupFeed"); + put("feed_id", String.valueOf(feed.id)); + if (feed.is_cat) + put("is_cat", "1"); + } + }; + + req.execute(map); + } + + @SuppressWarnings("unchecked") + public void toggleArticlesMarked(final ArticleList articles) { + ApiRequest req = new ApiRequest(getApplicationContext()); + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", articlesToIdString(articles)); + put("mode", "2"); + put("field", "0"); + } + }; + + req.execute(map); + } + + @SuppressWarnings("unchecked") + public void toggleArticlesUnread(final ArticleList articles) { + ApiRequest req = new ApiRequest(getApplicationContext()); + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", articlesToIdString(articles)); + put("mode", "2"); + put("field", "2"); + } + }; + + req.execute(map); + //refresh(); + } + + @SuppressWarnings("unchecked") + public void toggleArticlesPublished(final ArticleList articles) { + ApiRequest req = new ApiRequest(getApplicationContext()); + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "updateArticle"); + put("article_ids", articlesToIdString(articles)); + put("mode", "2"); + put("field", "1"); + } + }; + + req.execute(map); + } + + + protected void initMenu() { + if (m_menu != null) { + if (getSessionId() != null) { + m_menu.setGroupVisible(R.id.menu_group_logged_in, true); + m_menu.setGroupVisible(R.id.menu_group_logged_out, false); + } else { + m_menu.setGroupVisible(R.id.menu_group_logged_in, false); + m_menu.setGroupVisible(R.id.menu_group_logged_out, true); + } + + m_menu.setGroupVisible(R.id.menu_group_headlines, false); + m_menu.setGroupVisible(R.id.menu_group_article, false); + m_menu.setGroupVisible(R.id.menu_group_feeds, false); + + m_menu.findItem(R.id.set_labels).setEnabled(getApiLevel() >= 1); + m_menu.findItem(R.id.article_set_note).setEnabled(getApiLevel() >= 1); + m_menu.findItem(R.id.subscribe_to_feed).setEnabled(getApiLevel() >= 5); + + MenuItem search = m_menu.findItem(R.id.search); + search.setEnabled(getApiLevel() >= 2); + + ArticlePager ap = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (ap != null) { + Article article = ap.getSelectedArticle(); + + if (article != null) { + m_menu.findItem(R.id.toggle_marked).setIcon(article.marked ? R.drawable.ic_important_light : + R.drawable.ic_unimportant_light); + + m_menu.findItem(R.id.toggle_published).setIcon(article.published ? R.drawable.ic_menu_published_light : + R.drawable.ic_menu_unpublished_light); + + m_menu.findItem(R.id.set_unread).setIcon(article.unread ? R.drawable.ic_unread_light : + R.drawable.ic_read_light); + } + } + + /* if (android.os.Build.VERSION.SDK_INT >= 14) { + ShareActionProvider shareProvider = (ShareActionProvider) m_menu.findItem(R.id.share_article).getActionProvider(); + + ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (af != null && af.getSelectedArticle() != null) { + shareProvider.setShareIntent(getShareIntent(af.getSelectedArticle())); + + if (!isSmallScreen()) { + m_menu.findItem(R.id.share_article).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + } + } + } */ + + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + if (hf != null) { + if (hf.getSelectedArticles().size() > 0 && m_headlinesActionMode == null) { + m_headlinesActionMode = startActionMode(m_headlinesActionModeCallback); + } else if (hf.getSelectedArticles().size() == 0 && m_headlinesActionMode != null) { + m_headlinesActionMode.finish(); + } + } + + if (!isCompatMode()) { + SearchView searchView = (SearchView) search.getActionView(); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + private String query = ""; + + @Override + public boolean onQueryTextSubmit(String query) { + HeadlinesFragment frag = (HeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + if (frag != null) { + frag.setSearchQuery(query); + this.query = query; + } + + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + if (newText.equals("") && !newText.equals(this.query)) { + HeadlinesFragment frag = (HeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + if (frag != null) { + frag.setSearchQuery(newText); + this.query = newText; + } + } + + return false; + } + }); + } + } + } + + protected void refresh(boolean includeHeadlines) { + FeedCategoriesFragment cf = (FeedCategoriesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_CATS); + + if (cf != null) { + cf.refresh(false); + } + + FeedsFragment ff = (FeedsFragment) getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS); + + if (ff != null) { + ff.refresh(false); + } + + if (includeHeadlines) { + HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + if (hf != null) { + hf.refresh(false); + } + + ArticlePager af = (ArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (af != null) { + af.refresh(false); + } + } + } + + protected void refresh() { + refresh(true); + } + + private class LoginRequest extends ApiRequest { + boolean m_refreshAfterLogin = false; + + public LoginRequest(Context context, boolean refresh) { + super(context); + m_refreshAfterLogin = refresh; + } + + @SuppressWarnings("unchecked") + protected void onPostExecute(JsonElement result) { + if (result != null) { + try { + JsonObject content = result.getAsJsonObject(); + + if (content != null) { + setSessionId(content.get("session_id").getAsString()); + + JsonElement apiLevel = content.get("api_level"); + + GlobalState.getInstance().m_canUseProgress = m_canUseProgress; + + Log.d(TAG, "Authenticated! canUseProgress=" + m_canUseProgress); + + if (apiLevel != null) { + setApiLevel(apiLevel.getAsInt()); + Log.d(TAG, "Received API level: " + getApiLevel()); + + loginSuccess(m_refreshAfterLogin); + + } else { + + ApiRequest req = new ApiRequest(m_context) { + protected void onPostExecute(JsonElement result) { + setApiLevel(0); + + if (result != null) { + try { + setApiLevel(result.getAsJsonObject().get("level").getAsInt()); + } catch (Exception e) { + e.printStackTrace(); + } + } else if (m_lastError != ApiError.API_UNKNOWN_METHOD) { + // Unknown method means old tt-rss, in that case we assume API 0 and continue + + setLoadingStatus(getErrorMessage(), false); + loginFailure(); + return; + } + + Log.d(TAG, "Received API level: " + getApiLevel()); + + loginSuccess(m_refreshAfterLogin); + + return; + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", getSessionId()); + put("op", "getApiLevel"); + } + }; + + req.execute(map); + + setLoadingStatus(R.string.loading_message, true); + } + + return; + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + setSessionId(null); + setLoadingStatus(getErrorMessage(), false); + + loginFailure(); + } + + } + + public void setViewMode(String viewMode) { + SharedPreferences.Editor editor = m_prefs.edit(); + editor.putString("view_mode", viewMode); + editor.commit(); + } + + public String getViewMode() { + return m_prefs.getString("view_mode", "adaptive"); + } + + public void setLastContentImageHitTestUrl(String url) { + m_lastImageHitTestUrl = url; + } + + public String getLastContentImageHitTestUrl() { + return m_lastImageHitTestUrl; + } + +} diff --git a/src/org/fox/ttrss/PreferencesActivity.java b/src/org/fox/ttrss/PreferencesActivity.java index 3b11600c..274d1ba4 100644 --- a/src/org/fox/ttrss/PreferencesActivity.java +++ b/src/org/fox/ttrss/PreferencesActivity.java @@ -1,20 +1,20 @@ -package org.fox.ttrss;
-
-import android.os.Bundle;
-import android.preference.PreferenceActivity;
-
-public class PreferencesActivity extends PreferenceActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- addPreferencesFromResource(R.xml.preferences);
-
- boolean compatMode = android.os.Build.VERSION.SDK_INT <= 10;
-
- if (compatMode) {
- findPreference("dim_status_bar").setEnabled(false);
- }
- }
-
-}
+package org.fox.ttrss; + +import android.os.Bundle; +import android.preference.PreferenceActivity; + +public class PreferencesActivity extends PreferenceActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.preferences); + + boolean compatMode = android.os.Build.VERSION.SDK_INT <= 10; + + if (compatMode) { + findPreference("dim_status_bar").setEnabled(false); + } + } + +} diff --git a/src/org/fox/ttrss/TitleWebView.java b/src/org/fox/ttrss/TitleWebView.java index e39fc268..d55f2e35 100644 --- a/src/org/fox/ttrss/TitleWebView.java +++ b/src/org/fox/ttrss/TitleWebView.java @@ -1,91 +1,91 @@ -package org.fox.ttrss;
-
-// http://www.techques.com/question/1-9718245/Webview-in-Scrollview
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.webkit.WebView;
-
-public class TitleWebView extends WebView{
-
- public TitleWebView(Context context, AttributeSet attrs){
- super(context, attrs);
- }
-
- private int titleHeight;
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- // determine height of title bar
- View title = getChildAt(0);
- titleHeight = title==null ? 0 : title.getMeasuredHeight();
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev){
- return true; // don't pass our touch events to children (title bar), we send these in dispatchTouchEvent
- }
-
- private boolean touchInTitleBar;
- @Override
- public boolean dispatchTouchEvent(MotionEvent me){
-
- boolean wasInTitle = false;
- switch(me.getActionMasked()){
- case MotionEvent.ACTION_DOWN:
- touchInTitleBar = (me.getY() <= visibleTitleHeight());
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- wasInTitle = touchInTitleBar;
- touchInTitleBar = false;
- break;
- }
- if(touchInTitleBar || wasInTitle) {
- View title = getChildAt(0);
- if(title!=null) {
- // this touch belongs to title bar, dispatch it here
- me.offsetLocation(0, getScrollY());
- return title.dispatchTouchEvent(me);
- }
- }
- // this is our touch, offset and process
- me.offsetLocation(0, -titleHeight);
- return super.dispatchTouchEvent(me);
- }
-
- /**
- * @return visible height of title (may return negative values)
- */
- private int visibleTitleHeight(){
- return titleHeight-getScrollY();
- }
-
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt){
- super.onScrollChanged(l, t, oldl, oldt);
- View title = getChildAt(0);
- if(title!=null) // undo horizontal scroll, so that title scrolls only vertically
- title.offsetLeftAndRight(l - title.getLeft());
- }
-
- @Override
- protected void onDraw(Canvas c){
-
- c.save();
- int tH = visibleTitleHeight();
- if(tH>0) {
- // clip so that it doesn't clear background under title bar
- int sx = getScrollX(), sy = getScrollY();
- c.clipRect(sx, sy+tH, sx+getWidth(), sy+getHeight());
- }
- c.translate(0, titleHeight);
- super.onDraw(c);
- c.restore();
- }
+package org.fox.ttrss; + +// http://www.techques.com/question/1-9718245/Webview-in-Scrollview + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.webkit.WebView; + +public class TitleWebView extends WebView{ + + public TitleWebView(Context context, AttributeSet attrs){ + super(context, attrs); + } + + private int titleHeight; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + // determine height of title bar + View title = getChildAt(0); + titleHeight = title==null ? 0 : title.getMeasuredHeight(); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev){ + return true; // don't pass our touch events to children (title bar), we send these in dispatchTouchEvent + } + + private boolean touchInTitleBar; + @Override + public boolean dispatchTouchEvent(MotionEvent me){ + + boolean wasInTitle = false; + switch(me.getActionMasked()){ + case MotionEvent.ACTION_DOWN: + touchInTitleBar = (me.getY() <= visibleTitleHeight()); + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + wasInTitle = touchInTitleBar; + touchInTitleBar = false; + break; + } + if(touchInTitleBar || wasInTitle) { + View title = getChildAt(0); + if(title!=null) { + // this touch belongs to title bar, dispatch it here + me.offsetLocation(0, getScrollY()); + return title.dispatchTouchEvent(me); + } + } + // this is our touch, offset and process + me.offsetLocation(0, -titleHeight); + return super.dispatchTouchEvent(me); + } + + /** + * @return visible height of title (may return negative values) + */ + private int visibleTitleHeight(){ + return titleHeight-getScrollY(); + } + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt){ + super.onScrollChanged(l, t, oldl, oldt); + View title = getChildAt(0); + if(title!=null) // undo horizontal scroll, so that title scrolls only vertically + title.offsetLeftAndRight(l - title.getLeft()); + } + + @Override + protected void onDraw(Canvas c){ + + c.save(); + int tH = visibleTitleHeight(); + if(tH>0) { + // clip so that it doesn't clear background under title bar + int sx = getScrollX(), sy = getScrollY(); + c.clipRect(sx, sy+tH, sx+getWidth(), sy+getHeight()); + } + c.translate(0, titleHeight); + super.onDraw(c); + c.restore(); + } }
\ No newline at end of file diff --git a/src/org/fox/ttrss/offline/OfflineActivity.java b/src/org/fox/ttrss/offline/OfflineActivity.java index bca949de..319b76c8 100644 --- a/src/org/fox/ttrss/offline/OfflineActivity.java +++ b/src/org/fox/ttrss/offline/OfflineActivity.java @@ -1,637 +1,634 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.CommonActivity;
-import org.fox.ttrss.PreferencesActivity;
-import org.fox.ttrss.R;
-
-import android.annotation.SuppressLint;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.util.Log;
-import android.view.ActionMode;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.EditText;
-import android.widget.SearchView;
-
-public class OfflineActivity extends CommonActivity {
- private final String TAG = this.getClass().getSimpleName();
-
- protected SharedPreferences m_prefs;
- protected Menu m_menu;
-
- private ActionMode m_headlinesActionMode;
- private HeadlinesActionModeCallback m_headlinesActionModeCallback;
-
- @SuppressLint("NewApi")
- private class HeadlinesActionModeCallback implements ActionMode.Callback {
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return false;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- deselectAllArticles();
- m_headlinesActionMode = null;
- initMenu();
- }
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.headlines_action_menu, menu);
-
- return true;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- onOptionsItemSelected(item);
- return false;
- }
- };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_PROGRESS);
-
- setProgressBarVisibility(false);
-
- setContentView(R.layout.login);
-
- setLoadingStatus(R.string.blank, false);
- findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- initMenu();
-
- Intent intent = getIntent();
-
- if (intent.getExtras() != null) {
- if (intent.getBooleanExtra("initial", false)) {
- intent = new Intent(OfflineActivity.this, OfflineFeedsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-
- startActivityForResult(intent, 0);
- finish();
- }
- }
-
- /* if (savedInstanceState != null) {
-
- } */
-
- if (!isCompatMode()) {
- m_headlinesActionModeCallback = new HeadlinesActionModeCallback();
- }
-
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
- }
-
- protected void selectArticles(int feedId, boolean isCat, int mode) {
- switch (mode) {
- case 0:
- SQLiteStatement stmtSelectAll = null;
-
- if (isCat) {
- stmtSelectAll = getWritableDb().compileStatement(
- "UPDATE articles SET selected = 1 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- } else {
- stmtSelectAll = getWritableDb().compileStatement(
- "UPDATE articles SET selected = 1 WHERE feed_id = ?");
- }
-
- stmtSelectAll.bindLong(1, feedId);
- stmtSelectAll.execute();
- stmtSelectAll.close();
-
- break;
- case 1:
-
- SQLiteStatement stmtSelectUnread = null;
-
- if (isCat) {
- stmtSelectUnread = getWritableDb().compileStatement(
- "UPDATE articles SET selected = 1 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?) AND unread = 1");
- } else {
- stmtSelectUnread = getWritableDb().compileStatement(
- "UPDATE articles SET selected = 1 WHERE feed_id = ? AND unread = 1");
- }
-
- stmtSelectUnread.bindLong(1, feedId);
- stmtSelectUnread.execute();
- stmtSelectUnread.close();
-
- break;
- case 2:
- deselectAllArticles();
- break;
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- final OfflineHeadlinesFragment ohf = (OfflineHeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- /* final OfflineFeedsFragment off = (OfflineFeedsFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_FEEDS); */
-
- /* final OfflineFeedCategoriesFragment ocf = (OfflineFeedCategoriesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_CATS); */
-
- final OfflineArticlePager oap = (OfflineArticlePager) getSupportFragmentManager()
- .findFragmentByTag(FRAG_ARTICLE);
-
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- case R.id.go_online:
- switchOnline();
- return true;
- case R.id.search:
- if (ohf != null && isCompatMode()) {
- Dialog dialog = new Dialog(this);
-
- final EditText edit = new EditText(this);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(R.string.search)
- .setPositiveButton(getString(R.string.search),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
-
- String query = edit.getText().toString().trim();
-
- ohf.setSearchQuery(query);
-
- }
- })
- .setNegativeButton(getString(R.string.cancel),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
-
- //
-
- }
- }).setView(edit);
-
- dialog = builder.create();
- dialog.show();
- }
-
- return true;
- case R.id.preferences:
- Intent intent = new Intent(this, PreferencesActivity.class);
- startActivityForResult(intent, 0);
- return true;
- case R.id.headlines_select:
- if (ohf != null) {
- Dialog dialog = new Dialog(this);
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.headlines_select_dialog);
-
- builder.setSingleChoiceItems(new String[] {
- getString(R.string.headlines_select_all),
- getString(R.string.headlines_select_unread),
- getString(R.string.headlines_select_none) }, 0,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
-
- selectArticles(ohf.getFeedId(), ohf.getFeedIsCat(), which);
- initMenu();
- refresh();
-
- dialog.cancel();
- }
- });
-
- dialog = builder.create();
- dialog.show();
- }
- return true;
- case R.id.headlines_mark_as_read:
- if (ohf != null) {
- int feedId = ohf.getFeedId();
- boolean isCat = ohf.getFeedIsCat();
-
- SQLiteStatement stmt = null;
-
- if (isCat) {
- stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- } else {
- stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id = ?");
- }
- stmt.bindLong(1, feedId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.share_article:
- if (true) {
- int articleId = oap.getSelectedArticleId();
-
- shareArticle(articleId);
- }
- return true;
- case R.id.toggle_marked:
- if (oap != null) {
- int articleId = oap.getSelectedArticleId();
-
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, marked = NOT marked WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.selection_select_none:
- deselectAllArticles();
- return true;
- case R.id.selection_toggle_unread:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, unread = NOT unread WHERE selected = 1");
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.selection_toggle_marked:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, marked = NOT marked WHERE selected = 1");
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.selection_toggle_published:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, published = NOT published WHERE selected = 1");
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.toggle_published:
- if (oap != null) {
- int articleId = oap.getSelectedArticleId();
-
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, published = NOT published WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.catchup_above:
- if (oap != null) {
- int articleId = oap.getSelectedArticleId();
- int feedId = oap.getFeedId();
- boolean isCat = oap.getFeedIsCat();
-
- SQLiteStatement stmt = null;
-
- if (isCat) {
- stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE " +
- "updated >= (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " +
- "AND feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- } else {
- stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE " +
- "updated >= (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " +
- "AND feed_id = ?");
- }
-
- stmt.bindLong(1, articleId);
- stmt.bindLong(2, feedId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.set_unread:
- if (oap != null) {
- int articleId = oap.getSelectedArticleId();
-
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 1 WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- default:
- Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
- return super.onOptionsItemSelected(item);
- }
- }
-
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.offline_menu, menu);
-
- m_menu = menu;
-
- initMenu();
-
- return true;
- }
-
- @SuppressLint("NewApi")
- protected void initMenu() {
- if (m_menu != null) {
- m_menu.setGroupVisible(R.id.menu_group_headlines, false);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, false);
- m_menu.setGroupVisible(R.id.menu_group_article, false);
- m_menu.setGroupVisible(R.id.menu_group_feeds, false);
-
- if (!isCompatMode()) {
- MenuItem search = m_menu.findItem(R.id.search);
-
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- if (hf != null) {
- if (hf.getSelectedArticleCount() > 0 && m_headlinesActionMode == null) {
- m_headlinesActionMode = startActionMode(m_headlinesActionModeCallback);
- } else if (hf.getSelectedArticleCount() == 0 && m_headlinesActionMode != null) {
- m_headlinesActionMode.finish();
- }
- }
-
- OfflineArticlePager ap = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (ap != null) {
- int articleId = ap.getSelectedArticleId();
-
- Cursor article = getArticleById(articleId);
-
- if (article != null) {
- boolean unread = article.getInt(article.getColumnIndex("unread")) == 1;
- boolean marked = article.getInt(article.getColumnIndex("marked")) == 1;
- boolean published = article.getInt(article.getColumnIndex("published")) == 1;
-
- m_menu.findItem(R.id.toggle_marked).setIcon(marked ? R.drawable.ic_important_light :
- R.drawable.ic_unimportant_light);
-
- m_menu.findItem(R.id.toggle_published).setIcon(published ? R.drawable.ic_menu_published_light :
- R.drawable.ic_menu_unpublished_light);
-
- m_menu.findItem(R.id.set_unread).setIcon(unread ? R.drawable.ic_unread_light :
- R.drawable.ic_read_light);
-
- article.close();
- }
- }
-
- SearchView searchView = (SearchView) search.getActionView();
- searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- private String query = "";
-
- @Override
- public boolean onQueryTextSubmit(String query) {
- OfflineHeadlinesFragment frag = (OfflineHeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- if (frag != null) {
- frag.setSearchQuery(query);
- this.query = query;
- }
-
- return false;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- if (newText.equals("") && !newText.equals(this.query)) {
- OfflineHeadlinesFragment frag = (OfflineHeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- if (frag != null) {
- frag.setSearchQuery(newText);
- this.query = newText;
- }
- }
-
- return false;
- }
- });
- }
- }
- }
-
- private void switchOnline() {
- SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = localPrefs.edit();
- editor.putBoolean("offline_mode_active", false);
- editor.commit();
-
- Intent refresh = new Intent(this, org.fox.ttrss.OnlineActivity.class);
- startActivity(refresh);
- finish();
- }
-
- protected Cursor getArticleById(int articleId) {
- Cursor c = getReadableDb().query("articles", null,
- BaseColumns._ID + "=?",
- new String[] { String.valueOf(articleId) }, null, null, null);
-
- c.moveToFirst();
-
- return c;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (m_prefs.getBoolean("use_volume_keys", false)) {
- OfflineArticlePager ap = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- ap.selectArticle(false);
- return true;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- ap.selectArticle(true);
- return true;
- }
- }
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
- // Handle onKeyUp too to suppress beep
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (m_prefs.getBoolean("use_volume_keys", false)) {
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- return true;
- }
- }
-
- return super.onKeyUp(keyCode, event);
- }
-
- protected Cursor getFeedById(int feedId) {
- Cursor c = getReadableDb().query("feeds", null,
- BaseColumns._ID + "=?",
- new String[] { String.valueOf(feedId) }, null, null, null);
-
- c.moveToFirst();
-
- return c;
- }
-
- protected Cursor getCatById(int catId) {
- Cursor c = getReadableDb().query("categories", null,
- BaseColumns._ID + "=?",
- new String[] { String.valueOf(catId) }, null, null, null);
-
- c.moveToFirst();
-
- return c;
- }
-
- protected Intent getShareIntent(Cursor article) {
- if (article != null) {
- String title = article.getString(article.getColumnIndex("title"));
- String link = article.getString(article.getColumnIndex("link"));
-
- Intent intent = new Intent(Intent.ACTION_SEND);
-
- intent.setType("text/plain");
- intent.putExtra(Intent.EXTRA_SUBJECT, title);
- intent.putExtra(Intent.EXTRA_TEXT, link);
-
- return intent;
- } else {
- return null;
- }
- }
-
- protected void shareArticle(int articleId) {
-
- Cursor article = getArticleById(articleId);
-
- if (article != null) {
- shareArticle(article);
- article.close();
- }
- }
-
- private void shareArticle(Cursor article) {
- if (article != null) {
- Intent intent = getShareIntent(article);
-
- startActivity(Intent.createChooser(intent,
- getString(R.string.share_article)));
- }
- }
-
- protected int getSelectedArticleCount() {
- Cursor c = getReadableDb().query("articles",
- new String[] { "COUNT(*)" }, "selected = 1", null, null, null,
- null);
- c.moveToFirst();
- int selected = c.getInt(0);
- c.close();
-
- return selected;
- }
-
- protected void deselectAllArticles() {
- getWritableDb().execSQL("UPDATE articles SET selected = 0 ");
- refresh();
- }
-
- protected void refresh() {
- OfflineFeedsFragment ff = (OfflineFeedsFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_FEEDS);
-
- if (ff != null) {
- ff.refresh();
- }
-
- OfflineFeedCategoriesFragment cf = (OfflineFeedCategoriesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_CATS);
-
- if (cf != null) {
- cf.refresh();
- }
-
- OfflineHeadlinesFragment ohf = (OfflineHeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- if (ohf != null) {
- ohf.refresh();
- }
-
- initMenu();
- }
-
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.CommonActivity; +import org.fox.ttrss.PreferencesActivity; +import org.fox.ttrss.R; + +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.util.Log; +import android.view.KeyEvent; + +import android.view.View; +import android.view.Window; +import android.widget.EditText; +import android.widget.SearchView; + +public class OfflineActivity extends CommonActivity { + private final String TAG = this.getClass().getSimpleName(); + + protected SharedPreferences m_prefs; + protected Menu m_menu; + + private ActionMode m_headlinesActionMode; + private HeadlinesActionModeCallback m_headlinesActionModeCallback; + + @SuppressLint("NewApi") + private class HeadlinesActionModeCallback implements ActionMode.Callback { + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + m_headlinesActionMode = null; + deselectAllArticles(); + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + + MenuInflater inflater = getSupportMenuInflater(); + inflater.inflate(R.menu.headlines_action_menu, menu); + + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + onOptionsItemSelected(item); + return false; + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_PROGRESS); + + setProgressBarVisibility(false); + + setContentView(R.layout.login); + + setLoadingStatus(R.string.blank, false); + findViewById(R.id.loading_container).setVisibility(View.GONE); + + initMenu(); + + Intent intent = getIntent(); + + if (intent.getExtras() != null) { + if (intent.getBooleanExtra("initial", false)) { + intent = new Intent(OfflineActivity.this, OfflineFeedsActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + + startActivityForResult(intent, 0); + finish(); + } + } + + /* if (savedInstanceState != null) { + + } */ + + m_headlinesActionModeCallback = new HeadlinesActionModeCallback(); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + } + + protected void selectArticles(int feedId, boolean isCat, int mode) { + switch (mode) { + case 0: + SQLiteStatement stmtSelectAll = null; + + if (isCat) { + stmtSelectAll = getWritableDb().compileStatement( + "UPDATE articles SET selected = 1 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + } else { + stmtSelectAll = getWritableDb().compileStatement( + "UPDATE articles SET selected = 1 WHERE feed_id = ?"); + } + + stmtSelectAll.bindLong(1, feedId); + stmtSelectAll.execute(); + stmtSelectAll.close(); + + break; + case 1: + + SQLiteStatement stmtSelectUnread = null; + + if (isCat) { + stmtSelectUnread = getWritableDb().compileStatement( + "UPDATE articles SET selected = 1 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?) AND unread = 1"); + } else { + stmtSelectUnread = getWritableDb().compileStatement( + "UPDATE articles SET selected = 1 WHERE feed_id = ? AND unread = 1"); + } + + stmtSelectUnread.bindLong(1, feedId); + stmtSelectUnread.execute(); + stmtSelectUnread.close(); + + break; + case 2: + deselectAllArticles(); + break; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + final OfflineHeadlinesFragment ohf = (OfflineHeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + /* final OfflineFeedsFragment off = (OfflineFeedsFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_FEEDS); */ + + /* final OfflineFeedCategoriesFragment ocf = (OfflineFeedCategoriesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_CATS); */ + + final OfflineArticlePager oap = (OfflineArticlePager) getSupportFragmentManager() + .findFragmentByTag(FRAG_ARTICLE); + + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + case R.id.go_online: + switchOnline(); + return true; + case R.id.search: + if (ohf != null && isCompatMode()) { + Dialog dialog = new Dialog(this); + + final EditText edit = new EditText(this); + + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setTitle(R.string.search) + .setPositiveButton(getString(R.string.search), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + + String query = edit.getText().toString().trim(); + + ohf.setSearchQuery(query); + + } + }) + .setNegativeButton(getString(R.string.cancel), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + + // + + } + }).setView(edit); + + dialog = builder.create(); + dialog.show(); + } + + return true; + case R.id.preferences: + Intent intent = new Intent(this, PreferencesActivity.class); + startActivityForResult(intent, 0); + return true; + case R.id.headlines_select: + if (ohf != null) { + Dialog dialog = new Dialog(this); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.headlines_select_dialog); + + builder.setSingleChoiceItems(new String[] { + getString(R.string.headlines_select_all), + getString(R.string.headlines_select_unread), + getString(R.string.headlines_select_none) }, 0, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int which) { + + selectArticles(ohf.getFeedId(), ohf.getFeedIsCat(), which); + initMenu(); + refresh(); + + dialog.cancel(); + } + }); + + dialog = builder.create(); + dialog.show(); + } + return true; + case R.id.headlines_mark_as_read: + if (ohf != null) { + int feedId = ohf.getFeedId(); + boolean isCat = ohf.getFeedIsCat(); + + SQLiteStatement stmt = null; + + if (isCat) { + stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + } else { + stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id = ?"); + } + stmt.bindLong(1, feedId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.share_article: + if (true) { + int articleId = oap.getSelectedArticleId(); + + shareArticle(articleId); + } + return true; + case R.id.toggle_marked: + if (oap != null) { + int articleId = oap.getSelectedArticleId(); + + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, marked = NOT marked WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + /* case R.id.selection_select_none: + deselectAllArticles(); + return true; */ + case R.id.selection_toggle_unread: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, unread = NOT unread WHERE selected = 1"); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.selection_toggle_marked: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, marked = NOT marked WHERE selected = 1"); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.selection_toggle_published: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, published = NOT published WHERE selected = 1"); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.toggle_published: + if (oap != null) { + int articleId = oap.getSelectedArticleId(); + + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, published = NOT published WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.catchup_above: + if (oap != null) { + int articleId = oap.getSelectedArticleId(); + int feedId = oap.getFeedId(); + boolean isCat = oap.getFeedIsCat(); + + SQLiteStatement stmt = null; + + if (isCat) { + stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE " + + "updated >= (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " + + "AND feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + } else { + stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE " + + "updated >= (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " + + "AND feed_id = ?"); + } + + stmt.bindLong(1, articleId); + stmt.bindLong(2, feedId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.set_unread: + if (oap != null) { + int articleId = oap.getSelectedArticleId(); + + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 1 WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + default: + Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getSupportMenuInflater(); + inflater.inflate(R.menu.offline_menu, menu); + + m_menu = menu; + + initMenu(); + + return true; + } + + @SuppressLint("NewApi") + protected void initMenu() { + if (m_menu != null) { + m_menu.setGroupVisible(R.id.menu_group_headlines, false); + m_menu.setGroupVisible(R.id.menu_group_article, false); + m_menu.setGroupVisible(R.id.menu_group_feeds, false); + + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + if (hf != null) { + if (hf.getSelectedArticleCount() > 0 && m_headlinesActionMode == null) { + m_headlinesActionMode = startActionMode(m_headlinesActionModeCallback); + } else if (hf.getSelectedArticleCount() == 0 && m_headlinesActionMode != null) { + m_headlinesActionMode.finish(); + } + } + + OfflineArticlePager ap = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (ap != null) { + int articleId = ap.getSelectedArticleId(); + + Cursor article = getArticleById(articleId); + + if (article != null) { + boolean unread = article.getInt(article.getColumnIndex("unread")) == 1; + boolean marked = article.getInt(article.getColumnIndex("marked")) == 1; + boolean published = article.getInt(article.getColumnIndex("published")) == 1; + + m_menu.findItem(R.id.toggle_marked).setIcon(marked ? R.drawable.ic_important_light : + R.drawable.ic_unimportant_light); + + m_menu.findItem(R.id.toggle_published).setIcon(published ? R.drawable.ic_menu_published_light : + R.drawable.ic_menu_unpublished_light); + + m_menu.findItem(R.id.set_unread).setIcon(unread ? R.drawable.ic_unread_light : + R.drawable.ic_read_light); + + article.close(); + } + } + + if (!isCompatMode()) { + MenuItem search = m_menu.findItem(R.id.search); + + SearchView searchView = (SearchView) search.getActionView(); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + private String query = ""; + + @Override + public boolean onQueryTextSubmit(String query) { + OfflineHeadlinesFragment frag = (OfflineHeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + if (frag != null) { + frag.setSearchQuery(query); + this.query = query; + } + + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + if (newText.equals("") && !newText.equals(this.query)) { + OfflineHeadlinesFragment frag = (OfflineHeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + if (frag != null) { + frag.setSearchQuery(newText); + this.query = newText; + } + } + + return false; + } + }); + } + } + } + + private void switchOnline() { + SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = localPrefs.edit(); + editor.putBoolean("offline_mode_active", false); + editor.commit(); + + Intent refresh = new Intent(this, org.fox.ttrss.OnlineActivity.class); + startActivity(refresh); + finish(); + } + + protected Cursor getArticleById(int articleId) { + Cursor c = getReadableDb().query("articles", null, + BaseColumns._ID + "=?", + new String[] { String.valueOf(articleId) }, null, null, null); + + c.moveToFirst(); + + return c; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (m_prefs.getBoolean("use_volume_keys", false)) { + OfflineArticlePager ap = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + ap.selectArticle(false); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + ap.selectArticle(true); + return true; + } + } + } + + return super.onKeyDown(keyCode, event); + } + + // Handle onKeyUp too to suppress beep + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (m_prefs.getBoolean("use_volume_keys", false)) { + + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + return true; + } + } + + return super.onKeyUp(keyCode, event); + } + + protected Cursor getFeedById(int feedId) { + Cursor c = getReadableDb().query("feeds", null, + BaseColumns._ID + "=?", + new String[] { String.valueOf(feedId) }, null, null, null); + + c.moveToFirst(); + + return c; + } + + protected Cursor getCatById(int catId) { + Cursor c = getReadableDb().query("categories", null, + BaseColumns._ID + "=?", + new String[] { String.valueOf(catId) }, null, null, null); + + c.moveToFirst(); + + return c; + } + + protected Intent getShareIntent(Cursor article) { + if (article != null) { + String title = article.getString(article.getColumnIndex("title")); + String link = article.getString(article.getColumnIndex("link")); + + Intent intent = new Intent(Intent.ACTION_SEND); + + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, title); + intent.putExtra(Intent.EXTRA_TEXT, link); + + return intent; + } else { + return null; + } + } + + protected void shareArticle(int articleId) { + + Cursor article = getArticleById(articleId); + + if (article != null) { + shareArticle(article); + article.close(); + } + } + + private void shareArticle(Cursor article) { + if (article != null) { + Intent intent = getShareIntent(article); + + startActivity(Intent.createChooser(intent, + getString(R.string.share_article))); + } + } + + protected int getSelectedArticleCount() { + Cursor c = getReadableDb().query("articles", + new String[] { "COUNT(*)" }, "selected = 1", null, null, null, + null); + c.moveToFirst(); + int selected = c.getInt(0); + c.close(); + + return selected; + } + + protected void deselectAllArticles() { + getWritableDb().execSQL("UPDATE articles SET selected = 0 "); + refresh(); + } + + protected void refresh() { + OfflineFeedsFragment ff = (OfflineFeedsFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_FEEDS); + + if (ff != null) { + ff.refresh(); + } + + OfflineFeedCategoriesFragment cf = (OfflineFeedCategoriesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_CATS); + + if (cf != null) { + cf.refresh(); + } + + OfflineHeadlinesFragment ohf = (OfflineHeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + if (ohf != null) { + ohf.refresh(); + } + + initMenu(); + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineArticleFragment.java b/src/org/fox/ttrss/offline/OfflineArticleFragment.java index 22d1ae02..d7c97f01 100644 --- a/src/org/fox/ttrss/offline/OfflineArticleFragment.java +++ b/src/org/fox/ttrss/offline/OfflineArticleFragment.java @@ -1,413 +1,413 @@ -package org.fox.ttrss.offline;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.fox.ttrss.CommonActivity;
-import org.fox.ttrss.R;
-import org.fox.ttrss.util.ImageCacheService;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.GestureDetector;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebSettings.LayoutAlgorithm;
-import android.webkit.WebView;
-import android.widget.TextView;
-
-public class OfflineArticleFragment extends Fragment implements GestureDetector.OnDoubleTapListener {
- private final String TAG = this.getClass().getSimpleName();
-
- private SharedPreferences m_prefs;
- private int m_articleId;
- private boolean m_isCat = false; // FIXME use
- private Cursor m_cursor;
- private OfflineActivity m_activity;
- private GestureDetector m_detector;
-
- public OfflineArticleFragment() {
- super();
- }
-
- public OfflineArticleFragment(int articleId) {
- super();
- m_articleId = articleId;
- }
-
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- /* AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo(); */
-
- switch (item.getItemId()) {
- case R.id.article_link_share:
- m_activity.shareArticle(m_articleId);
- return true;
- case R.id.article_link_copy:
- if (true) {
- Cursor article = m_activity.getArticleById(m_articleId);
-
- if (article != null) {
- m_activity.copyToClipboard(article.getString(article.getColumnIndex("link")));
- article.close();
- }
- }
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.article_link_context_menu, menu);
- menu.setHeaderTitle(m_cursor.getString(m_cursor.getColumnIndex("title")));
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- @SuppressLint("NewApi")
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_articleId = savedInstanceState.getInt("articleId");
- }
-
- View view = inflater.inflate(R.layout.article_fragment, container, false);
-
- m_cursor = m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles.*", "feeds.title AS feed_title" }, "articles." + BaseColumns._ID + "=?",
- new String[] { String.valueOf(m_articleId) }, null, null, null);
-
- m_cursor.moveToFirst();
-
- if (m_cursor.isFirst()) {
-
- TextView title = (TextView)view.findViewById(R.id.title);
-
- if (title != null) {
-
- String titleStr;
-
- if (m_cursor.getString(m_cursor.getColumnIndex("title")).length() > 200)
- titleStr = m_cursor.getString(m_cursor.getColumnIndex("title")).substring(0, 200) + "...";
- else
- titleStr = m_cursor.getString(m_cursor.getColumnIndex("title"));
-
- final String link = m_cursor.getString(m_cursor.getColumnIndex("link"));
-
- title.setText(titleStr);
- //title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
- title.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW,
- Uri.parse(link.trim()));
- startActivity(intent);
- } catch (Exception e) {
- e.printStackTrace();
- m_activity.toast(R.string.error_other_error);
- }
- }
- });
-
- registerForContextMenu(title);
- }
-
- TextView comments = (TextView)view.findViewById(R.id.comments);
-
- if (comments != null) {
- comments.setVisibility(View.GONE);
- }
-
- WebView web = (WebView)view.findViewById(R.id.content);
-
- if (web != null) {
-
- web.setWebChromeClient(new WebChromeClient() {
- @Override
- public void onProgressChanged(WebView view, int progress) {
- m_activity.setProgress(Math.round(((float)progress / 100f) * 10000));
- if (progress == 100) {
- m_activity.setProgressBarVisibility(false);
- }
- }
- });
-
- web.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- return m_detector.onTouchEvent(event);
- }
- });
-
- String content;
- String cssOverride = "";
-
- WebSettings ws = web.getSettings();
- ws.setSupportZoom(true);
- ws.setBuiltInZoomControls(false);
-
- web.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
-
- TypedValue tv = new TypedValue();
- getActivity().getTheme().resolveAttribute(R.attr.linkColor, tv, true);
-
- // prevent flicker in ics
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- web.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
-
- if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) {
- cssOverride = "body { background : transparent; color : #e0e0e0}";
- } else if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK_GRAY")) {
- cssOverride = "body { background : transparent; color : #e0e0e0}";
- } else {
- cssOverride = "body { background : transparent; }";
- }
- web.setBackgroundColor(getResources().getColor(android.R.color.transparent));
-
- String hexColor = String.format("#%06X", (0xFFFFFF & tv.data));
- cssOverride += " a:link {color: "+hexColor+";} a:visited { color: "+hexColor+";}";
-
- String articleContent = m_cursor.getString(m_cursor.getColumnIndex("content"));
- Document doc = Jsoup.parse(articleContent);
-
- if (doc != null) {
- if (m_prefs.getBoolean("offline_image_cache_enabled", false)) {
-
- Elements images = doc.select("img");
-
- for (Element img : images) {
- String url = img.attr("src");
-
- if (ImageCacheService.isUrlCached(m_activity, url)) {
- img.attr("src", "file://" + ImageCacheService.getCacheFileName(m_activity, url));
- }
- }
- }
-
- // thanks webview for crashing on <video> tag
- Elements videos = doc.select("video");
-
- for (Element video : videos)
- video.remove();
-
- articleContent = doc.toString();
- }
-
- String align = m_prefs.getBoolean("justify_article_text", true) ? "text-align : justified" : "";
-
- switch (Integer.parseInt(m_prefs.getString("font_size", "0"))) {
- case 0:
- cssOverride += "body { "+align+"; font-size : 14px; } ";
- break;
- case 1:
- cssOverride += "body { "+align+"; font-size : 18px; } ";
- break;
- case 2:
- cssOverride += "body { "+align+"; font-size : 21px; } ";
- break;
- }
-
- content =
- "<html>" +
- "<head>" +
- "<meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\">" +
- "<style type=\"text/css\">" +
- "body { padding : 0px; margin : 0px; }" +
- cssOverride +
- "</style>" +
- "</head>" +
- "<body>" + articleContent + "<p> </p><p> </p></body></html>";;
-
- try {
- web.loadDataWithBaseURL(null, content, "text/html", "utf-8", null);
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
-
-
- }
-
- TextView dv = (TextView)view.findViewById(R.id.date);
-
- if (dv != null) {
- Date d = new Date(m_cursor.getInt(m_cursor.getColumnIndex("updated")) * 1000L);
- SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy, HH:mm");
- dv.setText(df.format(d));
- }
-
- TextView tagv = (TextView)view.findViewById(R.id.tags);
-
- if (tagv != null) {
- int feedTitleIndex = m_cursor.getColumnIndex("feed_title");
-
- if (feedTitleIndex != -1 && m_isCat) {
- tagv.setText(m_cursor.getString(feedTitleIndex));
- } else {
- String tagsStr = m_cursor.getString(m_cursor.getColumnIndex("tags"));
- tagv.setText(tagsStr);
- }
- }
-
- TextView author = (TextView)view.findViewById(R.id.author);
-
- if (author != null) {
- author.setVisibility(View.GONE);
- }
- }
-
- return view;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- m_cursor.close();
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("articleId", m_articleId);
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
-
- m_activity = (OfflineActivity) activity;
-
- m_detector = new GestureDetector(m_activity, new GestureDetector.OnGestureListener() {
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- // TODO Auto-generated method stub
- return false;
- }
- });
-
- m_detector.setOnDoubleTapListener(this);
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent arg0) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent arg0) {
- // TODO Auto-generated method stub
- return false;
- }
-
- private void onLeftSideTapped() {
- OfflineArticlePager ap = (OfflineArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- ap.selectArticle(false);
- }
- }
-
- private void onRightSideTapped() {
- OfflineArticlePager ap = (OfflineArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- ap.selectArticle(true);
- }
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
-
- int width = getView().getWidth();
- int x = Math.round(e.getX());
-
- if (x <= width/15) {
- onLeftSideTapped();
- return true;
- } else if (x >= width-(width/15)) {
- onRightSideTapped();
- return true;
- } /* else if (!m_activity.isCompatMode()) {
- ActionBar bar = m_activity.getActionBar();
-
- if (bar.isShowing()) {
- bar.hide();
- } else {
- bar.show();
- }
- } */
-
- return false;
- }
-
-
-}
+package org.fox.ttrss.offline; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.fox.ttrss.CommonActivity; +import org.fox.ttrss.R; +import org.fox.ttrss.util.ImageCacheService; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.util.TypedValue; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.GestureDetector; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebSettings.LayoutAlgorithm; +import android.webkit.WebView; +import android.widget.TextView; + +public class OfflineArticleFragment extends Fragment implements GestureDetector.OnDoubleTapListener { + private final String TAG = this.getClass().getSimpleName(); + + private SharedPreferences m_prefs; + private int m_articleId; + private boolean m_isCat = false; // FIXME use + private Cursor m_cursor; + private OfflineActivity m_activity; + private GestureDetector m_detector; + + public OfflineArticleFragment() { + super(); + } + + public OfflineArticleFragment(int articleId) { + super(); + m_articleId = articleId; + } + + + @Override + public boolean onContextItemSelected(MenuItem item) { + /* AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); */ + + switch (item.getItemId()) { + case R.id.article_link_share: + m_activity.shareArticle(m_articleId); + return true; + case R.id.article_link_copy: + if (true) { + Cursor article = m_activity.getArticleById(m_articleId); + + if (article != null) { + m_activity.copyToClipboard(article.getString(article.getColumnIndex("link"))); + article.close(); + } + } + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.article_link_context_menu, menu); + menu.setHeaderTitle(m_cursor.getString(m_cursor.getColumnIndex("title"))); + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + @SuppressLint("NewApi") + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_articleId = savedInstanceState.getInt("articleId"); + } + + View view = inflater.inflate(R.layout.article_fragment, container, false); + + m_cursor = m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles.*", "feeds.title AS feed_title" }, "articles." + BaseColumns._ID + "=?", + new String[] { String.valueOf(m_articleId) }, null, null, null); + + m_cursor.moveToFirst(); + + if (m_cursor.isFirst()) { + + TextView title = (TextView)view.findViewById(R.id.title); + + if (title != null) { + + String titleStr; + + if (m_cursor.getString(m_cursor.getColumnIndex("title")).length() > 200) + titleStr = m_cursor.getString(m_cursor.getColumnIndex("title")).substring(0, 200) + "..."; + else + titleStr = m_cursor.getString(m_cursor.getColumnIndex("title")); + + final String link = m_cursor.getString(m_cursor.getColumnIndex("link")); + + title.setText(titleStr); + //title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); + title.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse(link.trim())); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + m_activity.toast(R.string.error_other_error); + } + } + }); + + registerForContextMenu(title); + } + + TextView comments = (TextView)view.findViewById(R.id.comments); + + if (comments != null) { + comments.setVisibility(View.GONE); + } + + WebView web = (WebView)view.findViewById(R.id.content); + + if (web != null) { + + web.setWebChromeClient(new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int progress) { + m_activity.setProgress(Math.round(((float)progress / 100f) * 10000)); + if (progress == 100) { + m_activity.setProgressBarVisibility(false); + } + } + }); + + web.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return m_detector.onTouchEvent(event); + } + }); + + String content; + String cssOverride = ""; + + WebSettings ws = web.getSettings(); + ws.setSupportZoom(true); + ws.setBuiltInZoomControls(false); + + web.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); + + TypedValue tv = new TypedValue(); + getActivity().getTheme().resolveAttribute(R.attr.linkColor, tv, true); + + // prevent flicker in ics + if (android.os.Build.VERSION.SDK_INT >= 11) { + web.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + + if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) { + cssOverride = "body { background : transparent; color : #e0e0e0}"; + } else if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK_GRAY")) { + cssOverride = "body { background : transparent; color : #e0e0e0}"; + } else { + cssOverride = "body { background : transparent; }"; + } + web.setBackgroundColor(getResources().getColor(android.R.color.transparent)); + + String hexColor = String.format("#%06X", (0xFFFFFF & tv.data)); + cssOverride += " a:link {color: "+hexColor+";} a:visited { color: "+hexColor+";}"; + + String articleContent = m_cursor.getString(m_cursor.getColumnIndex("content")); + Document doc = Jsoup.parse(articleContent); + + if (doc != null) { + if (m_prefs.getBoolean("offline_image_cache_enabled", false)) { + + Elements images = doc.select("img"); + + for (Element img : images) { + String url = img.attr("src"); + + if (ImageCacheService.isUrlCached(m_activity, url)) { + img.attr("src", "file://" + ImageCacheService.getCacheFileName(m_activity, url)); + } + } + } + + // thanks webview for crashing on <video> tag + Elements videos = doc.select("video"); + + for (Element video : videos) + video.remove(); + + articleContent = doc.toString(); + } + + String align = m_prefs.getBoolean("justify_article_text", true) ? "text-align : justified" : ""; + + switch (Integer.parseInt(m_prefs.getString("font_size", "0"))) { + case 0: + cssOverride += "body { "+align+"; font-size : 14px; } "; + break; + case 1: + cssOverride += "body { "+align+"; font-size : 18px; } "; + break; + case 2: + cssOverride += "body { "+align+"; font-size : 21px; } "; + break; + } + + content = + "<html>" + + "<head>" + + "<meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\">" + + "<style type=\"text/css\">" + + "body { padding : 0px; margin : 0px; }" + + cssOverride + + "</style>" + + "</head>" + + "<body>" + articleContent + "<p> </p><p> </p></body></html>";; + + try { + web.loadDataWithBaseURL(null, content, "text/html", "utf-8", null); + } catch (RuntimeException e) { + e.printStackTrace(); + } + + + } + + TextView dv = (TextView)view.findViewById(R.id.date); + + if (dv != null) { + Date d = new Date(m_cursor.getInt(m_cursor.getColumnIndex("updated")) * 1000L); + SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy, HH:mm"); + dv.setText(df.format(d)); + } + + TextView tagv = (TextView)view.findViewById(R.id.tags); + + if (tagv != null) { + int feedTitleIndex = m_cursor.getColumnIndex("feed_title"); + + if (feedTitleIndex != -1 && m_isCat) { + tagv.setText(m_cursor.getString(feedTitleIndex)); + } else { + String tagsStr = m_cursor.getString(m_cursor.getColumnIndex("tags")); + tagv.setText(tagsStr); + } + } + + TextView author = (TextView)view.findViewById(R.id.author); + + if (author != null) { + author.setVisibility(View.GONE); + } + } + + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + m_cursor.close(); + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("articleId", m_articleId); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + + m_activity = (OfflineActivity) activity; + + m_detector = new GestureDetector(m_activity, new GestureDetector.OnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onShowPress(MotionEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, + float distanceY) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onLongPress(MotionEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onDown(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + }); + + m_detector.setOnDoubleTapListener(this); + } + + @Override + public boolean onDoubleTap(MotionEvent arg0) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent arg0) { + // TODO Auto-generated method stub + return false; + } + + private void onLeftSideTapped() { + OfflineArticlePager ap = (OfflineArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + ap.selectArticle(false); + } + } + + private void onRightSideTapped() { + OfflineArticlePager ap = (OfflineArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + ap.selectArticle(true); + } + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + + int width = getView().getWidth(); + int x = Math.round(e.getX()); + + if (x <= width/15) { + onLeftSideTapped(); + return true; + } else if (x >= width-(width/15)) { + onRightSideTapped(); + return true; + } /* else if (!m_activity.isCompatMode()) { + ActionBar bar = m_activity.getSupportActionBar(); + + if (bar.isShowing()) { + bar.hide(); + } else { + bar.show(); + } + } */ + + return false; + } + + +} diff --git a/src/org/fox/ttrss/offline/OfflineArticlePager.java b/src/org/fox/ttrss/offline/OfflineArticlePager.java index 48742c12..a4a90031 100644 --- a/src/org/fox/ttrss/offline/OfflineArticlePager.java +++ b/src/org/fox/ttrss/offline/OfflineArticlePager.java @@ -1,284 +1,284 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.R;
-
-import com.viewpagerindicator.UnderlinePageIndicator;
-
-import android.app.Activity;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-
-public class OfflineArticlePager extends Fragment {
- private final String TAG = this.getClass().getSimpleName();
-
- private PagerAdapter m_adapter;
- private OfflineActivity m_activity;
- private OfflineHeadlinesEventListener m_listener;
- private boolean m_isCat;
- private int m_feedId;
- private int m_articleId;
- private String m_searchQuery = "";
- private Cursor m_cursor;
- private SharedPreferences m_prefs;
-
- public int getFeedId() {
- return m_feedId;
- }
-
- public boolean getFeedIsCat() {
- return m_isCat;
- }
-
- public Cursor createCursor() {
- String feedClause = null;
-
- if (m_isCat) {
- feedClause = "feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)";
- } else {
- feedClause = "feed_id = ?";
- }
-
- String orderBy = (m_prefs.getBoolean("offline_oldest_first", false)) ? "updated" : "updated DESC";
-
- if (m_searchQuery == null || m_searchQuery.equals("")) {
- return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles."+BaseColumns._ID, "feeds.title AS feed_title" }, feedClause,
- new String[] { String.valueOf(m_feedId) }, null, null, orderBy);
- } else {
- return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles."+BaseColumns._ID },
- feedClause + " AND (articles.title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%')",
- new String[] { String.valueOf(m_feedId), m_searchQuery, m_searchQuery }, null, null, orderBy);
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
- }
-
- private class PagerAdapter extends FragmentStatePagerAdapter {
- public PagerAdapter(FragmentManager fm) {
- super(fm);
- }
-
- @Override
- public Fragment getItem(int position) {
- Log.d(TAG, "getItem: " + position);
-
- if (m_cursor.moveToPosition(position)) {
-
- if (m_prefs.getBoolean("dim_status_bar", false) && getView() != null && !m_activity.isCompatMode()) {
- getView().setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
- }
-
- return new OfflineArticleFragment(m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)));
- }
-
- return null;
- }
-
- @Override
- public int getCount() {
- return m_cursor.getCount();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (!m_activity.isCompatMode() && m_prefs.getBoolean("dim_status_bar", false)) {
- getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
- }
-
- if (m_prefs.getBoolean("full_screen_mode", false)) {
- m_activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
-
- /* if (!m_activity.isCompatMode()) {
- m_activity.getActionBar().hide();
- } */
- }
- }
-
- public OfflineArticlePager() {
- super();
- }
-
- public OfflineArticlePager(int articleId, int feedId, boolean isCat) {
- super();
-
- m_feedId = feedId;
- m_isCat = isCat;
- m_articleId = articleId;
-
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.article_pager, container, false);
-
- if (savedInstanceState != null) {
- m_articleId = savedInstanceState.getInt("articleId", 0);
- m_feedId = savedInstanceState.getInt("feedId", 0);
- m_isCat = savedInstanceState.getBoolean("isCat", false);
- }
-
- Log.d(TAG, "feed=" + m_feedId + "; iscat=" + m_isCat);
-
- m_cursor = createCursor();
-
- m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager());
-
- int position = 0;
-
- Log.d(TAG, "maId=" + m_articleId);
-
- if (m_articleId != 0) {
- if (m_cursor.moveToFirst()) {
-
- while (!m_cursor.isAfterLast()) {
- if (m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)) == m_articleId) {
- position = m_cursor.getPosition();
- break;
- }
- m_cursor.moveToNext();
- }
- }
- } else {
- if (m_cursor.moveToFirst()) {
- m_articleId = m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID));
- m_listener.onArticleSelected(m_articleId, false);
-
- Log.d(TAG, "maId=" + m_articleId);
- }
- }
-
-
- ViewPager pager = (ViewPager) view.findViewById(R.id.article_pager);
-
- pager.setAdapter(m_adapter);
-
- UnderlinePageIndicator indicator = (UnderlinePageIndicator)view.findViewById(R.id.article_titles);
- indicator.setViewPager(pager);
-
- pager.setCurrentItem(position);
- indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
-
- @Override
- public void onPageScrollStateChanged(int arg0) {
- }
-
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {
- }
-
- @Override
- public void onPageSelected(int position) {
- if (m_cursor.moveToPosition(position)) {
- int articleId = m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID));
-
- m_articleId = articleId;
- m_listener.onArticleSelected(articleId, false);
- }
- }
- });
-
- return view;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_activity = (OfflineActivity)activity;
- m_listener = (OfflineHeadlinesEventListener)activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
-
- }
-
- public void refresh() {
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
-
- m_cursor = createCursor();
-
- if (m_cursor != null) {
- m_adapter.notifyDataSetChanged();
- }
- }
-
- public int getSelectedArticleId() {
- return m_articleId;
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("articleId", m_articleId);
- out.putInt("feedId", m_feedId);
- out.putBoolean("isCat", m_isCat);
-
- }
-
- public void setSearchQuery(String searchQuery) {
- m_searchQuery = searchQuery;
- }
-
- public void setArticleId(int articleId) {
- m_articleId = articleId;
-
- int position = getArticleIdPosition(articleId);
-
- ViewPager pager = (ViewPager) getView().findViewById(R.id.article_pager);
-
- pager.setCurrentItem(position);
-
- }
-
- public int getArticleIdPosition(int articleId) {
- m_cursor.moveToFirst();
-
- while (!m_cursor.isAfterLast()) {
- if (m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)) == articleId) {
- return m_cursor.getPosition();
- }
- m_cursor.moveToNext();
- }
-
- return -1;
- }
-
- public void selectArticle(boolean next) {
- int position = getArticleIdPosition(m_articleId);
-
- if (position != -1) {
- if (next)
- position++;
- else
- position--;
-
- Log.d(TAG, "pos=" + position);
-
- if (m_cursor.moveToPosition(position)) {
- setArticleId(m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)));
- }
- }
- }
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.R; + +import com.viewpagerindicator.UnderlinePageIndicator; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.view.ViewPager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +public class OfflineArticlePager extends Fragment { + private final String TAG = this.getClass().getSimpleName(); + + private PagerAdapter m_adapter; + private OfflineActivity m_activity; + private OfflineHeadlinesEventListener m_listener; + private boolean m_isCat; + private int m_feedId; + private int m_articleId; + private String m_searchQuery = ""; + private Cursor m_cursor; + private SharedPreferences m_prefs; + + public int getFeedId() { + return m_feedId; + } + + public boolean getFeedIsCat() { + return m_isCat; + } + + public Cursor createCursor() { + String feedClause = null; + + if (m_isCat) { + feedClause = "feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"; + } else { + feedClause = "feed_id = ?"; + } + + String orderBy = (m_prefs.getBoolean("offline_oldest_first", false)) ? "updated" : "updated DESC"; + + if (m_searchQuery == null || m_searchQuery.equals("")) { + return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles."+BaseColumns._ID, "feeds.title AS feed_title" }, feedClause, + new String[] { String.valueOf(m_feedId) }, null, null, orderBy); + } else { + return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles."+BaseColumns._ID }, + feedClause + " AND (articles.title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%')", + new String[] { String.valueOf(m_feedId), m_searchQuery, m_searchQuery }, null, null, orderBy); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + } + + private class PagerAdapter extends FragmentStatePagerAdapter { + public PagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + Log.d(TAG, "getItem: " + position); + + if (m_cursor.moveToPosition(position)) { + + if (m_prefs.getBoolean("dim_status_bar", false) && getView() != null && !m_activity.isCompatMode()) { + getView().setSystemUiVisibility(View.STATUS_BAR_HIDDEN); + } + + return new OfflineArticleFragment(m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID))); + } + + return null; + } + + @Override + public int getCount() { + return m_cursor.getCount(); + } + } + + @Override + public void onResume() { + super.onResume(); + + if (!m_activity.isCompatMode() && m_prefs.getBoolean("dim_status_bar", false)) { + getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + + if (m_prefs.getBoolean("full_screen_mode", false)) { + m_activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + + /* if (!m_activity.isCompatMode()) { + m_activity.getSupportActionBar().hide(); + } */ + } + } + + public OfflineArticlePager() { + super(); + } + + public OfflineArticlePager(int articleId, int feedId, boolean isCat) { + super(); + + m_feedId = feedId; + m_isCat = isCat; + m_articleId = articleId; + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.article_pager, container, false); + + if (savedInstanceState != null) { + m_articleId = savedInstanceState.getInt("articleId", 0); + m_feedId = savedInstanceState.getInt("feedId", 0); + m_isCat = savedInstanceState.getBoolean("isCat", false); + } + + Log.d(TAG, "feed=" + m_feedId + "; iscat=" + m_isCat); + + m_cursor = createCursor(); + + m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager()); + + int position = 0; + + Log.d(TAG, "maId=" + m_articleId); + + if (m_articleId != 0) { + if (m_cursor.moveToFirst()) { + + while (!m_cursor.isAfterLast()) { + if (m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)) == m_articleId) { + position = m_cursor.getPosition(); + break; + } + m_cursor.moveToNext(); + } + } + } else { + if (m_cursor.moveToFirst()) { + m_articleId = m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)); + m_listener.onArticleSelected(m_articleId, false); + + Log.d(TAG, "maId=" + m_articleId); + } + } + + + ViewPager pager = (ViewPager) view.findViewById(R.id.article_pager); + + pager.setAdapter(m_adapter); + + UnderlinePageIndicator indicator = (UnderlinePageIndicator)view.findViewById(R.id.article_titles); + indicator.setViewPager(pager); + + pager.setCurrentItem(position); + indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + + @Override + public void onPageScrollStateChanged(int arg0) { + } + + @Override + public void onPageScrolled(int arg0, float arg1, int arg2) { + } + + @Override + public void onPageSelected(int position) { + if (m_cursor.moveToPosition(position)) { + int articleId = m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)); + + m_articleId = articleId; + m_listener.onArticleSelected(articleId, false); + } + } + }); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (OfflineActivity)activity; + m_listener = (OfflineHeadlinesEventListener)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + + } + + public void refresh() { + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + + m_cursor = createCursor(); + + if (m_cursor != null) { + m_adapter.notifyDataSetChanged(); + } + } + + public int getSelectedArticleId() { + return m_articleId; + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("articleId", m_articleId); + out.putInt("feedId", m_feedId); + out.putBoolean("isCat", m_isCat); + + } + + public void setSearchQuery(String searchQuery) { + m_searchQuery = searchQuery; + } + + public void setArticleId(int articleId) { + m_articleId = articleId; + + int position = getArticleIdPosition(articleId); + + ViewPager pager = (ViewPager) getView().findViewById(R.id.article_pager); + + pager.setCurrentItem(position); + + } + + public int getArticleIdPosition(int articleId) { + m_cursor.moveToFirst(); + + while (!m_cursor.isAfterLast()) { + if (m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)) == articleId) { + return m_cursor.getPosition(); + } + m_cursor.moveToNext(); + } + + return -1; + } + + public void selectArticle(boolean next) { + int position = getArticleIdPosition(m_articleId); + + if (position != -1) { + if (next) + position++; + else + position--; + + Log.d(TAG, "pos=" + position); + + if (m_cursor.moveToPosition(position)) { + setArticleId(m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID))); + } + } + } +} diff --git a/src/org/fox/ttrss/offline/OfflineDownloadService.java b/src/org/fox/ttrss/offline/OfflineDownloadService.java index 992c21f6..2fe87570 100644 --- a/src/org/fox/ttrss/offline/OfflineDownloadService.java +++ b/src/org/fox/ttrss/offline/OfflineDownloadService.java @@ -1,486 +1,486 @@ -package org.fox.ttrss.offline;
-
-import java.lang.reflect.Type;
-import java.util.HashMap;
-import java.util.List;
-
-import org.fox.ttrss.ApiRequest;
-import org.fox.ttrss.OnlineActivity;
-import org.fox.ttrss.R;
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.Feed;
-import org.fox.ttrss.types.FeedCategory;
-import org.fox.ttrss.util.DatabaseHelper;
-import org.fox.ttrss.util.ImageCacheService;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Binder;
-import android.os.IBinder;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.util.Log;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.reflect.TypeToken;
-
-public class OfflineDownloadService extends Service {
-
- private final String TAG = this.getClass().getSimpleName();
-
- public static final int NOTIFY_DOWNLOADING = 1;
- public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.DownloadComplete";
- public static final String INTENT_ACTION_CANCEL = "org.fox.ttrss.intent.action.Cancel";
-
- private static final int OFFLINE_SYNC_SEQ = 50;
- private static final int OFFLINE_SYNC_MAX = OFFLINE_SYNC_SEQ * 10;
-
- private SQLiteDatabase m_writableDb;
- private SQLiteDatabase m_readableDb;
- private int m_articleOffset = 0;
- private String m_sessionId;
- private NotificationManager m_nmgr;
-
- private boolean m_downloadInProgress = false;
- private boolean m_downloadImages = false;
- private int m_syncMax;
- private SharedPreferences m_prefs;
- private boolean m_canProceed = true;
-
- private final IBinder m_binder = new LocalBinder();
-
- public class LocalBinder extends Binder {
- OfflineDownloadService getService() {
- return OfflineDownloadService.this;
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return m_binder;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- m_downloadImages = m_prefs.getBoolean("offline_image_cache_enabled", false);
- m_syncMax = Integer.parseInt(m_prefs.getString("offline_sync_max", String.valueOf(OFFLINE_SYNC_MAX)));
-
- initDatabase();
- }
-
- @SuppressWarnings("deprecation")
- private void updateNotification(String msg) {
- Notification notification = new Notification(R.drawable.icon,
- getString(R.string.notify_downloading_title), System.currentTimeMillis());
-
- Intent intent = new Intent(this, OnlineActivity.class);
- intent.setAction(INTENT_ACTION_CANCEL);
-
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- intent, 0);
-
- notification.flags |= Notification.FLAG_ONGOING_EVENT;
- notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
-
- notification.setLatestEventInfo(this, getString(R.string.notify_downloading_title), msg, contentIntent);
-
- m_nmgr.notify(NOTIFY_DOWNLOADING, notification);
- }
-
- private void updateNotification(int msgResId) {
- updateNotification(getString(msgResId));
- }
-
- private void downloadFailed() {
- m_readableDb.close();
- m_writableDb.close();
-
- m_nmgr.cancel(NOTIFY_DOWNLOADING);
-
- // TODO send notification to activity?
-
- m_downloadInProgress = false;
- stopSelf();
- }
-
- private boolean isCacheServiceRunning() {
- ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
- for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
- if ("org.fox.ttrss.ImageCacheService".equals(service.service.getClassName())) {
- return true;
- }
- }
- return false;
- }
-
- public void downloadComplete() {
- m_downloadInProgress = false;
-
- // if cache service is running, it will send a finished intent on its own
- if (!isCacheServiceRunning()) {
- m_nmgr.cancel(NOTIFY_DOWNLOADING);
-
- Intent intent = new Intent();
- intent.setAction(INTENT_ACTION_SUCCESS);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- sendBroadcast(intent);
- } else {
- updateNotification(getString(R.string.notify_downloading_images, 0));
- }
-
- m_readableDb.close();
- m_writableDb.close();
-
- stopSelf();
- }
-
- private void initDatabase() {
- DatabaseHelper dh = new DatabaseHelper(getApplicationContext());
- m_writableDb = dh.getWritableDatabase();
- m_readableDb = dh.getReadableDatabase();
- }
-
- /* private synchronized SQLiteDatabase getReadableDb() {
- return m_readableDb;
- } */
-
- private synchronized SQLiteDatabase getWritableDb() {
- return m_writableDb;
- }
-
- @SuppressWarnings("unchecked")
- private void downloadArticles() {
- Log.d(TAG, "offline: downloading articles... offset=" + m_articleOffset);
-
- updateNotification(getString(R.string.notify_downloading_articles, m_articleOffset));
-
- OfflineArticlesRequest req = new OfflineArticlesRequest(this);
-
- @SuppressWarnings("serial")
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getHeadlines");
- put("sid", m_sessionId);
- put("feed_id", "-4");
- put("view_mode", "unread");
- put("show_content", "true");
- put("skip", String.valueOf(m_articleOffset));
- put("limit", String.valueOf(OFFLINE_SYNC_SEQ));
- }
- };
-
- req.execute(map);
- }
-
- private void downloadFeeds() {
-
- updateNotification(R.string.notify_downloading_feeds);
-
- getWritableDb().execSQL("DELETE FROM feeds;");
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected JsonElement doInBackground(HashMap<String, String>... params) {
- JsonElement content = super.doInBackground(params);
-
- if (content != null) {
-
- try {
- Type listType = new TypeToken<List<Feed>>() {}.getType();
- List<Feed> feeds = new Gson().fromJson(content, listType);
-
- SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO feeds " +
- "("+BaseColumns._ID+", title, feed_url, has_icon, cat_id) " +
- "VALUES (?, ?, ?, ?, ?);");
-
- for (Feed feed : feeds) {
- stmtInsert.bindLong(1, feed.id);
- stmtInsert.bindString(2, feed.title);
- stmtInsert.bindString(3, feed.feed_url);
- stmtInsert.bindLong(4, feed.has_icon ? 1 : 0);
- stmtInsert.bindLong(5, feed.cat_id);
-
- stmtInsert.execute();
- }
-
- stmtInsert.close();
-
- Log.d(TAG, "offline: done downloading feeds");
-
- m_articleOffset = 0;
-
- getWritableDb().execSQL("DELETE FROM articles;");
- } catch (Exception e) {
- e.printStackTrace();
- updateNotification(R.string.offline_switch_error);
- downloadFailed();
- }
- }
-
- return content;
- }
-
- @Override
- protected void onPostExecute(JsonElement content) {
- if (content != null) {
- if (m_canProceed) {
- downloadArticles();
- } else {
- downloadFailed();
- }
- } else {
- updateNotification(getErrorMessage());
- downloadFailed();
- }
- }
-
- };
-
- @SuppressWarnings("serial")
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getFeeds");
- put("sid", m_sessionId);
- put("cat_id", "-3");
- put("unread_only", "true");
- }
- };
-
- req.execute(map);
- }
-
- private void downloadCategories() {
-
- updateNotification(R.string.notify_downloading_feeds);
-
- getWritableDb().execSQL("DELETE FROM categories;");
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected JsonElement doInBackground(HashMap<String, String>... params) {
- JsonElement content = super.doInBackground(params);
-
- if (content != null) {
- try {
- Type listType = new TypeToken<List<FeedCategory>>() {}.getType();
- List<FeedCategory> cats = new Gson().fromJson(content, listType);
-
- SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO categories " +
- "("+BaseColumns._ID+", title) " +
- "VALUES (?, ?);");
-
- for (FeedCategory cat : cats) {
- stmtInsert.bindLong(1, cat.id);
- stmtInsert.bindString(2, cat.title);
-
- stmtInsert.execute();
- }
-
- stmtInsert.close();
-
- Log.d(TAG, "offline: done downloading categories");
-
- } catch (Exception e) {
- e.printStackTrace();
- updateNotification(R.string.offline_switch_error);
- downloadFailed();
- }
- }
-
- return content;
- }
- @Override
- protected void onPostExecute(JsonElement content) {
- if (content != null) {
- if (m_canProceed) {
- downloadFeeds();
- } else {
- downloadFailed();
- }
- } else {
- updateNotification(getErrorMessage());
- downloadFailed();
- }
- }
-
- };
-
- @SuppressWarnings("serial")
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getCategories");
- put("sid", m_sessionId);
- //put("cat_id", "-3");
- put("unread_only", "true");
- }
- };
-
- req.execute(map);
- }
-
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- m_nmgr.cancel(NOTIFY_DOWNLOADING);
-
- m_canProceed = false;
- Log.d(TAG, "onDestroy");
-
- //m_readableDb.close();
- //m_writableDb.close();
- }
-
- public class OfflineArticlesRequest extends ApiRequest {
- List<Article> m_articles;
-
- public OfflineArticlesRequest(Context context) {
- super(context);
- }
-
- @Override
- protected JsonElement doInBackground(HashMap<String, String>... params) {
- JsonElement content = super.doInBackground(params);
-
- if (content != null) {
-
- try {
- Type listType = new TypeToken<List<Article>>() {}.getType();
- m_articles = new Gson().fromJson(content, listType);
-
- SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO articles " +
- "("+BaseColumns._ID+", unread, marked, published, updated, is_updated, title, link, feed_id, tags, content) " +
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
-
- for (Article article : m_articles) {
-
- String tagsString = "";
-
- for (String t : article.tags) {
- tagsString += t + ", ";
- }
-
- tagsString = tagsString.replaceAll(", $", "");
-
- stmtInsert.bindLong(1, article.id);
- stmtInsert.bindLong(2, article.unread ? 1 : 0);
- stmtInsert.bindLong(3, article.marked ? 1 : 0);
- stmtInsert.bindLong(4, article.published ? 1 : 0);
- stmtInsert.bindLong(5, article.updated);
- stmtInsert.bindLong(6, article.is_updated ? 1 : 0);
- stmtInsert.bindString(7, article.title);
- stmtInsert.bindString(8, article.link);
- stmtInsert.bindLong(9, article.feed_id);
- stmtInsert.bindString(10, tagsString); // comma-separated tags
- stmtInsert.bindString(11, article.content);
-
- if (m_downloadImages) {
- Document doc = Jsoup.parse(article.content);
-
- if (doc != null) {
- Elements images = doc.select("img");
-
- for (Element img : images) {
- String url = img.attr("src");
-
- if (url.indexOf("://") != -1) {
- if (!ImageCacheService.isUrlCached(OfflineDownloadService.this, url)) {
- Intent intent = new Intent(OfflineDownloadService.this,
- ImageCacheService.class);
-
- intent.putExtra("url", url);
- startService(intent);
- }
- }
- }
- }
- }
-
- try {
- stmtInsert.execute();
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
-
- m_articleOffset += m_articles.size();
-
- Log.d(TAG, "offline: received " + m_articles.size() + " articles; canProc=" + m_canProceed);
-
- stmtInsert.close();
-
- } catch (Exception e) {
- updateNotification(R.string.offline_switch_error);
- Log.d(TAG, "offline: failed: exception when loading articles");
- e.printStackTrace();
- downloadFailed();
- }
-
- }
-
- return content;
- }
-
- @Override
- protected void onPostExecute(JsonElement content) {
- if (content != null) {
-
- if (m_canProceed && m_articles != null) {
- if (m_articles.size() == OFFLINE_SYNC_SEQ && m_articleOffset < m_syncMax) {
- downloadArticles();
- } else {
- downloadComplete();
- }
- } else {
- downloadFailed();
- }
-
- } else {
- Log.d(TAG, "offline: failed: " + getErrorMessage());
- updateNotification(getErrorMessage());
- downloadFailed();
- }
- }
- }
-
- @Override
- public void onStart(Intent intent, int startId) {
- try {
- if (getWritableDb().isDbLockedByCurrentThread() || getWritableDb().isDbLockedByOtherThreads()) {
- return;
- }
-
- m_sessionId = intent.getStringExtra("sessionId");
-
- if (!m_downloadInProgress) {
- if (m_downloadImages) ImageCacheService.cleanupCache(this, false);
-
- updateNotification(R.string.notify_downloading_init);
- m_downloadInProgress = true;
-
- downloadCategories();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
+package org.fox.ttrss.offline; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; + +import org.fox.ttrss.ApiRequest; +import org.fox.ttrss.OnlineActivity; +import org.fox.ttrss.R; +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.Feed; +import org.fox.ttrss.types.FeedCategory; +import org.fox.ttrss.util.DatabaseHelper; +import org.fox.ttrss.util.ImageCacheService; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; +import android.os.Binder; +import android.os.IBinder; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +public class OfflineDownloadService extends Service { + + private final String TAG = this.getClass().getSimpleName(); + + public static final int NOTIFY_DOWNLOADING = 1; + public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.DownloadComplete"; + public static final String INTENT_ACTION_CANCEL = "org.fox.ttrss.intent.action.Cancel"; + + private static final int OFFLINE_SYNC_SEQ = 50; + private static final int OFFLINE_SYNC_MAX = OFFLINE_SYNC_SEQ * 10; + + private SQLiteDatabase m_writableDb; + private SQLiteDatabase m_readableDb; + private int m_articleOffset = 0; + private String m_sessionId; + private NotificationManager m_nmgr; + + private boolean m_downloadInProgress = false; + private boolean m_downloadImages = false; + private int m_syncMax; + private SharedPreferences m_prefs; + private boolean m_canProceed = true; + + private final IBinder m_binder = new LocalBinder(); + + public class LocalBinder extends Binder { + OfflineDownloadService getService() { + return OfflineDownloadService.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return m_binder; + } + + @Override + public void onCreate() { + super.onCreate(); + m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + m_downloadImages = m_prefs.getBoolean("offline_image_cache_enabled", false); + m_syncMax = Integer.parseInt(m_prefs.getString("offline_sync_max", String.valueOf(OFFLINE_SYNC_MAX))); + + initDatabase(); + } + + @SuppressWarnings("deprecation") + private void updateNotification(String msg) { + Notification notification = new Notification(R.drawable.icon, + getString(R.string.notify_downloading_title), System.currentTimeMillis()); + + Intent intent = new Intent(this, OnlineActivity.class); + intent.setAction(INTENT_ACTION_CANCEL); + + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + intent, 0); + + notification.flags |= Notification.FLAG_ONGOING_EVENT; + notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE; + + notification.setLatestEventInfo(this, getString(R.string.notify_downloading_title), msg, contentIntent); + + m_nmgr.notify(NOTIFY_DOWNLOADING, notification); + } + + private void updateNotification(int msgResId) { + updateNotification(getString(msgResId)); + } + + private void downloadFailed() { + m_readableDb.close(); + m_writableDb.close(); + + m_nmgr.cancel(NOTIFY_DOWNLOADING); + + // TODO send notification to activity? + + m_downloadInProgress = false; + stopSelf(); + } + + private boolean isCacheServiceRunning() { + ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if ("org.fox.ttrss.ImageCacheService".equals(service.service.getClassName())) { + return true; + } + } + return false; + } + + public void downloadComplete() { + m_downloadInProgress = false; + + // if cache service is running, it will send a finished intent on its own + if (!isCacheServiceRunning()) { + m_nmgr.cancel(NOTIFY_DOWNLOADING); + + Intent intent = new Intent(); + intent.setAction(INTENT_ACTION_SUCCESS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + sendBroadcast(intent); + } else { + updateNotification(getString(R.string.notify_downloading_images, 0)); + } + + m_readableDb.close(); + m_writableDb.close(); + + stopSelf(); + } + + private void initDatabase() { + DatabaseHelper dh = new DatabaseHelper(getApplicationContext()); + m_writableDb = dh.getWritableDatabase(); + m_readableDb = dh.getReadableDatabase(); + } + + /* private synchronized SQLiteDatabase getReadableDb() { + return m_readableDb; + } */ + + private synchronized SQLiteDatabase getWritableDb() { + return m_writableDb; + } + + @SuppressWarnings("unchecked") + private void downloadArticles() { + Log.d(TAG, "offline: downloading articles... offset=" + m_articleOffset); + + updateNotification(getString(R.string.notify_downloading_articles, m_articleOffset)); + + OfflineArticlesRequest req = new OfflineArticlesRequest(this); + + @SuppressWarnings("serial") + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getHeadlines"); + put("sid", m_sessionId); + put("feed_id", "-4"); + put("view_mode", "unread"); + put("show_content", "true"); + put("skip", String.valueOf(m_articleOffset)); + put("limit", String.valueOf(OFFLINE_SYNC_SEQ)); + } + }; + + req.execute(map); + } + + private void downloadFeeds() { + + updateNotification(R.string.notify_downloading_feeds); + + getWritableDb().execSQL("DELETE FROM feeds;"); + + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected JsonElement doInBackground(HashMap<String, String>... params) { + JsonElement content = super.doInBackground(params); + + if (content != null) { + + try { + Type listType = new TypeToken<List<Feed>>() {}.getType(); + List<Feed> feeds = new Gson().fromJson(content, listType); + + SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO feeds " + + "("+BaseColumns._ID+", title, feed_url, has_icon, cat_id) " + + "VALUES (?, ?, ?, ?, ?);"); + + for (Feed feed : feeds) { + stmtInsert.bindLong(1, feed.id); + stmtInsert.bindString(2, feed.title); + stmtInsert.bindString(3, feed.feed_url); + stmtInsert.bindLong(4, feed.has_icon ? 1 : 0); + stmtInsert.bindLong(5, feed.cat_id); + + stmtInsert.execute(); + } + + stmtInsert.close(); + + Log.d(TAG, "offline: done downloading feeds"); + + m_articleOffset = 0; + + getWritableDb().execSQL("DELETE FROM articles;"); + } catch (Exception e) { + e.printStackTrace(); + updateNotification(R.string.offline_switch_error); + downloadFailed(); + } + } + + return content; + } + + @Override + protected void onPostExecute(JsonElement content) { + if (content != null) { + if (m_canProceed) { + downloadArticles(); + } else { + downloadFailed(); + } + } else { + updateNotification(getErrorMessage()); + downloadFailed(); + } + } + + }; + + @SuppressWarnings("serial") + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getFeeds"); + put("sid", m_sessionId); + put("cat_id", "-3"); + put("unread_only", "true"); + } + }; + + req.execute(map); + } + + private void downloadCategories() { + + updateNotification(R.string.notify_downloading_feeds); + + getWritableDb().execSQL("DELETE FROM categories;"); + + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected JsonElement doInBackground(HashMap<String, String>... params) { + JsonElement content = super.doInBackground(params); + + if (content != null) { + try { + Type listType = new TypeToken<List<FeedCategory>>() {}.getType(); + List<FeedCategory> cats = new Gson().fromJson(content, listType); + + SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO categories " + + "("+BaseColumns._ID+", title) " + + "VALUES (?, ?);"); + + for (FeedCategory cat : cats) { + stmtInsert.bindLong(1, cat.id); + stmtInsert.bindString(2, cat.title); + + stmtInsert.execute(); + } + + stmtInsert.close(); + + Log.d(TAG, "offline: done downloading categories"); + + } catch (Exception e) { + e.printStackTrace(); + updateNotification(R.string.offline_switch_error); + downloadFailed(); + } + } + + return content; + } + @Override + protected void onPostExecute(JsonElement content) { + if (content != null) { + if (m_canProceed) { + downloadFeeds(); + } else { + downloadFailed(); + } + } else { + updateNotification(getErrorMessage()); + downloadFailed(); + } + } + + }; + + @SuppressWarnings("serial") + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getCategories"); + put("sid", m_sessionId); + //put("cat_id", "-3"); + put("unread_only", "true"); + } + }; + + req.execute(map); + } + + + @Override + public void onDestroy() { + super.onDestroy(); + m_nmgr.cancel(NOTIFY_DOWNLOADING); + + m_canProceed = false; + Log.d(TAG, "onDestroy"); + + //m_readableDb.close(); + //m_writableDb.close(); + } + + public class OfflineArticlesRequest extends ApiRequest { + List<Article> m_articles; + + public OfflineArticlesRequest(Context context) { + super(context); + } + + @Override + protected JsonElement doInBackground(HashMap<String, String>... params) { + JsonElement content = super.doInBackground(params); + + if (content != null) { + + try { + Type listType = new TypeToken<List<Article>>() {}.getType(); + m_articles = new Gson().fromJson(content, listType); + + SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO articles " + + "("+BaseColumns._ID+", unread, marked, published, updated, is_updated, title, link, feed_id, tags, content) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + + for (Article article : m_articles) { + + String tagsString = ""; + + for (String t : article.tags) { + tagsString += t + ", "; + } + + tagsString = tagsString.replaceAll(", $", ""); + + stmtInsert.bindLong(1, article.id); + stmtInsert.bindLong(2, article.unread ? 1 : 0); + stmtInsert.bindLong(3, article.marked ? 1 : 0); + stmtInsert.bindLong(4, article.published ? 1 : 0); + stmtInsert.bindLong(5, article.updated); + stmtInsert.bindLong(6, article.is_updated ? 1 : 0); + stmtInsert.bindString(7, article.title); + stmtInsert.bindString(8, article.link); + stmtInsert.bindLong(9, article.feed_id); + stmtInsert.bindString(10, tagsString); // comma-separated tags + stmtInsert.bindString(11, article.content); + + if (m_downloadImages) { + Document doc = Jsoup.parse(article.content); + + if (doc != null) { + Elements images = doc.select("img"); + + for (Element img : images) { + String url = img.attr("src"); + + if (url.indexOf("://") != -1) { + if (!ImageCacheService.isUrlCached(OfflineDownloadService.this, url)) { + Intent intent = new Intent(OfflineDownloadService.this, + ImageCacheService.class); + + intent.putExtra("url", url); + startService(intent); + } + } + } + } + } + + try { + stmtInsert.execute(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + m_articleOffset += m_articles.size(); + + Log.d(TAG, "offline: received " + m_articles.size() + " articles; canProc=" + m_canProceed); + + stmtInsert.close(); + + } catch (Exception e) { + updateNotification(R.string.offline_switch_error); + Log.d(TAG, "offline: failed: exception when loading articles"); + e.printStackTrace(); + downloadFailed(); + } + + } + + return content; + } + + @Override + protected void onPostExecute(JsonElement content) { + if (content != null) { + + if (m_canProceed && m_articles != null) { + if (m_articles.size() == OFFLINE_SYNC_SEQ && m_articleOffset < m_syncMax) { + downloadArticles(); + } else { + downloadComplete(); + } + } else { + downloadFailed(); + } + + } else { + Log.d(TAG, "offline: failed: " + getErrorMessage()); + updateNotification(getErrorMessage()); + downloadFailed(); + } + } + } + + @Override + public void onStart(Intent intent, int startId) { + try { + if (getWritableDb().isDbLockedByCurrentThread() || getWritableDb().isDbLockedByOtherThreads()) { + return; + } + + m_sessionId = intent.getStringExtra("sessionId"); + + if (!m_downloadInProgress) { + if (m_downloadImages) ImageCacheService.cleanupCache(this, false); + + updateNotification(R.string.notify_downloading_init); + m_downloadInProgress = true; + + downloadCategories(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java b/src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java index e27c6e4b..dbc62f4f 100644 --- a/src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java +++ b/src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java @@ -1,324 +1,324 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.widget.SimpleCursorAdapter;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class OfflineFeedCategoriesFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener {
- private final String TAG = this.getClass().getSimpleName();
- private SharedPreferences m_prefs;
- private FeedCategoryListAdapter m_adapter;
- private int m_selectedCatId;
- private Cursor m_cursor;
- private OfflineFeedsActivity m_activity;
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.category_menu, menu);
-
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
- Cursor cursor = (Cursor)m_adapter.getItem(info.position);
-
- if (cursor != null)
- menu.setHeaderTitle(cursor.getString(cursor.getColumnIndex("title")));
-
- if (!m_activity.isSmallScreen()) {
- menu.findItem(R.id.browse_articles).setVisible(false);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- public Cursor createCursor() {
- String unreadOnly = BaseColumns._ID + "> 0 AND " + (m_activity.getUnreadOnly() ? "unread > 0" : "1");
-
- String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title";
-
- return m_activity.getReadableDb().query("cats_unread",
- null, unreadOnly, null, null, null, order);
- }
-
- public void refresh() {
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
-
- m_cursor = createCursor();
-
- if (m_cursor != null) {
- m_adapter.changeCursor(m_cursor);
- m_adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- refresh();
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
-
- switch (item.getItemId()) {
- case R.id.browse_articles:
- if (true) {
- int catId = getCatIdAtPosition(info.position);
- if (catId != -10000) {
- m_activity.openFeedArticles(catId, true);
- }
- }
- return true;
- case R.id.browse_headlines:
- if (true) {
- int catId = getCatIdAtPosition(info.position);
- if (catId != -10000) {
- m_activity.onCatSelected(catId, true);
- }
- }
- return true;
- case R.id.browse_feeds:
- if (true) {
- int catId = getCatIdAtPosition(info.position);
- if (catId != -10000) {
- m_activity.onCatSelected(catId, false);
- }
- }
- return true;
- case R.id.catchup_category:
- if (true) {
- int catId = getCatIdAtPosition(info.position);
- if (catId != -10000) {
- m_activity.catchupFeed(catId, true);
- }
- }
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_selectedCatId = savedInstanceState.getInt("selectedFeedId");
- }
-
- View view = inflater.inflate(R.layout.feeds_fragment, container, false);
-
- ListView list = (ListView)view.findViewById(R.id.feeds);
-
- m_cursor = createCursor();
-
- m_adapter = new FeedCategoryListAdapter(getActivity(), R.layout.feeds_row, m_cursor,
- new String[] { "title", "unread" }, new int[] { R.id.title, R.id.unread_counter }, 0);
-
- list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- list.setEmptyView(view.findViewById(R.id.no_feeds));
- registerForContextMenu(list);
-
- view.findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- return view;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_activity = (OfflineFeedsActivity)activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- m_prefs.registerOnSharedPreferenceChangeListener(this);
-
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("selectedFeedId", m_selectedCatId);
- }
-
- @Override
- public void onItemClick(AdapterView<?> av, View view, int position, long id) {
- ListView list = (ListView)getActivity().findViewById(R.id.feeds);
-
- if (list != null) {
- Cursor cursor = (Cursor) list.getItemAtPosition(position);
-
- if (cursor != null) {
- int feedId = (int) cursor.getLong(0);
- Log.d(TAG, "clicked on feed " + feedId);
-
- if (m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES")) &&
- m_prefs.getBoolean("browse_cats_like_feeds", false)) {
-
- m_activity.openFeedArticles(feedId, true);
-
- } else {
- m_activity.onCatSelected(feedId);
- }
-
- if (!m_activity.isSmallScreen())
- m_selectedCatId = feedId;
-
- m_adapter.notifyDataSetChanged();
- }
- }
- }
-
- /* public void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- getActivity().setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- private class FeedCategoryListAdapter extends SimpleCursorAdapter {
-
-
- public FeedCategoryListAdapter(Context context, int layout, Cursor c,
- String[] from, int[] to, int flags) {
- super(context, layout, c, from, to, flags);
- }
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_SELECTED = 1;
-
- public static final int VIEW_COUNT = VIEW_SELECTED+1;
-
- @Override
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- Cursor cursor = (Cursor) this.getItem(position);
-
- if (!m_activity.isSmallScreen() && cursor.getLong(0) == m_selectedCatId) {
- return VIEW_SELECTED;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
-
- Cursor cursor = (Cursor)getItem(position);
-
- if (v == null) {
- int layoutId = R.layout.feeds_row;
-
- switch (getItemViewType(position)) {
- case VIEW_SELECTED:
- layoutId = R.layout.feeds_row_selected;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- }
-
- TextView tt = (TextView) v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(cursor.getString(cursor.getColumnIndex("title")));
- }
-
- TextView tu = (TextView) v.findViewById(R.id.unread_counter);
-
- if (tu != null) {
- tu.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex("unread"))));
- tu.setVisibility((cursor.getInt(cursor.getColumnIndex("unread")) > 0) ? View.VISIBLE : View.INVISIBLE);
- }
-
- ImageView icon = (ImageView)v.findViewById(R.id.icon);
-
- if (icon != null) {
- icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- return v;
- }
- }
-
- public void sortCategories() {
- try {
- refresh();
- } catch (NullPointerException e) {
- // activity is gone?
- } catch (IllegalStateException e) {
- // we're probably closing and DB is gone already
- }
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
-
- sortCategories();
- }
-
- public int getCatIdAtPosition(int position) {
- Cursor c = (Cursor)m_adapter.getItem(position);
-
- if (c != null) {
- int catId = c.getInt(0);
- c.close();
- return catId;
- }
-
- return -10000;
- }
-
- public void setSelectedFeedId(int feedId) {
- m_selectedCatId = feedId;
- refresh();
- }
-
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.R; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.database.Cursor; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SimpleCursorAdapter; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +public class OfflineFeedCategoriesFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener { + private final String TAG = this.getClass().getSimpleName(); + private SharedPreferences m_prefs; + private FeedCategoryListAdapter m_adapter; + private int m_selectedCatId; + private Cursor m_cursor; + private OfflineFeedsActivity m_activity; + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.category_menu, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + Cursor cursor = (Cursor)m_adapter.getItem(info.position); + + if (cursor != null) + menu.setHeaderTitle(cursor.getString(cursor.getColumnIndex("title"))); + + if (!m_activity.isSmallScreen()) { + menu.findItem(R.id.browse_articles).setVisible(false); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + public Cursor createCursor() { + String unreadOnly = BaseColumns._ID + "> 0 AND " + (m_activity.getUnreadOnly() ? "unread > 0" : "1"); + + String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title"; + + return m_activity.getReadableDb().query("cats_unread", + null, unreadOnly, null, null, null, order); + } + + public void refresh() { + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + + m_cursor = createCursor(); + + if (m_cursor != null) { + m_adapter.changeCursor(m_cursor); + m_adapter.notifyDataSetChanged(); + } + } + + @Override + public void onResume() { + super.onResume(); + refresh(); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + + switch (item.getItemId()) { + case R.id.browse_articles: + if (true) { + int catId = getCatIdAtPosition(info.position); + if (catId != -10000) { + m_activity.openFeedArticles(catId, true); + } + } + return true; + case R.id.browse_headlines: + if (true) { + int catId = getCatIdAtPosition(info.position); + if (catId != -10000) { + m_activity.onCatSelected(catId, true); + } + } + return true; + case R.id.browse_feeds: + if (true) { + int catId = getCatIdAtPosition(info.position); + if (catId != -10000) { + m_activity.onCatSelected(catId, false); + } + } + return true; + case R.id.catchup_category: + if (true) { + int catId = getCatIdAtPosition(info.position); + if (catId != -10000) { + m_activity.catchupFeed(catId, true); + } + } + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_selectedCatId = savedInstanceState.getInt("selectedFeedId"); + } + + View view = inflater.inflate(R.layout.feeds_fragment, container, false); + + ListView list = (ListView)view.findViewById(R.id.feeds); + + m_cursor = createCursor(); + + m_adapter = new FeedCategoryListAdapter(getActivity(), R.layout.feeds_row, m_cursor, + new String[] { "title", "unread" }, new int[] { R.id.title, R.id.unread_counter }, 0); + + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + list.setEmptyView(view.findViewById(R.id.no_feeds)); + registerForContextMenu(list); + + view.findViewById(R.id.loading_container).setVisibility(View.GONE); + + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (OfflineFeedsActivity)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + m_prefs.registerOnSharedPreferenceChangeListener(this); + + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("selectedFeedId", m_selectedCatId); + } + + @Override + public void onItemClick(AdapterView<?> av, View view, int position, long id) { + ListView list = (ListView)getActivity().findViewById(R.id.feeds); + + if (list != null) { + Cursor cursor = (Cursor) list.getItemAtPosition(position); + + if (cursor != null) { + int feedId = (int) cursor.getLong(0); + Log.d(TAG, "clicked on feed " + feedId); + + if (m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES")) && + m_prefs.getBoolean("browse_cats_like_feeds", false)) { + + m_activity.openFeedArticles(feedId, true); + + } else { + m_activity.onCatSelected(feedId); + } + + if (!m_activity.isSmallScreen()) + m_selectedCatId = feedId; + + m_adapter.notifyDataSetChanged(); + } + } + } + + /* public void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + getActivity().setProgressBarIndeterminateVisibility(showProgress); + } */ + + private class FeedCategoryListAdapter extends SimpleCursorAdapter { + + + public FeedCategoryListAdapter(Context context, int layout, Cursor c, + String[] from, int[] to, int flags) { + super(context, layout, c, from, to, flags); + } + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_SELECTED = 1; + + public static final int VIEW_COUNT = VIEW_SELECTED+1; + + @Override + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + Cursor cursor = (Cursor) this.getItem(position); + + if (!m_activity.isSmallScreen() && cursor.getLong(0) == m_selectedCatId) { + return VIEW_SELECTED; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + + Cursor cursor = (Cursor)getItem(position); + + if (v == null) { + int layoutId = R.layout.feeds_row; + + switch (getItemViewType(position)) { + case VIEW_SELECTED: + layoutId = R.layout.feeds_row_selected; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + } + + TextView tt = (TextView) v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(cursor.getString(cursor.getColumnIndex("title"))); + } + + TextView tu = (TextView) v.findViewById(R.id.unread_counter); + + if (tu != null) { + tu.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex("unread")))); + tu.setVisibility((cursor.getInt(cursor.getColumnIndex("unread")) > 0) ? View.VISIBLE : View.INVISIBLE); + } + + ImageView icon = (ImageView)v.findViewById(R.id.icon); + + if (icon != null) { + icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + return v; + } + } + + public void sortCategories() { + try { + refresh(); + } catch (NullPointerException e) { + // activity is gone? + } catch (IllegalStateException e) { + // we're probably closing and DB is gone already + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + + sortCategories(); + } + + public int getCatIdAtPosition(int position) { + Cursor c = (Cursor)m_adapter.getItem(position); + + if (c != null) { + int catId = c.getInt(0); + c.close(); + return catId; + } + + return -10000; + } + + public void setSelectedFeedId(int feedId) { + m_selectedCatId = feedId; + refresh(); + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineFeedsActivity.java b/src/org/fox/ttrss/offline/OfflineFeedsActivity.java index 920d2865..506cd493 100644 --- a/src/org/fox/ttrss/offline/OfflineFeedsActivity.java +++ b/src/org/fox/ttrss/offline/OfflineFeedsActivity.java @@ -1,312 +1,314 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.GlobalState;
-import org.fox.ttrss.R;
-
-import android.animation.LayoutTransition;
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-public class OfflineFeedsActivity extends OfflineActivity implements OfflineHeadlinesEventListener {
- private final String TAG = this.getClass().getSimpleName();
-
- private boolean m_actionbarUpEnabled = false;
-
- @SuppressLint("NewApi")
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.feeds);
-
- setSmallScreen(findViewById(R.id.headlines_fragment) == null);
-
- GlobalState.getInstance().load(savedInstanceState);
-
- if (savedInstanceState != null) {
-
- m_actionbarUpEnabled = savedInstanceState.getBoolean("actionbarUpEnabled");
-
- if (!isCompatMode() && m_actionbarUpEnabled) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- }
-
- } else {
- Intent intent = getIntent();
-
- if (intent.getIntExtra("feed", -10000) != -10000 || intent.getIntExtra("category", -10000) != -10000 ||
- intent.getIntExtra("article", -10000) != -10000) {
-
- if (!isCompatMode()) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- m_actionbarUpEnabled = true;
- }
-
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- int feedId = intent.getIntExtra("feed", -10000);
- int catId = intent.getIntExtra("category", -10000);
- int articleId = intent.getIntExtra("article", -10000);
- boolean isCat = intent.getBooleanExtra("isCat", false);
-
- if (articleId != -10000) {
- ft.replace(R.id.feeds_fragment, new OfflineArticlePager(articleId, feedId, isCat), FRAG_ARTICLE);
- } else {
- if (feedId != -10000) {
- ft.replace(R.id.feeds_fragment, new OfflineHeadlinesFragment(feedId, isCat), FRAG_HEADLINES);
- }
-
- if (catId != -10000) {
- ft.replace(R.id.feeds_fragment, new OfflineFeedsFragment(catId), FRAG_FEEDS);
- }
- }
-
- ft.commit();
- } else {
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- if (m_prefs.getBoolean("enable_cats", false)) {
- ft.replace(R.id.feeds_fragment, new OfflineFeedCategoriesFragment(), FRAG_CATS);
- } else {
- ft.replace(R.id.feeds_fragment, new OfflineFeedsFragment(), FRAG_FEEDS);
- }
-
- ft.commit();
- }
- }
-
- setLoadingStatus(R.string.blank, false);
- findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- initMenu();
-
- /* if (!isSmallScreen()) {
- LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container);
- container.setWeightSum(3f);
- } */
-
- if (!isCompatMode() && !isSmallScreen()) {
- ((ViewGroup)findViewById(R.id.headlines_fragment)).setLayoutTransition(new LayoutTransition());
- ((ViewGroup)findViewById(R.id.feeds_fragment)).setLayoutTransition(new LayoutTransition());
- }
- }
-
- public void openFeedArticles(int feedId, boolean isCat) {
- if (isSmallScreen()) {
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class);
-
- intent.putExtra("feed", feedId);
- intent.putExtra("isCat", isCat);
- intent.putExtra("article", 0);
- startActivityForResult(intent, 0);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.show_feeds:
- setUnreadOnly(!getUnreadOnly());
- initMenu();
- refresh();
- return true;
- default:
- Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putBoolean("actionbarUpEnabled", m_actionbarUpEnabled);
-
- GlobalState.getInstance().save(out);
- }
-
- public void initMenu() {
- super.initMenu();
-
- if (m_menu != null) {
- Fragment ff = getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS);
- Fragment cf = getSupportFragmentManager().findFragmentByTag(FRAG_CATS);
- OfflineArticlePager af = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- m_menu.setGroupVisible(R.id.menu_group_feeds, (ff != null && ff.isAdded()) || (cf != null && cf.isAdded()));
-
- m_menu.setGroupVisible(R.id.menu_group_article, af != null && af.isAdded());
-
- m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded() && getSelectedArticleCount() == 0);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.isAdded() && getSelectedArticleCount() != 0);
-
- MenuItem item = m_menu.findItem(R.id.show_feeds);
-
- if (getUnreadOnly()) {
- item.setTitle(R.string.menu_all_feeds);
- } else {
- item.setTitle(R.string.menu_unread_feeds);
- }
- }
- }
-
- public void onCatSelected(int catId) {
- onCatSelected(catId, m_prefs.getBoolean("browse_cats_like_feeds", false));
- }
-
- public void onCatSelected(int catId, boolean openAsFeed) {
- if (openAsFeed) {
- onFeedSelected(catId, true, true);
- } else {
- if (isSmallScreen()) {
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class);
- intent.putExtra("category", catId);
-
- startActivityForResult(intent, 0);
- } else {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- OfflineFeedsFragment ff = new OfflineFeedsFragment(catId);
-
- ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS);
- ft.addToBackStack(null);
-
- ft.commit();
- }
- }
- }
-
- public void onFeedSelected(int feedId) {
- onFeedSelected(feedId, false, true);
- }
-
- public void onFeedSelected(final int feedId, final boolean isCat, boolean open) {
-
- if (open) {
- if (isSmallScreen()) {
-
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class);
- intent.putExtra("feed", feedId);
- intent.putExtra("isCat", isCat);
-
- startActivityForResult(intent, 0);
-
- } else {
- /* if (!isCompatMode()) {
- LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container);
- float wSum = container.getWeightSum();
- if (wSum <= 2.0f) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(container, "weightSum", wSum, 3.0f);
- anim.setDuration(200);
- anim.start();
- }
- } */
-
- // ^ no idea why the animation hangs half the time :(
-
- LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container);
- container.setWeightSum(3f);
-
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- OfflineHeadlinesFragment hf = new OfflineHeadlinesFragment(feedId, isCat);
- ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES);
-
- ft.commit();
- }
- }, 10);
-
- }
- }
- }
-
- public void catchupFeed(int feedId, boolean isCat) {
- if (isCat) {
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id IN (SELECT "+
- BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- stmt.bindLong(1, feedId);
- stmt.execute();
- stmt.close();
- } else {
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id = ?");
- stmt.bindLong(1, feedId);
- stmt.execute();
- stmt.close();
- }
-
- refresh();
- }
-
- @Override
- public void onArticleSelected(int articleId, boolean open) {
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 " + "WHERE " + BaseColumns._ID
- + " = ?");
-
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- initMenu();
-
- if (open) {
- if (isSmallScreen()) {
-
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class);
- intent.putExtra("feed", hf.getFeedId());
- intent.putExtra("isCat", hf.getFeedIsCat());
- intent.putExtra("article", articleId);
-
- startActivityForResult(intent, 0);
-
- } else {
-
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineHeadlinesActivity.class);
- intent.putExtra("feed", hf.getFeedId());
- intent.putExtra("isCat", hf.getFeedIsCat());
- intent.putExtra("article", articleId);
-
- startActivityForResult(intent, 0);
- }
- } else {
- refresh();
- }
-
- initMenu();
-
- }
-
- @Override
- public void onArticleSelected(int articleId) {
- onArticleSelected(articleId, true);
- }
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.GlobalState; +import org.fox.ttrss.R; + +import com.actionbarsherlock.view.MenuItem; + +import android.animation.LayoutTransition; +import android.annotation.SuppressLint; +import android.content.Intent; +import android.database.sqlite.SQLiteStatement; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +public class OfflineFeedsActivity extends OfflineActivity implements OfflineHeadlinesEventListener { + private final String TAG = this.getClass().getSimpleName(); + + private boolean m_actionbarUpEnabled = false; + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + setContentView(R.layout.feeds); + + setSmallScreen(findViewById(R.id.headlines_fragment) == null); + + GlobalState.getInstance().load(savedInstanceState); + + if (savedInstanceState != null) { + + m_actionbarUpEnabled = savedInstanceState.getBoolean("actionbarUpEnabled"); + + if (!isCompatMode() && m_actionbarUpEnabled) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + } else { + Intent intent = getIntent(); + + if (intent.getIntExtra("feed", -10000) != -10000 || intent.getIntExtra("category", -10000) != -10000 || + intent.getIntExtra("article", -10000) != -10000) { + + if (!isCompatMode()) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + m_actionbarUpEnabled = true; + } + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + int feedId = intent.getIntExtra("feed", -10000); + int catId = intent.getIntExtra("category", -10000); + int articleId = intent.getIntExtra("article", -10000); + boolean isCat = intent.getBooleanExtra("isCat", false); + + if (articleId != -10000) { + ft.replace(R.id.feeds_fragment, new OfflineArticlePager(articleId, feedId, isCat), FRAG_ARTICLE); + } else { + if (feedId != -10000) { + ft.replace(R.id.feeds_fragment, new OfflineHeadlinesFragment(feedId, isCat), FRAG_HEADLINES); + } + + if (catId != -10000) { + ft.replace(R.id.feeds_fragment, new OfflineFeedsFragment(catId), FRAG_FEEDS); + } + } + + ft.commit(); + } else { + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + if (m_prefs.getBoolean("enable_cats", false)) { + ft.replace(R.id.feeds_fragment, new OfflineFeedCategoriesFragment(), FRAG_CATS); + } else { + ft.replace(R.id.feeds_fragment, new OfflineFeedsFragment(), FRAG_FEEDS); + } + + ft.commit(); + } + } + + setLoadingStatus(R.string.blank, false); + findViewById(R.id.loading_container).setVisibility(View.GONE); + + initMenu(); + + /* if (!isSmallScreen()) { + LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container); + container.setWeightSum(3f); + } */ + + if (!isCompatMode() && !isSmallScreen()) { + ((ViewGroup)findViewById(R.id.headlines_fragment)).setLayoutTransition(new LayoutTransition()); + ((ViewGroup)findViewById(R.id.feeds_fragment)).setLayoutTransition(new LayoutTransition()); + } + } + + public void openFeedArticles(int feedId, boolean isCat) { + if (isSmallScreen()) { + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class); + + intent.putExtra("feed", feedId); + intent.putExtra("isCat", isCat); + intent.putExtra("article", 0); + startActivityForResult(intent, 0); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.show_feeds: + setUnreadOnly(!getUnreadOnly()); + initMenu(); + refresh(); + return true; + default: + Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putBoolean("actionbarUpEnabled", m_actionbarUpEnabled); + + GlobalState.getInstance().save(out); + } + + public void initMenu() { + super.initMenu(); + + if (m_menu != null) { + Fragment ff = getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS); + Fragment cf = getSupportFragmentManager().findFragmentByTag(FRAG_CATS); + OfflineArticlePager af = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + m_menu.setGroupVisible(R.id.menu_group_feeds, (ff != null && ff.isAdded()) || (cf != null && cf.isAdded())); + + m_menu.setGroupVisible(R.id.menu_group_article, af != null && af.isAdded()); + + m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded()); + //m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded() && getSelectedArticleCount() == 0); + //m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.isAdded() && getSelectedArticleCount() != 0); + + MenuItem item = m_menu.findItem(R.id.show_feeds); + + if (getUnreadOnly()) { + item.setTitle(R.string.menu_all_feeds); + } else { + item.setTitle(R.string.menu_unread_feeds); + } + } + } + + public void onCatSelected(int catId) { + onCatSelected(catId, m_prefs.getBoolean("browse_cats_like_feeds", false)); + } + + public void onCatSelected(int catId, boolean openAsFeed) { + if (openAsFeed) { + onFeedSelected(catId, true, true); + } else { + if (isSmallScreen()) { + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class); + intent.putExtra("category", catId); + + startActivityForResult(intent, 0); + } else { + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + OfflineFeedsFragment ff = new OfflineFeedsFragment(catId); + + ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS); + ft.addToBackStack(null); + + ft.commit(); + } + } + } + + public void onFeedSelected(int feedId) { + onFeedSelected(feedId, false, true); + } + + public void onFeedSelected(final int feedId, final boolean isCat, boolean open) { + + if (open) { + if (isSmallScreen()) { + + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class); + intent.putExtra("feed", feedId); + intent.putExtra("isCat", isCat); + + startActivityForResult(intent, 0); + + } else { + /* if (!isCompatMode()) { + LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container); + float wSum = container.getWeightSum(); + if (wSum <= 2.0f) { + ObjectAnimator anim = ObjectAnimator.ofFloat(container, "weightSum", wSum, 3.0f); + anim.setDuration(200); + anim.start(); + } + } */ + + // ^ no idea why the animation hangs half the time :( + + LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container); + container.setWeightSum(3f); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + OfflineHeadlinesFragment hf = new OfflineHeadlinesFragment(feedId, isCat); + ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES); + + ft.commit(); + } + }, 10); + + } + } + } + + public void catchupFeed(int feedId, boolean isCat) { + if (isCat) { + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id IN (SELECT "+ + BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + stmt.bindLong(1, feedId); + stmt.execute(); + stmt.close(); + } else { + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id = ?"); + stmt.bindLong(1, feedId); + stmt.execute(); + stmt.close(); + } + + refresh(); + } + + @Override + public void onArticleSelected(int articleId, boolean open) { + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 " + "WHERE " + BaseColumns._ID + + " = ?"); + + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + initMenu(); + + if (open) { + if (isSmallScreen()) { + + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class); + intent.putExtra("feed", hf.getFeedId()); + intent.putExtra("isCat", hf.getFeedIsCat()); + intent.putExtra("article", articleId); + + startActivityForResult(intent, 0); + + } else { + + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineHeadlinesActivity.class); + intent.putExtra("feed", hf.getFeedId()); + intent.putExtra("isCat", hf.getFeedIsCat()); + intent.putExtra("article", articleId); + + startActivityForResult(intent, 0); + } + } else { + refresh(); + } + + initMenu(); + + } + + @Override + public void onArticleSelected(int articleId) { + onArticleSelected(articleId, true); + } +} diff --git a/src/org/fox/ttrss/offline/OfflineFeedsFragment.java b/src/org/fox/ttrss/offline/OfflineFeedsFragment.java index 7de6bbdd..09cb7b63 100644 --- a/src/org/fox/ttrss/offline/OfflineFeedsFragment.java +++ b/src/org/fox/ttrss/offline/OfflineFeedsFragment.java @@ -1,354 +1,354 @@ -package org.fox.ttrss.offline;
-
-import java.io.File;
-
-import org.fox.ttrss.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Bundle;
-import android.os.Environment;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.widget.SimpleCursorAdapter;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class OfflineFeedsFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener {
- private final String TAG = this.getClass().getSimpleName();
- private SharedPreferences m_prefs;
- private FeedListAdapter m_adapter;
- private static final String ICON_PATH = "/data/org.fox.ttrss/icons/";
- private int m_selectedFeedId;
- private int m_catId = -1;
- private boolean m_enableFeedIcons;
- private Cursor m_cursor;
- private OfflineFeedsActivity m_activity;
-
- public OfflineFeedsFragment() {
- //
- }
-
- public OfflineFeedsFragment(int catId) {
- m_catId = catId;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- refresh();
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
- switch (item.getItemId()) {
- case R.id.browse_articles:
- if (true) {
- int feedId = getFeedIdAtPosition(info.position);
- if (feedId != -10000) {
- m_activity.openFeedArticles(feedId, false);
- }
- }
- return true;
- case R.id.browse_headlines:
- if (true) {
- int feedId = getFeedIdAtPosition(info.position);
- if (feedId != -10000) {
- m_activity.onFeedSelected(feedId);
- }
- }
- return true;
- case R.id.catchup_feed:
- int feedId = getFeedIdAtPosition(info.position);
- if (feedId != -10000) {
- m_activity.catchupFeed(feedId, false);
- }
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.feed_menu, menu);
-
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
- Cursor cursor = (Cursor)m_adapter.getItem(info.position);
-
- if (cursor != null)
- menu.setHeaderTitle(cursor.getString(cursor.getColumnIndex("title")));
-
- if (!m_activity.isSmallScreen()) {
- menu.findItem(R.id.browse_articles).setVisible(false);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- public Cursor createCursor() {
- String unreadOnly = m_activity.getUnreadOnly() ? "unread > 0" : "1";
- String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title";
-
- if (m_catId != -1) {
- return m_activity.getReadableDb().query("feeds_unread",
- null, unreadOnly + " AND cat_id = ?", new String[] { String.valueOf(m_catId) }, null, null, order);
- } else {
- return m_activity.getReadableDb().query("feeds_unread",
- null, unreadOnly, null, null, null, order);
- }
- }
-
- public void refresh() {
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
-
- m_cursor = createCursor();
-
- if (m_cursor != null) {
- m_adapter.changeCursor(m_cursor);
- m_adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_selectedFeedId = savedInstanceState.getInt("selectedFeedId");
- m_catId = savedInstanceState.getInt("catId");
- }
-
- View view = inflater.inflate(R.layout.feeds_fragment, container, false);
-
- ListView list = (ListView)view.findViewById(R.id.feeds);
-
- m_cursor = createCursor();
-
- m_adapter = new FeedListAdapter(getActivity(), R.layout.feeds_row, m_cursor,
- new String[] { "title", "unread" }, new int[] { R.id.title, R.id.unread_counter }, 0);
-
- list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- list.setEmptyView(view.findViewById(R.id.no_feeds));
- registerForContextMenu(list);
-
- view.findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false);
-
- return view;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_activity = (OfflineFeedsActivity)activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- m_prefs.registerOnSharedPreferenceChangeListener(this);
-
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("selectedFeedId", m_selectedFeedId);
- out.putInt("catId", m_catId);
- }
-
- @Override
- public void onItemClick(AdapterView<?> av, View view, int position, long id) {
- ListView list = (ListView)getActivity().findViewById(R.id.feeds);
-
- if (list != null) {
- Cursor cursor = (Cursor) list.getItemAtPosition(position);
-
- if (cursor != null) {
- int feedId = (int) cursor.getLong(0);
- Log.d(TAG, "clicked on feed " + feedId);
-
- if (!m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES"))) {
- m_activity.openFeedArticles(feedId, false);
- } else {
- m_activity.onFeedSelected(feedId);
- }
-
- if (!m_activity.isSmallScreen())
- m_selectedFeedId = feedId;
-
- m_adapter.notifyDataSetChanged();
- }
- }
- }
-
- /* public void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- getActivity().setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- private class FeedListAdapter extends SimpleCursorAdapter {
-
-
- public FeedListAdapter(Context context, int layout, Cursor c,
- String[] from, int[] to, int flags) {
- super(context, layout, c, from, to, flags);
- }
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_SELECTED = 1;
-
- public static final int VIEW_COUNT = VIEW_SELECTED+1;
-
- @Override
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- Cursor cursor = (Cursor) this.getItem(position);
-
- if (!m_activity.isSmallScreen() && cursor.getLong(0) == m_selectedFeedId) {
- return VIEW_SELECTED;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
-
- Cursor cursor = (Cursor)getItem(position);
-
- if (v == null) {
- int layoutId = R.layout.feeds_row;
-
- switch (getItemViewType(position)) {
- case VIEW_SELECTED:
- layoutId = R.layout.feeds_row_selected;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- }
-
- TextView tt = (TextView) v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(cursor.getString(cursor.getColumnIndex("title")));
- }
-
- TextView tu = (TextView) v.findViewById(R.id.unread_counter);
-
- if (tu != null) {
- tu.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex("unread"))));
- tu.setVisibility((cursor.getInt(cursor.getColumnIndex("unread")) > 0) ? View.VISIBLE : View.INVISIBLE);
- }
-
- ImageView icon = (ImageView)v.findViewById(R.id.icon);
-
- if (icon != null) {
-
- if (m_enableFeedIcons) {
-
- File storage = Environment.getExternalStorageDirectory();
-
- File iconFile = new File(storage.getAbsolutePath() + ICON_PATH + cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)) + ".ico");
- if (iconFile.exists()) {
- Bitmap bmpOrig = BitmapFactory.decodeFile(iconFile.getAbsolutePath());
- if (bmpOrig != null) {
- icon.setImageBitmap(bmpOrig);
- }
- } else {
- icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- } else {
- icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- }
-
- return v;
- }
- }
-
- public void sortFeeds() {
- try {
- refresh();
- } catch (NullPointerException e) {
- // activity is gone?
- } catch (IllegalStateException e) {
- // we're probably closing and DB is gone already
- }
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
-
- sortFeeds();
- m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false);
-
- }
-
- public int getFeedIdAtPosition(int position) {
- Cursor c = (Cursor)m_adapter.getItem(position);
-
- if (c != null) {
- int feedId = c.getInt(0);
- c.close();
- return feedId;
- }
-
- return -10000;
- }
-
- public void setSelectedFeedId(int feedId) {
- m_selectedFeedId = feedId;
- refresh();
- }
-
-}
+package org.fox.ttrss.offline; + +import java.io.File; + +import org.fox.ttrss.R; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SimpleCursorAdapter; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +public class OfflineFeedsFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener { + private final String TAG = this.getClass().getSimpleName(); + private SharedPreferences m_prefs; + private FeedListAdapter m_adapter; + private static final String ICON_PATH = "/data/org.fox.ttrss/icons/"; + private int m_selectedFeedId; + private int m_catId = -1; + private boolean m_enableFeedIcons; + private Cursor m_cursor; + private OfflineFeedsActivity m_activity; + + public OfflineFeedsFragment() { + // + } + + public OfflineFeedsFragment(int catId) { + m_catId = catId; + } + + @Override + public void onResume() { + super.onResume(); + refresh(); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + switch (item.getItemId()) { + case R.id.browse_articles: + if (true) { + int feedId = getFeedIdAtPosition(info.position); + if (feedId != -10000) { + m_activity.openFeedArticles(feedId, false); + } + } + return true; + case R.id.browse_headlines: + if (true) { + int feedId = getFeedIdAtPosition(info.position); + if (feedId != -10000) { + m_activity.onFeedSelected(feedId); + } + } + return true; + case R.id.catchup_feed: + int feedId = getFeedIdAtPosition(info.position); + if (feedId != -10000) { + m_activity.catchupFeed(feedId, false); + } + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.feed_menu, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + Cursor cursor = (Cursor)m_adapter.getItem(info.position); + + if (cursor != null) + menu.setHeaderTitle(cursor.getString(cursor.getColumnIndex("title"))); + + if (!m_activity.isSmallScreen()) { + menu.findItem(R.id.browse_articles).setVisible(false); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + public Cursor createCursor() { + String unreadOnly = m_activity.getUnreadOnly() ? "unread > 0" : "1"; + String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title"; + + if (m_catId != -1) { + return m_activity.getReadableDb().query("feeds_unread", + null, unreadOnly + " AND cat_id = ?", new String[] { String.valueOf(m_catId) }, null, null, order); + } else { + return m_activity.getReadableDb().query("feeds_unread", + null, unreadOnly, null, null, null, order); + } + } + + public void refresh() { + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + + m_cursor = createCursor(); + + if (m_cursor != null) { + m_adapter.changeCursor(m_cursor); + m_adapter.notifyDataSetChanged(); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_selectedFeedId = savedInstanceState.getInt("selectedFeedId"); + m_catId = savedInstanceState.getInt("catId"); + } + + View view = inflater.inflate(R.layout.feeds_fragment, container, false); + + ListView list = (ListView)view.findViewById(R.id.feeds); + + m_cursor = createCursor(); + + m_adapter = new FeedListAdapter(getActivity(), R.layout.feeds_row, m_cursor, + new String[] { "title", "unread" }, new int[] { R.id.title, R.id.unread_counter }, 0); + + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + list.setEmptyView(view.findViewById(R.id.no_feeds)); + registerForContextMenu(list); + + view.findViewById(R.id.loading_container).setVisibility(View.GONE); + + m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false); + + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (OfflineFeedsActivity)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + m_prefs.registerOnSharedPreferenceChangeListener(this); + + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("selectedFeedId", m_selectedFeedId); + out.putInt("catId", m_catId); + } + + @Override + public void onItemClick(AdapterView<?> av, View view, int position, long id) { + ListView list = (ListView)getActivity().findViewById(R.id.feeds); + + if (list != null) { + Cursor cursor = (Cursor) list.getItemAtPosition(position); + + if (cursor != null) { + int feedId = (int) cursor.getLong(0); + Log.d(TAG, "clicked on feed " + feedId); + + if (!m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES"))) { + m_activity.openFeedArticles(feedId, false); + } else { + m_activity.onFeedSelected(feedId); + } + + if (!m_activity.isSmallScreen()) + m_selectedFeedId = feedId; + + m_adapter.notifyDataSetChanged(); + } + } + } + + /* public void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + getActivity().setProgressBarIndeterminateVisibility(showProgress); + } */ + + private class FeedListAdapter extends SimpleCursorAdapter { + + + public FeedListAdapter(Context context, int layout, Cursor c, + String[] from, int[] to, int flags) { + super(context, layout, c, from, to, flags); + } + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_SELECTED = 1; + + public static final int VIEW_COUNT = VIEW_SELECTED+1; + + @Override + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + Cursor cursor = (Cursor) this.getItem(position); + + if (!m_activity.isSmallScreen() && cursor.getLong(0) == m_selectedFeedId) { + return VIEW_SELECTED; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + + Cursor cursor = (Cursor)getItem(position); + + if (v == null) { + int layoutId = R.layout.feeds_row; + + switch (getItemViewType(position)) { + case VIEW_SELECTED: + layoutId = R.layout.feeds_row_selected; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + } + + TextView tt = (TextView) v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(cursor.getString(cursor.getColumnIndex("title"))); + } + + TextView tu = (TextView) v.findViewById(R.id.unread_counter); + + if (tu != null) { + tu.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex("unread")))); + tu.setVisibility((cursor.getInt(cursor.getColumnIndex("unread")) > 0) ? View.VISIBLE : View.INVISIBLE); + } + + ImageView icon = (ImageView)v.findViewById(R.id.icon); + + if (icon != null) { + + if (m_enableFeedIcons) { + + File storage = Environment.getExternalStorageDirectory(); + + File iconFile = new File(storage.getAbsolutePath() + ICON_PATH + cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)) + ".ico"); + if (iconFile.exists()) { + Bitmap bmpOrig = BitmapFactory.decodeFile(iconFile.getAbsolutePath()); + if (bmpOrig != null) { + icon.setImageBitmap(bmpOrig); + } + } else { + icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + } else { + icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + } + + return v; + } + } + + public void sortFeeds() { + try { + refresh(); + } catch (NullPointerException e) { + // activity is gone? + } catch (IllegalStateException e) { + // we're probably closing and DB is gone already + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + + sortFeeds(); + m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false); + + } + + public int getFeedIdAtPosition(int position) { + Cursor c = (Cursor)m_adapter.getItem(position); + + if (c != null) { + int feedId = c.getInt(0); + c.close(); + return feedId; + } + + return -10000; + } + + public void setSelectedFeedId(int feedId) { + m_selectedFeedId = feedId; + refresh(); + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java b/src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java index 6faa292b..867a2e5d 100644 --- a/src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java +++ b/src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java @@ -1,142 +1,144 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.GlobalState;
-import org.fox.ttrss.R;
-
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.view.View;
-
-public class OfflineHeadlinesActivity extends OfflineActivity implements OfflineHeadlinesEventListener {
- @SuppressWarnings("unused")
- private final String TAG = this.getClass().getSimpleName();
-
- protected SharedPreferences m_prefs;
-
- @SuppressLint("NewApi")
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.headlines);
-
- if (!isCompatMode()) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- }
-
- setSmallScreen(findViewById(R.id.headlines_fragment) == null);
-
- if (isPortrait()) {
- findViewById(R.id.headlines_fragment).setVisibility(View.GONE);
- }
-
- if (savedInstanceState == null) {
- Intent i = getIntent();
-
- if (i.getExtras() != null) {
- int feedId = i.getIntExtra("feed", 0);
- boolean isCat = i.getBooleanExtra("isCat", false);
- int articleId = i.getIntExtra("article", 0);
- String searchQuery = i.getStringExtra("searchQuery");
-
- OfflineHeadlinesFragment hf = new OfflineHeadlinesFragment(feedId, isCat);
- OfflineArticlePager af = new OfflineArticlePager(articleId, feedId, isCat);
-
- hf.setActiveArticleId(articleId);
-
- hf.setSearchQuery(searchQuery);
- af.setSearchQuery(searchQuery);
-
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES);
- ft.replace(R.id.article_fragment, af, FRAG_ARTICLE);
-
- ft.commit();
-
- Cursor c;
-
- if (isCat) {
- c = getCatById(feedId);
- } else {
- c = getFeedById(feedId);
- }
-
- if (c != null) {
- setTitle(c.getString(c.getColumnIndex("title")));
- c.close();
- }
-
- }
- }
-
- setLoadingStatus(R.string.blank, false);
- findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- initMenu();
- }
-
- @Override
- public void onArticleSelected(int articleId, boolean open) {
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 " + "WHERE " + BaseColumns._ID
- + " = ?");
-
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- if (open) {
- OfflineArticlePager af = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- af.setArticleId(articleId);
- } else {
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- hf.setActiveArticleId(articleId);
- }
-
- GlobalState.getInstance().m_selectedArticleId = articleId;
-
- initMenu();
- refresh();
- }
-
- @Override
- protected void initMenu() {
- super.initMenu();
-
- if (m_menu != null) {
- m_menu.setGroupVisible(R.id.menu_group_feeds, false);
-
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.getSelectedArticleCount() == 0);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.getSelectedArticleCount() != 0);
-
- Fragment af = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- m_menu.setGroupVisible(R.id.menu_group_article, af != null);
-
- m_menu.findItem(R.id.search).setVisible(false);
- }
- }
-
- @Override
- public void onArticleSelected(int articleId) {
- onArticleSelected(articleId, true);
- }
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.GlobalState; +import org.fox.ttrss.R; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.view.View; + +public class OfflineHeadlinesActivity extends OfflineActivity implements OfflineHeadlinesEventListener { + @SuppressWarnings("unused") + private final String TAG = this.getClass().getSimpleName(); + + protected SharedPreferences m_prefs; + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + setContentView(R.layout.headlines); + + if (!isCompatMode()) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + setSmallScreen(findViewById(R.id.headlines_fragment) == null); + + if (isPortrait()) { + findViewById(R.id.headlines_fragment).setVisibility(View.GONE); + } + + if (savedInstanceState == null) { + Intent i = getIntent(); + + if (i.getExtras() != null) { + int feedId = i.getIntExtra("feed", 0); + boolean isCat = i.getBooleanExtra("isCat", false); + int articleId = i.getIntExtra("article", 0); + String searchQuery = i.getStringExtra("searchQuery"); + + OfflineHeadlinesFragment hf = new OfflineHeadlinesFragment(feedId, isCat); + OfflineArticlePager af = new OfflineArticlePager(articleId, feedId, isCat); + + hf.setActiveArticleId(articleId); + + hf.setSearchQuery(searchQuery); + af.setSearchQuery(searchQuery); + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES); + ft.replace(R.id.article_fragment, af, FRAG_ARTICLE); + + ft.commit(); + + Cursor c; + + if (isCat) { + c = getCatById(feedId); + } else { + c = getFeedById(feedId); + } + + if (c != null) { + setTitle(c.getString(c.getColumnIndex("title"))); + c.close(); + } + + } + } + + setLoadingStatus(R.string.blank, false); + findViewById(R.id.loading_container).setVisibility(View.GONE); + + initMenu(); + } + + @Override + public void onArticleSelected(int articleId, boolean open) { + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 " + "WHERE " + BaseColumns._ID + + " = ?"); + + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + if (open) { + OfflineArticlePager af = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + af.setArticleId(articleId); + } else { + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + hf.setActiveArticleId(articleId); + } + + GlobalState.getInstance().m_selectedArticleId = articleId; + + initMenu(); + refresh(); + } + + @Override + protected void initMenu() { + super.initMenu(); + + if (m_menu != null) { + m_menu.setGroupVisible(R.id.menu_group_feeds, false); + + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded()); + + //m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.getSelectedArticleCount() == 0); + //m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.getSelectedArticleCount() != 0); + + Fragment af = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + m_menu.setGroupVisible(R.id.menu_group_article, af != null); + + m_menu.findItem(R.id.search).setVisible(false); + } + } + + @Override + public void onArticleSelected(int articleId) { + onArticleSelected(articleId, true); + } +} diff --git a/src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java b/src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java index cdff5913..0818a66b 100644 --- a/src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java +++ b/src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java @@ -1,7 +1,7 @@ -package org.fox.ttrss.offline;
-
-
-public interface OfflineHeadlinesEventListener {
- void onArticleSelected(int articleId, boolean open);
- void onArticleSelected(int articleId);
-}
+package org.fox.ttrss.offline; + + +public interface OfflineHeadlinesEventListener { + void onArticleSelected(int articleId, boolean open); + void onArticleSelected(int articleId); +} diff --git a/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java b/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java index 96de96fe..be724eb1 100644 --- a/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java +++ b/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java @@ -1,649 +1,649 @@ -package org.fox.ttrss.offline;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.TimeZone;
-
-import org.fox.ttrss.GlobalState;
-import org.fox.ttrss.R;
-import org.jsoup.Jsoup;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteStatement;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.widget.SimpleCursorAdapter;
-import android.text.Html;
-import android.text.Html.ImageGetter;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class OfflineHeadlinesFragment extends Fragment implements OnItemClickListener {
- public static enum ArticlesSelection { ALL, NONE, UNREAD };
-
- private final String TAG = this.getClass().getSimpleName();
-
- private int m_feedId;
- private boolean m_feedIsCat = false;
- private int m_activeArticleId;
- private String m_searchQuery = "";
-
- private SharedPreferences m_prefs;
-
- private Cursor m_cursor;
- private ArticleListAdapter m_adapter;
-
- private OfflineHeadlinesEventListener m_listener;
- private OfflineActivity m_activity;
-
- private ImageGetter m_dummyGetter = new ImageGetter() {
-
- @SuppressWarnings("deprecation")
- @Override
- public Drawable getDrawable(String source) {
- return new BitmapDrawable();
- }
-
- };
-
- public OfflineHeadlinesFragment(int feedId, boolean isCat) {
- m_feedId = feedId;
- m_feedIsCat = isCat;
- }
-
- public OfflineHeadlinesFragment() {
- //
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
- }
-
- public int getSelectedArticleCount() {
- Cursor c = m_activity.getReadableDb().query("articles",
- new String[] { "COUNT(*)" }, "selected = 1", null, null, null, null);
- c.moveToFirst();
- int selected = c.getInt(0);
- c.close();
-
- return selected;
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
-
- switch (item.getItemId()) {
- case R.id.article_link_copy:
- if (true) {
- int articleId = getArticleIdAtPosition(info.position);
-
- Cursor article = m_activity.getArticleById(articleId);
-
- if (article != null) {
- m_activity.copyToClipboard(article.getString(article.getColumnIndex("link")));
- article.close();
- }
- }
- return true;
- case R.id.selection_toggle_marked:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = m_activity.getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, marked = NOT marked WHERE selected = 1");
- stmt.execute();
- stmt.close();
- } else {
- int articleId = getArticleIdAtPosition(info.position);
-
- SQLiteStatement stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, marked = NOT marked WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
- }
- refresh();
- return true;
- case R.id.selection_toggle_published:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = m_activity.getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, published = NOT published WHERE selected = 1");
- stmt.execute();
- stmt.close();
- } else {
- int articleId = getArticleIdAtPosition(info.position);
-
- SQLiteStatement stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, published = NOT published WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
- }
- refresh();
- return true;
- case R.id.selection_toggle_unread:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = m_activity.getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, unread = NOT unread WHERE selected = 1");
- stmt.execute();
- stmt.close();
- } else {
- int articleId = getArticleIdAtPosition(info.position);
-
- SQLiteStatement stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = NOT unread WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
- }
- refresh();
- return true;
- case R.id.share_article:
- if (true) {
- int articleId = getArticleIdAtPosition(info.position);
- m_activity.shareArticle(articleId);
- }
- return true;
- case R.id.catchup_above:
- if (true) {
- int articleId = getArticleIdAtPosition(info.position);
-
- SQLiteStatement stmt = null;
-
- String updatedOperator = (m_prefs.getBoolean("offline_oldest_first", false)) ? "<" : ">";
-
- if (m_feedIsCat) {
- stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE " +
- "updated "+updatedOperator+" (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " +
- "AND unread = 1 AND feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- } else {
- stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE " +
- "updated "+updatedOperator+" (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " +
- "AND unread = 1 AND feed_id = ?");
- }
-
- stmt.bindLong(1, articleId);
- stmt.bindLong(2, m_feedId);
- stmt.execute();
- stmt.close();
- }
- refresh();
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.headlines_context_menu, menu);
-
- if (getSelectedArticleCount() > 0) {
- menu.setHeaderTitle(R.string.headline_context_multiple);
- menu.setGroupVisible(R.id.menu_group_single_article, false);
- } else {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
- Cursor c = getArticleAtPosition(info.position);
- menu.setHeaderTitle(c.getString(c.getColumnIndex("title")));
- //c.close();
- menu.setGroupVisible(R.id.menu_group_single_article, true);
-
- menu.findItem(R.id.set_labels).setVisible(false);
- menu.findItem(R.id.article_set_note).setVisible(false);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (GlobalState.getInstance().m_selectedArticleId != 0) {
- m_activeArticleId = GlobalState.getInstance().m_selectedArticleId;
- GlobalState.getInstance().m_selectedArticleId = 0;
- }
-
- if (m_activeArticleId != 0) {
- setActiveArticleId(m_activeArticleId);
- }
-
- refresh();
- }
-
- public void refresh() {
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
-
- m_cursor = createCursor();
-
- if (m_cursor != null) {
- m_adapter.changeCursor(m_cursor);
- m_adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_feedId = savedInstanceState.getInt("feedId");
- m_activeArticleId = savedInstanceState.getInt("activeArticleId");
- //m_selectedArticles = savedInstanceState.getParcelableArrayList("selectedArticles");
- m_searchQuery = (String) savedInstanceState.getCharSequence("searchQuery");
- m_feedIsCat = savedInstanceState.getBoolean("feedIsCat");
- } else {
- m_activity.getWritableDb().execSQL("UPDATE articles SET selected = 0 ");
- }
-
- View view = inflater.inflate(R.layout.headlines_fragment, container, false);
-
- m_cursor = createCursor();
-
- ListView list = (ListView)view.findViewById(R.id.headlines);
- m_adapter = new ArticleListAdapter(getActivity(), R.layout.headlines_row, m_cursor,
- new String[] { "title" }, new int[] { R.id.title }, 0);
-
- list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- list.setEmptyView(view.findViewById(R.id.no_headlines));
- registerForContextMenu(list);
-
- if (m_activity.isSmallScreen() || m_activity.isPortrait())
- view.findViewById(R.id.headlines_fragment).setPadding(0, 0, 0, 0);
-
- getActivity().setProgressBarIndeterminateVisibility(false);
-
- return view;
- }
-
- public Cursor createCursor() {
- String feedClause = null;
-
- if (m_feedIsCat) {
- feedClause = "feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)";
- } else {
- feedClause = "feed_id = ?";
- }
-
- String orderBy = (m_prefs.getBoolean("offline_oldest_first", false)) ? "updated" : "updated DESC";
-
- if (m_searchQuery == null || m_searchQuery.equals("")) {
- return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles.*", "feeds.title AS feed_title" }, feedClause,
- new String[] { String.valueOf(m_feedId) }, null, null, orderBy);
- } else {
- return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles.*", "feeds.title AS feed_title" },
- feedClause + " AND (articles.title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%')",
- new String[] { String.valueOf(m_feedId), m_searchQuery, m_searchQuery }, null, null, orderBy);
- }
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- m_listener = (OfflineHeadlinesEventListener) activity;
- m_activity = (OfflineActivity) activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- }
-
- @Override
- public void onItemClick(AdapterView<?> av, View view, int position, long id) {
- ListView list = (ListView)av;
-
- Log.d(TAG, "onItemClick=" + position);
-
- if (list != null) {
- /* Cursor cursor = (Cursor)list.getItemAtPosition(position);
-
- int articleId = cursor.getInt(0); */
-
- int articleId = getArticleIdAtPosition(position);
-
- if (getActivity().findViewById(R.id.article_fragment) != null) {
- m_activeArticleId = articleId;
- }
-
- m_listener.onArticleSelected(articleId);
-
- refresh();
- }
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("feedId", m_feedId);
- out.putInt("activeArticleId", m_activeArticleId);
- //out.putParcelableArrayList("selectedArticles", m_selectedArticles);
- out.putCharSequence("searchQuery", m_searchQuery);
- out.putBoolean("feedIsCat", m_feedIsCat);
- }
-
- /* public void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- getActivity().setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- private class ArticleListAdapter extends SimpleCursorAdapter {
- public ArticleListAdapter(Context context, int layout, Cursor c,
- String[] from, int[] to, int flags) {
- super(context, layout, c, from, to, flags);
- // TODO Auto-generated constructor stub
- }
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_UNREAD = 1;
- public static final int VIEW_SELECTED = 2;
- public static final int VIEW_SELECTED_UNREAD = 3;
- public static final int VIEW_LOADMORE = 4;
-
- public static final int VIEW_COUNT = VIEW_LOADMORE+1;
-
-
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- Cursor c = (Cursor) getItem(position);
-
- //Log.d(TAG, "@gIVT " + position + " " + c.getInt(0) + " vs " + m_activeArticleId);
-
- if (c.getInt(0) == m_activeArticleId && c.getInt(c.getColumnIndex("unread")) == 1) {
- return VIEW_SELECTED_UNREAD;
- } else if (c.getInt(0) == m_activeArticleId) {
- return VIEW_SELECTED;
- } else if (c.getInt(c.getColumnIndex("unread")) == 1) {
- return VIEW_UNREAD;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- View v = convertView;
-
- Cursor article = (Cursor)getItem(position);
- final int articleId = article.getInt(0);
-
- if (v == null) {
- int layoutId = R.layout.headlines_row;
-
- switch (getItemViewType(position)) {
- case VIEW_LOADMORE:
- layoutId = R.layout.headlines_row_loadmore;
- break;
- case VIEW_UNREAD:
- layoutId = R.layout.headlines_row_unread;
- break;
- case VIEW_SELECTED_UNREAD:
- layoutId = R.layout.headlines_row_selected_unread;
- break;
- case VIEW_SELECTED:
- layoutId = R.layout.headlines_row_selected;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- // http://code.google.com/p/android/issues/detail?id=3414
- ((ViewGroup)v).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- }
-
- TextView tt = (TextView)v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(Html.fromHtml(article.getString(article.getColumnIndex("title"))));
- }
-
- TextView ft = (TextView)v.findViewById(R.id.feed_title);
-
- int feedTitleIndex = article.getColumnIndex("feed_title");
-
- if (ft != null && feedTitleIndex != -1 && m_feedIsCat) {
- String feedTitle = article.getString(feedTitleIndex);
-
- if (feedTitle.length() > 20)
- feedTitle = feedTitle.substring(0, 20) + "...";
-
- if (feedTitle.length() > 0) {
- ft.setText(feedTitle);
- } else {
- ft.setVisibility(View.GONE);
- }
- } else if (ft != null) {
- ft.setVisibility(View.GONE);
- }
-
- ImageView marked = (ImageView)v.findViewById(R.id.marked);
-
- if (marked != null) {
- marked.setImageResource(article.getInt(article.getColumnIndex("marked")) == 1 ? android.R.drawable.star_on : android.R.drawable.star_off);
-
- marked.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET modified = 1, marked = NOT marked " +
- "WHERE " + BaseColumns._ID + " = ?");
-
- stmtUpdate.bindLong(1, articleId);
- stmtUpdate.execute();
- stmtUpdate.close();
-
- refresh();
- }
- });
- }
-
- ImageView published = (ImageView)v.findViewById(R.id.published);
-
- if (published != null) {
- published.setImageResource(article.getInt(article.getColumnIndex("published")) == 1 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
-
- published.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET modified = 1, published = NOT published " +
- "WHERE " + BaseColumns._ID + " = ?");
-
- stmtUpdate.bindLong(1, articleId);
- stmtUpdate.execute();
- stmtUpdate.close();
-
- refresh();
- }
- });
- }
-
- TextView te = (TextView)v.findViewById(R.id.excerpt);
-
- if (te != null) {
- String excerpt = Jsoup.parse(article.getString(article.getColumnIndex("content"))).text();
-
- if (excerpt.length() > 100)
- excerpt = excerpt.substring(0, 100) + "...";
-
- te.setText(excerpt);
- }
-
- /* ImageView separator = (ImageView)v.findViewById(R.id.headlines_separator);
-
- if (separator != null && m_offlineServices.isSmallScreen()) {
- separator.setVisibility(View.GONE);
- } */
-
- TextView dv = (TextView) v.findViewById(R.id.date);
-
- if (dv != null) {
- Date d = new Date((long)article.getInt(article.getColumnIndex("updated")) * 1000);
- DateFormat df = new SimpleDateFormat("MMM dd, HH:mm");
- df.setTimeZone(TimeZone.getDefault());
- dv.setText(df.format(d));
- }
-
- CheckBox cb = (CheckBox) v.findViewById(R.id.selected);
-
- if (cb != null) {
- cb.setChecked(article.getInt(article.getColumnIndex("selected")) == 1);
- cb.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View view) {
- CheckBox cb = (CheckBox)view;
-
- SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET selected = ? " +
- "WHERE " + BaseColumns._ID + " = ?");
-
- stmtUpdate.bindLong(1, cb.isChecked() ? 1 : 0);
- stmtUpdate.bindLong(2, articleId);
- stmtUpdate.execute();
- stmtUpdate.close();
-
- refresh();
-
- m_activity.initMenu();
-
- }
- });
- }
-
- /* ImageButton ib = (ImageButton) v.findViewById(R.id.article_menu_button);
-
- if (ib != null) {
- ib.setVisibility(android.os.Build.VERSION.SDK_INT >= 10 ? View.VISIBLE : View.GONE);
- ib.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- getActivity().openContextMenu(v);
- }
- });
- } */
-
- return v;
- }
- }
-
- public void notifyUpdated() {
- m_adapter.notifyDataSetChanged();
- }
-
- public void setActiveArticleId(int articleId) {
- m_activeArticleId = articleId;
- try {
- m_adapter.notifyDataSetChanged();
-
- ListView list = (ListView)getView().findViewById(R.id.headlines);
-
- Log.d(TAG, articleId + " position " + getArticleIdPosition(articleId));
-
- if (list != null) {
- list.setSelection(getArticleIdPosition(articleId));
- }
- } catch (NullPointerException e) {
- // invoked before view is created, nvm
- }
- }
-
- public Cursor getArticleAtPosition(int position) {
- return (Cursor) m_adapter.getItem(position);
- }
-
- public int getArticleIdAtPosition(int position) {
- /*Cursor c = getArticleAtPosition(position);
-
- if (c != null) {
- int id = c.getInt(0);
- return id;
- } */
-
- return (int) m_adapter.getItemId(position);
- }
-
- public int getActiveArticleId() {
- return m_activeArticleId;
- }
-
- public int getArticleIdPosition(int articleId) {
- for (int i = 0; i < m_adapter.getCount(); i++) {
- if (articleId == m_adapter.getItemId(i))
- return i;
- }
-
- return -1;
- }
-
- public int getArticleCount() {
- return m_adapter.getCount();
- }
-
- public void setSearchQuery(String query) {
- if (!m_searchQuery.equals(query)) {
- m_searchQuery = query;
- }
- }
-
- public int getFeedId() {
- return m_feedId;
- }
-
- public boolean getFeedIsCat() {
- return m_feedIsCat;
- }
-
- public String getSearchQuery() {
- return m_searchQuery;
- }
-
-}
+package org.fox.ttrss.offline; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import org.fox.ttrss.GlobalState; +import org.fox.ttrss.R; +import org.jsoup.Jsoup; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SimpleCursorAdapter; +import android.text.Html; +import android.text.Html.ImageGetter; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +public class OfflineHeadlinesFragment extends Fragment implements OnItemClickListener { + public static enum ArticlesSelection { ALL, NONE, UNREAD }; + + private final String TAG = this.getClass().getSimpleName(); + + private int m_feedId; + private boolean m_feedIsCat = false; + private int m_activeArticleId; + private String m_searchQuery = ""; + + private SharedPreferences m_prefs; + + private Cursor m_cursor; + private ArticleListAdapter m_adapter; + + private OfflineHeadlinesEventListener m_listener; + private OfflineActivity m_activity; + + private ImageGetter m_dummyGetter = new ImageGetter() { + + @SuppressWarnings("deprecation") + @Override + public Drawable getDrawable(String source) { + return new BitmapDrawable(); + } + + }; + + public OfflineHeadlinesFragment(int feedId, boolean isCat) { + m_feedId = feedId; + m_feedIsCat = isCat; + } + + public OfflineHeadlinesFragment() { + // + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + } + + public int getSelectedArticleCount() { + Cursor c = m_activity.getReadableDb().query("articles", + new String[] { "COUNT(*)" }, "selected = 1", null, null, null, null); + c.moveToFirst(); + int selected = c.getInt(0); + c.close(); + + return selected; + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + + switch (item.getItemId()) { + case R.id.article_link_copy: + if (true) { + int articleId = getArticleIdAtPosition(info.position); + + Cursor article = m_activity.getArticleById(articleId); + + if (article != null) { + m_activity.copyToClipboard(article.getString(article.getColumnIndex("link"))); + article.close(); + } + } + return true; + case R.id.selection_toggle_marked: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = m_activity.getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, marked = NOT marked WHERE selected = 1"); + stmt.execute(); + stmt.close(); + } else { + int articleId = getArticleIdAtPosition(info.position); + + SQLiteStatement stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, marked = NOT marked WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + } + refresh(); + return true; + case R.id.selection_toggle_published: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = m_activity.getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, published = NOT published WHERE selected = 1"); + stmt.execute(); + stmt.close(); + } else { + int articleId = getArticleIdAtPosition(info.position); + + SQLiteStatement stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, published = NOT published WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + } + refresh(); + return true; + case R.id.selection_toggle_unread: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = m_activity.getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, unread = NOT unread WHERE selected = 1"); + stmt.execute(); + stmt.close(); + } else { + int articleId = getArticleIdAtPosition(info.position); + + SQLiteStatement stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = NOT unread WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + } + refresh(); + return true; + case R.id.share_article: + if (true) { + int articleId = getArticleIdAtPosition(info.position); + m_activity.shareArticle(articleId); + } + return true; + case R.id.catchup_above: + if (true) { + int articleId = getArticleIdAtPosition(info.position); + + SQLiteStatement stmt = null; + + String updatedOperator = (m_prefs.getBoolean("offline_oldest_first", false)) ? "<" : ">"; + + if (m_feedIsCat) { + stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE " + + "updated "+updatedOperator+" (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " + + "AND unread = 1 AND feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + } else { + stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE " + + "updated "+updatedOperator+" (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " + + "AND unread = 1 AND feed_id = ?"); + } + + stmt.bindLong(1, articleId); + stmt.bindLong(2, m_feedId); + stmt.execute(); + stmt.close(); + } + refresh(); + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.headlines_context_menu, menu); + + if (getSelectedArticleCount() > 0) { + menu.setHeaderTitle(R.string.headline_context_multiple); + menu.setGroupVisible(R.id.menu_group_single_article, false); + } else { + AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo; + Cursor c = getArticleAtPosition(info.position); + menu.setHeaderTitle(c.getString(c.getColumnIndex("title"))); + //c.close(); + menu.setGroupVisible(R.id.menu_group_single_article, true); + + menu.findItem(R.id.set_labels).setVisible(false); + menu.findItem(R.id.article_set_note).setVisible(false); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + @Override + public void onResume() { + super.onResume(); + + if (GlobalState.getInstance().m_selectedArticleId != 0) { + m_activeArticleId = GlobalState.getInstance().m_selectedArticleId; + GlobalState.getInstance().m_selectedArticleId = 0; + } + + if (m_activeArticleId != 0) { + setActiveArticleId(m_activeArticleId); + } + + refresh(); + } + + public void refresh() { + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + + m_cursor = createCursor(); + + if (m_cursor != null) { + m_adapter.changeCursor(m_cursor); + m_adapter.notifyDataSetChanged(); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_feedId = savedInstanceState.getInt("feedId"); + m_activeArticleId = savedInstanceState.getInt("activeArticleId"); + //m_selectedArticles = savedInstanceState.getParcelableArrayList("selectedArticles"); + m_searchQuery = (String) savedInstanceState.getCharSequence("searchQuery"); + m_feedIsCat = savedInstanceState.getBoolean("feedIsCat"); + } else { + m_activity.getWritableDb().execSQL("UPDATE articles SET selected = 0 "); + } + + View view = inflater.inflate(R.layout.headlines_fragment, container, false); + + m_cursor = createCursor(); + + ListView list = (ListView)view.findViewById(R.id.headlines); + m_adapter = new ArticleListAdapter(getActivity(), R.layout.headlines_row, m_cursor, + new String[] { "title" }, new int[] { R.id.title }, 0); + + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + list.setEmptyView(view.findViewById(R.id.no_headlines)); + registerForContextMenu(list); + + if (m_activity.isSmallScreen() || m_activity.isPortrait()) + view.findViewById(R.id.headlines_fragment).setPadding(0, 0, 0, 0); + + getActivity().setProgressBarIndeterminateVisibility(false); + + return view; + } + + public Cursor createCursor() { + String feedClause = null; + + if (m_feedIsCat) { + feedClause = "feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"; + } else { + feedClause = "feed_id = ?"; + } + + String orderBy = (m_prefs.getBoolean("offline_oldest_first", false)) ? "updated" : "updated DESC"; + + if (m_searchQuery == null || m_searchQuery.equals("")) { + return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles.*", "feeds.title AS feed_title" }, feedClause, + new String[] { String.valueOf(m_feedId) }, null, null, orderBy); + } else { + return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles.*", "feeds.title AS feed_title" }, + feedClause + " AND (articles.title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%')", + new String[] { String.valueOf(m_feedId), m_searchQuery, m_searchQuery }, null, null, orderBy); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + m_listener = (OfflineHeadlinesEventListener) activity; + m_activity = (OfflineActivity) activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + } + + @Override + public void onItemClick(AdapterView<?> av, View view, int position, long id) { + ListView list = (ListView)av; + + Log.d(TAG, "onItemClick=" + position); + + if (list != null) { + /* Cursor cursor = (Cursor)list.getItemAtPosition(position); + + int articleId = cursor.getInt(0); */ + + int articleId = getArticleIdAtPosition(position); + + if (getActivity().findViewById(R.id.article_fragment) != null) { + m_activeArticleId = articleId; + } + + m_listener.onArticleSelected(articleId); + + refresh(); + } + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("feedId", m_feedId); + out.putInt("activeArticleId", m_activeArticleId); + //out.putParcelableArrayList("selectedArticles", m_selectedArticles); + out.putCharSequence("searchQuery", m_searchQuery); + out.putBoolean("feedIsCat", m_feedIsCat); + } + + /* public void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + getActivity().setProgressBarIndeterminateVisibility(showProgress); + } */ + + private class ArticleListAdapter extends SimpleCursorAdapter { + public ArticleListAdapter(Context context, int layout, Cursor c, + String[] from, int[] to, int flags) { + super(context, layout, c, from, to, flags); + // TODO Auto-generated constructor stub + } + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_UNREAD = 1; + public static final int VIEW_SELECTED = 2; + public static final int VIEW_SELECTED_UNREAD = 3; + public static final int VIEW_LOADMORE = 4; + + public static final int VIEW_COUNT = VIEW_LOADMORE+1; + + + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + Cursor c = (Cursor) getItem(position); + + //Log.d(TAG, "@gIVT " + position + " " + c.getInt(0) + " vs " + m_activeArticleId); + + if (c.getInt(0) == m_activeArticleId && c.getInt(c.getColumnIndex("unread")) == 1) { + return VIEW_SELECTED_UNREAD; + } else if (c.getInt(0) == m_activeArticleId) { + return VIEW_SELECTED; + } else if (c.getInt(c.getColumnIndex("unread")) == 1) { + return VIEW_UNREAD; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + View v = convertView; + + Cursor article = (Cursor)getItem(position); + final int articleId = article.getInt(0); + + if (v == null) { + int layoutId = R.layout.headlines_row; + + switch (getItemViewType(position)) { + case VIEW_LOADMORE: + layoutId = R.layout.headlines_row_loadmore; + break; + case VIEW_UNREAD: + layoutId = R.layout.headlines_row_unread; + break; + case VIEW_SELECTED_UNREAD: + layoutId = R.layout.headlines_row_selected_unread; + break; + case VIEW_SELECTED: + layoutId = R.layout.headlines_row_selected; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + // http://code.google.com/p/android/issues/detail?id=3414 + ((ViewGroup)v).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + } + + TextView tt = (TextView)v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(Html.fromHtml(article.getString(article.getColumnIndex("title")))); + } + + TextView ft = (TextView)v.findViewById(R.id.feed_title); + + int feedTitleIndex = article.getColumnIndex("feed_title"); + + if (ft != null && feedTitleIndex != -1 && m_feedIsCat) { + String feedTitle = article.getString(feedTitleIndex); + + if (feedTitle.length() > 20) + feedTitle = feedTitle.substring(0, 20) + "..."; + + if (feedTitle.length() > 0) { + ft.setText(feedTitle); + } else { + ft.setVisibility(View.GONE); + } + } else if (ft != null) { + ft.setVisibility(View.GONE); + } + + ImageView marked = (ImageView)v.findViewById(R.id.marked); + + if (marked != null) { + marked.setImageResource(article.getInt(article.getColumnIndex("marked")) == 1 ? android.R.drawable.star_on : android.R.drawable.star_off); + + marked.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET modified = 1, marked = NOT marked " + + "WHERE " + BaseColumns._ID + " = ?"); + + stmtUpdate.bindLong(1, articleId); + stmtUpdate.execute(); + stmtUpdate.close(); + + refresh(); + } + }); + } + + ImageView published = (ImageView)v.findViewById(R.id.published); + + if (published != null) { + published.setImageResource(article.getInt(article.getColumnIndex("published")) == 1 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + + published.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET modified = 1, published = NOT published " + + "WHERE " + BaseColumns._ID + " = ?"); + + stmtUpdate.bindLong(1, articleId); + stmtUpdate.execute(); + stmtUpdate.close(); + + refresh(); + } + }); + } + + TextView te = (TextView)v.findViewById(R.id.excerpt); + + if (te != null) { + String excerpt = Jsoup.parse(article.getString(article.getColumnIndex("content"))).text(); + + if (excerpt.length() > 100) + excerpt = excerpt.substring(0, 100) + "..."; + + te.setText(excerpt); + } + + /* ImageView separator = (ImageView)v.findViewById(R.id.headlines_separator); + + if (separator != null && m_offlineServices.isSmallScreen()) { + separator.setVisibility(View.GONE); + } */ + + TextView dv = (TextView) v.findViewById(R.id.date); + + if (dv != null) { + Date d = new Date((long)article.getInt(article.getColumnIndex("updated")) * 1000); + DateFormat df = new SimpleDateFormat("MMM dd, HH:mm"); + df.setTimeZone(TimeZone.getDefault()); + dv.setText(df.format(d)); + } + + CheckBox cb = (CheckBox) v.findViewById(R.id.selected); + + if (cb != null) { + cb.setChecked(article.getInt(article.getColumnIndex("selected")) == 1); + cb.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View view) { + CheckBox cb = (CheckBox)view; + + SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET selected = ? " + + "WHERE " + BaseColumns._ID + " = ?"); + + stmtUpdate.bindLong(1, cb.isChecked() ? 1 : 0); + stmtUpdate.bindLong(2, articleId); + stmtUpdate.execute(); + stmtUpdate.close(); + + refresh(); + + m_activity.initMenu(); + + } + }); + } + + /* ImageButton ib = (ImageButton) v.findViewById(R.id.article_menu_button); + + if (ib != null) { + ib.setVisibility(android.os.Build.VERSION.SDK_INT >= 10 ? View.VISIBLE : View.GONE); + ib.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + getActivity().openContextMenu(v); + } + }); + } */ + + return v; + } + } + + public void notifyUpdated() { + m_adapter.notifyDataSetChanged(); + } + + public void setActiveArticleId(int articleId) { + m_activeArticleId = articleId; + try { + m_adapter.notifyDataSetChanged(); + + ListView list = (ListView)getView().findViewById(R.id.headlines); + + Log.d(TAG, articleId + " position " + getArticleIdPosition(articleId)); + + if (list != null) { + list.setSelection(getArticleIdPosition(articleId)); + } + } catch (NullPointerException e) { + // invoked before view is created, nvm + } + } + + public Cursor getArticleAtPosition(int position) { + return (Cursor) m_adapter.getItem(position); + } + + public int getArticleIdAtPosition(int position) { + /*Cursor c = getArticleAtPosition(position); + + if (c != null) { + int id = c.getInt(0); + return id; + } */ + + return (int) m_adapter.getItemId(position); + } + + public int getActiveArticleId() { + return m_activeArticleId; + } + + public int getArticleIdPosition(int articleId) { + for (int i = 0; i < m_adapter.getCount(); i++) { + if (articleId == m_adapter.getItemId(i)) + return i; + } + + return -1; + } + + public int getArticleCount() { + return m_adapter.getCount(); + } + + public void setSearchQuery(String query) { + if (!m_searchQuery.equals(query)) { + m_searchQuery = query; + } + } + + public int getFeedId() { + return m_feedId; + } + + public boolean getFeedIsCat() { + return m_feedIsCat; + } + + public String getSearchQuery() { + return m_searchQuery; + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineUploadService.java b/src/org/fox/ttrss/offline/OfflineUploadService.java index 3624bdf7..55ed4467 100644 --- a/src/org/fox/ttrss/offline/OfflineUploadService.java +++ b/src/org/fox/ttrss/offline/OfflineUploadService.java @@ -1,273 +1,273 @@ -package org.fox.ttrss.offline;
-
-import java.util.HashMap;
-
-import org.fox.ttrss.ApiRequest;
-import org.fox.ttrss.OnlineActivity;
-import org.fox.ttrss.R;
-import org.fox.ttrss.util.DatabaseHelper;
-
-import android.app.IntentService;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.util.Log;
-
-import com.google.gson.JsonElement;
-
-public class OfflineUploadService extends IntentService {
- private final String TAG = this.getClass().getSimpleName();
-
- public static final int NOTIFY_UPLOADING = 2;
- public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.UploadComplete";
-
- private SQLiteDatabase m_writableDb;
- private SQLiteDatabase m_readableDb;
- private String m_sessionId;
- private NotificationManager m_nmgr;
- private boolean m_uploadInProgress = false;
-
- public OfflineUploadService() {
- super("OfflineUploadService");
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- initDatabase();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- m_nmgr.cancel(NOTIFY_UPLOADING);
- }
-
- @SuppressWarnings("deprecation")
- private void updateNotification(String msg) {
- Notification notification = new Notification(R.drawable.icon,
- getString(R.string.notify_uploading_title), System.currentTimeMillis());
-
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- new Intent(this, OnlineActivity.class), 0);
-
- notification.flags |= Notification.FLAG_ONGOING_EVENT;
- notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
-
- notification.setLatestEventInfo(this, getString(R.string.notify_uploading_title), msg, contentIntent);
-
- m_nmgr.notify(NOTIFY_UPLOADING, notification);
- }
-
- private void updateNotification(int msgResId) {
- updateNotification(getString(msgResId));
- }
-
- private void initDatabase() {
- DatabaseHelper dh = new DatabaseHelper(getApplicationContext());
- m_writableDb = dh.getWritableDatabase();
- m_readableDb = dh.getReadableDatabase();
- }
-
- private synchronized SQLiteDatabase getReadableDb() {
- return m_readableDb;
- }
-
- private synchronized SQLiteDatabase getWritableDb() {
- return m_writableDb;
- }
-
- private void uploadRead() {
- Log.d(TAG, "syncing modified offline data... (read)");
-
- final String ids = getModifiedIds(ModifiedCriteria.READ);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- uploadMarked();
- } else {
- updateNotification(getErrorMessage());
- uploadFailed();
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "0");
- put("field", "2");
- }
- };
-
- req.execute(map);
- } else {
- uploadMarked();
- }
- }
-
- private enum ModifiedCriteria {
- READ, MARKED, PUBLISHED
- };
-
- private String getModifiedIds(ModifiedCriteria criteria) {
-
- String criteriaStr = "";
-
- switch (criteria) {
- case READ:
- criteriaStr = "unread = 0";
- break;
- case MARKED:
- criteriaStr = "marked = 1";
- break;
- case PUBLISHED:
- criteriaStr = "published = 1";
- break;
- }
-
- Cursor c = getReadableDb().query("articles", null,
- "modified = 1 AND " + criteriaStr, null, null, null, null);
-
- String tmp = "";
-
- while (c.moveToNext()) {
- tmp += c.getInt(0) + ",";
- }
-
- tmp = tmp.replaceAll(",$", "");
-
- c.close();
-
- return tmp;
- }
-
- private void uploadMarked() {
- Log.d(TAG, "syncing modified offline data... (marked)");
-
- final String ids = getModifiedIds(ModifiedCriteria.MARKED);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- uploadPublished();
- } else {
- updateNotification(getErrorMessage());
- uploadFailed();
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "1");
- put("field", "0");
- }
- };
-
- req.execute(map);
- } else {
- uploadPublished();
- }
- }
-
- private void uploadFailed() {
- m_readableDb.close();
- m_writableDb.close();
-
- // TODO send notification to activity?
-
- m_uploadInProgress = false;
- }
-
- private void uploadSuccess() {
- getWritableDb().execSQL("UPDATE articles SET modified = 0");
-
- Intent intent = new Intent();
- intent.setAction(INTENT_ACTION_SUCCESS);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- sendBroadcast(intent);
-
- m_readableDb.close();
- m_writableDb.close();
-
- m_uploadInProgress = false;
-
- m_nmgr.cancel(NOTIFY_UPLOADING);
- }
-
- private void uploadPublished() {
- Log.d(TAG, "syncing modified offline data... (published)");
-
- final String ids = getModifiedIds(ModifiedCriteria.MARKED);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- uploadSuccess();
- } else {
- updateNotification(getErrorMessage());
- uploadFailed();
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "1");
- put("field", "1");
- }
- };
-
- req.execute(map);
- } else {
- uploadSuccess();
- }
- }
-
-
- @Override
- protected void onHandleIntent(Intent intent) {
- try {
- if (getWritableDb().isDbLockedByCurrentThread() || getWritableDb().isDbLockedByOtherThreads()) {
- return;
- }
-
- m_sessionId = intent.getStringExtra("sessionId");
-
- if (!m_uploadInProgress) {
- m_uploadInProgress = true;
-
- updateNotification(R.string.notify_uploading_sending_data);
-
- uploadRead();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
+package org.fox.ttrss.offline; + +import java.util.HashMap; + +import org.fox.ttrss.ApiRequest; +import org.fox.ttrss.OnlineActivity; +import org.fox.ttrss.R; +import org.fox.ttrss.util.DatabaseHelper; + +import android.app.IntentService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.util.Log; + +import com.google.gson.JsonElement; + +public class OfflineUploadService extends IntentService { + private final String TAG = this.getClass().getSimpleName(); + + public static final int NOTIFY_UPLOADING = 2; + public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.UploadComplete"; + + private SQLiteDatabase m_writableDb; + private SQLiteDatabase m_readableDb; + private String m_sessionId; + private NotificationManager m_nmgr; + private boolean m_uploadInProgress = false; + + public OfflineUploadService() { + super("OfflineUploadService"); + } + + @Override + public void onCreate() { + super.onCreate(); + m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + initDatabase(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + m_nmgr.cancel(NOTIFY_UPLOADING); + } + + @SuppressWarnings("deprecation") + private void updateNotification(String msg) { + Notification notification = new Notification(R.drawable.icon, + getString(R.string.notify_uploading_title), System.currentTimeMillis()); + + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + new Intent(this, OnlineActivity.class), 0); + + notification.flags |= Notification.FLAG_ONGOING_EVENT; + notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE; + + notification.setLatestEventInfo(this, getString(R.string.notify_uploading_title), msg, contentIntent); + + m_nmgr.notify(NOTIFY_UPLOADING, notification); + } + + private void updateNotification(int msgResId) { + updateNotification(getString(msgResId)); + } + + private void initDatabase() { + DatabaseHelper dh = new DatabaseHelper(getApplicationContext()); + m_writableDb = dh.getWritableDatabase(); + m_readableDb = dh.getReadableDatabase(); + } + + private synchronized SQLiteDatabase getReadableDb() { + return m_readableDb; + } + + private synchronized SQLiteDatabase getWritableDb() { + return m_writableDb; + } + + private void uploadRead() { + Log.d(TAG, "syncing modified offline data... (read)"); + + final String ids = getModifiedIds(ModifiedCriteria.READ); + + if (ids.length() > 0) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + uploadMarked(); + } else { + updateNotification(getErrorMessage()); + uploadFailed(); + } + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", ids); + put("mode", "0"); + put("field", "2"); + } + }; + + req.execute(map); + } else { + uploadMarked(); + } + } + + private enum ModifiedCriteria { + READ, MARKED, PUBLISHED + }; + + private String getModifiedIds(ModifiedCriteria criteria) { + + String criteriaStr = ""; + + switch (criteria) { + case READ: + criteriaStr = "unread = 0"; + break; + case MARKED: + criteriaStr = "marked = 1"; + break; + case PUBLISHED: + criteriaStr = "published = 1"; + break; + } + + Cursor c = getReadableDb().query("articles", null, + "modified = 1 AND " + criteriaStr, null, null, null, null); + + String tmp = ""; + + while (c.moveToNext()) { + tmp += c.getInt(0) + ","; + } + + tmp = tmp.replaceAll(",$", ""); + + c.close(); + + return tmp; + } + + private void uploadMarked() { + Log.d(TAG, "syncing modified offline data... (marked)"); + + final String ids = getModifiedIds(ModifiedCriteria.MARKED); + + if (ids.length() > 0) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + uploadPublished(); + } else { + updateNotification(getErrorMessage()); + uploadFailed(); + } + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", ids); + put("mode", "1"); + put("field", "0"); + } + }; + + req.execute(map); + } else { + uploadPublished(); + } + } + + private void uploadFailed() { + m_readableDb.close(); + m_writableDb.close(); + + // TODO send notification to activity? + + m_uploadInProgress = false; + } + + private void uploadSuccess() { + getWritableDb().execSQL("UPDATE articles SET modified = 0"); + + Intent intent = new Intent(); + intent.setAction(INTENT_ACTION_SUCCESS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + sendBroadcast(intent); + + m_readableDb.close(); + m_writableDb.close(); + + m_uploadInProgress = false; + + m_nmgr.cancel(NOTIFY_UPLOADING); + } + + private void uploadPublished() { + Log.d(TAG, "syncing modified offline data... (published)"); + + final String ids = getModifiedIds(ModifiedCriteria.MARKED); + + if (ids.length() > 0) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + uploadSuccess(); + } else { + updateNotification(getErrorMessage()); + uploadFailed(); + } + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", ids); + put("mode", "1"); + put("field", "1"); + } + }; + + req.execute(map); + } else { + uploadSuccess(); + } + } + + + @Override + protected void onHandleIntent(Intent intent) { + try { + if (getWritableDb().isDbLockedByCurrentThread() || getWritableDb().isDbLockedByOtherThreads()) { + return; + } + + m_sessionId = intent.getStringExtra("sessionId"); + + if (!m_uploadInProgress) { + m_uploadInProgress = true; + + updateNotification(R.string.notify_uploading_sending_data); + + uploadRead(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/org/fox/ttrss/share/CommonActivity.java b/src/org/fox/ttrss/share/CommonActivity.java index 808bd31e..21c8e443 100644 --- a/src/org/fox/ttrss/share/CommonActivity.java +++ b/src/org/fox/ttrss/share/CommonActivity.java @@ -1,57 +1,57 @@ -package org.fox.ttrss.share;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Display;
-import android.widget.Toast;
-
-public class CommonActivity extends Activity {
- private final String TAG = this.getClass().getSimpleName();
-
- private boolean m_smallScreenMode = true;
- private boolean m_compatMode = false;
-
- protected void setSmallScreen(boolean smallScreen) {
- Log.d(TAG, "m_smallScreenMode=" + smallScreen);
- m_smallScreenMode = smallScreen;
- }
-
- public void toast(int msgId) {
- Toast toast = Toast.makeText(CommonActivity.this, msgId, Toast.LENGTH_SHORT);
- toast.show();
- }
-
- public void toast(String msg) {
- Toast toast = Toast.makeText(CommonActivity.this, msg, Toast.LENGTH_SHORT);
- toast.show();
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_compatMode = android.os.Build.VERSION.SDK_INT <= 10;
-
- Log.d(TAG, "m_compatMode=" + m_compatMode);
-
- super.onCreate(savedInstanceState);
- }
-
- public boolean isSmallScreen() {
- return m_smallScreenMode;
- }
-
- public boolean isCompatMode() {
- return m_compatMode;
- }
-
- public boolean isPortrait() {
- Display display = getWindowManager().getDefaultDisplay();
-
- int width = display.getWidth();
- int height = display.getHeight();
-
- return width < height;
- }
-
-
-}
+package org.fox.ttrss.share; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.Display; +import android.widget.Toast; + +public class CommonActivity extends Activity { + private final String TAG = this.getClass().getSimpleName(); + + private boolean m_smallScreenMode = true; + private boolean m_compatMode = false; + + protected void setSmallScreen(boolean smallScreen) { + Log.d(TAG, "m_smallScreenMode=" + smallScreen); + m_smallScreenMode = smallScreen; + } + + public void toast(int msgId) { + Toast toast = Toast.makeText(CommonActivity.this, msgId, Toast.LENGTH_SHORT); + toast.show(); + } + + public void toast(String msg) { + Toast toast = Toast.makeText(CommonActivity.this, msg, Toast.LENGTH_SHORT); + toast.show(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + m_compatMode = android.os.Build.VERSION.SDK_INT <= 10; + + Log.d(TAG, "m_compatMode=" + m_compatMode); + + super.onCreate(savedInstanceState); + } + + public boolean isSmallScreen() { + return m_smallScreenMode; + } + + public boolean isCompatMode() { + return m_compatMode; + } + + public boolean isPortrait() { + Display display = getWindowManager().getDefaultDisplay(); + + int width = display.getWidth(); + int height = display.getHeight(); + + return width < height; + } + + +} diff --git a/src/org/fox/ttrss/share/CommonShareActivity.java b/src/org/fox/ttrss/share/CommonShareActivity.java index ab90d08c..4935e44e 100644 --- a/src/org/fox/ttrss/share/CommonShareActivity.java +++ b/src/org/fox/ttrss/share/CommonShareActivity.java @@ -1,186 +1,186 @@ -package org.fox.ttrss.share;
-
-import java.util.HashMap;
-
-import org.fox.ttrss.ApiRequest;
-import org.fox.ttrss.PreferencesActivity;
-import org.fox.ttrss.R;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-
-public abstract class CommonShareActivity extends CommonActivity {
- protected SharedPreferences m_prefs;
- protected String m_sessionId;
- protected int m_apiLevel = 0;
-
- private final String TAG = this.getClass().getSimpleName();
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- super.onCreate(savedInstanceState);
-
- if (savedInstanceState != null) {
- m_sessionId = savedInstanceState.getString("sessionId");
- m_apiLevel = savedInstanceState.getInt("apiLevel");
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putString("sessionId", m_sessionId);
- out.putInt("apiLevel", m_apiLevel);
- }
-
- protected abstract void onLoggedIn(int requestId);
-
- protected abstract void onLoggingIn(int requestId);
-
- @SuppressWarnings({ "unchecked", "serial" })
- public void login(int requestId) {
-
- if (m_prefs.getString("ttrss_url", "").trim().length() == 0) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(R.string.dialog_need_configure_prompt)
- .setCancelable(false)
- .setPositiveButton(R.string.dialog_open_preferences, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- // launch preferences
-
- Intent intent = new Intent(CommonShareActivity.this,
- PreferencesActivity.class);
- startActivityForResult(intent, 0);
- }
- })
- .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
-
- } else {
-
- LoginRequest ar = new LoginRequest(getApplicationContext(), requestId);
-
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("op", "login");
- put("user", m_prefs.getString("login", "").trim());
- put("password", m_prefs.getString("password", "").trim());
- }
- };
-
- onLoggingIn(requestId);
-
- ar.execute(map);
- }
- }
-
- protected class LoginRequest extends ApiRequest {
- private int m_requestId;
-
- public LoginRequest(Context context, int requestId) {
- super(context);
- m_requestId = requestId;
- }
-
- @SuppressWarnings("unchecked")
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- try {
- JsonObject content = result.getAsJsonObject();
- if (content != null) {
- m_sessionId = content.get("session_id").getAsString();
-
- Log.d(TAG, "Authenticated!");
-
- ApiRequest req = new ApiRequest(m_context) {
- protected void onPostExecute(JsonElement result) {
- m_apiLevel = 0;
-
- if (result != null) {
- try {
- m_apiLevel = result.getAsJsonObject()
- .get("level").getAsInt();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- Log.d(TAG, "Received API level: " + m_apiLevel);
-
- onLoggedIn(m_requestId);
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "getApiLevel");
- }
- };
-
- req.execute(map);
-
- return;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- m_sessionId = null;
-
- toast(getErrorMessage());
- setProgressBarIndeterminateVisibility(false);
- }
-
- }
-
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.preferences:
- Intent intent = new Intent(CommonShareActivity.this,
- PreferencesActivity.class);
- startActivityForResult(intent, 0);
- return true;
- default:
- Log.d(TAG,
- "onOptionsItemSelected, unhandled id=" + item.getItemId());
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.share_menu, menu);
- return true;
- }
-
-
-
-}
+package org.fox.ttrss.share; + +import java.util.HashMap; + +import org.fox.ttrss.ApiRequest; +import org.fox.ttrss.PreferencesActivity; +import org.fox.ttrss.R; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + + +public abstract class CommonShareActivity extends CommonActivity { + protected SharedPreferences m_prefs; + protected String m_sessionId; + protected int m_apiLevel = 0; + + private final String TAG = this.getClass().getSimpleName(); + + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + super.onCreate(savedInstanceState); + + if (savedInstanceState != null) { + m_sessionId = savedInstanceState.getString("sessionId"); + m_apiLevel = savedInstanceState.getInt("apiLevel"); + } + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putString("sessionId", m_sessionId); + out.putInt("apiLevel", m_apiLevel); + } + + protected abstract void onLoggedIn(int requestId); + + protected abstract void onLoggingIn(int requestId); + + @SuppressWarnings({ "unchecked", "serial" }) + public void login(int requestId) { + + if (m_prefs.getString("ttrss_url", "").trim().length() == 0) { + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.dialog_need_configure_prompt) + .setCancelable(false) + .setPositiveButton(R.string.dialog_open_preferences, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // launch preferences + + Intent intent = new Intent(CommonShareActivity.this, + PreferencesActivity.class); + startActivityForResult(intent, 0); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + + } else { + + LoginRequest ar = new LoginRequest(getApplicationContext(), requestId); + + HashMap<String, String> map = new HashMap<String, String>() { + { + put("op", "login"); + put("user", m_prefs.getString("login", "").trim()); + put("password", m_prefs.getString("password", "").trim()); + } + }; + + onLoggingIn(requestId); + + ar.execute(map); + } + } + + protected class LoginRequest extends ApiRequest { + private int m_requestId; + + public LoginRequest(Context context, int requestId) { + super(context); + m_requestId = requestId; + } + + @SuppressWarnings("unchecked") + protected void onPostExecute(JsonElement result) { + if (result != null) { + try { + JsonObject content = result.getAsJsonObject(); + if (content != null) { + m_sessionId = content.get("session_id").getAsString(); + + Log.d(TAG, "Authenticated!"); + + ApiRequest req = new ApiRequest(m_context) { + protected void onPostExecute(JsonElement result) { + m_apiLevel = 0; + + if (result != null) { + try { + m_apiLevel = result.getAsJsonObject() + .get("level").getAsInt(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + Log.d(TAG, "Received API level: " + m_apiLevel); + + onLoggedIn(m_requestId); + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "getApiLevel"); + } + }; + + req.execute(map); + + return; + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + m_sessionId = null; + + toast(getErrorMessage()); + setProgressBarIndeterminateVisibility(false); + } + + } + + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.preferences: + Intent intent = new Intent(CommonShareActivity.this, + PreferencesActivity.class); + startActivityForResult(intent, 0); + return true; + default: + Log.d(TAG, + "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.share_menu, menu); + return true; + } + + + +} diff --git a/src/org/fox/ttrss/share/ShareActivity.java b/src/org/fox/ttrss/share/ShareActivity.java index 8c7bcdf1..dff48502 100644 --- a/src/org/fox/ttrss/share/ShareActivity.java +++ b/src/org/fox/ttrss/share/ShareActivity.java @@ -1,146 +1,146 @@ -package org.fox.ttrss.share;
-
-import java.util.HashMap;
-
-import org.fox.ttrss.ApiRequest;
-import org.fox.ttrss.R;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.EditText;
-
-import com.google.gson.JsonElement;
-
-public class ShareActivity extends CommonShareActivity {
- private final String TAG = this.getClass().getSimpleName();
-
- private Button m_button;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- //setTheme(R.style.DarkTheme);
-
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_LEFT_ICON);
-
- Intent intent = getIntent();
-
- String urlValue = intent.getStringExtra(Intent.EXTRA_TEXT);
- String titleValue = intent.getStringExtra(Intent.EXTRA_SUBJECT);
- String contentValue = "";
-
- if (savedInstanceState != null) {
- urlValue = savedInstanceState.getString("url");
- titleValue = savedInstanceState.getString("title");
- contentValue = savedInstanceState.getString("content");
- }
-
- setContentView(R.layout.share);
-
- getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.icon);
-
- setSmallScreen(false);
-
- EditText url = (EditText) findViewById(R.id.url);
- url.setText(urlValue);
-
- EditText title = (EditText) findViewById(R.id.title);
- title.setText(titleValue);
-
- EditText content = (EditText) findViewById(R.id.content);
- content.setText(contentValue);
-
- m_button = (Button) findViewById(R.id.share_button);
-
- m_button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- login(0);
- }
- });
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- EditText url = (EditText) findViewById(R.id.url);
-
- if (url != null) {
- out.putString("url", url.getText().toString());
- }
-
- EditText title = (EditText) findViewById(R.id.title);
-
- if (title != null) {
- out.putString("title", title.getText().toString());
- }
-
- EditText content = (EditText) findViewById(R.id.content);
-
- if (content != null) {
- out.putString("content", content.getText().toString());
- }
-
- }
-
- private void postData() {
- m_button.setEnabled(false);
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- setProgressBarIndeterminateVisibility(false);
-
- if (m_lastError != ApiError.NO_ERROR) {
- toast(getErrorMessage());
- } else {
- toast(R.string.share_article_posted);
- finish();
- }
-
- m_button.setEnabled(true);
- }
- };
-
- final EditText url = (EditText) findViewById(R.id.url);
- final EditText title = (EditText) findViewById(R.id.title);
- final EditText content = (EditText) findViewById(R.id.content);
-
- if (url != null && title != null && content != null) {
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "shareToPublished");
- put("title", title.getText().toString());
- put("url", url.getText().toString());
- put("content", content.getText().toString());
- }
- };
-
- setProgressBarIndeterminateVisibility(true);
-
- req.execute(map);
- }
- }
-
-
- @Override
- public void onLoggingIn(int requestId) {
- m_button.setEnabled(false);
- }
-
- @Override
- protected void onLoggedIn(int requestId) {
- m_button.setEnabled(true);
-
- if (m_apiLevel < 4) {
- toast(R.string.api_too_low);
- } else {
- postData();
- }
- }
-}
+package org.fox.ttrss.share; + +import java.util.HashMap; + +import org.fox.ttrss.ApiRequest; +import org.fox.ttrss.R; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.Window; +import android.widget.Button; +import android.widget.EditText; + +import com.google.gson.JsonElement; + +public class ShareActivity extends CommonShareActivity { + private final String TAG = this.getClass().getSimpleName(); + + private Button m_button; + + @Override + public void onCreate(Bundle savedInstanceState) { + //setTheme(R.style.DarkTheme); + + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_LEFT_ICON); + + Intent intent = getIntent(); + + String urlValue = intent.getStringExtra(Intent.EXTRA_TEXT); + String titleValue = intent.getStringExtra(Intent.EXTRA_SUBJECT); + String contentValue = ""; + + if (savedInstanceState != null) { + urlValue = savedInstanceState.getString("url"); + titleValue = savedInstanceState.getString("title"); + contentValue = savedInstanceState.getString("content"); + } + + setContentView(R.layout.share); + + getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.icon); + + setSmallScreen(false); + + EditText url = (EditText) findViewById(R.id.url); + url.setText(urlValue); + + EditText title = (EditText) findViewById(R.id.title); + title.setText(titleValue); + + EditText content = (EditText) findViewById(R.id.content); + content.setText(contentValue); + + m_button = (Button) findViewById(R.id.share_button); + + m_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + login(0); + } + }); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + EditText url = (EditText) findViewById(R.id.url); + + if (url != null) { + out.putString("url", url.getText().toString()); + } + + EditText title = (EditText) findViewById(R.id.title); + + if (title != null) { + out.putString("title", title.getText().toString()); + } + + EditText content = (EditText) findViewById(R.id.content); + + if (content != null) { + out.putString("content", content.getText().toString()); + } + + } + + private void postData() { + m_button.setEnabled(false); + + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + setProgressBarIndeterminateVisibility(false); + + if (m_lastError != ApiError.NO_ERROR) { + toast(getErrorMessage()); + } else { + toast(R.string.share_article_posted); + finish(); + } + + m_button.setEnabled(true); + } + }; + + final EditText url = (EditText) findViewById(R.id.url); + final EditText title = (EditText) findViewById(R.id.title); + final EditText content = (EditText) findViewById(R.id.content); + + if (url != null && title != null && content != null) { + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "shareToPublished"); + put("title", title.getText().toString()); + put("url", url.getText().toString()); + put("content", content.getText().toString()); + } + }; + + setProgressBarIndeterminateVisibility(true); + + req.execute(map); + } + } + + + @Override + public void onLoggingIn(int requestId) { + m_button.setEnabled(false); + } + + @Override + protected void onLoggedIn(int requestId) { + m_button.setEnabled(true); + + if (m_apiLevel < 4) { + toast(R.string.api_too_low); + } else { + postData(); + } + } +} diff --git a/src/org/fox/ttrss/share/SubscribeActivity.java b/src/org/fox/ttrss/share/SubscribeActivity.java index eb9ed66d..d37e8818 100644 --- a/src/org/fox/ttrss/share/SubscribeActivity.java +++ b/src/org/fox/ttrss/share/SubscribeActivity.java @@ -1,304 +1,304 @@ -package org.fox.ttrss.share;
-
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-
-import org.fox.ttrss.ApiRequest;
-import org.fox.ttrss.ApiRequest.ApiError;
-import org.fox.ttrss.types.FeedCategory;
-import org.fox.ttrss.types.FeedCategoryList;
-import org.fox.ttrss.R;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.view.Window;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Spinner;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.reflect.TypeToken;
-
-public class SubscribeActivity extends CommonShareActivity {
- private final String TAG = this.getClass().getSimpleName();
-
- private Button m_postButton;
- private Button m_catButton;
- private CatListAdapter m_adapter;
- private FeedCategoryList m_cats = new FeedCategoryList();
-
- private static final int REQ_CATS = 1;
- private static final int REQ_POST = 2;
-
- class CatTitleComparator implements Comparator<FeedCategory> {
-
- @Override
- public int compare(FeedCategory a, FeedCategory b) {
- if (a.id >= 0 && b.id >= 0)
- return a.title.compareTo(b.title);
- else
- return a.id - b.id;
- }
-
- }
-
- public void sortCats() {
- Comparator<FeedCategory> cmp = new CatTitleComparator();
-
- Collections.sort(m_cats, cmp);
- try {
- m_adapter.notifyDataSetChanged();
- } catch (NullPointerException e) {
- // adapter missing
- }
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_LEFT_ICON);
-
- String urlValue = getIntent().getDataString();
-
- if (savedInstanceState != null) {
- urlValue = savedInstanceState.getString("url");
-
- ArrayList<FeedCategory> list = savedInstanceState.getParcelableArrayList("cats");
-
- for (FeedCategory c : list)
- m_cats.add(c);
- }
-
- setContentView(R.layout.subscribe);
-
- getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.icon);
-
- setSmallScreen(false);
-
- Spinner catList = (Spinner) findViewById(R.id.category_spinner);
-
- if (m_cats.size() == 0) m_cats.add(new FeedCategory(0, "Uncategorized", 0));
-
- m_adapter = new CatListAdapter(this, android.R.layout.simple_spinner_dropdown_item, m_cats);
- catList.setAdapter(m_adapter);
-
- EditText feedUrl = (EditText) findViewById(R.id.feed_url);
- feedUrl.setText(urlValue);
-
- m_postButton = (Button) findViewById(R.id.subscribe_button);
-
- m_postButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- login(REQ_POST);
- }
- });
-
- m_catButton = (Button) findViewById(R.id.cats_button);
-
- m_catButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- login(REQ_CATS);
- }
- });
-
- login(REQ_CATS);
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- EditText url = (EditText) findViewById(R.id.url);
-
- if (url != null) {
- out.putString("url", url.getText().toString());
- }
-
- out.putParcelableArrayList("cats", m_cats);
-
- }
-
- private void subscribeToFeed() {
- m_postButton.setEnabled(false);
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- setProgressBarIndeterminateVisibility(false);
-
- if (m_lastError != ApiError.NO_ERROR) {
- toast(getErrorMessage());
- } else {
- try {
- switch (m_apiStatusCode) {
- case 0:
- toast(R.string.error_feed_already_exists_);
- finish();
- break;
- case 1:
- toast(R.string.subscribed_to_feed);
- finish();
- break;
- case 2:
- toast(R.string.error_invalid_url);
- break;
- case 3:
- toast(R.string.error_url_is_an_html_page_no_feeds_found);
- break;
- case 4:
- toast(R.string.error_url_contains_multiple_feeds);
- break;
- case 5:
- toast(R.string.error_could_not_download_url);
- break;
- }
-
- } catch (Exception e) {
- toast(R.string.error_while_subscribing);
- e.printStackTrace();
- }
- }
-
- m_postButton.setEnabled(true);
- }
- };
-
- Spinner catSpinner = (Spinner) findViewById(R.id.category_spinner);
-
- final FeedCategory cat = (FeedCategory) m_adapter.getCategory(catSpinner.getSelectedItemPosition());
- final EditText feedUrl = (EditText) findViewById(R.id.feed_url);
-
- if (feedUrl != null ) {
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "subscribeToFeed");
- put("feed_url", feedUrl.getText().toString());
-
- if (cat != null) {
- put("category_id", String.valueOf(cat.id));
- }
- }
- };
-
- setProgressBarIndeterminateVisibility(true);
-
- req.execute(map);
- }
- }
-
- @Override
- public void onLoggingIn(int requestId) {
- switch (requestId) {
- case REQ_CATS:
- m_catButton.setEnabled(false);
- break;
- case REQ_POST:
- m_postButton.setEnabled(false);
- break;
- }
- }
-
- private void updateCats() {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected void onPostExecute(JsonElement result) {
- setProgressBarIndeterminateVisibility(false);
-
- if (m_lastError != ApiError.NO_ERROR) {
- toast(getErrorMessage());
- } else {
- JsonArray content = result.getAsJsonArray();
-
- if (content != null) {
- Type listType = new TypeToken<List<FeedCategory>>() {}.getType();
- final List<FeedCategory> cats = new Gson().fromJson(content, listType);
-
- m_cats.clear();
- m_cats.add(new FeedCategory(0, "Uncategorized", 0));
-
- for (FeedCategory c : cats) {
- if (c.id > 0)
- m_cats.add(c);
- }
-
- sortCats();
-
- m_adapter.notifyDataSetChanged();
-
- toast(R.string.category_list_updated);
- }
- }
-
- m_catButton.setEnabled(true);
- }
- };
-
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "getCategories");
- }
- };
-
- setProgressBarIndeterminateVisibility(true);
-
- req.execute(map);
- }
-
- @Override
- protected void onLoggedIn(int requestId) {
- switch (requestId) {
- case REQ_CATS:
- updateCats();
- break;
- case REQ_POST:
- m_postButton.setEnabled(true);
- if (m_apiLevel < 5) {
- toast(R.string.api_too_low);
- } else {
- subscribeToFeed();
- }
- break;
- }
- }
-
- private class CatListAdapter extends ArrayAdapter<String> {
- private List<FeedCategory> m_items;
-
- public CatListAdapter(Context context, int resource,
- List<FeedCategory> items) {
- super(context, resource);
-
- m_items = items;
- }
-
- @Override
- public String getItem(int item) {
- return m_items.get(item).title;
- }
-
- public FeedCategory getCategory(int item) {
- try {
- return m_items.get(item);
- } catch (ArrayIndexOutOfBoundsException e) {
- return null;
- }
- }
-
- @Override
- public int getCount() {
- return m_items.size();
- }
- }
-
-}
+package org.fox.ttrss.share; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +import org.fox.ttrss.ApiRequest; +import org.fox.ttrss.ApiRequest.ApiError; +import org.fox.ttrss.types.FeedCategory; +import org.fox.ttrss.types.FeedCategoryList; +import org.fox.ttrss.R; + +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.view.Window; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Spinner; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +public class SubscribeActivity extends CommonShareActivity { + private final String TAG = this.getClass().getSimpleName(); + + private Button m_postButton; + private Button m_catButton; + private CatListAdapter m_adapter; + private FeedCategoryList m_cats = new FeedCategoryList(); + + private static final int REQ_CATS = 1; + private static final int REQ_POST = 2; + + class CatTitleComparator implements Comparator<FeedCategory> { + + @Override + public int compare(FeedCategory a, FeedCategory b) { + if (a.id >= 0 && b.id >= 0) + return a.title.compareTo(b.title); + else + return a.id - b.id; + } + + } + + public void sortCats() { + Comparator<FeedCategory> cmp = new CatTitleComparator(); + + Collections.sort(m_cats, cmp); + try { + m_adapter.notifyDataSetChanged(); + } catch (NullPointerException e) { + // adapter missing + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_LEFT_ICON); + + String urlValue = getIntent().getDataString(); + + if (savedInstanceState != null) { + urlValue = savedInstanceState.getString("url"); + + ArrayList<FeedCategory> list = savedInstanceState.getParcelableArrayList("cats"); + + for (FeedCategory c : list) + m_cats.add(c); + } + + setContentView(R.layout.subscribe); + + getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.icon); + + setSmallScreen(false); + + Spinner catList = (Spinner) findViewById(R.id.category_spinner); + + if (m_cats.size() == 0) m_cats.add(new FeedCategory(0, "Uncategorized", 0)); + + m_adapter = new CatListAdapter(this, android.R.layout.simple_spinner_dropdown_item, m_cats); + catList.setAdapter(m_adapter); + + EditText feedUrl = (EditText) findViewById(R.id.feed_url); + feedUrl.setText(urlValue); + + m_postButton = (Button) findViewById(R.id.subscribe_button); + + m_postButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + login(REQ_POST); + } + }); + + m_catButton = (Button) findViewById(R.id.cats_button); + + m_catButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + login(REQ_CATS); + } + }); + + login(REQ_CATS); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + EditText url = (EditText) findViewById(R.id.url); + + if (url != null) { + out.putString("url", url.getText().toString()); + } + + out.putParcelableArrayList("cats", m_cats); + + } + + private void subscribeToFeed() { + m_postButton.setEnabled(false); + + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + setProgressBarIndeterminateVisibility(false); + + if (m_lastError != ApiError.NO_ERROR) { + toast(getErrorMessage()); + } else { + try { + switch (m_apiStatusCode) { + case 0: + toast(R.string.error_feed_already_exists_); + finish(); + break; + case 1: + toast(R.string.subscribed_to_feed); + finish(); + break; + case 2: + toast(R.string.error_invalid_url); + break; + case 3: + toast(R.string.error_url_is_an_html_page_no_feeds_found); + break; + case 4: + toast(R.string.error_url_contains_multiple_feeds); + break; + case 5: + toast(R.string.error_could_not_download_url); + break; + } + + } catch (Exception e) { + toast(R.string.error_while_subscribing); + e.printStackTrace(); + } + } + + m_postButton.setEnabled(true); + } + }; + + Spinner catSpinner = (Spinner) findViewById(R.id.category_spinner); + + final FeedCategory cat = (FeedCategory) m_adapter.getCategory(catSpinner.getSelectedItemPosition()); + final EditText feedUrl = (EditText) findViewById(R.id.feed_url); + + if (feedUrl != null ) { + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "subscribeToFeed"); + put("feed_url", feedUrl.getText().toString()); + + if (cat != null) { + put("category_id", String.valueOf(cat.id)); + } + } + }; + + setProgressBarIndeterminateVisibility(true); + + req.execute(map); + } + } + + @Override + public void onLoggingIn(int requestId) { + switch (requestId) { + case REQ_CATS: + m_catButton.setEnabled(false); + break; + case REQ_POST: + m_postButton.setEnabled(false); + break; + } + } + + private void updateCats() { + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected void onPostExecute(JsonElement result) { + setProgressBarIndeterminateVisibility(false); + + if (m_lastError != ApiError.NO_ERROR) { + toast(getErrorMessage()); + } else { + JsonArray content = result.getAsJsonArray(); + + if (content != null) { + Type listType = new TypeToken<List<FeedCategory>>() {}.getType(); + final List<FeedCategory> cats = new Gson().fromJson(content, listType); + + m_cats.clear(); + m_cats.add(new FeedCategory(0, "Uncategorized", 0)); + + for (FeedCategory c : cats) { + if (c.id > 0) + m_cats.add(c); + } + + sortCats(); + + m_adapter.notifyDataSetChanged(); + + toast(R.string.category_list_updated); + } + } + + m_catButton.setEnabled(true); + } + }; + + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "getCategories"); + } + }; + + setProgressBarIndeterminateVisibility(true); + + req.execute(map); + } + + @Override + protected void onLoggedIn(int requestId) { + switch (requestId) { + case REQ_CATS: + updateCats(); + break; + case REQ_POST: + m_postButton.setEnabled(true); + if (m_apiLevel < 5) { + toast(R.string.api_too_low); + } else { + subscribeToFeed(); + } + break; + } + } + + private class CatListAdapter extends ArrayAdapter<String> { + private List<FeedCategory> m_items; + + public CatListAdapter(Context context, int resource, + List<FeedCategory> items) { + super(context, resource); + + m_items = items; + } + + @Override + public String getItem(int item) { + return m_items.get(item).title; + } + + public FeedCategory getCategory(int item) { + try { + return m_items.get(item); + } catch (ArrayIndexOutOfBoundsException e) { + return null; + } + } + + @Override + public int getCount() { + return m_items.size(); + } + } + +} diff --git a/src/org/fox/ttrss/types/Article.java b/src/org/fox/ttrss/types/Article.java index 46da68ab..914a4708 100644 --- a/src/org/fox/ttrss/types/Article.java +++ b/src/org/fox/ttrss/types/Article.java @@ -1,109 +1,109 @@ -package org.fox.ttrss.types;
-import java.util.ArrayList;
-import java.util.List;
-
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-// TODO: serialize Labels
-public class Article implements Parcelable {
- public int id;
- public boolean unread;
- public boolean marked;
- public boolean published;
- public int updated;
- public boolean is_updated;
- public String title;
- public String link;
- public int feed_id;
- public List<String> tags;
- public List<Attachment> attachments;
- public String content;
- public List<List<String>> labels;
- public String feed_title;
- public int comments_count;
- public String comments_link;
- public boolean always_display_attachments;
- public String author;
-
- public Article(Parcel in) {
- readFromParcel(in);
- }
-
- public Article() {
-
- }
-
- public Article(int id) {
- this.id = id;
- this.title = "";
- this.link = "";
- this.tags = new ArrayList<String>();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(id);
- out.writeInt(unread ? 1 : 0);
- out.writeInt(marked ? 1 : 0);
- out.writeInt(published ? 1 : 0);
- out.writeInt(updated);
- out.writeInt(is_updated ? 1 : 0);
- out.writeString(title);
- out.writeString(link);
- out.writeInt(feed_id);
- out.writeStringList(tags);
- out.writeString(content);
- out.writeList(attachments);
- out.writeString(feed_title);
- out.writeInt(comments_count);
- out.writeString(comments_link);
- out.writeInt(always_display_attachments ? 1 : 0);
- out.writeString(author);
- }
-
- public void readFromParcel(Parcel in) {
- id = in.readInt();
- unread = in.readInt() == 1;
- marked = in.readInt() == 1;
- published = in.readInt() == 1;
- updated = in.readInt();
- is_updated = in.readInt() == 1;
- title = in.readString();
- link = in.readString();
- feed_id = in.readInt();
-
- if (tags == null) tags = new ArrayList<String>();
- in.readStringList(tags);
-
- content = in.readString();
-
- attachments = new ArrayList<Attachment>();
- in.readList(attachments, Attachment.class.getClassLoader());
-
- feed_title = in.readString();
-
- comments_count = in.readInt();
- comments_link = in.readString();
- always_display_attachments = in.readInt() == 1;
- author = in.readString();
- }
-
- @SuppressWarnings("rawtypes")
- public static final Parcelable.Creator CREATOR =
- new Parcelable.Creator() {
- public Article createFromParcel(Parcel in) {
- return new Article(in);
- }
-
- public Article[] newArray(int size) {
- return new Article[size];
- }
- };
-}
+package org.fox.ttrss.types; +import java.util.ArrayList; +import java.util.List; + + +import android.os.Parcel; +import android.os.Parcelable; + +// TODO: serialize Labels +public class Article implements Parcelable { + public int id; + public boolean unread; + public boolean marked; + public boolean published; + public int updated; + public boolean is_updated; + public String title; + public String link; + public int feed_id; + public List<String> tags; + public List<Attachment> attachments; + public String content; + public List<List<String>> labels; + public String feed_title; + public int comments_count; + public String comments_link; + public boolean always_display_attachments; + public String author; + + public Article(Parcel in) { + readFromParcel(in); + } + + public Article() { + + } + + public Article(int id) { + this.id = id; + this.title = ""; + this.link = ""; + this.tags = new ArrayList<String>(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(id); + out.writeInt(unread ? 1 : 0); + out.writeInt(marked ? 1 : 0); + out.writeInt(published ? 1 : 0); + out.writeInt(updated); + out.writeInt(is_updated ? 1 : 0); + out.writeString(title); + out.writeString(link); + out.writeInt(feed_id); + out.writeStringList(tags); + out.writeString(content); + out.writeList(attachments); + out.writeString(feed_title); + out.writeInt(comments_count); + out.writeString(comments_link); + out.writeInt(always_display_attachments ? 1 : 0); + out.writeString(author); + } + + public void readFromParcel(Parcel in) { + id = in.readInt(); + unread = in.readInt() == 1; + marked = in.readInt() == 1; + published = in.readInt() == 1; + updated = in.readInt(); + is_updated = in.readInt() == 1; + title = in.readString(); + link = in.readString(); + feed_id = in.readInt(); + + if (tags == null) tags = new ArrayList<String>(); + in.readStringList(tags); + + content = in.readString(); + + attachments = new ArrayList<Attachment>(); + in.readList(attachments, Attachment.class.getClassLoader()); + + feed_title = in.readString(); + + comments_count = in.readInt(); + comments_link = in.readString(); + always_display_attachments = in.readInt() == 1; + author = in.readString(); + } + + @SuppressWarnings("rawtypes") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public Article createFromParcel(Parcel in) { + return new Article(in); + } + + public Article[] newArray(int size) { + return new Article[size]; + } + }; +} diff --git a/src/org/fox/ttrss/types/ArticleList.java b/src/org/fox/ttrss/types/ArticleList.java index b68b4362..5fe36d95 100644 --- a/src/org/fox/ttrss/types/ArticleList.java +++ b/src/org/fox/ttrss/types/ArticleList.java @@ -1,58 +1,58 @@ -package org.fox.ttrss.types;
-
-import java.util.ArrayList;
-
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-@SuppressWarnings("serial")
-public class ArticleList extends ArrayList<Article> implements Parcelable {
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(this.size());
- for (Article article : this) {
- out.writeParcelable(article, flags);
- }
- }
-
- public Article findById(int id) {
- for (Article a : this) {
- if (a.id == id)
- return a;
- }
- return null;
- }
-
- public void readFromParcel(Parcel in) {
- int length = in.readInt();
-
- for (int i = 0; i < length; i++) {
- Article article = in.readParcelable(Article.class.getClassLoader());
- this.add(article);
- }
- }
-
- public ArticleList() { }
-
- public ArticleList(Parcel in) {
- readFromParcel(in);
- }
-
- @SuppressWarnings("rawtypes")
- public static final Parcelable.Creator CREATOR =
- new Parcelable.Creator() {
- public ArticleList createFromParcel(Parcel in) {
- return new ArticleList(in);
- }
-
- public ArticleList[] newArray(int size) {
- return new ArticleList[size];
- }
- };
+package org.fox.ttrss.types; + +import java.util.ArrayList; + + +import android.os.Parcel; +import android.os.Parcelable; + +@SuppressWarnings("serial") +public class ArticleList extends ArrayList<Article> implements Parcelable { + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(this.size()); + for (Article article : this) { + out.writeParcelable(article, flags); + } + } + + public Article findById(int id) { + for (Article a : this) { + if (a.id == id) + return a; + } + return null; + } + + public void readFromParcel(Parcel in) { + int length = in.readInt(); + + for (int i = 0; i < length; i++) { + Article article = in.readParcelable(Article.class.getClassLoader()); + this.add(article); + } + } + + public ArticleList() { } + + public ArticleList(Parcel in) { + readFromParcel(in); + } + + @SuppressWarnings("rawtypes") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public ArticleList createFromParcel(Parcel in) { + return new ArticleList(in); + } + + public ArticleList[] newArray(int size) { + return new ArticleList[size]; + } + }; }
\ No newline at end of file diff --git a/src/org/fox/ttrss/types/Attachment.java b/src/org/fox/ttrss/types/Attachment.java index 58e5b37f..9e363dba 100644 --- a/src/org/fox/ttrss/types/Attachment.java +++ b/src/org/fox/ttrss/types/Attachment.java @@ -1,75 +1,75 @@ -package org.fox.ttrss.types;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class Attachment implements Parcelable {
- public int id;
- public String content_url;
- public String content_type;
- public String title;
- public String duration;
- public int post_id;
-
- public Attachment(Parcel in) {
- readFromParcel(in);
- }
-
- public Attachment() {
-
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(id);
- out.writeString(content_url);
- out.writeString(content_type);
- out.writeString(title);
- out.writeString(duration);
- out.writeInt(post_id);
- }
-
- public String toString() {
- if (title != null && title.length() > 0) {
- return title;
- } else {
- try {
- URL url = new URL(content_url.trim());
- return new File(url.getFile()).getName();
- } catch (MalformedURLException e) {
- return content_url;
- }
- }
- }
-
- public void readFromParcel(Parcel in) {
- id = in.readInt();
- content_url = in.readString();
- content_type = in.readString();
- title = in.readString();
- duration = in.readString();
- post_id = in.readInt();
- }
-
- @SuppressWarnings("rawtypes")
- public static final Parcelable.Creator CREATOR =
- new Parcelable.Creator() {
- public Attachment createFromParcel(Parcel in) {
- return new Attachment(in);
- }
-
- public Attachment[] newArray(int size) {
- return new Attachment[size];
- }
- };
-
-}
+package org.fox.ttrss.types; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; + +import android.os.Parcel; +import android.os.Parcelable; + +public class Attachment implements Parcelable { + public int id; + public String content_url; + public String content_type; + public String title; + public String duration; + public int post_id; + + public Attachment(Parcel in) { + readFromParcel(in); + } + + public Attachment() { + + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(id); + out.writeString(content_url); + out.writeString(content_type); + out.writeString(title); + out.writeString(duration); + out.writeInt(post_id); + } + + public String toString() { + if (title != null && title.length() > 0) { + return title; + } else { + try { + URL url = new URL(content_url.trim()); + return new File(url.getFile()).getName(); + } catch (MalformedURLException e) { + return content_url; + } + } + } + + public void readFromParcel(Parcel in) { + id = in.readInt(); + content_url = in.readString(); + content_type = in.readString(); + title = in.readString(); + duration = in.readString(); + post_id = in.readInt(); + } + + @SuppressWarnings("rawtypes") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public Attachment createFromParcel(Parcel in) { + return new Attachment(in); + } + + public Attachment[] newArray(int size) { + return new Attachment[size]; + } + }; + +} diff --git a/src/org/fox/ttrss/types/Feed.java b/src/org/fox/ttrss/types/Feed.java index c0649be3..6cf4a1b1 100644 --- a/src/org/fox/ttrss/types/Feed.java +++ b/src/org/fox/ttrss/types/Feed.java @@ -1,90 +1,90 @@ -package org.fox.ttrss.types;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class Feed implements Comparable<Feed>, Parcelable {
- public String feed_url;
- public String title;
- public int id;
- public int unread;
- public boolean has_icon;
- public int cat_id;
- public int last_updated;
- public int order_id;
- public boolean is_cat;
-
- public Feed(int id, String title, boolean is_cat) {
- this.id = id;
- this.title = title;
- this.is_cat = is_cat;
- }
-
- public Feed(Parcel in) {
- readFromParcel(in);
- }
-
- public Feed() {
-
- }
-
- public boolean equals(Feed feed) {
- if (feed == this)
- return true;
-
- if (feed == null)
- return false;
-
- return feed.id == this.id && (this.title == null || this.title.equals(feed.title)) && this.is_cat == feed.is_cat;
- }
-
- @Override
- public int compareTo(Feed feed) {
- if (feed.unread != this.unread)
- return feed.unread - this.unread;
- else
- 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);
- out.writeInt(is_cat ? 1 : 0);
- out.writeInt(order_id);
- }
-
- 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();
- is_cat = in.readInt() == 1;
- order_id = in.readInt();
- }
-
- @SuppressWarnings("rawtypes")
- public static final Parcelable.Creator CREATOR =
- new Parcelable.Creator() {
- public Feed createFromParcel(Parcel in) {
- return new Feed(in);
- }
-
- public Feed[] newArray(int size) {
- return new Feed[size];
- }
- };
+package org.fox.ttrss.types; + +import android.os.Parcel; +import android.os.Parcelable; + +public class Feed implements Comparable<Feed>, Parcelable { + public String feed_url; + public String title; + public int id; + public int unread; + public boolean has_icon; + public int cat_id; + public int last_updated; + public int order_id; + public boolean is_cat; + + public Feed(int id, String title, boolean is_cat) { + this.id = id; + this.title = title; + this.is_cat = is_cat; + } + + public Feed(Parcel in) { + readFromParcel(in); + } + + public Feed() { + + } + + public boolean equals(Feed feed) { + if (feed == this) + return true; + + if (feed == null) + return false; + + return feed.id == this.id && (this.title == null || this.title.equals(feed.title)) && this.is_cat == feed.is_cat; + } + + @Override + public int compareTo(Feed feed) { + if (feed.unread != this.unread) + return feed.unread - this.unread; + else + 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); + out.writeInt(is_cat ? 1 : 0); + out.writeInt(order_id); + } + + 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(); + is_cat = in.readInt() == 1; + order_id = in.readInt(); + } + + @SuppressWarnings("rawtypes") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public Feed createFromParcel(Parcel in) { + return new Feed(in); + } + + public Feed[] newArray(int size) { + return new Feed[size]; + } + }; }
\ No newline at end of file diff --git a/src/org/fox/ttrss/types/FeedCategory.java b/src/org/fox/ttrss/types/FeedCategory.java index 202a2dd6..c8193f94 100644 --- a/src/org/fox/ttrss/types/FeedCategory.java +++ b/src/org/fox/ttrss/types/FeedCategory.java @@ -1,58 +1,58 @@ -package org.fox.ttrss.types;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class FeedCategory implements Parcelable {
- public int id;
- public String title;
- public int unread;
- public int order_id;
-
- public FeedCategory(Parcel in) {
- readFromParcel(in);
- }
-
- public FeedCategory(int id, String title, int unread) {
- this.id = id;
- this.title = title;
- this.unread = unread;
- this.order_id = 0;
- }
-
- public FeedCategory() {
-
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(id);
- out.writeString(title);
- out.writeInt(unread);
- out.writeInt(order_id);
- }
-
- public void readFromParcel(Parcel in) {
- id = in.readInt();
- title = in.readString();
- unread = in.readInt();
- order_id = in.readInt();
- }
-
- @SuppressWarnings("rawtypes")
- public static final Parcelable.Creator CREATOR =
- new Parcelable.Creator() {
- public FeedCategory createFromParcel(Parcel in) {
- return new FeedCategory(in);
- }
-
- public FeedCategory[] newArray(int size) {
- return new FeedCategory[size];
- }
- };
-}
+package org.fox.ttrss.types; + +import android.os.Parcel; +import android.os.Parcelable; + +public class FeedCategory implements Parcelable { + public int id; + public String title; + public int unread; + public int order_id; + + public FeedCategory(Parcel in) { + readFromParcel(in); + } + + public FeedCategory(int id, String title, int unread) { + this.id = id; + this.title = title; + this.unread = unread; + this.order_id = 0; + } + + public FeedCategory() { + + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(id); + out.writeString(title); + out.writeInt(unread); + out.writeInt(order_id); + } + + public void readFromParcel(Parcel in) { + id = in.readInt(); + title = in.readString(); + unread = in.readInt(); + order_id = in.readInt(); + } + + @SuppressWarnings("rawtypes") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public FeedCategory createFromParcel(Parcel in) { + return new FeedCategory(in); + } + + public FeedCategory[] newArray(int size) { + return new FeedCategory[size]; + } + }; +} diff --git a/src/org/fox/ttrss/types/FeedCategoryList.java b/src/org/fox/ttrss/types/FeedCategoryList.java index 6a850058..0b85ce3b 100644 --- a/src/org/fox/ttrss/types/FeedCategoryList.java +++ b/src/org/fox/ttrss/types/FeedCategoryList.java @@ -1,52 +1,52 @@ -package org.fox.ttrss.types;
-
-import java.util.ArrayList;
-
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-@SuppressWarnings("serial")
-public class FeedCategoryList extends ArrayList<FeedCategory> implements Parcelable {
-
- public FeedCategoryList() { }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(this.size());
- for (FeedCategory feed : this) {
- out.writeParcelable(feed, flags);
- }
- }
-
- public void readFromParcel(Parcel in) {
- int length = in.readInt();
-
- for (int i = 0; i < length; i++) {
- FeedCategory feed = in.readParcelable(FeedCategory.class.getClassLoader());
- this.add(feed);
- }
-
- }
-
- public FeedCategoryList(Parcel in) {
- readFromParcel(in);
- }
-
- @SuppressWarnings("rawtypes")
- public static final Parcelable.Creator CREATOR =
- new Parcelable.Creator() {
- public FeedCategoryList createFromParcel(Parcel in) {
- return new FeedCategoryList(in);
- }
-
- public FeedCategoryList[] newArray(int size) {
- return new FeedCategoryList[size];
- }
- };
- }
+package org.fox.ttrss.types; + +import java.util.ArrayList; + + +import android.os.Parcel; +import android.os.Parcelable; + +@SuppressWarnings("serial") +public class FeedCategoryList extends ArrayList<FeedCategory> implements Parcelable { + + public FeedCategoryList() { } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(this.size()); + for (FeedCategory feed : this) { + out.writeParcelable(feed, flags); + } + } + + public void readFromParcel(Parcel in) { + int length = in.readInt(); + + for (int i = 0; i < length; i++) { + FeedCategory feed = in.readParcelable(FeedCategory.class.getClassLoader()); + this.add(feed); + } + + } + + public FeedCategoryList(Parcel in) { + readFromParcel(in); + } + + @SuppressWarnings("rawtypes") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public FeedCategoryList createFromParcel(Parcel in) { + return new FeedCategoryList(in); + } + + public FeedCategoryList[] newArray(int size) { + return new FeedCategoryList[size]; + } + }; + } diff --git a/src/org/fox/ttrss/types/FeedList.java b/src/org/fox/ttrss/types/FeedList.java index e5775f70..2d972919 100644 --- a/src/org/fox/ttrss/types/FeedList.java +++ b/src/org/fox/ttrss/types/FeedList.java @@ -1,52 +1,52 @@ -package org.fox.ttrss.types;
-
-import java.util.ArrayList;
-
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-@SuppressWarnings("serial")
-public class FeedList extends ArrayList<Feed> implements Parcelable {
-
- public FeedList() { }
-
- @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 FeedList(Parcel in) {
- readFromParcel(in);
- }
-
- @SuppressWarnings("rawtypes")
- public static final Parcelable.Creator CREATOR =
- new Parcelable.Creator() {
- public FeedList createFromParcel(Parcel in) {
- return new FeedList(in);
- }
-
- public FeedList[] newArray(int size) {
- return new FeedList[size];
- }
- };
- }
+package org.fox.ttrss.types; + +import java.util.ArrayList; + + +import android.os.Parcel; +import android.os.Parcelable; + +@SuppressWarnings("serial") +public class FeedList extends ArrayList<Feed> implements Parcelable { + + public FeedList() { } + + @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 FeedList(Parcel in) { + readFromParcel(in); + } + + @SuppressWarnings("rawtypes") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public FeedList createFromParcel(Parcel in) { + return new FeedList(in); + } + + public FeedList[] newArray(int size) { + return new FeedList[size]; + } + }; + } diff --git a/src/org/fox/ttrss/types/Label.java b/src/org/fox/ttrss/types/Label.java index ff81ffa6..0d4f3699 100644 --- a/src/org/fox/ttrss/types/Label.java +++ b/src/org/fox/ttrss/types/Label.java @@ -1,13 +1,13 @@ -package org.fox.ttrss.types;
-
-public class Label {
- public int id;
- public String caption;
- public String fg_color;
- public String bg_color;
- public boolean checked;
-
- public Label() {
-
- }
-}
+package org.fox.ttrss.types; + +public class Label { + public int id; + public String caption; + public String fg_color; + public String bg_color; + public boolean checked; + + public Label() { + + } +} diff --git a/src/org/fox/ttrss/util/AppRater.java b/src/org/fox/ttrss/util/AppRater.java index 08163710..21dccdff 100644 --- a/src/org/fox/ttrss/util/AppRater.java +++ b/src/org/fox/ttrss/util/AppRater.java @@ -1,105 +1,105 @@ -package org.fox.ttrss.util;
-
-// From http://androidsnippets.com/prompt-engaged-users-to-rate-your-app-in-the-android-market-appirater
-
-import android.app.Dialog;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-public class AppRater {
- private final static String APP_TITLE = "Tiny Tiny RSS";
- private final static String APP_PNAME = "org.fox.ttrss";
-
- private final static int DAYS_UNTIL_PROMPT = 3;
- private final static int LAUNCHES_UNTIL_PROMPT = 7;
-
- public static void appLaunched(Context mContext) {
- SharedPreferences prefs = mContext.getSharedPreferences("apprater", 0);
-
- if (prefs.getBoolean("dontshowagain", false)) { return ; }
-
- SharedPreferences.Editor editor = prefs.edit();
-
- // Increment launch counter
- long launch_count = prefs.getLong("launch_count", 0) + 1;
- editor.putLong("launch_count", launch_count);
-
- // Get date of first launch
- Long date_firstLaunch = prefs.getLong("date_firstlaunch", 0);
- if (date_firstLaunch == 0) {
- date_firstLaunch = System.currentTimeMillis();
- editor.putLong("date_firstlaunch", date_firstLaunch);
- }
-
- // Wait at least n days before opening
- if (launch_count >= LAUNCHES_UNTIL_PROMPT &&
- !prefs.getBoolean("dontshowagain", false) &&
- System.currentTimeMillis() >= date_firstLaunch + (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000)) {
-
- showRateDialog(mContext, editor);
- }
-
- editor.commit();
- }
-
- public static void showRateDialog(final Context mContext, final SharedPreferences.Editor editor) {
- final Dialog dialog = new Dialog(mContext);
- dialog.setTitle("Rate " + APP_TITLE);
-
- LinearLayout ll = new LinearLayout(mContext);
- ll.setOrientation(LinearLayout.VERTICAL);
-
- TextView tv = new TextView(mContext);
- tv.setText("If you enjoy using " + APP_TITLE + ", please take a moment to rate it. Thanks for your support!");
- tv.setWidth(240);
- tv.setPadding(4, 0, 4, 10);
- ll.addView(tv);
-
- Button b1 = new Button(mContext);
- b1.setText("Rate " + APP_TITLE);
- b1.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- try {
- mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + APP_PNAME)));
- } catch (ActivityNotFoundException e) {
- mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + APP_PNAME)));
- }
- dialog.dismiss();
- }
- });
- ll.addView(b1);
-
- Button b2 = new Button(mContext);
- b2.setText("Remind me later");
- b2.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- dialog.dismiss();
- }
- });
- ll.addView(b2);
-
- Button b3 = new Button(mContext);
- b3.setText("No, thanks");
- b3.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- if (editor != null) {
- editor.putBoolean("dontshowagain", true);
- editor.commit();
- }
- dialog.dismiss();
- }
- });
- ll.addView(b3);
-
- dialog.setContentView(ll);
- dialog.show();
- }
+package org.fox.ttrss.util; + +// From http://androidsnippets.com/prompt-engaged-users-to-rate-your-app-in-the-android-market-appirater + +import android.app.Dialog; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class AppRater { + private final static String APP_TITLE = "Tiny Tiny RSS"; + private final static String APP_PNAME = "org.fox.ttrss"; + + private final static int DAYS_UNTIL_PROMPT = 3; + private final static int LAUNCHES_UNTIL_PROMPT = 7; + + public static void appLaunched(Context mContext) { + SharedPreferences prefs = mContext.getSharedPreferences("apprater", 0); + + if (prefs.getBoolean("dontshowagain", false)) { return ; } + + SharedPreferences.Editor editor = prefs.edit(); + + // Increment launch counter + long launch_count = prefs.getLong("launch_count", 0) + 1; + editor.putLong("launch_count", launch_count); + + // Get date of first launch + Long date_firstLaunch = prefs.getLong("date_firstlaunch", 0); + if (date_firstLaunch == 0) { + date_firstLaunch = System.currentTimeMillis(); + editor.putLong("date_firstlaunch", date_firstLaunch); + } + + // Wait at least n days before opening + if (launch_count >= LAUNCHES_UNTIL_PROMPT && + !prefs.getBoolean("dontshowagain", false) && + System.currentTimeMillis() >= date_firstLaunch + (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000)) { + + showRateDialog(mContext, editor); + } + + editor.commit(); + } + + public static void showRateDialog(final Context mContext, final SharedPreferences.Editor editor) { + final Dialog dialog = new Dialog(mContext); + dialog.setTitle("Rate " + APP_TITLE); + + LinearLayout ll = new LinearLayout(mContext); + ll.setOrientation(LinearLayout.VERTICAL); + + TextView tv = new TextView(mContext); + tv.setText("If you enjoy using " + APP_TITLE + ", please take a moment to rate it. Thanks for your support!"); + tv.setWidth(240); + tv.setPadding(4, 0, 4, 10); + ll.addView(tv); + + Button b1 = new Button(mContext); + b1.setText("Rate " + APP_TITLE); + b1.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + try { + mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + APP_PNAME))); + } catch (ActivityNotFoundException e) { + mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + APP_PNAME))); + } + dialog.dismiss(); + } + }); + ll.addView(b1); + + Button b2 = new Button(mContext); + b2.setText("Remind me later"); + b2.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + dialog.dismiss(); + } + }); + ll.addView(b2); + + Button b3 = new Button(mContext); + b3.setText("No, thanks"); + b3.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + if (editor != null) { + editor.putBoolean("dontshowagain", true); + editor.commit(); + } + dialog.dismiss(); + } + }); + ll.addView(b3); + + dialog.setContentView(ll); + dialog.show(); + } }
\ No newline at end of file diff --git a/src/org/fox/ttrss/util/DatabaseHelper.java b/src/org/fox/ttrss/util/DatabaseHelper.java index 501aadd1..cf5380e0 100644 --- a/src/org/fox/ttrss/util/DatabaseHelper.java +++ b/src/org/fox/ttrss/util/DatabaseHelper.java @@ -1,86 +1,86 @@ -package org.fox.ttrss.util;
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.provider.BaseColumns;
-
-
-public class DatabaseHelper extends SQLiteOpenHelper {
-
- @SuppressWarnings("unused")
- private final String TAG = this.getClass().getSimpleName();
- public static final String DATABASE_NAME = "OfflineStorage.db";
- public static final int DATABASE_VERSION = 3;
-
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("DROP TABLE IF EXISTS categories;");
- db.execSQL("DROP TABLE IF EXISTS feeds;");
- db.execSQL("DROP TABLE IF EXISTS articles;");
- db.execSQL("DROP VIEW IF EXISTS feeds_unread;");
- db.execSQL("DROP TRIGGER IF EXISTS articles_set_modified;");
-
- db.execSQL("CREATE TABLE IF NOT EXISTS feeds (" +
- BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- "feed_url TEXT, " +
- "title TEXT, " +
- "has_icon BOOLEAN, " +
- "cat_id INTEGER" +
- ");");
-
- db.execSQL("CREATE TABLE IF NOT EXISTS categories (" +
- BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- "title TEXT" +
- ");");
-
- db.execSQL("CREATE TABLE IF NOT EXISTS articles (" +
- BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- "unread BOOLEAN, " +
- "marked BOOLEAN, " +
- "published BOOLEAN, " +
- "updated INTEGER, " +
- "is_updated BOOLEAN, " +
- "title TEXT, " +
- "link TEXT, " +
- "feed_id INTEGER, " +
- "tags TEXT, " +
- "content TEXT, " +
- "selected BOOLEAN, " +
- "modified BOOLEAN" +
- ");");
-
- db.execSQL("CREATE TRIGGER articles_set_modified UPDATE OF marked, published, unread ON articles " +
- "BEGIN " +
- " UPDATE articles SET modified = 1 WHERE " + BaseColumns._ID + " = " + "OLD." + BaseColumns._ID + "; " +
- "END;");
-
- db.execSQL("CREATE VIEW feeds_unread AS SELECT feeds."+BaseColumns._ID+" AS "+BaseColumns._ID+", " +
- "feeds.title AS title, " +
- "cat_id, " +
- "SUM(articles.unread) AS unread FROM feeds " +
- "LEFT JOIN articles ON (articles.feed_id = feeds."+BaseColumns._ID+") " +
- "GROUP BY feeds."+BaseColumns._ID+", feeds.title;");
-
- //sqlite> select categories._id,categories.title,sum(articles.unread) from categories left j
- //oin feeds on (feeds.cat_id = categories._id) left join articles on (articles.feed_id = fee
- //ds._id) group by categories._id;
-
- db.execSQL("CREATE VIEW cats_unread AS SELECT categories."+BaseColumns._ID+" AS "+BaseColumns._ID+", " +
- "categories.title AS title, " +
- "SUM(articles.unread) AS unread FROM categories " +
- "LEFT JOIN feeds ON (feeds.cat_id = categories."+BaseColumns._ID+") "+
- "LEFT JOIN articles ON (articles.feed_id = feeds."+BaseColumns._ID+") " +
- "GROUP BY categories."+BaseColumns._ID+", categories.title;");
-
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- onCreate(db);
- }
-
-}
+package org.fox.ttrss.util; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.provider.BaseColumns; + + +public class DatabaseHelper extends SQLiteOpenHelper { + + @SuppressWarnings("unused") + private final String TAG = this.getClass().getSimpleName(); + public static final String DATABASE_NAME = "OfflineStorage.db"; + public static final int DATABASE_VERSION = 3; + + public DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("DROP TABLE IF EXISTS categories;"); + db.execSQL("DROP TABLE IF EXISTS feeds;"); + db.execSQL("DROP TABLE IF EXISTS articles;"); + db.execSQL("DROP VIEW IF EXISTS feeds_unread;"); + db.execSQL("DROP TRIGGER IF EXISTS articles_set_modified;"); + + db.execSQL("CREATE TABLE IF NOT EXISTS feeds (" + + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + "feed_url TEXT, " + + "title TEXT, " + + "has_icon BOOLEAN, " + + "cat_id INTEGER" + + ");"); + + db.execSQL("CREATE TABLE IF NOT EXISTS categories (" + + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + "title TEXT" + + ");"); + + db.execSQL("CREATE TABLE IF NOT EXISTS articles (" + + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + "unread BOOLEAN, " + + "marked BOOLEAN, " + + "published BOOLEAN, " + + "updated INTEGER, " + + "is_updated BOOLEAN, " + + "title TEXT, " + + "link TEXT, " + + "feed_id INTEGER, " + + "tags TEXT, " + + "content TEXT, " + + "selected BOOLEAN, " + + "modified BOOLEAN" + + ");"); + + db.execSQL("CREATE TRIGGER articles_set_modified UPDATE OF marked, published, unread ON articles " + + "BEGIN " + + " UPDATE articles SET modified = 1 WHERE " + BaseColumns._ID + " = " + "OLD." + BaseColumns._ID + "; " + + "END;"); + + db.execSQL("CREATE VIEW feeds_unread AS SELECT feeds."+BaseColumns._ID+" AS "+BaseColumns._ID+", " + + "feeds.title AS title, " + + "cat_id, " + + "SUM(articles.unread) AS unread FROM feeds " + + "LEFT JOIN articles ON (articles.feed_id = feeds."+BaseColumns._ID+") " + + "GROUP BY feeds."+BaseColumns._ID+", feeds.title;"); + + //sqlite> select categories._id,categories.title,sum(articles.unread) from categories left j + //oin feeds on (feeds.cat_id = categories._id) left join articles on (articles.feed_id = fee + //ds._id) group by categories._id; + + db.execSQL("CREATE VIEW cats_unread AS SELECT categories."+BaseColumns._ID+" AS "+BaseColumns._ID+", " + + "categories.title AS title, " + + "SUM(articles.unread) AS unread FROM categories " + + "LEFT JOIN feeds ON (feeds.cat_id = categories."+BaseColumns._ID+") "+ + "LEFT JOIN articles ON (articles.feed_id = feeds."+BaseColumns._ID+") " + + "GROUP BY categories."+BaseColumns._ID+", categories.title;"); + + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + onCreate(db); + } + +} diff --git a/src/org/fox/ttrss/util/HeadlinesRequest.java b/src/org/fox/ttrss/util/HeadlinesRequest.java index ca76887f..9ad5ef91 100644 --- a/src/org/fox/ttrss/util/HeadlinesRequest.java +++ b/src/org/fox/ttrss/util/HeadlinesRequest.java @@ -1,83 +1,83 @@ -package org.fox.ttrss.util;
-
-import java.lang.reflect.Type;
-import java.util.List;
-
-import org.fox.ttrss.ApiRequest;
-import org.fox.ttrss.GlobalState;
-import org.fox.ttrss.OnlineActivity;
-import org.fox.ttrss.R;
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.ArticleList;
-
-import android.content.Context;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.reflect.TypeToken;
-
-public class HeadlinesRequest extends ApiRequest {
- public static final int HEADLINES_REQUEST_SIZE = 30;
- public static final int HEADLINES_BUFFER_MAX = 1500;
-
- private int m_offset = 0;
- private OnlineActivity m_activity;
- private ArticleList m_articles = GlobalState.getInstance().m_loadedArticles;
-
- public HeadlinesRequest(Context context, OnlineActivity activity) {
- super(context);
-
- m_activity = activity;
- }
-
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- try {
- JsonArray content = result.getAsJsonArray();
- if (content != null) {
- Type listType = new TypeToken<List<Article>>() {}.getType();
- final List<Article> articles = new Gson().fromJson(content, listType);
-
- while (m_articles.size() > HEADLINES_BUFFER_MAX)
- m_articles.remove(0);
-
- if (m_offset == 0)
- m_articles.clear();
- else
- if (m_articles.get(m_articles.size()-1).id == -1)
- m_articles.remove(m_articles.size()-1); // remove previous placeholder
-
- for (Article f : articles)
- m_articles.add(f);
-
- if (articles.size() == HEADLINES_REQUEST_SIZE) {
- Article placeholder = new Article(-1);
- m_articles.add(placeholder);
- }
-
- /* if (m_articles.size() == 0)
- m_activity.setLoadingStatus(R.string.no_headlines_to_display, false);
- else */
-
- m_activity.setLoadingStatus(R.string.blank, false);
-
- return;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- if (m_lastError == ApiError.LOGIN_FAILED) {
- m_activity.login();
- } else {
- m_activity.setLoadingStatus(getErrorMessage(), false);
- }
- }
-
- public void setOffset(int skip) {
- m_offset = skip;
- }
-}
+package org.fox.ttrss.util; + +import java.lang.reflect.Type; +import java.util.List; + +import org.fox.ttrss.ApiRequest; +import org.fox.ttrss.GlobalState; +import org.fox.ttrss.OnlineActivity; +import org.fox.ttrss.R; +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; + +import android.content.Context; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +public class HeadlinesRequest extends ApiRequest { + public static final int HEADLINES_REQUEST_SIZE = 30; + public static final int HEADLINES_BUFFER_MAX = 1500; + + private int m_offset = 0; + private OnlineActivity m_activity; + private ArticleList m_articles = GlobalState.getInstance().m_loadedArticles; + + public HeadlinesRequest(Context context, OnlineActivity activity) { + super(context); + + m_activity = activity; + } + + protected void onPostExecute(JsonElement result) { + if (result != null) { + try { + JsonArray content = result.getAsJsonArray(); + if (content != null) { + Type listType = new TypeToken<List<Article>>() {}.getType(); + final List<Article> articles = new Gson().fromJson(content, listType); + + while (m_articles.size() > HEADLINES_BUFFER_MAX) + m_articles.remove(0); + + if (m_offset == 0) + m_articles.clear(); + else + if (m_articles.get(m_articles.size()-1).id == -1) + m_articles.remove(m_articles.size()-1); // remove previous placeholder + + for (Article f : articles) + m_articles.add(f); + + if (articles.size() == HEADLINES_REQUEST_SIZE) { + Article placeholder = new Article(-1); + m_articles.add(placeholder); + } + + /* if (m_articles.size() == 0) + m_activity.setLoadingStatus(R.string.no_headlines_to_display, false); + else */ + + m_activity.setLoadingStatus(R.string.blank, false); + + return; + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (m_lastError == ApiError.LOGIN_FAILED) { + m_activity.login(); + } else { + m_activity.setLoadingStatus(getErrorMessage(), false); + } + } + + public void setOffset(int skip) { + m_offset = skip; + } +} diff --git a/src/org/fox/ttrss/util/ImageCacheService.java b/src/org/fox/ttrss/util/ImageCacheService.java index 96342d60..8bd4840c 100644 --- a/src/org/fox/ttrss/util/ImageCacheService.java +++ b/src/org/fox/ttrss/util/ImageCacheService.java @@ -1,211 +1,211 @@ -package org.fox.ttrss.util;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Date;
-
-import org.fox.ttrss.OnlineActivity;
-import org.fox.ttrss.R;
-import org.fox.ttrss.offline.OfflineDownloadService;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.app.IntentService;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Environment;
-
-public class ImageCacheService extends IntentService {
-
- @SuppressWarnings("unused")
- private final String TAG = this.getClass().getSimpleName();
-
- public static final int NOTIFY_DOWNLOADING = 1;
-
- private static final String CACHE_PATH = "/image-cache/";
-
- private int m_imagesDownloaded = 0;
-
- private NotificationManager m_nmgr;
-
- public ImageCacheService() {
- super("ImageCacheService");
- }
-
- private boolean isDownloadServiceRunning() {
- ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
- for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
- if ("org.fox.ttrss.OfflineDownloadService".equals(service.service.getClassName())) {
- return true;
- }
- }
- return false;
- }
-
-
- @Override
- public void onCreate() {
- super.onCreate();
- m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- }
-
- public static boolean isUrlCached(Context context, String url) {
- String hashedUrl = md5(url);
-
- File storage = context.getExternalCacheDir();
-
- File file = new File(storage.getAbsolutePath() + CACHE_PATH + "/" + hashedUrl + ".png");
-
- return file.exists();
- }
-
- public static String getCacheFileName(Context context, String url) {
- String hashedUrl = md5(url);
-
- File storage = context.getExternalCacheDir();
-
- File file = new File(storage.getAbsolutePath() + CACHE_PATH + "/" + hashedUrl + ".png");
-
- return file.getAbsolutePath();
- }
-
- public static void cleanupCache(Context context, boolean deleteAll) {
- if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
- File storage = context.getExternalCacheDir();
- File cachePath = new File(storage.getAbsolutePath() + CACHE_PATH);
-
- long now = new Date().getTime();
-
- if (cachePath.isDirectory()) {
- for (File file : cachePath.listFiles()) {
- if (deleteAll || now - file.lastModified() > 1000*60*60*24*7) {
- file.delete();
- }
- }
- }
- }
- }
-
- protected static String md5(String s) {
- try {
- MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
- digest.update(s.getBytes());
- byte messageDigest[] = digest.digest();
-
- StringBuffer hexString = new StringBuffer();
- for (int i=0; i<messageDigest.length; i++)
- hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
-
- return hexString.toString();
-
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
-
- return null;
- }
-
- private InputStream getStream(String urlString) {
- try {
- URL url = new URL(urlString);
- URLConnection urlConnection = url.openConnection();
- urlConnection.setConnectTimeout(250);
- return urlConnection.getInputStream();
- } catch (Exception ex) {
- return null;
- }
- }
-
- @SuppressWarnings("deprecation")
- private void updateNotification(String msg) {
- Notification notification = new Notification(R.drawable.icon,
- getString(R.string.notify_downloading_title), System.currentTimeMillis());
-
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- new Intent(this, OnlineActivity.class), 0);
-
- notification.flags |= Notification.FLAG_ONGOING_EVENT;
- notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
-
- notification.setLatestEventInfo(this, getString(R.string.notify_downloading_title), msg, contentIntent);
-
- m_nmgr.notify(NOTIFY_DOWNLOADING, notification);
- }
-
- /* private void updateNotification(int msgResId) {
- updateNotification(getString(msgResId));
- } */
-
- @Override
- protected void onHandleIntent(Intent intent) {
- String url = intent.getStringExtra("url");
-
- //Log.d(TAG, "got request to download URL=" + url);
-
- if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
- return;
-
- String hashedUrl = md5(url);
-
- File storage = getExternalCacheDir();
- File cachePath = new File(storage.getAbsolutePath() + CACHE_PATH);
- if (!cachePath.exists()) cachePath.mkdirs();
-
- if (cachePath.isDirectory() && hashedUrl != null) {
- File outputFile = new File(cachePath.getAbsolutePath() + "/" + hashedUrl + ".png");
-
- if (!outputFile.exists()) {
-
- //Log.d(TAG, "downloading to " + outputFile.getAbsolutePath());
-
- InputStream is = getStream(url);
-
- if (is != null) {
- try {
- FileOutputStream fos = new FileOutputStream(outputFile);
-
- byte[] buffer = new byte[1024];
- int len = 0;
- while ((len = is.read(buffer)) != -1) {
- fos.write(buffer, 0, len);
- }
-
- fos.close();
- is.close();
-
- m_imagesDownloaded++;
-
- updateNotification(getString(R.string.notify_downloading_images, m_imagesDownloaded));
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (!isDownloadServiceRunning()) {
- m_nmgr.cancel(NOTIFY_DOWNLOADING);
-
- Intent success = new Intent();
- success.setAction(OfflineDownloadService.INTENT_ACTION_SUCCESS);
- success.addCategory(Intent.CATEGORY_DEFAULT);
- sendBroadcast(success);
- }
- }
-
-}
+package org.fox.ttrss.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Date; + +import org.fox.ttrss.OnlineActivity; +import org.fox.ttrss.R; +import org.fox.ttrss.offline.OfflineDownloadService; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.app.IntentService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Environment; + +public class ImageCacheService extends IntentService { + + @SuppressWarnings("unused") + private final String TAG = this.getClass().getSimpleName(); + + public static final int NOTIFY_DOWNLOADING = 1; + + private static final String CACHE_PATH = "/image-cache/"; + + private int m_imagesDownloaded = 0; + + private NotificationManager m_nmgr; + + public ImageCacheService() { + super("ImageCacheService"); + } + + private boolean isDownloadServiceRunning() { + ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if ("org.fox.ttrss.OfflineDownloadService".equals(service.service.getClassName())) { + return true; + } + } + return false; + } + + + @Override + public void onCreate() { + super.onCreate(); + m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + } + + public static boolean isUrlCached(Context context, String url) { + String hashedUrl = md5(url); + + File storage = context.getExternalCacheDir(); + + File file = new File(storage.getAbsolutePath() + CACHE_PATH + "/" + hashedUrl + ".png"); + + return file.exists(); + } + + public static String getCacheFileName(Context context, String url) { + String hashedUrl = md5(url); + + File storage = context.getExternalCacheDir(); + + File file = new File(storage.getAbsolutePath() + CACHE_PATH + "/" + hashedUrl + ".png"); + + return file.getAbsolutePath(); + } + + public static void cleanupCache(Context context, boolean deleteAll) { + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + File storage = context.getExternalCacheDir(); + File cachePath = new File(storage.getAbsolutePath() + CACHE_PATH); + + long now = new Date().getTime(); + + if (cachePath.isDirectory()) { + for (File file : cachePath.listFiles()) { + if (deleteAll || now - file.lastModified() > 1000*60*60*24*7) { + file.delete(); + } + } + } + } + } + + protected static String md5(String s) { + try { + MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); + digest.update(s.getBytes()); + byte messageDigest[] = digest.digest(); + + StringBuffer hexString = new StringBuffer(); + for (int i=0; i<messageDigest.length; i++) + hexString.append(Integer.toHexString(0xFF & messageDigest[i])); + + return hexString.toString(); + + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + return null; + } + + private InputStream getStream(String urlString) { + try { + URL url = new URL(urlString); + URLConnection urlConnection = url.openConnection(); + urlConnection.setConnectTimeout(250); + return urlConnection.getInputStream(); + } catch (Exception ex) { + return null; + } + } + + @SuppressWarnings("deprecation") + private void updateNotification(String msg) { + Notification notification = new Notification(R.drawable.icon, + getString(R.string.notify_downloading_title), System.currentTimeMillis()); + + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + new Intent(this, OnlineActivity.class), 0); + + notification.flags |= Notification.FLAG_ONGOING_EVENT; + notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE; + + notification.setLatestEventInfo(this, getString(R.string.notify_downloading_title), msg, contentIntent); + + m_nmgr.notify(NOTIFY_DOWNLOADING, notification); + } + + /* private void updateNotification(int msgResId) { + updateNotification(getString(msgResId)); + } */ + + @Override + protected void onHandleIntent(Intent intent) { + String url = intent.getStringExtra("url"); + + //Log.d(TAG, "got request to download URL=" + url); + + if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) + return; + + String hashedUrl = md5(url); + + File storage = getExternalCacheDir(); + File cachePath = new File(storage.getAbsolutePath() + CACHE_PATH); + if (!cachePath.exists()) cachePath.mkdirs(); + + if (cachePath.isDirectory() && hashedUrl != null) { + File outputFile = new File(cachePath.getAbsolutePath() + "/" + hashedUrl + ".png"); + + if (!outputFile.exists()) { + + //Log.d(TAG, "downloading to " + outputFile.getAbsolutePath()); + + InputStream is = getStream(url); + + if (is != null) { + try { + FileOutputStream fos = new FileOutputStream(outputFile); + + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = is.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + + fos.close(); + is.close(); + + m_imagesDownloaded++; + + updateNotification(getString(R.string.notify_downloading_images, m_imagesDownloaded)); + + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (!isDownloadServiceRunning()) { + m_nmgr.cancel(NOTIFY_DOWNLOADING); + + Intent success = new Intent(); + success.setAction(OfflineDownloadService.INTENT_ACTION_SUCCESS); + success.addCategory(Intent.CATEGORY_DEFAULT); + sendBroadcast(success); + } + } + +} diff --git a/src/org/fox/ttrss/util/PrefsBackupAgent.java b/src/org/fox/ttrss/util/PrefsBackupAgent.java index a786be56..2b33615f 100644 --- a/src/org/fox/ttrss/util/PrefsBackupAgent.java +++ b/src/org/fox/ttrss/util/PrefsBackupAgent.java @@ -1,19 +1,19 @@ -package org.fox.ttrss.util;
-
-import android.app.backup.BackupAgentHelper;
-import android.app.backup.SharedPreferencesBackupHelper;
-
-public class PrefsBackupAgent extends BackupAgentHelper {
- // The name of the SharedPreferences file
- static final String PREFS = "org.fox.ttrss_preferences";
-
- // A key to uniquely identify the set of backup data
- static final String PREFS_BACKUP_KEY = "prefs";
-
- // Allocate a helper and add it to the backup agent
- @Override
- public void onCreate() {
- SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
- addHelper(PREFS_BACKUP_KEY, helper);
- }
-}
+package org.fox.ttrss.util; + +import android.app.backup.BackupAgentHelper; +import android.app.backup.SharedPreferencesBackupHelper; + +public class PrefsBackupAgent extends BackupAgentHelper { + // The name of the SharedPreferences file + static final String PREFS = "org.fox.ttrss_preferences"; + + // A key to uniquely identify the set of backup data + static final String PREFS_BACKUP_KEY = "prefs"; + + // Allocate a helper and add it to the backup agent + @Override + public void onCreate() { + SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS); + addHelper(PREFS_BACKUP_KEY, helper); + } +} |