initial
This commit is contained in:
parent
86a4f6c2de
commit
ced80be1ae
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.fox.ttrss"
|
package="org.fox.ttrss"
|
||||||
android:versionCode="97"
|
android:versionCode="100"
|
||||||
android:versionName="0.7.5" >
|
android:versionName="0.8.0" >
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="8"
|
android:minSdkVersion="8"
|
||||||
@ -19,15 +19,7 @@
|
|||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
android:label="@string/app_name" >
|
android:label="@string/app_name" >
|
||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".OnlineActivity"
|
||||||
android:label="@string/app_name" >
|
|
||||||
</activity>
|
|
||||||
<activity
|
|
||||||
android:name=".offline.OfflineActivity"
|
|
||||||
android:label="@string/app_name" >
|
|
||||||
</activity>
|
|
||||||
<activity
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:label="@string/app_name" >
|
android:label="@string/app_name" >
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@ -40,6 +32,21 @@
|
|||||||
android:label="@string/preferences" >
|
android:label="@string/preferences" >
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".FeedsActivity"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".HeadlinesActivity"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ArticleActivity"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".offline.OfflineDownloadService"
|
android:name=".offline.OfflineDownloadService"
|
||||||
android:enabled="true" />
|
android:enabled="true" />
|
||||||
|
48
res/layout-sw600dp-port/headlines.xml
Normal file
48
res/layout-sw600dp-port/headlines.xml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/loading_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?loadingBackground"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="visible" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loading_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:text="@string/loading_message"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/headlines_fragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="0.3"
|
||||||
|
android:background="?headlinesBackgroundSolid" >
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/article_fragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="0.7"
|
||||||
|
android:background="?articleBackground" >
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
47
res/layout-sw600dp/feeds.xml
Normal file
47
res/layout-sw600dp/feeds.xml
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/loading_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?loadingBackground"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loading_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:text="@string/loading_message"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/feeds_fragment"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="0.4"
|
||||||
|
android:background="?feedlistBackground" >
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/headlines_fragment"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="0.6"
|
||||||
|
android:background="?headlinesBackground" >
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
48
res/layout-sw600dp/headlines.xml
Normal file
48
res/layout-sw600dp/headlines.xml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/headlines"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/loading_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?loadingBackground"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="visible" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loading_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:text="@string/loading_message"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/headlines_fragment"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="0.4"
|
||||||
|
android:background="?headlinesBackground" >
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/article_fragment"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="0.6"
|
||||||
|
android:background="?articleBackground" >
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
27
res/layout/feeds.xml
Normal file
27
res/layout/feeds.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/loading_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loading_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:text="@string/loading_message" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/feeds_fragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
27
res/layout/headlines.xml
Normal file
27
res/layout/headlines.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/headlines"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/loading_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loading_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:text="@string/loading_message" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
21
res/layout/online.xml
Normal file
21
res/layout/online.xml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/online"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/loading_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loading_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:text="@string/loading_message" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -2,41 +2,6 @@
|
|||||||
|
|
||||||
<group android:id="@+id/menu_group_logged_in" >
|
<group android:id="@+id/menu_group_logged_in" >
|
||||||
|
|
||||||
<group android:id="@+id/menu_group_feeds" >
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<item
|
|
||||||
android:id="@+id/back_to_categories"
|
|
||||||
android:icon="@android:drawable/ic_menu_close_clear_cancel"
|
|
||||||
android:showAsAction=""
|
|
||||||
android:title="@string/back_to_categories"/>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/show_feeds"
|
|
||||||
android:icon="@android:drawable/ic_menu_agenda"
|
|
||||||
android:showAsAction=""
|
|
||||||
android:title="@string/menu_all_feeds"/>
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/update_feeds"
|
|
||||||
android:icon="@android:drawable/ic_menu_rotate"
|
|
||||||
android:showAsAction="ifRoom"
|
|
||||||
android:title="@string/update_feeds"/>
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/go_offline"
|
|
||||||
android:icon="@drawable/ic_menu_cloud"
|
|
||||||
android:showAsAction=""
|
|
||||||
android:title="@string/go_offline"/>
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/logout"
|
|
||||||
android:icon="@drawable/ic_menu_exit"
|
|
||||||
android:showAsAction=""
|
|
||||||
android:title="@string/logout"/>
|
|
||||||
</group>
|
|
||||||
|
|
||||||
<group android:id="@+id/menu_group_headlines" >
|
<group android:id="@+id/menu_group_headlines" >
|
||||||
|
|
||||||
<item
|
<item
|
||||||
|
29
res/menu/online_menu.xml
Normal file
29
res/menu/online_menu.xml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<group android:id="@+id/menu_group_logged_in" >
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/logout"
|
||||||
|
android:icon="@drawable/ic_menu_exit"
|
||||||
|
android:showAsAction=""
|
||||||
|
android:title="@string/logout"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group android:id="@+id/menu_group_logged_out" >
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/login"
|
||||||
|
android:icon="@android:drawable/ic_menu_rotate"
|
||||||
|
android:showAsAction="ifRoom|withText"
|
||||||
|
android:title="@string/login_login"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/preferences"
|
||||||
|
android:icon="@android:drawable/ic_menu_preferences"
|
||||||
|
android:showAsAction=""
|
||||||
|
android:title="@string/preferences"/>
|
||||||
|
|
||||||
|
|
||||||
|
</menu>
|
9
src/org/fox/ttrss/ArticleEventListener.java
Normal file
9
src/org/fox/ttrss/ArticleEventListener.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package org.fox.ttrss;
|
||||||
|
|
||||||
|
public interface ArticleEventListener {
|
||||||
|
|
||||||
|
void copyToClipboard(String content_url);
|
||||||
|
|
||||||
|
boolean isSmallScreen();
|
||||||
|
|
||||||
|
}
|
@ -44,7 +44,7 @@ public class ArticleFragment extends Fragment {
|
|||||||
|
|
||||||
private SharedPreferences m_prefs;
|
private SharedPreferences m_prefs;
|
||||||
private Article m_article;
|
private Article m_article;
|
||||||
private OnlineServices m_onlineServices;
|
private ArticleEventListener m_onlineServices;
|
||||||
//private Article m_nextArticle;
|
//private Article m_nextArticle;
|
||||||
//private Article m_prevArticle;
|
//private Article m_prevArticle;
|
||||||
|
|
||||||
@ -296,7 +296,7 @@ public class ArticleFragment extends Fragment {
|
|||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
|
|
||||||
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
||||||
m_onlineServices = (OnlineServices)activity;
|
m_onlineServices = (ArticleEventListener)activity;
|
||||||
//m_article = m_onlineServices.getSelectedArticle();
|
//m_article = m_onlineServices.getSelectedArticle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ public class ArticlePager extends Fragment {
|
|||||||
|
|
||||||
private final String TAG = "ArticlePager";
|
private final String TAG = "ArticlePager";
|
||||||
private PagerAdapter m_adapter;
|
private PagerAdapter m_adapter;
|
||||||
private OnlineServices m_onlineServices;
|
private HeadlinesEventListener m_onlineServices;
|
||||||
private HeadlinesFragment m_hf;
|
private HeadlinesFragment m_hf;
|
||||||
private Article m_article;
|
private Article m_article;
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ public class ArticlePager extends Fragment {
|
|||||||
article.unread = false;
|
article.unread = false;
|
||||||
m_onlineServices.saveArticleUnread(article);
|
m_onlineServices.saveArticleUnread(article);
|
||||||
}
|
}
|
||||||
m_onlineServices.setSelectedArticle(article);
|
m_onlineServices.onArticleSelected(article, false);
|
||||||
|
|
||||||
//Log.d(TAG, "Page #" + position + "/" + m_adapter.getCount());
|
//Log.d(TAG, "Page #" + position + "/" + m_adapter.getCount());
|
||||||
|
|
||||||
@ -104,8 +104,8 @@ public class ArticlePager extends Fragment {
|
|||||||
public void onAttach(Activity activity) {
|
public void onAttach(Activity activity) {
|
||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
|
|
||||||
m_hf = (HeadlinesFragment) getActivity().getSupportFragmentManager().findFragmentByTag(MainActivity.FRAG_HEADLINES);
|
m_hf = (HeadlinesFragment) getActivity().getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_HEADLINES);
|
||||||
m_onlineServices = (OnlineServices)activity;
|
m_onlineServices = (HeadlinesEventListener)activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import android.util.DisplayMetrics;
|
|||||||
import android.util.FloatMath;
|
import android.util.FloatMath;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
public class CommonActivity extends FragmentActivity {
|
public class CommonActivity extends FragmentActivity {
|
||||||
@ -31,6 +32,16 @@ public class CommonActivity extends FragmentActivity {
|
|||||||
m_smallScreenMode = smallScreen;
|
m_smallScreenMode = smallScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setLoadingStatus(int status, boolean showProgress) {
|
||||||
|
TextView tv = (TextView) findViewById(R.id.loading_message);
|
||||||
|
|
||||||
|
if (tv != null) {
|
||||||
|
tv.setText(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
setProgressBarIndeterminateVisibility(showProgress);
|
||||||
|
}
|
||||||
|
|
||||||
public void toast(int msgId) {
|
public void toast(int msgId) {
|
||||||
Toast toast = Toast.makeText(CommonActivity.this, msgId, Toast.LENGTH_SHORT);
|
Toast toast = Toast.makeText(CommonActivity.this, msgId, Toast.LENGTH_SHORT);
|
||||||
toast.show();
|
toast.show();
|
||||||
|
@ -7,6 +7,7 @@ import java.util.Comparator;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.fox.ttrss.types.Feed;
|
||||||
import org.fox.ttrss.types.FeedCategory;
|
import org.fox.ttrss.types.FeedCategory;
|
||||||
import org.fox.ttrss.types.FeedCategoryList;
|
import org.fox.ttrss.types.FeedCategoryList;
|
||||||
|
|
||||||
@ -17,9 +18,11 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
@ -42,7 +45,7 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
private FeedCategoryListAdapter m_adapter;
|
private FeedCategoryListAdapter m_adapter;
|
||||||
private FeedCategoryList m_cats = new FeedCategoryList();
|
private FeedCategoryList m_cats = new FeedCategoryList();
|
||||||
private FeedCategory m_selectedCat;
|
private FeedCategory m_selectedCat;
|
||||||
private OnlineServices m_onlineServices;
|
private FeedsActivity m_activity;
|
||||||
|
|
||||||
class CatUnreadComparator implements Comparator<FeedCategory> {
|
class CatUnreadComparator implements Comparator<FeedCategory> {
|
||||||
@Override
|
@Override
|
||||||
@ -82,6 +85,45 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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.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
|
@Override
|
||||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
ContextMenuInfo menuInfo) {
|
ContextMenuInfo menuInfo) {
|
||||||
@ -117,11 +159,6 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
list.setOnItemClickListener(this);
|
list.setOnItemClickListener(this);
|
||||||
registerForContextMenu(list);
|
registerForContextMenu(list);
|
||||||
|
|
||||||
if (m_cats == null || m_cats.size() == 0)
|
|
||||||
refresh(false);
|
|
||||||
else
|
|
||||||
getActivity().setProgressBarIndeterminateVisibility(false);
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,13 +166,22 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
public void onAttach(Activity activity) {
|
public void onAttach(Activity activity) {
|
||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
|
|
||||||
m_onlineServices = (OnlineServices)activity;
|
m_activity = (FeedsActivity)activity;
|
||||||
|
|
||||||
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
||||||
m_prefs.registerOnSharedPreferenceChangeListener(this);
|
m_prefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
refresh(false);
|
||||||
|
|
||||||
|
m_activity.initMenu();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState (Bundle out) {
|
public void onSaveInstanceState (Bundle out) {
|
||||||
super.onSaveInstanceState(out);
|
super.onSaveInstanceState(out);
|
||||||
@ -161,8 +207,8 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
public void refresh(boolean background) {
|
public void refresh(boolean background) {
|
||||||
CatsRequest req = new CatsRequest(getActivity().getApplicationContext());
|
CatsRequest req = new CatsRequest(getActivity().getApplicationContext());
|
||||||
|
|
||||||
final String sessionId = m_onlineServices.getSessionId();
|
final String sessionId = m_activity.getSessionId();
|
||||||
final boolean unreadOnly = m_onlineServices.getUnreadOnly();
|
final boolean unreadOnly = m_activity.getUnreadOnly();
|
||||||
|
|
||||||
if (sessionId != null) {
|
if (sessionId != null) {
|
||||||
|
|
||||||
@ -205,7 +251,7 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
|
|
||||||
m_cats.clear();
|
m_cats.clear();
|
||||||
|
|
||||||
int apiLevel = m_onlineServices.getApiLevel();
|
int apiLevel = m_activity.getApiLevel();
|
||||||
|
|
||||||
// virtual cats implemented in getCategories since api level 1
|
// virtual cats implemented in getCategories since api level 1
|
||||||
if (apiLevel == 0) {
|
if (apiLevel == 0) {
|
||||||
@ -233,7 +279,7 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_lastError == ApiError.LOGIN_FAILED) {
|
if (m_lastError == ApiError.LOGIN_FAILED) {
|
||||||
m_onlineServices.login();
|
m_activity.login();
|
||||||
} else {
|
} else {
|
||||||
setLoadingStatus(getErrorMessage(), false);
|
setLoadingStatus(getErrorMessage(), false);
|
||||||
}
|
}
|
||||||
@ -247,7 +293,7 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
if (m_prefs.getBoolean("sort_feeds_by_unread", false)) {
|
if (m_prefs.getBoolean("sort_feeds_by_unread", false)) {
|
||||||
cmp = new CatUnreadComparator();
|
cmp = new CatUnreadComparator();
|
||||||
} else {
|
} else {
|
||||||
if (m_onlineServices.getApiLevel() >= 3) {
|
if (m_activity.getApiLevel() >= 3) {
|
||||||
cmp = new CatOrderComparator();
|
cmp = new CatOrderComparator();
|
||||||
} else {
|
} else {
|
||||||
cmp = new CatTitleComparator();
|
cmp = new CatTitleComparator();
|
||||||
@ -280,7 +326,7 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
FeedCategory cat = items.get(position);
|
FeedCategory cat = items.get(position);
|
||||||
|
|
||||||
if (!m_onlineServices.isSmallScreen() && m_selectedCat != null && cat.id == m_selectedCat.id) {
|
if (!m_activity.isSmallScreen() && m_selectedCat != null && cat.id == m_selectedCat.id) {
|
||||||
return VIEW_SELECTED;
|
return VIEW_SELECTED;
|
||||||
} else {
|
} else {
|
||||||
return VIEW_NORMAL;
|
return VIEW_NORMAL;
|
||||||
@ -344,9 +390,9 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe
|
|||||||
|
|
||||||
if (list != null) {
|
if (list != null) {
|
||||||
FeedCategory cat = (FeedCategory)list.getItemAtPosition(position);
|
FeedCategory cat = (FeedCategory)list.getItemAtPosition(position);
|
||||||
m_onlineServices.onCatSelected(cat);
|
m_activity.onCatSelected(cat);
|
||||||
|
|
||||||
if (!m_onlineServices.isSmallScreen())
|
if (!m_activity.isSmallScreen())
|
||||||
m_selectedCat = cat;
|
m_selectedCat = cat;
|
||||||
|
|
||||||
m_adapter.notifyDataSetChanged();
|
m_adapter.notifyDataSetChanged();
|
||||||
|
212
src/org/fox/ttrss/FeedsActivity.java
Normal file
212
src/org/fox/ttrss/FeedsActivity.java
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
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.types.FeedCategory;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentTransaction;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
|
||||||
|
public class FeedsActivity extends OnlineActivity implements HeadlinesEventListener, ArticleEventListener {
|
||||||
|
private final String TAG = this.getClass().getSimpleName();
|
||||||
|
|
||||||
|
protected SharedPreferences m_prefs;
|
||||||
|
|
||||||
|
private boolean m_unreadOnly = true;
|
||||||
|
private boolean m_unreadArticlesOnly = true;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
m_prefs = PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(getApplicationContext());
|
||||||
|
|
||||||
|
if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) {
|
||||||
|
setTheme(R.style.DarkTheme);
|
||||||
|
} else {
|
||||||
|
setTheme(R.style.LightTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.feeds);
|
||||||
|
|
||||||
|
setSmallScreen(findViewById(R.id.headlines_fragment) == null);
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
ft.commit();
|
||||||
|
} else if (isSmallScreen()) {
|
||||||
|
Fragment frag = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
|
||||||
|
if (frag != null) {
|
||||||
|
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||||
|
ft.remove(frag);
|
||||||
|
ft.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getUnreadOnly() {
|
||||||
|
return m_unreadOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initMenu() {
|
||||||
|
super.initMenu();
|
||||||
|
if (m_menu != null) {
|
||||||
|
Fragment ff = getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS);
|
||||||
|
Fragment cf = getSupportFragmentManager().findFragmentByTag(FRAG_CATS);
|
||||||
|
Fragment af = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
|
||||||
|
|
||||||
|
m_menu.setGroupVisible(R.id.menu_group_feeds, ff != null || cf != null);
|
||||||
|
|
||||||
|
m_menu.setGroupVisible(R.id.menu_group_article, af != null);
|
||||||
|
|
||||||
|
HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
|
||||||
|
|
||||||
|
m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.getSelectedArticles().size() == 0);
|
||||||
|
m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.getSelectedArticles().size() != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void onFeedSelected(Feed feed) {
|
||||||
|
FragmentTransaction ft = getSupportFragmentManager()
|
||||||
|
.beginTransaction();
|
||||||
|
|
||||||
|
HeadlinesFragment hf = new HeadlinesFragment(feed);
|
||||||
|
|
||||||
|
if (isSmallScreen()) {
|
||||||
|
ft.replace(R.id.feeds_fragment, hf, FRAG_HEADLINES);
|
||||||
|
ft.addToBackStack(null);
|
||||||
|
} else {
|
||||||
|
ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES);
|
||||||
|
}
|
||||||
|
ft.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCatSelected(FeedCategory cat, boolean openAsFeed) {
|
||||||
|
|
||||||
|
FragmentTransaction ft = getSupportFragmentManager()
|
||||||
|
.beginTransaction();
|
||||||
|
|
||||||
|
if (!openAsFeed) {
|
||||||
|
FeedsFragment ff = new FeedsFragment(cat);
|
||||||
|
|
||||||
|
ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS);
|
||||||
|
} else {
|
||||||
|
Feed feed = new Feed(cat.id, cat.title, true);
|
||||||
|
onFeedSelected(feed);
|
||||||
|
}
|
||||||
|
|
||||||
|
ft.addToBackStack(null);
|
||||||
|
|
||||||
|
ft.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCatSelected(FeedCategory cat) {
|
||||||
|
onCatSelected(cat, m_prefs.getBoolean("browse_cats_like_feeds", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
default:
|
||||||
|
Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loginSuccess() {
|
||||||
|
setLoadingStatus(R.string.blank, false);
|
||||||
|
findViewById(R.id.loading_container).setVisibility(View.GONE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle out) {
|
||||||
|
super.onSaveInstanceState(out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getUnreadArticlesOnly() {
|
||||||
|
return m_unreadArticlesOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onArticleListSelectionChange(ArticleList m_selectedArticles) {
|
||||||
|
initMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onArticleSelected(Article article, boolean open) {
|
||||||
|
if (article.unread) {
|
||||||
|
article.unread = false;
|
||||||
|
saveArticleUnread(article);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (open) {
|
||||||
|
if (isSmallScreen()) {
|
||||||
|
FragmentTransaction ft = getSupportFragmentManager()
|
||||||
|
.beginTransaction();
|
||||||
|
|
||||||
|
Fragment frag = new ArticlePager(article);
|
||||||
|
|
||||||
|
ft.hide(getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES));
|
||||||
|
ft.add(R.id.feeds_fragment, frag, FRAG_ARTICLE);
|
||||||
|
ft.addToBackStack(null);
|
||||||
|
|
||||||
|
ft.commit();
|
||||||
|
} else {
|
||||||
|
Intent intent = new Intent(FeedsActivity.this, HeadlinesActivity.class);
|
||||||
|
intent.putExtra("sessionId", m_sessionId);
|
||||||
|
intent.putExtra("apiLevel", m_apiLevel);
|
||||||
|
|
||||||
|
HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
|
||||||
|
|
||||||
|
intent.putExtra("feed", hf.getFeed());
|
||||||
|
intent.putParcelableArrayListExtra("articles", hf.getAllArticles());
|
||||||
|
intent.putExtra("activeArticle", article);
|
||||||
|
intent.putExtra("article", article);
|
||||||
|
|
||||||
|
//intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
||||||
|
|
||||||
|
startActivityForResult(intent, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
|
||||||
|
if (hf != null) hf.setActiveArticle(article);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onArticleSelected(Article article) {
|
||||||
|
onArticleSelected(article, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
src/org/fox/ttrss/FeedsEventListener.java
Normal file
5
src/org/fox/ttrss/FeedsEventListener.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package org.fox.ttrss;
|
||||||
|
|
||||||
|
public interface FeedsEventListener {
|
||||||
|
|
||||||
|
}
|
@ -45,6 +45,7 @@ import android.util.Log;
|
|||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
@ -65,7 +66,7 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
private SharedPreferences m_prefs;
|
private SharedPreferences m_prefs;
|
||||||
private FeedListAdapter m_adapter;
|
private FeedListAdapter m_adapter;
|
||||||
private FeedList m_feeds = new FeedList();
|
private FeedList m_feeds = new FeedList();
|
||||||
private OnlineServices m_onlineServices;
|
private FeedsActivity m_activity;
|
||||||
private Feed m_selectedFeed;
|
private Feed m_selectedFeed;
|
||||||
private FeedCategory m_activeCategory;
|
private FeedCategory m_activeCategory;
|
||||||
private static final String ICON_PATH = "/data/org.fox.ttrss/icons/";
|
private static final String ICON_PATH = "/data/org.fox.ttrss/icons/";
|
||||||
@ -121,6 +122,26 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
|
||||||
|
.getMenuInfo();
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
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
|
@Override
|
||||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
ContextMenuInfo menuInfo) {
|
ContextMenuInfo menuInfo) {
|
||||||
@ -159,11 +180,6 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
|
|
||||||
m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false);
|
m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false);
|
||||||
|
|
||||||
if (m_feeds == null || m_feeds.size() == 0)
|
|
||||||
refresh(false);
|
|
||||||
else
|
|
||||||
getActivity().setProgressBarIndeterminateVisibility(false);
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,9 +195,16 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
||||||
m_prefs.registerOnSharedPreferenceChangeListener(this);
|
m_prefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
|
|
||||||
m_onlineServices = (OnlineServices)activity;
|
m_activity = (FeedsActivity)activity;
|
||||||
|
}
|
||||||
|
|
||||||
//m_selectedFeed = m_onlineServices.getActiveFeed();
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
refresh(false);
|
||||||
|
|
||||||
|
m_activity.initMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -200,9 +223,9 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
|
|
||||||
if (list != null) {
|
if (list != null) {
|
||||||
Feed feed = (Feed)list.getItemAtPosition(position);
|
Feed feed = (Feed)list.getItemAtPosition(position);
|
||||||
m_onlineServices.onFeedSelected(feed);
|
m_activity.onFeedSelected(feed);
|
||||||
|
|
||||||
if (!m_onlineServices.isSmallScreen())
|
if (!m_activity.isSmallScreen())
|
||||||
m_selectedFeed = feed;
|
m_selectedFeed = feed;
|
||||||
|
|
||||||
m_adapter.notifyDataSetChanged();
|
m_adapter.notifyDataSetChanged();
|
||||||
@ -215,8 +238,8 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
|
|
||||||
final int catId = (m_activeCategory != null) ? m_activeCategory.id : -4;
|
final int catId = (m_activeCategory != null) ? m_activeCategory.id : -4;
|
||||||
|
|
||||||
final String sessionId = m_onlineServices.getSessionId();
|
final String sessionId = m_activity.getSessionId();
|
||||||
final boolean unreadOnly = m_onlineServices.getUnreadOnly();
|
final boolean unreadOnly = m_activity.getUnreadOnly();
|
||||||
|
|
||||||
FeedsRequest req = new FeedsRequest(getActivity().getApplicationContext(), catId);
|
FeedsRequest req = new FeedsRequest(getActivity().getApplicationContext(), catId);
|
||||||
|
|
||||||
@ -292,7 +315,7 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final String sessionId = m_onlineServices.getSessionId();
|
final String sessionId = m_activity.getSessionId();
|
||||||
|
|
||||||
HashMap<String,String> map = new HashMap<String,String>() {
|
HashMap<String,String> map = new HashMap<String,String>() {
|
||||||
{
|
{
|
||||||
@ -347,7 +370,7 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_lastError == ApiError.LOGIN_FAILED) {
|
if (m_lastError == ApiError.LOGIN_FAILED) {
|
||||||
m_onlineServices.login();
|
m_activity.login();
|
||||||
} else {
|
} else {
|
||||||
setLoadingStatus(getErrorMessage(), false);
|
setLoadingStatus(getErrorMessage(), false);
|
||||||
}
|
}
|
||||||
@ -375,7 +398,7 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
Feed feed = items.get(position);
|
Feed feed = items.get(position);
|
||||||
|
|
||||||
if (!m_onlineServices.isSmallScreen() && m_selectedFeed != null && feed.id == m_selectedFeed.id) {
|
if (!m_activity.isSmallScreen() && m_selectedFeed != null && feed.id == m_selectedFeed.id) {
|
||||||
return VIEW_SELECTED;
|
return VIEW_SELECTED;
|
||||||
} else {
|
} else {
|
||||||
return VIEW_NORMAL;
|
return VIEW_NORMAL;
|
||||||
@ -449,7 +472,7 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh
|
|||||||
if (m_prefs.getBoolean("sort_feeds_by_unread", false)) {
|
if (m_prefs.getBoolean("sort_feeds_by_unread", false)) {
|
||||||
cmp = new FeedUnreadComparator();
|
cmp = new FeedUnreadComparator();
|
||||||
} else {
|
} else {
|
||||||
if (m_onlineServices.getApiLevel() >= 3) {
|
if (m_activity.getApiLevel() >= 3) {
|
||||||
cmp = new FeedOrderComparator();
|
cmp = new FeedOrderComparator();
|
||||||
} else {
|
} else {
|
||||||
cmp = new FeedTitleComparator();
|
cmp = new FeedTitleComparator();
|
||||||
|
160
src/org/fox/ttrss/HeadlinesActivity.java
Normal file
160
src/org/fox/ttrss/HeadlinesActivity.java
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
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.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentTransaction;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public class HeadlinesActivity extends OnlineActivity implements HeadlinesEventListener, ArticleEventListener {
|
||||||
|
private final String TAG = this.getClass().getSimpleName();
|
||||||
|
|
||||||
|
protected SharedPreferences m_prefs;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
m_prefs = PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(getApplicationContext());
|
||||||
|
|
||||||
|
if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) {
|
||||||
|
setTheme(R.style.DarkTheme);
|
||||||
|
} else {
|
||||||
|
setTheme(R.style.LightTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.headlines);
|
||||||
|
|
||||||
|
if (!isCompatMode()) {
|
||||||
|
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSmallScreen(findViewById(R.id.headlines_fragment) == null);
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||||
|
|
||||||
|
Intent i = getIntent();
|
||||||
|
|
||||||
|
if (i.getExtras() != null) {
|
||||||
|
Feed feed = i.getParcelableExtra("feed");
|
||||||
|
Article activeArticle = i.getParcelableExtra("activeArticle");
|
||||||
|
Article article = i.getParcelableExtra("article");
|
||||||
|
|
||||||
|
ArrayList<Article> alist = i.getParcelableArrayListExtra("articles");
|
||||||
|
ArticleList articles = new ArticleList();
|
||||||
|
|
||||||
|
for (Article a : alist)
|
||||||
|
articles.add(a);
|
||||||
|
|
||||||
|
HeadlinesFragment hf = new HeadlinesFragment(feed, activeArticle, articles);
|
||||||
|
|
||||||
|
ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES);
|
||||||
|
|
||||||
|
ArticlePager af = new ArticlePager(article);
|
||||||
|
|
||||||
|
ft.replace(R.id.article_fragment, af, FRAG_ARTICLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ft.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loginSuccess() {
|
||||||
|
Log.d(TAG, "loginSuccess");
|
||||||
|
|
||||||
|
setLoadingStatus(R.string.blank, false);
|
||||||
|
findViewById(R.id.loading_container).setVisibility(View.GONE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle out) {
|
||||||
|
super.onSaveInstanceState(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home:
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getUnreadArticlesOnly() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initMenu() {
|
||||||
|
super.initMenu();
|
||||||
|
|
||||||
|
if (m_menu != 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, hf != null && hf.getSelectedArticles().size() == 0);
|
||||||
|
m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.getSelectedArticles().size() != 0);
|
||||||
|
|
||||||
|
Fragment af = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
|
||||||
|
|
||||||
|
m_menu.setGroupVisible(R.id.menu_group_article, af != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 (open) {
|
||||||
|
FragmentTransaction ft = getSupportFragmentManager()
|
||||||
|
.beginTransaction();
|
||||||
|
|
||||||
|
Fragment frag = new ArticlePager(article);
|
||||||
|
|
||||||
|
ft.replace(R.id.article_fragment, frag, FRAG_ARTICLE);
|
||||||
|
//ft.addToBackStack(null);
|
||||||
|
|
||||||
|
ft.commit();
|
||||||
|
} else {
|
||||||
|
HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
|
||||||
|
if (hf != null) hf.setActiveArticle(article);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
14
src/org/fox/ttrss/HeadlinesEventListener.java
Normal file
14
src/org/fox/ttrss/HeadlinesEventListener.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package org.fox.ttrss;
|
||||||
|
|
||||||
|
import org.fox.ttrss.types.Article;
|
||||||
|
import org.fox.ttrss.types.ArticleList;
|
||||||
|
|
||||||
|
public interface HeadlinesEventListener {
|
||||||
|
|
||||||
|
boolean getUnreadArticlesOnly();
|
||||||
|
void onArticleListSelectionChange(ArticleList m_selectedArticles);
|
||||||
|
void onArticleSelected(Article article);
|
||||||
|
void saveArticleUnread(Article article);
|
||||||
|
void onArticleSelected(Article article, boolean b);
|
||||||
|
|
||||||
|
}
|
@ -34,6 +34,7 @@ import android.util.Log;
|
|||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -70,14 +71,16 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
private boolean m_canLoadMore = false;
|
private boolean m_canLoadMore = false;
|
||||||
private boolean m_combinedMode = true;
|
private boolean m_combinedMode = true;
|
||||||
private String m_searchQuery = "";
|
private String m_searchQuery = "";
|
||||||
|
private boolean m_noRefresh = false;
|
||||||
|
|
||||||
private SharedPreferences m_prefs;
|
private SharedPreferences m_prefs;
|
||||||
|
|
||||||
private ArticleListAdapter m_adapter;
|
private ArticleListAdapter m_adapter;
|
||||||
private ArticleList m_articles = new ArticleList();
|
private ArticleList m_articles = new ArticleList();
|
||||||
private ArticleList m_selectedArticles = new ArticleList();
|
private ArticleList m_selectedArticles = new ArticleList();
|
||||||
|
private HeadlinesEventListener m_listener;
|
||||||
|
|
||||||
private OnlineServices m_onlineServices;
|
private OnlineActivity m_activity;
|
||||||
|
|
||||||
private ImageGetter m_dummyGetter = new ImageGetter() {
|
private ImageGetter m_dummyGetter = new ImageGetter() {
|
||||||
|
|
||||||
@ -87,7 +90,6 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public ArticleList getSelectedArticles() {
|
public ArticleList getSelectedArticles() {
|
||||||
return m_selectedArticles;
|
return m_selectedArticles;
|
||||||
}
|
}
|
||||||
@ -96,15 +98,125 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
m_feed = feed;
|
m_feed = feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HeadlinesFragment(Feed feed, Article activeArticle, ArticleList articles) {
|
||||||
|
m_feed = feed;
|
||||||
|
m_activeArticle = activeArticle;
|
||||||
|
m_articles = articles;
|
||||||
|
m_noRefresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
public HeadlinesFragment() {
|
public HeadlinesFragment() {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
|
||||||
|
.getMenuInfo();
|
||||||
|
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
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.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) {
|
||||||
|
a.unread = false;
|
||||||
|
tmp.add(a);
|
||||||
|
if (article.id == a.id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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
|
@Override
|
||||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
ContextMenuInfo menuInfo) {
|
ContextMenuInfo menuInfo) {
|
||||||
|
|
||||||
getActivity().getMenuInflater().inflate(R.menu.headlines_menu, menu);
|
getActivity().getMenuInflater().inflate(R.menu.headlines_context_menu, menu);
|
||||||
|
|
||||||
if (m_selectedArticles.size() > 0) {
|
if (m_selectedArticles.size() > 0) {
|
||||||
menu.setHeaderTitle(R.string.headline_context_multiple);
|
menu.setHeaderTitle(R.string.headline_context_multiple);
|
||||||
@ -116,8 +228,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
menu.setGroupVisible(R.id.menu_group_single_article, true);
|
menu.setGroupVisible(R.id.menu_group_single_article, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.findItem(R.id.set_labels).setEnabled(m_onlineServices.getApiLevel() >= 1);
|
menu.findItem(R.id.set_labels).setEnabled(m_activity.getApiLevel() >= 1);
|
||||||
menu.findItem(R.id.article_set_note).setEnabled(m_onlineServices.getApiLevel() >= 1);
|
menu.findItem(R.id.article_set_note).setEnabled(m_activity.getApiLevel() >= 1);
|
||||||
|
|
||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
|
|
||||||
@ -146,24 +258,32 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
//list.setEmptyView(view.findViewById(R.id.no_headlines));
|
//list.setEmptyView(view.findViewById(R.id.no_headlines));
|
||||||
registerForContextMenu(list);
|
registerForContextMenu(list);
|
||||||
|
|
||||||
if (m_onlineServices.isSmallScreen() || m_onlineServices.isPortrait())
|
if (m_activity.isSmallScreen() || m_activity.isPortrait())
|
||||||
view.findViewById(R.id.headlines_fragment).setPadding(0, 0, 0, 0);
|
view.findViewById(R.id.headlines_fragment).setPadding(0, 0, 0, 0);
|
||||||
|
|
||||||
Log.d(TAG, "onCreateView, feed=" + m_feed);
|
Log.d(TAG, "onCreateView, feed=" + m_feed);
|
||||||
|
|
||||||
if (m_feed != null && (m_articles == null || m_articles.size() == 0))
|
|
||||||
refresh(false);
|
|
||||||
else
|
|
||||||
getActivity().setProgressBarIndeterminateVisibility(false);
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (!m_noRefresh) {
|
||||||
|
refresh(false);
|
||||||
|
m_noRefresh = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_activity.initMenu();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Activity activity) {
|
public void onAttach(Activity activity) {
|
||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
||||||
m_onlineServices = (OnlineServices) activity;
|
m_activity = (OnlineActivity) activity;
|
||||||
|
m_listener = (HeadlinesEventListener) activity;
|
||||||
|
|
||||||
m_combinedMode = m_prefs.getBoolean("combined_mode", false);
|
m_combinedMode = m_prefs.getBoolean("combined_mode", false);
|
||||||
}
|
}
|
||||||
@ -179,9 +299,9 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
if (article.id >= 0) {
|
if (article.id >= 0) {
|
||||||
if (m_combinedMode) {
|
if (m_combinedMode) {
|
||||||
article.unread = false;
|
article.unread = false;
|
||||||
m_onlineServices.saveArticleUnread(article);
|
m_activity.saveArticleUnread(article);
|
||||||
} else {
|
} else {
|
||||||
m_onlineServices.onArticleSelected(article);
|
m_listener.onArticleSelected(article);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_activeArticle = article;
|
m_activeArticle = article;
|
||||||
@ -196,8 +316,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
|
|
||||||
HeadlinesRequest req = new HeadlinesRequest(getActivity().getApplicationContext());
|
HeadlinesRequest req = new HeadlinesRequest(getActivity().getApplicationContext());
|
||||||
|
|
||||||
final String sessionId = m_onlineServices.getSessionId();
|
final String sessionId = m_activity.getSessionId();
|
||||||
final boolean showUnread = m_onlineServices.getUnreadArticlesOnly();
|
final boolean showUnread = m_listener.getUnreadArticlesOnly();
|
||||||
final boolean isCat = m_feed.is_cat;
|
final boolean isCat = m_feed.is_cat;
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
|
|
||||||
@ -319,7 +439,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_lastError == ApiError.LOGIN_FAILED) {
|
if (m_lastError == ApiError.LOGIN_FAILED) {
|
||||||
m_onlineServices.login();
|
m_activity.login();
|
||||||
} else {
|
} else {
|
||||||
setLoadingStatus(getErrorMessage(), false);
|
setLoadingStatus(getErrorMessage(), false);
|
||||||
}
|
}
|
||||||
@ -428,7 +548,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
article.marked = !article.marked;
|
article.marked = !article.marked;
|
||||||
m_adapter.notifyDataSetChanged();
|
m_adapter.notifyDataSetChanged();
|
||||||
|
|
||||||
m_onlineServices.saveArticleMarked(article);
|
m_activity.saveArticleMarked(article);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -445,7 +565,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
article.published = !article.published;
|
article.published = !article.published;
|
||||||
m_adapter.notifyDataSetChanged();
|
m_adapter.notifyDataSetChanged();
|
||||||
|
|
||||||
m_onlineServices.saveArticlePublished(article);
|
m_activity.saveArticlePublished(article);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -533,7 +653,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
Attachment attachment = (Attachment) spinner.getSelectedItem();
|
Attachment attachment = (Attachment) spinner.getSelectedItem();
|
||||||
|
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
m_onlineServices.copyToClipboard(attachment.content_url);
|
m_activity.copyToClipboard(attachment.content_url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -590,7 +710,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
m_selectedArticles.remove(article);
|
m_selectedArticles.remove(article);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_onlineServices.onArticleListSelectionChange(m_selectedArticles);
|
m_listener.onArticleListSelectionChange(m_selectedArticles);
|
||||||
|
|
||||||
Log.d(TAG, "num selected: " + m_selectedArticles.size());
|
Log.d(TAG, "num selected: " + m_selectedArticles.size());
|
||||||
}
|
}
|
||||||
@ -710,5 +830,9 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Feed getFeed() {
|
||||||
|
return m_feed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
526
src/org/fox/ttrss/OnlineActivity.java
Normal file
526
src/org/fox/ttrss/OnlineActivity.java
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
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 com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
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.support.v4.app.FragmentTransaction;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.widget.SearchView;
|
||||||
|
|
||||||
|
public class OnlineActivity extends CommonActivity {
|
||||||
|
private final String TAG = this.getClass().getSimpleName();
|
||||||
|
|
||||||
|
protected String m_sessionId;
|
||||||
|
protected SharedPreferences m_prefs;
|
||||||
|
protected int m_apiLevel = 0;
|
||||||
|
protected Menu m_menu;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
m_prefs = PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(getApplicationContext());
|
||||||
|
|
||||||
|
if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) {
|
||||||
|
setTheme(R.style.DarkTheme);
|
||||||
|
} else {
|
||||||
|
setTheme(R.style.LightTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||||
|
|
||||||
|
setProgressBarIndeterminateVisibility(false);
|
||||||
|
|
||||||
|
if (getIntent().getExtras() != null) {
|
||||||
|
Intent i = getIntent();
|
||||||
|
|
||||||
|
m_sessionId = i.getStringExtra("sessionId");
|
||||||
|
m_apiLevel = i.getIntExtra("apiLevel", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
m_sessionId = savedInstanceState.getString("sessionId");
|
||||||
|
m_apiLevel = savedInstanceState.getInt("apiLevel");
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "m_sessionId=" + m_sessionId);
|
||||||
|
Log.d(TAG, "m_apiLevel=" + m_apiLevel);
|
||||||
|
|
||||||
|
setContentView(R.layout.online);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void login() {
|
||||||
|
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 {
|
||||||
|
|
||||||
|
LoginRequest ar = new LoginRequest(getApplicationContext());
|
||||||
|
|
||||||
|
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() {
|
||||||
|
setLoadingStatus(R.string.blank, false);
|
||||||
|
findViewById(R.id.loading_container).setVisibility(View.GONE);
|
||||||
|
|
||||||
|
initMenu();
|
||||||
|
|
||||||
|
Intent intent = new Intent(OnlineActivity.this, FeedsActivity.class);
|
||||||
|
intent.putExtra("sessionId", m_sessionId);
|
||||||
|
intent.putExtra("apiLevel", m_apiLevel);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
||||||
|
|
||||||
|
startActivityForResult(intent, 0);
|
||||||
|
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.logout:
|
||||||
|
logout();
|
||||||
|
return true;
|
||||||
|
case R.id.login:
|
||||||
|
login();
|
||||||
|
return true;
|
||||||
|
case R.id.preferences:
|
||||||
|
Intent intent = new Intent(OnlineActivity.this,
|
||||||
|
PreferencesActivity.class);
|
||||||
|
startActivityForResult(intent, 0);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void logout() {
|
||||||
|
m_sessionId = null;
|
||||||
|
|
||||||
|
findViewById(R.id.loading_container).setVisibility(View.VISIBLE);
|
||||||
|
setLoadingStatus(R.string.login_ready, false);
|
||||||
|
|
||||||
|
initMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void loginFailure() {
|
||||||
|
m_sessionId = null;
|
||||||
|
initMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle out) {
|
||||||
|
super.onSaveInstanceState(out);
|
||||||
|
|
||||||
|
out.putString("sessionId", m_sessionId);
|
||||||
|
out.putInt("apiLevel", m_apiLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (m_sessionId == null) {
|
||||||
|
login();
|
||||||
|
} else {
|
||||||
|
loginSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getSessionId() {
|
||||||
|
return m_sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getApiLevel() {
|
||||||
|
return m_apiLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "serial" })
|
||||||
|
public void saveArticleUnread(final Article article) {
|
||||||
|
ApiRequest req = new ApiRequest(getApplicationContext());
|
||||||
|
|
||||||
|
HashMap<String, String> map = new HashMap<String, String>() {
|
||||||
|
{
|
||||||
|
put("sid", m_sessionId);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HashMap<String, String> map = new HashMap<String, String>() {
|
||||||
|
{
|
||||||
|
put("sid", m_sessionId);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HashMap<String, String> map = new HashMap<String, String>() {
|
||||||
|
{
|
||||||
|
put("sid", m_sessionId);
|
||||||
|
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", m_sessionId);
|
||||||
|
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 shareArticle(Article article) {
|
||||||
|
if (article != null) {
|
||||||
|
|
||||||
|
Intent intent = getShareIntent(article);
|
||||||
|
|
||||||
|
startActivity(Intent.createChooser(intent,
|
||||||
|
getString(R.string.share_article)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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", m_sessionId);
|
||||||
|
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", m_sessionId);
|
||||||
|
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", m_sessionId);
|
||||||
|
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", m_sessionId);
|
||||||
|
put("op", "updateArticle");
|
||||||
|
put("article_ids", articlesToIdString(articles));
|
||||||
|
put("mode", "2");
|
||||||
|
put("field", "1");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
req.execute(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void initMenu() {
|
||||||
|
Log.d(TAG, "initMenu:" + m_menu);
|
||||||
|
|
||||||
|
if (m_menu != null) {
|
||||||
|
if (m_sessionId != 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(m_apiLevel >= 1);
|
||||||
|
m_menu.findItem(R.id.article_set_note).setEnabled(m_apiLevel >= 1);
|
||||||
|
|
||||||
|
m_menu.findItem(R.id.close_feed).setVisible(!isSmallScreen());
|
||||||
|
m_menu.findItem(R.id.close_article).setVisible(!isSmallScreen());
|
||||||
|
|
||||||
|
MenuItem search = m_menu.findItem(R.id.search);
|
||||||
|
search.setEnabled(m_apiLevel >= 2);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LoginRequest extends ApiRequest {
|
||||||
|
public LoginRequest(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
|
||||||
|
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||||
|
|
||||||
|
loginSuccess();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
HashMap<String, String> map = new HashMap<String, String>() {
|
||||||
|
{
|
||||||
|
put("sid", m_sessionId);
|
||||||
|
put("op", "getApiLevel");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
req.execute(map);
|
||||||
|
|
||||||
|
setLoadingStatus(R.string.loading_message, true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sessionId = null;
|
||||||
|
setLoadingStatus(getErrorMessage(), false);
|
||||||
|
|
||||||
|
loginFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,32 +0,0 @@
|
|||||||
package org.fox.ttrss;
|
|
||||||
|
|
||||||
import org.fox.ttrss.types.Article;
|
|
||||||
import org.fox.ttrss.types.ArticleList;
|
|
||||||
import org.fox.ttrss.types.Feed;
|
|
||||||
import org.fox.ttrss.types.FeedCategory;
|
|
||||||
|
|
||||||
public interface OnlineServices {
|
|
||||||
public enum RelativeArticle { BEFORE, AFTER };
|
|
||||||
|
|
||||||
public void saveArticleUnread(final Article article);
|
|
||||||
public void saveArticleMarked(final Article article);
|
|
||||||
public void saveArticlePublished(final Article article);
|
|
||||||
public void setSelectedArticle(Article article);
|
|
||||||
public boolean getUnreadArticlesOnly();
|
|
||||||
|
|
||||||
public void onCatSelected(FeedCategory cat);
|
|
||||||
public void onFeedSelected(Feed feed);
|
|
||||||
public void onArticleSelected(Article article);
|
|
||||||
public void onArticleListSelectionChange(ArticleList selection);
|
|
||||||
|
|
||||||
//public void initMainMenu();
|
|
||||||
public void login();
|
|
||||||
public String getSessionId();
|
|
||||||
public boolean isSmallScreen();
|
|
||||||
public boolean getUnreadOnly();
|
|
||||||
public int getApiLevel();
|
|
||||||
public boolean isPortrait();
|
|
||||||
|
|
||||||
public void copyToClipboard(String str);
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -1,238 +0,0 @@
|
|||||||
package org.fox.ttrss.offline;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
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.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.text.Html;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.ContextMenu;
|
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.webkit.WebSettings;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
import android.webkit.WebSettings.LayoutAlgorithm;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
public class OfflineArticleFragment extends Fragment {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final String TAG = this.getClass().getSimpleName();
|
|
||||||
|
|
||||||
private SharedPreferences m_prefs;
|
|
||||||
private int m_articleId;
|
|
||||||
private Cursor m_cursor;
|
|
||||||
private OfflineServices m_offlineServices;
|
|
||||||
|
|
||||||
public OfflineArticleFragment() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public OfflineArticleFragment(int articleId) {
|
|
||||||
super();
|
|
||||||
m_articleId = articleId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@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_offlineServices.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"));
|
|
||||||
|
|
||||||
title.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
title.setText(Html.fromHtml("<a href=\""+m_cursor.getString(m_cursor.getColumnIndex("link")).trim().replace("\"", "\\\"")+"\">" + titleStr + "</a>"));
|
|
||||||
registerForContextMenu(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
WebView web = (WebView)view.findViewById(R.id.content);
|
|
||||||
|
|
||||||
if (web != null) {
|
|
||||||
|
|
||||||
String content;
|
|
||||||
String cssOverride = "";
|
|
||||||
|
|
||||||
WebSettings ws = web.getSettings();
|
|
||||||
ws.setSupportZoom(true);
|
|
||||||
ws.setBuiltInZoomControls(true);
|
|
||||||
|
|
||||||
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}";
|
|
||||||
//view.setBackgroundColor(android.R.color.black);
|
|
||||||
web.setBackgroundColor(getResources().getColor(android.R.color.transparent));
|
|
||||||
} else {
|
|
||||||
cssOverride = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
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(url)) {
|
|
||||||
img.attr("src", "file://" + ImageCacheService.getCacheFileName(url));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// thanks webview for crashing on <video> tag
|
|
||||||
Elements videos = doc.select("video");
|
|
||||||
|
|
||||||
for (Element video : videos)
|
|
||||||
video.remove();
|
|
||||||
|
|
||||||
articleContent = doc.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
view.findViewById(R.id.attachments_holder).setVisibility(View.GONE);
|
|
||||||
|
|
||||||
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 + "</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_offlineServices.activeFeedIsCat()) {
|
|
||||||
tagv.setText(m_cursor.getString(feedTitleIndex));
|
|
||||||
} else {
|
|
||||||
String tagsStr = m_cursor.getString(m_cursor.getColumnIndex("tags"));
|
|
||||||
tagv.setText(tagsStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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_offlineServices = (OfflineServices)activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
package org.fox.ttrss.offline;
|
|
||||||
|
|
||||||
import org.fox.ttrss.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.database.sqlite.SQLiteStatement;
|
|
||||||
import android.os.Bundle;
|
|
||||||
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.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
public class OfflineArticlePager extends Fragment {
|
|
||||||
|
|
||||||
private PagerAdapter m_adapter;
|
|
||||||
private OfflineServices m_offlineServices;
|
|
||||||
private OfflineHeadlinesFragment m_hf;
|
|
||||||
private int m_articleId;
|
|
||||||
|
|
||||||
private class PagerAdapter extends FragmentStatePagerAdapter {
|
|
||||||
|
|
||||||
public PagerAdapter(FragmentManager fm) {
|
|
||||||
super(fm);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Fragment getItem(int position) {
|
|
||||||
int articleId = m_hf.getArticleIdAtPosition(position);
|
|
||||||
|
|
||||||
if (articleId != 0) {
|
|
||||||
return new OfflineArticleFragment(articleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return m_hf.getArticleCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public OfflineArticlePager() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public OfflineArticlePager(int articleId) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
m_articleId = articleId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.article_pager, container, false);
|
|
||||||
|
|
||||||
m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager());
|
|
||||||
|
|
||||||
ViewPager pager = (ViewPager) view.findViewById(R.id.article_pager);
|
|
||||||
|
|
||||||
int position = m_hf.getArticleIdPosition(m_articleId);
|
|
||||||
|
|
||||||
pager.setAdapter(m_adapter);
|
|
||||||
pager.setCurrentItem(position);
|
|
||||||
pager.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) {
|
|
||||||
int articleId = m_hf.getArticleIdAtPosition(position);
|
|
||||||
|
|
||||||
if (articleId != 0) {
|
|
||||||
m_offlineServices.setSelectedArticleId(articleId);
|
|
||||||
|
|
||||||
SQLiteStatement stmt = m_offlineServices.getWritableDb().compileStatement(
|
|
||||||
"UPDATE articles SET unread = 0 " + "WHERE " + BaseColumns._ID
|
|
||||||
+ " = ?");
|
|
||||||
|
|
||||||
stmt.bindLong(1, articleId);
|
|
||||||
stmt.execute();
|
|
||||||
stmt.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity) {
|
|
||||||
super.onAttach(activity);
|
|
||||||
|
|
||||||
m_hf = (OfflineHeadlinesFragment) getActivity().getSupportFragmentManager().findFragmentByTag(OfflineActivity.FRAG_HEADLINES);
|
|
||||||
m_offlineServices = (OfflineServices)activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,452 +0,0 @@
|
|||||||
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.MainActivity;
|
|
||||||
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 = 40;
|
|
||||||
private static final int OFFLINE_SYNC_MAX = 500;
|
|
||||||
|
|
||||||
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 = m_prefs.getInt("offline_sync_max", OFFLINE_SYNC_MAX);
|
|
||||||
|
|
||||||
initDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
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, MainActivity.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 void onPostExecute(JsonElement content) {
|
|
||||||
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;");
|
|
||||||
|
|
||||||
if (m_canProceed) {
|
|
||||||
downloadArticles();
|
|
||||||
} else {
|
|
||||||
downloadFailed();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
updateNotification(R.string.offline_switch_error);
|
|
||||||
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()) {
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(JsonElement content) {
|
|
||||||
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");
|
|
||||||
|
|
||||||
if (m_canProceed) {
|
|
||||||
downloadFeeds();
|
|
||||||
} else {
|
|
||||||
downloadFailed();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
updateNotification(R.string.offline_switch_error);
|
|
||||||
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 {
|
|
||||||
public OfflineArticlesRequest(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(JsonElement content) {
|
|
||||||
if (content != null) {
|
|
||||||
try {
|
|
||||||
Type listType = new TypeToken<List<Article>>() {}.getType();
|
|
||||||
List<Article> 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 : 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(url)) {
|
|
||||||
Intent intent = new Intent(OfflineDownloadService.this,
|
|
||||||
ImageCacheService.class);
|
|
||||||
|
|
||||||
intent.putExtra("url", url);
|
|
||||||
startService(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
stmtInsert.execute();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtInsert.close();
|
|
||||||
|
|
||||||
//m_canGetMoreArticles = articles.size() == 30;
|
|
||||||
m_articleOffset += articles.size();
|
|
||||||
|
|
||||||
Log.d(TAG, "offline: received " + articles.size() + " articles; canProc=" + m_canProceed);
|
|
||||||
|
|
||||||
if (m_canProceed) {
|
|
||||||
if (articles.size() == OFFLINE_SYNC_SEQ && m_articleOffset < m_syncMax) {
|
|
||||||
downloadArticles();
|
|
||||||
} else {
|
|
||||||
downloadComplete();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
downloadFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
updateNotification(R.string.offline_switch_error);
|
|
||||||
Log.d(TAG, "offline: failed: exception when loading articles");
|
|
||||||
e.printStackTrace();
|
|
||||||
downloadFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "offline: failed: " + getErrorMessage());
|
|
||||||
updateNotification(getErrorMessage());
|
|
||||||
downloadFailed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart(Intent intent, int startId) {
|
|
||||||
m_sessionId = intent.getStringExtra("sessionId");
|
|
||||||
|
|
||||||
if (!m_downloadInProgress) {
|
|
||||||
if (m_downloadImages) ImageCacheService.cleanupCache(false);
|
|
||||||
|
|
||||||
updateNotification(R.string.notify_downloading_init);
|
|
||||||
m_downloadInProgress = true;
|
|
||||||
|
|
||||||
downloadCategories();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,262 +0,0 @@
|
|||||||
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.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 OfflineServices m_offlineServices;
|
|
||||||
|
|
||||||
@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")));
|
|
||||||
|
|
||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cursor createCursor() {
|
|
||||||
String unreadOnly = BaseColumns._ID + "> 0 AND " + (m_offlineServices.getUnreadOnly() ? "unread > 0" : "1");
|
|
||||||
|
|
||||||
String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title";
|
|
||||||
|
|
||||||
return m_offlineServices.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 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_offlineServices = (OfflineServices)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);
|
|
||||||
|
|
||||||
m_offlineServices.onCatSelected(feedId);
|
|
||||||
|
|
||||||
if (!m_offlineServices.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_offlineServices.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 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSelectedFeedId(int feedId) {
|
|
||||||
m_selectedCatId = feedId;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,306 +0,0 @@
|
|||||||
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.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 OfflineServices m_offlineServices;
|
|
||||||
|
|
||||||
public OfflineFeedsFragment() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
public OfflineFeedsFragment(int catId) {
|
|
||||||
m_catId = catId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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")));
|
|
||||||
|
|
||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cursor createCursor() {
|
|
||||||
String unreadOnly = m_offlineServices.getUnreadOnly() ? "unread > 0" : "1";
|
|
||||||
String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title";
|
|
||||||
|
|
||||||
if (m_catId != -1) {
|
|
||||||
return m_offlineServices.getReadableDb().query("feeds_unread",
|
|
||||||
null, unreadOnly + " AND cat_id = ?", new String[] { String.valueOf(m_catId) }, null, null, order);
|
|
||||||
} else {
|
|
||||||
return m_offlineServices.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_offlineServices = (OfflineServices)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);
|
|
||||||
|
|
||||||
m_offlineServices.onFeedSelected(feedId);
|
|
||||||
|
|
||||||
if (!m_offlineServices.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_offlineServices.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 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSelectedFeedId(int feedId) {
|
|
||||||
m_selectedFeedId = feedId;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,527 +0,0 @@
|
|||||||
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.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.text.method.LinkMovementMethod;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.ContextMenu;
|
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
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.ImageButton;
|
|
||||||
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 boolean m_combinedMode = true;
|
|
||||||
private String m_searchQuery = "";
|
|
||||||
|
|
||||||
private SharedPreferences m_prefs;
|
|
||||||
|
|
||||||
private Cursor m_cursor;
|
|
||||||
private ArticleListAdapter m_adapter;
|
|
||||||
|
|
||||||
private OfflineServices m_offlineServices;
|
|
||||||
|
|
||||||
private ImageGetter m_dummyGetter = new ImageGetter() {
|
|
||||||
|
|
||||||
@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_offlineServices.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 void onCreateContextMenu(ContextMenu menu, View v,
|
|
||||||
ContextMenuInfo menuInfo) {
|
|
||||||
|
|
||||||
getActivity().getMenuInflater().inflate(R.menu.headlines_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
setActiveArticleId(m_offlineServices.getSelectedArticleId());
|
|
||||||
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_combinedMode = savedInstanceState.getBoolean("combinedMode");
|
|
||||||
m_searchQuery = (String) savedInstanceState.getCharSequence("searchQuery");
|
|
||||||
m_feedIsCat = savedInstanceState.getBoolean("feedIsCat");
|
|
||||||
}
|
|
||||||
|
|
||||||
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_offlineServices.isSmallScreen() || m_offlineServices.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 = ?";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_searchQuery.equals("")) {
|
|
||||||
return m_offlineServices.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, "updated DESC");
|
|
||||||
} else {
|
|
||||||
return m_offlineServices.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, "updated DESC");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity) {
|
|
||||||
super.onAttach(activity);
|
|
||||||
m_offlineServices = (OfflineServices)activity;
|
|
||||||
|
|
||||||
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
|
||||||
m_combinedMode = m_prefs.getBoolean("combined_mode", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
|
|
||||||
m_activeArticleId = cursor.getInt(0);
|
|
||||||
|
|
||||||
SQLiteStatement stmtUpdate = m_offlineServices.getWritableDb().compileStatement("UPDATE articles SET unread = 0 " +
|
|
||||||
"WHERE " + BaseColumns._ID + " = ?");
|
|
||||||
|
|
||||||
stmtUpdate.bindLong(1, m_activeArticleId);
|
|
||||||
stmtUpdate.execute();
|
|
||||||
stmtUpdate.close();
|
|
||||||
|
|
||||||
if (!m_combinedMode) {
|
|
||||||
m_offlineServices.openArticle(m_activeArticleId, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
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.putBoolean("combinedMode", m_combinedMode);
|
|
||||||
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_LOADMORE = 3;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
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:
|
|
||||||
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) {
|
|
||||||
if (m_combinedMode) {
|
|
||||||
tt.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
tt.setText(Html.fromHtml("<a href=\""+article.getString(article.getColumnIndex("link")).trim().replace("\"", "\\\"")+"\">" +
|
|
||||||
article.getString(article.getColumnIndex("title")) + "</a>"));
|
|
||||||
} else {
|
|
||||||
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 != null) {
|
|
||||||
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_offlineServices.getWritableDb().compileStatement("UPDATE articles SET 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_offlineServices.getWritableDb().compileStatement("UPDATE articles SET 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) {
|
|
||||||
if (!m_combinedMode) {
|
|
||||||
String excerpt = Jsoup.parse(article.getString(article.getColumnIndex("content"))).text();
|
|
||||||
|
|
||||||
if (excerpt.length() > 100)
|
|
||||||
excerpt = excerpt.substring(0, 100) + "...";
|
|
||||||
|
|
||||||
te.setText(excerpt);
|
|
||||||
} else {
|
|
||||||
te.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ImageView separator = (ImageView)v.findViewById(R.id.headlines_separator);
|
|
||||||
|
|
||||||
if (separator != null && m_offlineServices.isSmallScreen()) {
|
|
||||||
separator.setVisibility(View.GONE);
|
|
||||||
} */
|
|
||||||
|
|
||||||
TextView content = (TextView)v.findViewById(R.id.content);
|
|
||||||
|
|
||||||
if (content != null) {
|
|
||||||
if (m_combinedMode) {
|
|
||||||
content.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
|
|
||||||
content.setText(Html.fromHtml(article.getString(article.getColumnIndex("content")), m_dummyGetter, null));
|
|
||||||
|
|
||||||
switch (Integer.parseInt(m_prefs.getString("font_size", "0"))) {
|
|
||||||
case 0:
|
|
||||||
content.setTextSize(15F);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
content.setTextSize(18F);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
content.setTextSize(21F);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
content.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
v.findViewById(R.id.attachments_holder).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_offlineServices.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_offlineServices.initMainMenu();
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
// m_adapter.notifyDataSetChanged();
|
|
||||||
|
|
||||||
ListView list = (ListView)getView().findViewById(R.id.headlines);
|
|
||||||
|
|
||||||
if (list != null) {
|
|
||||||
list.setSelection(getArticleIdPosition(articleId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getArticleCount() {
|
|
||||||
return m_adapter.getCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSearchQuery(String query) {
|
|
||||||
if (!m_searchQuery.equals(query)) {
|
|
||||||
m_searchQuery = query;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package org.fox.ttrss.offline;
|
|
||||||
|
|
||||||
import org.fox.ttrss.OnlineServices;
|
|
||||||
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
|
|
||||||
public interface OfflineServices {
|
|
||||||
public int getActiveFeedId();
|
|
||||||
public SQLiteDatabase getReadableDb();
|
|
||||||
public SQLiteDatabase getWritableDb();
|
|
||||||
public int getRelativeArticleId(int baseId, int feedId, OnlineServices.RelativeArticle mode);
|
|
||||||
public void onFeedSelected(int feedId);
|
|
||||||
public void onCatSelected(int catId);
|
|
||||||
public void openArticle(int articleId, int compatAnimation);
|
|
||||||
public boolean getUnreadOnly();
|
|
||||||
public int getSelectedArticleId();
|
|
||||||
public void initMainMenu();
|
|
||||||
public boolean isSmallScreen();
|
|
||||||
public void setSelectedArticleId(int articleId);
|
|
||||||
public boolean activeFeedIsCat();
|
|
||||||
public boolean isPortrait();
|
|
||||||
}
|
|
@ -1,264 +0,0 @@
|
|||||||
package org.fox.ttrss.offline;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import org.fox.ttrss.ApiRequest;
|
|
||||||
import org.fox.ttrss.MainActivity;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, MainActivity.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", "0");
|
|
||||||
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", "0");
|
|
||||||
put("field", "1");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
req.execute(map);
|
|
||||||
} else {
|
|
||||||
uploadSuccess();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onHandleIntent(Intent intent) {
|
|
||||||
m_sessionId = intent.getStringExtra("sessionId");
|
|
||||||
|
|
||||||
if (!m_uploadInProgress) {
|
|
||||||
m_uploadInProgress = true;
|
|
||||||
|
|
||||||
updateNotification(R.string.notify_uploading_sending_data);
|
|
||||||
|
|
||||||
uploadRead();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
257
src/org/fox/ttrss/util/ApiRequest.java
Normal file
257
src/org/fox/ttrss/util/ApiRequest.java
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
package org.fox.ttrss.util;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.auth.AuthScope;
|
||||||
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||||
|
import org.apache.http.client.CredentialsProvider;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.protocol.ClientContext;
|
||||||
|
import org.apache.http.conn.scheme.Scheme;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||||
|
import org.apache.http.protocol.BasicHttpContext;
|
||||||
|
import org.apache.http.protocol.HttpContext;
|
||||||
|
import org.fox.ttrss.R;
|
||||||
|
import org.fox.ttrss.R.string;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.http.AndroidHttpClient;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
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, PARSE_ERROR, IO_ERROR, OTHER_ERROR, API_DISABLED, API_UNKNOWN, LOGIN_FAILED, INVALID_URL, INCORRECT_USAGE };
|
||||||
|
|
||||||
|
public static final int API_STATUS_OK = 0;
|
||||||
|
public static final int API_STATUS_ERR = 1;
|
||||||
|
|
||||||
|
private String m_api;
|
||||||
|
private boolean m_trustAny = false;
|
||||||
|
private boolean m_transportDebugging = false;
|
||||||
|
protected int m_httpStatusCode = 0;
|
||||||
|
protected int m_apiStatusCode = 0;
|
||||||
|
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_trustAny = m_prefs.getBoolean("ssl_trust_any", false);
|
||||||
|
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 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 LOGIN_FAILED:
|
||||||
|
return R.string.error_login_failed;
|
||||||
|
case INVALID_URL:
|
||||||
|
return R.string.error_invalid_api_url;
|
||||||
|
case INCORRECT_USAGE:
|
||||||
|
return R.string.error_api_incorrect_usage;
|
||||||
|
default:
|
||||||
|
Log.d(TAG, "getErrorMessage: unknown error code=" + m_lastError);
|
||||||
|
return R.string.error_unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JsonElement doInBackground(HashMap<String, String>... params) {
|
||||||
|
|
||||||
|
Gson gson = new Gson();
|
||||||
|
|
||||||
|
String requestStr = gson.toJson(new HashMap<String,String>(params[0]));
|
||||||
|
|
||||||
|
if (m_transportDebugging) Log.d(TAG, ">>> (" + requestStr + ") " + m_api);
|
||||||
|
|
||||||
|
AndroidHttpClient client = AndroidHttpClient.newInstance("Tiny Tiny RSS");
|
||||||
|
|
||||||
|
if (m_trustAny) {
|
||||||
|
client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", new EasySSLSocketFactory(), 443));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
HttpPost httpPost;
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpPost = new HttpPost(m_api + "/api/");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
m_lastError = ApiError.INVALID_URL;
|
||||||
|
e.printStackTrace();
|
||||||
|
client.close();
|
||||||
|
return null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
m_lastError = ApiError.OTHER_ERROR;
|
||||||
|
e.printStackTrace();
|
||||||
|
client.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpContext context = null;
|
||||||
|
|
||||||
|
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.");
|
||||||
|
|
||||||
|
URL targetUrl;
|
||||||
|
try {
|
||||||
|
targetUrl = new URL(m_api);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
m_lastError = ApiError.INVALID_URL;
|
||||||
|
e.printStackTrace();
|
||||||
|
client.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpHost targetHost = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), targetUrl.getProtocol());
|
||||||
|
CredentialsProvider cp = new BasicCredentialsProvider();
|
||||||
|
context = new BasicHttpContext();
|
||||||
|
|
||||||
|
cp.setCredentials(
|
||||||
|
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
|
||||||
|
new UsernamePasswordCredentials(httpLogin, httpPassword));
|
||||||
|
|
||||||
|
context.setAttribute(ClientContext.CREDS_PROVIDER, cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpPost.setEntity(new StringEntity(requestStr, "utf-8"));
|
||||||
|
HttpResponse execute = client.execute(httpPost, context);
|
||||||
|
|
||||||
|
m_httpStatusCode = execute.getStatusLine().getStatusCode();
|
||||||
|
|
||||||
|
switch (m_httpStatusCode) {
|
||||||
|
case 200:
|
||||||
|
InputStream content = execute.getEntity().getContent();
|
||||||
|
|
||||||
|
BufferedReader buffer = new BufferedReader(
|
||||||
|
new InputStreamReader(content), 8192);
|
||||||
|
|
||||||
|
String s = "";
|
||||||
|
String response = "";
|
||||||
|
|
||||||
|
while ((s = buffer.readLine()) != null) {
|
||||||
|
response += s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_transportDebugging) Log.d(TAG, "<<< " + response);
|
||||||
|
|
||||||
|
JsonParser parser = new JsonParser();
|
||||||
|
|
||||||
|
JsonElement result = parser.parse(response);
|
||||||
|
JsonObject resultObj = result.getAsJsonObject();
|
||||||
|
|
||||||
|
m_apiStatusCode = resultObj.get("status").getAsInt();
|
||||||
|
|
||||||
|
client.close();
|
||||||
|
|
||||||
|
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.INCORRECT_USAGE;
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Unknown API error: " + error);
|
||||||
|
m_lastError = ApiError.API_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
case 401:
|
||||||
|
m_lastError = ApiError.HTTP_UNAUTHORIZED;
|
||||||
|
break;
|
||||||
|
case 403:
|
||||||
|
m_lastError = ApiError.HTTP_FORBIDDEN;
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
m_lastError = ApiError.HTTP_NOT_FOUND;
|
||||||
|
break;
|
||||||
|
case 500:
|
||||||
|
m_lastError = ApiError.HTTP_SERVER_ERROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_lastError = ApiError.HTTP_OTHER_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.close();
|
||||||
|
return null;
|
||||||
|
} catch (javax.net.ssl.SSLPeerUnverifiedException e) {
|
||||||
|
m_lastError = ApiError.SSL_REJECTED;
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
m_lastError = ApiError.IO_ERROR;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
client.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,208 +0,0 @@
|
|||||||
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.MainActivity;
|
|
||||||
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.Intent;
|
|
||||||
import android.os.Environment;
|
|
||||||
|
|
||||||
public class ImageCacheService extends IntentService {
|
|
||||||
|
|
||||||
private final String TAG = this.getClass().getSimpleName();
|
|
||||||
|
|
||||||
public static final int NOTIFY_DOWNLOADING = 1;
|
|
||||||
|
|
||||||
private static final String CACHE_PATH = "/data/org.fox.ttrss/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(String url) {
|
|
||||||
String hashedUrl = md5(url);
|
|
||||||
|
|
||||||
File storage = Environment.getExternalStorageDirectory();
|
|
||||||
|
|
||||||
File file = new File(storage.getAbsolutePath() + CACHE_PATH + "/" + hashedUrl + ".png");
|
|
||||||
|
|
||||||
return file.exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getCacheFileName(String url) {
|
|
||||||
String hashedUrl = md5(url);
|
|
||||||
|
|
||||||
File storage = Environment.getExternalStorageDirectory();
|
|
||||||
|
|
||||||
File file = new File(storage.getAbsolutePath() + CACHE_PATH + "/" + hashedUrl + ".png");
|
|
||||||
|
|
||||||
return file.getAbsolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void cleanupCache(boolean deleteAll) {
|
|
||||||
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
|
|
||||||
File storage = Environment.getExternalStorageDirectory();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, MainActivity.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 = Environment.getExternalStorageDirectory();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user