mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-21 05:45:13 +00:00
Several changes in one commit (bad me)
- Speed up main feed list refresh by not downloading feed icons and using nested feed list (rather than flat) - Update icons on main feed list in background now that they are no longer downloaded from sync - Cache gson builder as to not take penalty to rebuild it for each parse - Perform bulk insert of records into Sqlite DB during main feed list sync - Add initial support for shared feed button off story page (still needs a bit of work) - Add 'mark item read' and 'mark previous items read' functionality to the feed story list view
This commit is contained in:
parent
dc0507f43f
commit
60a828a914
26 changed files with 453 additions and 130 deletions
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle" >
|
||||||
|
|
||||||
|
<gradient
|
||||||
|
android:angle="270"
|
||||||
|
android:endColor="#1e78c1"
|
||||||
|
android:startColor="#42aaff" />
|
||||||
|
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="5dp"
|
||||||
|
android:bottomRightRadius="5dp"
|
||||||
|
android:topLeftRadius="5dp"
|
||||||
|
android:topRightRadius="5dp" />
|
||||||
|
|
||||||
|
</shape>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle" >
|
||||||
|
|
||||||
|
<gradient
|
||||||
|
android:angle="270"
|
||||||
|
android:endColor="#2379bf"
|
||||||
|
android:startColor="#1e78c1" />
|
||||||
|
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="5dp"
|
||||||
|
android:bottomRightRadius="5dp"
|
||||||
|
android:topLeftRadius="5dp"
|
||||||
|
android:topRightRadius="5dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<item android:state_pressed="true" android:drawable="@drawable/savebutton_background_pressed" />
|
||||||
|
<item android:drawable="@drawable/savebutton_background_default" />
|
||||||
|
</selector>
|
|
@ -13,6 +13,19 @@
|
||||||
android:padding="10dp"
|
android:padding="10dp"
|
||||||
android:text="@string/share_this" />
|
android:text="@string/share_this" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/save_story_button"
|
||||||
|
style="@style/saveButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:layout_marginLeft="20dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:background="@drawable/selector_savebutton_background"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:text="@string/save_this" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/reading_shared_container"
|
android:id="@+id/reading_shared_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
12
media/android/NewsBlur/res/menu/context_story.xml
Normal file
12
media/android/NewsBlur/res/menu/context_story.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<item android:id="@+id/menu_mark_story_as_read"
|
||||||
|
android:title="@string/menu_mark_story_as_read" />
|
||||||
|
|
||||||
|
<item android:id="@+id/menu_mark_previous_stories_as_read"
|
||||||
|
android:title="@string/menu_mark_previous_stories_as_read" />
|
||||||
|
|
||||||
|
<!-- TODO: Share/Unshare, Save/Unsave, mark unread -->
|
||||||
|
|
||||||
|
</menu>
|
|
@ -59,6 +59,8 @@
|
||||||
<string name="error_sharing">There was an problem sharing this story.</string>
|
<string name="error_sharing">There was an problem sharing this story.</string>
|
||||||
<string name="share_newsblur">Share \"%s\" to your Blurblog?</string>
|
<string name="share_newsblur">Share \"%s\" to your Blurblog?</string>
|
||||||
|
|
||||||
|
<string name="save_this">Save this story</string>
|
||||||
|
|
||||||
<string name="reply_to">Reply to \"%s\"</string>
|
<string name="reply_to">Reply to \"%s\"</string>
|
||||||
|
|
||||||
<string name="alert_dialog_ok">Okay</string>
|
<string name="alert_dialog_ok">Okay</string>
|
||||||
|
@ -93,6 +95,8 @@
|
||||||
<string name="menu_sharenewsblur">Share this story</string>
|
<string name="menu_sharenewsblur">Share this story</string>
|
||||||
<string name="menu_textsize">Adjust text size</string>
|
<string name="menu_textsize">Adjust text size</string>
|
||||||
<string name="menu_save_story">Save this story</string>
|
<string name="menu_save_story">Save this story</string>
|
||||||
|
<string name="menu_mark_previous_stories_as_read">Mark previous as read</string>
|
||||||
|
<string name="menu_mark_story_as_read">Mark as read</string>
|
||||||
|
|
||||||
<string name="toast_marked_folder_as_read">Folder marked as read</string>
|
<string name="toast_marked_folder_as_read">Folder marked as read</string>
|
||||||
<string name="toast_marked_feed_as_read">Feed marked as read</string>
|
<string name="toast_marked_feed_as_read">Feed marked as read</string>
|
||||||
|
|
|
@ -35,6 +35,18 @@
|
||||||
<item name="android:padding">10dp</item>
|
<item name="android:padding">10dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="saveButton" parent="@android:style/Widget.Button">
|
||||||
|
<item name="android:background">@drawable/selector_sharebutton_background</item>
|
||||||
|
<item name="android:textColor">@color/button_text_selector</item>
|
||||||
|
<item name="android:textStyle">normal</item>
|
||||||
|
<item name="android:shadowDx">0</item>
|
||||||
|
<item name="android:shadowDy">0</item>
|
||||||
|
<item name="android:shadowRadius">5</item>
|
||||||
|
<item name="android:shadowColor">#003366</item>
|
||||||
|
<item name="android:textSize">16sp</item>
|
||||||
|
<item name="android:padding">10dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<style name="button" parent="@android:style/Widget.Button">
|
<style name="button" parent="@android:style/Widget.Button">
|
||||||
<item name="android:background">@drawable/selector_button_background</item>
|
<item name="android:background">@drawable/selector_button_background</item>
|
||||||
|
|
|
@ -69,11 +69,10 @@ public class FeedItemsList extends ItemsList {
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
if (!super.onOptionsItemSelected(item)) {
|
if (!super.onOptionsItemSelected(item)) {
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == R.id.menu_delete_feed) {
|
||||||
case R.id.menu_delete_feed:
|
|
||||||
deleteFeed();
|
deleteFeed();
|
||||||
return true;
|
return true;
|
||||||
default:
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -62,12 +62,10 @@ public abstract class ItemsList extends SherlockFragmentActivity implements Sync
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == android.R.id.home) {
|
||||||
case android.R.id.home:
|
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (item.getItemId() == R.id.menu_mark_all_as_read) {
|
||||||
case R.id.menu_mark_all_as_read:
|
|
||||||
markItemListAsRead();
|
markItemListAsRead();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,19 +90,18 @@ public class Main extends SherlockFragmentActivity implements StateChangedListen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == R.id.menu_profile) {
|
||||||
case R.id.menu_profile:
|
|
||||||
Intent profileIntent = new Intent(this, Profile.class);
|
Intent profileIntent = new Intent(this, Profile.class);
|
||||||
startActivity(profileIntent);
|
startActivity(profileIntent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_refresh:
|
} else if (item.getItemId() == R.id.menu_refresh) {
|
||||||
triggerRecount();
|
triggerRecount();
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_add_feed:
|
} else if (item.getItemId() == R.id.menu_add_feed) {
|
||||||
Intent intent = new Intent(this, SearchForFeeds.class);
|
Intent intent = new Intent(this, SearchForFeeds.class);
|
||||||
startActivityForResult(intent, 0);
|
startActivityForResult(intent, 0);
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_logout:
|
} else if (item.getItemId() == R.id.menu_logout) {
|
||||||
DialogFragment newFragment = new LogoutDialogFragment();
|
DialogFragment newFragment = new LogoutDialogFragment();
|
||||||
newFragment.show(getSupportFragmentManager(), "dialog");
|
newFragment.show(getSupportFragmentManager(), "dialog");
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import com.newsblur.fragment.SyncUpdateFragment;
|
||||||
import com.newsblur.fragment.TextSizeDialogFragment;
|
import com.newsblur.fragment.TextSizeDialogFragment;
|
||||||
import com.newsblur.network.APIManager;
|
import com.newsblur.network.APIManager;
|
||||||
import com.newsblur.util.AppConstants;
|
import com.newsblur.util.AppConstants;
|
||||||
|
import com.newsblur.util.FeedUtils;
|
||||||
import com.newsblur.util.PrefConstants;
|
import com.newsblur.util.PrefConstants;
|
||||||
import com.newsblur.util.PrefsUtils;
|
import com.newsblur.util.PrefsUtils;
|
||||||
import com.newsblur.util.UIUtils;
|
import com.newsblur.util.UIUtils;
|
||||||
|
@ -119,25 +120,24 @@ public abstract class Reading extends SherlockFragmentActivity implements OnPage
|
||||||
Story story = readingAdapter.getStory(currentItem);
|
Story story = readingAdapter.getStory(currentItem);
|
||||||
UserDetails user = PrefsUtils.getUserDetails(this);
|
UserDetails user = PrefsUtils.getUserDetails(this);
|
||||||
|
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == android.R.id.home) {
|
||||||
case android.R.id.home:
|
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_reading_original:
|
} else if (item.getItemId() == R.id.menu_reading_original) {
|
||||||
if (story != null) {
|
if (story != null) {
|
||||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||||
i.setData(Uri.parse(story.permalink));
|
i.setData(Uri.parse(story.permalink));
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_reading_sharenewsblur:
|
} else if (item.getItemId() == R.id.menu_reading_sharenewsblur) {
|
||||||
if (story != null) {
|
if (story != null) {
|
||||||
ReadingItemFragment currentFragment = (ReadingItemFragment) readingAdapter.instantiateItem(pager, currentItem);
|
ReadingItemFragment currentFragment = (ReadingItemFragment) readingAdapter.instantiateItem(pager, currentItem);
|
||||||
DialogFragment newFragment = ShareDialogFragment.newInstance(currentFragment, story, currentFragment.previouslySavedShareText);
|
DialogFragment newFragment = ShareDialogFragment.newInstance(currentFragment, story, currentFragment.previouslySavedShareText);
|
||||||
newFragment.show(getSupportFragmentManager(), "dialog");
|
newFragment.show(getSupportFragmentManager(), "dialog");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_shared:
|
} else if (item.getItemId() == R.id.menu_shared) {
|
||||||
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
||||||
intent.setType("text/plain");
|
intent.setType("text/plain");
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||||
|
@ -146,35 +146,15 @@ public abstract class Reading extends SherlockFragmentActivity implements OnPage
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, String.format(shareString, new Object[] { story.title, story.permalink }));
|
intent.putExtra(Intent.EXTRA_TEXT, String.format(shareString, new Object[] { story.title, story.permalink }));
|
||||||
startActivity(Intent.createChooser(intent, "Share using"));
|
startActivity(Intent.createChooser(intent, "Share using"));
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_textsize:
|
} else if (item.getItemId() == R.id.menu_textsize) {
|
||||||
float currentValue = getSharedPreferences(PrefConstants.PREFERENCES, 0).getFloat(PrefConstants.PREFERENCE_TEXT_SIZE, 0.5f);
|
float currentValue = getSharedPreferences(PrefConstants.PREFERENCES, 0).getFloat(PrefConstants.PREFERENCE_TEXT_SIZE, 0.5f);
|
||||||
TextSizeDialogFragment textSize = TextSizeDialogFragment.newInstance(currentValue);
|
TextSizeDialogFragment textSize = TextSizeDialogFragment.newInstance(currentValue);
|
||||||
textSize.show(getSupportFragmentManager(), TEXT_SIZE);
|
textSize.show(getSupportFragmentManager(), TEXT_SIZE);
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_reading_save:
|
} else if (item.getItemId() == R.id.menu_reading_save) {
|
||||||
if (story != null) {
|
FeedUtils.saveStory(story, Reading.this, apiManager);
|
||||||
final String feedId = story.feedId;
|
|
||||||
final String storyId = story.id;
|
|
||||||
new AsyncTask<Void, Void, Boolean>() {
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... arg) {
|
|
||||||
return apiManager.markStoryAsStarred(feedId, storyId);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean result) {
|
|
||||||
if (result) {
|
|
||||||
Toast.makeText(Reading.this, R.string.toast_story_saved, Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
|
||||||
Toast.makeText(Reading.this, R.string.toast_story_save_error, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
} else {
|
|
||||||
Log.w(this.getClass().getName(), "Couldn't save story, no selection found.");
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
default:
|
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,16 +83,12 @@ public class SearchForFeeds extends SherlockFragmentActivity implements LoaderCa
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == R.id.menu_search) {
|
||||||
|
|
||||||
case R.id.menu_search:
|
|
||||||
onSearchRequested();
|
onSearchRequested();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (item.getItemId() == android.R.id.home) {
|
||||||
case android.R.id.home:
|
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package com.newsblur.database;
|
package com.newsblur.database;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
@ -82,4 +85,20 @@ public class FeedItemsAdapter extends SimpleCursorAdapter {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Story getStory(int position) {
|
||||||
|
cursor.moveToPosition(position);
|
||||||
|
return Story.fromCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Story> getPreviousStories(int position) {
|
||||||
|
ArrayList<Story> stories = new ArrayList<Story>();
|
||||||
|
cursor.moveToPosition(0);
|
||||||
|
for(int i=0;i<=position && position < cursor.getCount();i++) {
|
||||||
|
Story story = Story.fromCursor(cursor);
|
||||||
|
stories.add(story);
|
||||||
|
cursor.moveToNext();
|
||||||
|
}
|
||||||
|
return stories;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package com.newsblur.database;
|
package com.newsblur.database;
|
||||||
|
|
||||||
import com.newsblur.util.AppConstants;
|
import android.R.string;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
|
@ -11,6 +10,8 @@ import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.newsblur.util.AppConstants;
|
||||||
|
|
||||||
public class FeedProvider extends ContentProvider {
|
public class FeedProvider extends ContentProvider {
|
||||||
|
|
||||||
private static final String TAG = "FeedProvider";
|
private static final String TAG = "FeedProvider";
|
||||||
|
@ -146,6 +147,41 @@ public class FeedProvider extends ContentProvider {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int bulkInsert(Uri uri, ContentValues[] valuesArray) {
|
||||||
|
int count = 0;
|
||||||
|
final SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
|
switch (uriMatcher.match(uri)) {
|
||||||
|
case ALL_FOLDERS:
|
||||||
|
db.beginTransaction();
|
||||||
|
try {
|
||||||
|
for(ContentValues values: valuesArray) {
|
||||||
|
db.insertWithOnConflict(DatabaseConstants.FEED_FOLDER_MAP_TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ALL_SOCIAL_FEEDS:
|
||||||
|
db.beginTransaction();
|
||||||
|
try {
|
||||||
|
for(ContentValues values: valuesArray) {
|
||||||
|
db.insertWithOnConflict(DatabaseConstants.SOCIALFEED_TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
count = super.bulkInsert(uri, valuesArray);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Uri insert(Uri uri, ContentValues values) {
|
public Uri insert(Uri uri, ContentValues values) {
|
||||||
final SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
final SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.newsblur.fragment;
|
package com.newsblur.fragment;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
@ -9,9 +12,13 @@ import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.support.v4.widget.CursorAdapter;
|
import android.support.v4.widget.CursorAdapter;
|
||||||
import android.support.v4.widget.SimpleCursorAdapter;
|
import android.view.ContextMenu;
|
||||||
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.View.OnCreateContextMenuListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
import android.widget.AbsListView.OnScrollListener;
|
import android.widget.AbsListView.OnScrollListener;
|
||||||
|
@ -27,16 +34,18 @@ import com.newsblur.database.DatabaseConstants;
|
||||||
import com.newsblur.database.FeedItemsAdapter;
|
import com.newsblur.database.FeedItemsAdapter;
|
||||||
import com.newsblur.database.FeedProvider;
|
import com.newsblur.database.FeedProvider;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
|
import com.newsblur.domain.Story;
|
||||||
|
import com.newsblur.network.MarkStoryAsReadTask;
|
||||||
import com.newsblur.util.NetworkUtils;
|
import com.newsblur.util.NetworkUtils;
|
||||||
import com.newsblur.view.FeedItemViewBinder;
|
import com.newsblur.view.FeedItemViewBinder;
|
||||||
|
|
||||||
public class FeedItemListFragment extends ItemListFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, OnScrollListener {
|
public class FeedItemListFragment extends ItemListFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, OnScrollListener, OnCreateContextMenuListener {
|
||||||
|
|
||||||
private static final String TAG = "itemListFragment";
|
private static final String TAG = "itemListFragment";
|
||||||
public static final String FRAGMENT_TAG = "itemListFragment";
|
public static final String FRAGMENT_TAG = "itemListFragment";
|
||||||
private ContentResolver contentResolver;
|
private ContentResolver contentResolver;
|
||||||
private String feedId;
|
private String feedId;
|
||||||
private SimpleCursorAdapter adapter;
|
private FeedItemsAdapter adapter;
|
||||||
private Uri storiesUri;
|
private Uri storiesUri;
|
||||||
private int currentState;
|
private int currentState;
|
||||||
private int currentPage = 1;
|
private int currentPage = 1;
|
||||||
|
@ -95,6 +104,7 @@ public class FeedItemListFragment extends ItemListFragment implements LoaderMana
|
||||||
adapter.setViewBinder(new FeedItemViewBinder(getActivity()));
|
adapter.setViewBinder(new FeedItemViewBinder(getActivity()));
|
||||||
itemList.setAdapter(adapter);
|
itemList.setAdapter(adapter);
|
||||||
itemList.setOnItemClickListener(this);
|
itemList.setOnItemClickListener(this);
|
||||||
|
itemList.setOnCreateContextMenuListener(this);
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +152,11 @@ public class FeedItemListFragment extends ItemListFragment implements LoaderMana
|
||||||
|
|
||||||
public void changeState(int state) {
|
public void changeState(int state) {
|
||||||
currentState = state;
|
currentState = state;
|
||||||
final String selection = FeedProvider.getStorySelectionFromState(state);
|
refreshStories();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshStories() {
|
||||||
|
final String selection = FeedProvider.getStorySelectionFromState(currentState);
|
||||||
Cursor cursor = contentResolver.query(storiesUri, null, selection, null, DatabaseConstants.STORY_DATE + " DESC");
|
Cursor cursor = contentResolver.query(storiesUri, null, selection, null, DatabaseConstants.STORY_DATE + " DESC");
|
||||||
adapter.swapCursor(cursor);
|
adapter.swapCursor(cursor);
|
||||||
}
|
}
|
||||||
|
@ -160,5 +174,57 @@ public class FeedItemListFragment extends ItemListFragment implements LoaderMana
|
||||||
public void onScrollStateChanged(AbsListView view, int scrollState) { }
|
public void onScrollStateChanged(AbsListView view, int scrollState) { }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
|
final AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
|
||||||
|
if (item.getItemId() == R.id.menu_mark_story_as_read) {
|
||||||
|
final Story story = adapter.getStory(menuInfo.position);
|
||||||
|
ArrayList<String> storyIdsToMarkRead = new ArrayList<String>();
|
||||||
|
storyIdsToMarkRead.add(story.id);
|
||||||
|
new MarkStoryAsReadTask(getActivity(), storyIdsToMarkRead, feedId) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void result) {
|
||||||
|
// TODO this isn't sufficient. We also need to update counts
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(DatabaseConstants.STORY_READ, true);
|
||||||
|
contentResolver.update(FeedProvider.STORY_URI.buildUpon().appendPath(story.id).build(), values, null, null);
|
||||||
|
refreshStories();
|
||||||
|
}
|
||||||
|
|
||||||
|
}.execute();
|
||||||
|
} else if (item.getItemId() == R.id.menu_mark_previous_stories_as_read) {
|
||||||
|
ArrayList<Story> previousStories = adapter.getPreviousStories(menuInfo.position);
|
||||||
|
final ArrayList<String> storyIdsToMarkRead = new ArrayList<String>();
|
||||||
|
for(Story story: previousStories) {
|
||||||
|
if(story.read == 0) {
|
||||||
|
storyIdsToMarkRead.add(story.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new MarkStoryAsReadTask(getActivity(), storyIdsToMarkRead, feedId) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void result) {
|
||||||
|
// TODO this isn't sufficient. We also need to update counts
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(DatabaseConstants.STORY_READ, true);
|
||||||
|
for(String storyId: storyIdsToMarkRead) {
|
||||||
|
contentResolver.update(FeedProvider.STORY_URI.buildUpon().appendPath(storyId).build(), values, null, null);
|
||||||
|
}
|
||||||
|
refreshStories();
|
||||||
|
}
|
||||||
|
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
return super.onContextItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
|
ContextMenuInfo menuInfo) {
|
||||||
|
MenuInflater inflater = getActivity().getMenuInflater();
|
||||||
|
|
||||||
|
inflater.inflate(R.menu.context_story, menu);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import com.newsblur.activity.AllStoriesItemsList;
|
||||||
import com.newsblur.activity.FeedItemsList;
|
import com.newsblur.activity.FeedItemsList;
|
||||||
import com.newsblur.activity.ItemsList;
|
import com.newsblur.activity.ItemsList;
|
||||||
import com.newsblur.activity.Main;
|
import com.newsblur.activity.Main;
|
||||||
|
import com.newsblur.activity.NewsBlurApplication;
|
||||||
import com.newsblur.activity.SocialFeedItemsList;
|
import com.newsblur.activity.SocialFeedItemsList;
|
||||||
import com.newsblur.database.DatabaseConstants;
|
import com.newsblur.database.DatabaseConstants;
|
||||||
import com.newsblur.database.FeedProvider;
|
import com.newsblur.database.FeedProvider;
|
||||||
|
@ -36,6 +37,7 @@ import com.newsblur.network.MarkFeedAsReadTask;
|
||||||
import com.newsblur.network.MarkFolderAsReadTask;
|
import com.newsblur.network.MarkFolderAsReadTask;
|
||||||
import com.newsblur.network.MarkSocialFeedAsReadTask;
|
import com.newsblur.network.MarkSocialFeedAsReadTask;
|
||||||
import com.newsblur.util.AppConstants;
|
import com.newsblur.util.AppConstants;
|
||||||
|
import com.newsblur.util.ImageLoader;
|
||||||
import com.newsblur.util.PrefConstants;
|
import com.newsblur.util.PrefConstants;
|
||||||
import com.newsblur.util.UIUtils;
|
import com.newsblur.util.UIUtils;
|
||||||
import com.newsblur.view.FolderTreeViewBinder;
|
import com.newsblur.view.FolderTreeViewBinder;
|
||||||
|
@ -64,7 +66,8 @@ public class FolderListFragment extends Fragment implements OnGroupClickListener
|
||||||
Cursor countCursor = resolver.query(FeedProvider.FEED_COUNT_URI, null, DatabaseConstants.SOCIAL_INTELLIGENCE_SOME, null, null);
|
Cursor countCursor = resolver.query(FeedProvider.FEED_COUNT_URI, null, DatabaseConstants.SOCIAL_INTELLIGENCE_SOME, null, null);
|
||||||
Cursor sharedCountCursor = resolver.query(FeedProvider.SOCIALCOUNT_URI, null, DatabaseConstants.SOCIAL_INTELLIGENCE_SOME, null, null);
|
Cursor sharedCountCursor = resolver.query(FeedProvider.SOCIALCOUNT_URI, null, DatabaseConstants.SOCIAL_INTELLIGENCE_SOME, null, null);
|
||||||
|
|
||||||
groupViewBinder = new FolderTreeViewBinder();
|
ImageLoader imageLoader = ((NewsBlurApplication) getActivity().getApplicationContext()).getImageLoader();
|
||||||
|
groupViewBinder = new FolderTreeViewBinder(imageLoader);
|
||||||
blogViewBinder = new SocialFeedViewBinder(getActivity());
|
blogViewBinder = new SocialFeedViewBinder(getActivity());
|
||||||
|
|
||||||
leftBound = UIUtils.convertDPsToPixels(getActivity(), 20);
|
leftBound = UIUtils.convertDPsToPixels(getActivity(), 20);
|
||||||
|
@ -72,7 +75,7 @@ public class FolderListFragment extends Fragment implements OnGroupClickListener
|
||||||
|
|
||||||
final String[] groupFrom = new String[] { DatabaseConstants.FOLDER_NAME, DatabaseConstants.SUM_POS, DatabaseConstants.SUM_NEUT };
|
final String[] groupFrom = new String[] { DatabaseConstants.FOLDER_NAME, DatabaseConstants.SUM_POS, DatabaseConstants.SUM_NEUT };
|
||||||
final int[] groupTo = new int[] { R.id.row_foldername, R.id.row_foldersumpos, R.id.row_foldersumneu };
|
final int[] groupTo = new int[] { R.id.row_foldername, R.id.row_foldersumpos, R.id.row_foldersumneu };
|
||||||
final String[] childFrom = new String[] { DatabaseConstants.FEED_TITLE, DatabaseConstants.FEED_FAVICON, DatabaseConstants.FEED_NEUTRAL_COUNT, DatabaseConstants.FEED_POSITIVE_COUNT };
|
final String[] childFrom = new String[] { DatabaseConstants.FEED_TITLE, DatabaseConstants.FEED_FAVICON_URL, DatabaseConstants.FEED_NEUTRAL_COUNT, DatabaseConstants.FEED_POSITIVE_COUNT };
|
||||||
final int[] childTo = new int[] { R.id.row_feedname, R.id.row_feedfavicon, R.id.row_feedneutral, R.id.row_feedpositive };
|
final int[] childTo = new int[] { R.id.row_feedname, R.id.row_feedfavicon, R.id.row_feedneutral, R.id.row_feedpositive };
|
||||||
final String[] blogFrom = new String[] { DatabaseConstants.SOCIAL_FEED_TITLE, DatabaseConstants.SOCIAL_FEED_ICON, DatabaseConstants.SOCIAL_FEED_NEUTRAL_COUNT, DatabaseConstants.SOCIAL_FEED_POSITIVE_COUNT };
|
final String[] blogFrom = new String[] { DatabaseConstants.SOCIAL_FEED_TITLE, DatabaseConstants.SOCIAL_FEED_ICON, DatabaseConstants.SOCIAL_FEED_NEUTRAL_COUNT, DatabaseConstants.SOCIAL_FEED_POSITIVE_COUNT };
|
||||||
final int[] blogTo = new int[] { R.id.row_socialfeed_name, R.id.row_socialfeed_icon, R.id.row_socialsumneu, R.id.row_socialsumpos };
|
final int[] blogTo = new int[] { R.id.row_socialfeed_name, R.id.row_socialfeed_icon, R.id.row_socialsumneu, R.id.row_socialsumpos };
|
||||||
|
@ -152,9 +155,7 @@ public class FolderListFragment extends Fragment implements OnGroupClickListener
|
||||||
@Override
|
@Override
|
||||||
public boolean onContextItemSelected(MenuItem item) {
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
final ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();
|
final ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == R.id.menu_mark_feed_as_read) {
|
||||||
|
|
||||||
case R.id.menu_mark_feed_as_read:
|
|
||||||
new MarkFeedAsReadTask(getActivity(), apiManager) {
|
new MarkFeedAsReadTask(getActivity(), apiManager) {
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Boolean result) {
|
protected void onPostExecute(Boolean result) {
|
||||||
|
@ -172,13 +173,11 @@ public class FolderListFragment extends Fragment implements OnGroupClickListener
|
||||||
}
|
}
|
||||||
}.execute(Long.toString(info.id));
|
}.execute(Long.toString(info.id));
|
||||||
return true;
|
return true;
|
||||||
|
} else if (item.getItemId() == R.id.menu_delete_feed) {
|
||||||
case R.id.menu_delete_feed:
|
|
||||||
Toast.makeText(getActivity(), "Deleted feed", Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), "Deleted feed", Toast.LENGTH_SHORT).show();
|
||||||
((Main) getActivity()).deleteFeed(info.id, null);
|
((Main) getActivity()).deleteFeed(info.id, null);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (item.getItemId() == R.id.menu_mark_folder_as_read) {
|
||||||
case R.id.menu_mark_folder_as_read:
|
|
||||||
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
||||||
if (folderAdapter.isExpandable(groupPosition)) {
|
if (folderAdapter.isExpandable(groupPosition)) {
|
||||||
final Cursor folderCursor = ((MixedExpandableListAdapter) list.getExpandableListAdapter()).getGroup(groupPosition);
|
final Cursor folderCursor = ((MixedExpandableListAdapter) list.getExpandableListAdapter()).getGroup(groupPosition);
|
||||||
|
|
|
@ -98,13 +98,10 @@ public class LoginRegisterFragment extends Fragment implements OnClickListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View viewClicked) {
|
public void onClick(View viewClicked) {
|
||||||
switch (viewClicked.getId()) {
|
if (viewClicked.getId() == R.id.login_button) {
|
||||||
case R.id.login_button:
|
|
||||||
logIn();
|
logIn();
|
||||||
break;
|
} else if (viewClicked.getId() == R.id.registration_button) {
|
||||||
case R.id.registration_button:
|
|
||||||
signUp();
|
signUp();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -179,13 +179,10 @@ public class ProfileDetailsFragment extends Fragment implements OnClickListener
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
switch (v.getId()) {
|
if (v.getId() == R.id.profile_follow_button) {
|
||||||
case R.id.profile_follow_button:
|
|
||||||
new FollowTask().execute();
|
new FollowTask().execute();
|
||||||
break;
|
} else if (v.getId() == R.id.profile_unfollow_button) {
|
||||||
case R.id.profile_unfollow_button:
|
|
||||||
new UnfollowTask().execute();
|
new UnfollowTask().execute();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,14 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.NewsBlurApplication;
|
import com.newsblur.activity.NewsBlurApplication;
|
||||||
|
import com.newsblur.activity.Reading;
|
||||||
import com.newsblur.domain.Classifier;
|
import com.newsblur.domain.Classifier;
|
||||||
import com.newsblur.domain.Story;
|
import com.newsblur.domain.Story;
|
||||||
import com.newsblur.domain.UserDetails;
|
import com.newsblur.domain.UserDetails;
|
||||||
import com.newsblur.network.APIManager;
|
import com.newsblur.network.APIManager;
|
||||||
import com.newsblur.network.SetupCommentSectionTask;
|
import com.newsblur.network.SetupCommentSectionTask;
|
||||||
import com.newsblur.util.AppConstants;
|
import com.newsblur.util.AppConstants;
|
||||||
|
import com.newsblur.util.FeedUtils;
|
||||||
import com.newsblur.util.ImageLoader;
|
import com.newsblur.util.ImageLoader;
|
||||||
import com.newsblur.util.PrefConstants;
|
import com.newsblur.util.PrefConstants;
|
||||||
import com.newsblur.util.PrefsUtils;
|
import com.newsblur.util.PrefsUtils;
|
||||||
|
@ -119,6 +121,7 @@ public class ReadingItemFragment extends Fragment implements ClassifierDialogFra
|
||||||
setupWebview(web);
|
setupWebview(web);
|
||||||
setupItemMetadata();
|
setupItemMetadata();
|
||||||
setupShareButton();
|
setupShareButton();
|
||||||
|
setupSaveButton();
|
||||||
|
|
||||||
if (story.sharedUserIds.length > 0 || story.commentCount > 0 ) {
|
if (story.sharedUserIds.length > 0 || story.commentCount > 0 ) {
|
||||||
view.findViewById(R.id.reading_share_bar).setVisibility(View.VISIBLE);
|
view.findViewById(R.id.reading_share_bar).setVisibility(View.VISIBLE);
|
||||||
|
@ -129,6 +132,18 @@ public class ReadingItemFragment extends Fragment implements ClassifierDialogFra
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupSaveButton() {
|
||||||
|
|
||||||
|
Button saveButton = (Button) view.findViewById(R.id.save_story_button);
|
||||||
|
|
||||||
|
saveButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
FeedUtils.saveStory(story, getActivity(), apiManager);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setupShareButton() {
|
private void setupShareButton() {
|
||||||
|
|
||||||
Button shareButton = (Button) view.findViewById(R.id.share_story_button);
|
Button shareButton = (Button) view.findViewById(R.id.share_story_button);
|
||||||
|
|
|
@ -6,8 +6,7 @@ public class APIConstants {
|
||||||
// they are not.
|
// they are not.
|
||||||
|
|
||||||
public static final String URL_LOGIN = "http://newsblur.com/api/login";
|
public static final String URL_LOGIN = "http://newsblur.com/api/login";
|
||||||
public static final String URL_FEEDS = "http://newsblur.com/reader/feeds/?include_favicons=true&flat=true";
|
public static final String URL_FEEDS = "http://newsblur.com/reader/feeds/";
|
||||||
public static final String URL_FEEDS_NO_UPDATE = "http://newsblur.com/reader/feeds/?include_favicons=true&flat=true&update_counts=false";
|
|
||||||
public static final String URL_USER_PROFILE = "http://newsblur.com/social/profile";
|
public static final String URL_USER_PROFILE = "http://newsblur.com/social/profile";
|
||||||
public static final String URL_MY_PROFILE = "http://newsblur.com/social/load_user_profile";
|
public static final String URL_MY_PROFILE = "http://newsblur.com/social/load_user_profile";
|
||||||
public static final String URL_FOLLOW = "http://newsblur.com/social/follow";
|
public static final String URL_FOLLOW = "http://newsblur.com/social/follow";
|
||||||
|
|
|
@ -48,16 +48,22 @@ public class APIManager {
|
||||||
|
|
||||||
private static final String TAG = "APIManager";
|
private static final String TAG = "APIManager";
|
||||||
private Context context;
|
private Context context;
|
||||||
private Gson gson;
|
private static Gson gson;
|
||||||
private ContentResolver contentResolver;
|
private ContentResolver contentResolver;
|
||||||
|
|
||||||
public APIManager(final Context context) {
|
public APIManager(final Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
contentResolver = context.getContentResolver();
|
||||||
|
initGsonIfNeededBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static synchronized void initGsonIfNeededBuilder() {
|
||||||
|
if(gson == null) {
|
||||||
final GsonBuilder builder = new GsonBuilder();
|
final GsonBuilder builder = new GsonBuilder();
|
||||||
builder.registerTypeAdapter(Date.class, new DateStringTypeAdapter());
|
builder.registerTypeAdapter(Date.class, new DateStringTypeAdapter());
|
||||||
contentResolver = context.getContentResolver();
|
|
||||||
gson = builder.create();
|
gson = builder.create();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public LoginResponse login(final String username, final String password) {
|
public LoginResponse login(final String username, final String password) {
|
||||||
final APIClient client = new APIClient(context);
|
final APIClient client = new APIClient(context);
|
||||||
|
@ -445,10 +451,9 @@ public class APIManager {
|
||||||
|
|
||||||
public boolean getFolderFeedMapping(boolean doUpdateCounts) {
|
public boolean getFolderFeedMapping(boolean doUpdateCounts) {
|
||||||
|
|
||||||
|
|
||||||
final APIClient client = new APIClient(context);
|
final APIClient client = new APIClient(context);
|
||||||
final APIResponse response = client.get(doUpdateCounts ? APIConstants.URL_FEEDS : APIConstants.URL_FEEDS_NO_UPDATE);
|
final APIResponse response = client.get(APIConstants.URL_FEEDS);
|
||||||
final FeedFolderResponse feedUpdate = gson.fromJson(response.responseString, FeedFolderResponse.class);
|
final FeedFolderResponse feedUpdate = new FeedFolderResponse(response.responseString, gson);
|
||||||
|
|
||||||
if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
|
if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
|
||||||
if (feedUpdate.folders.size() == 0) {
|
if (feedUpdate.folders.size() == 0) {
|
||||||
|
@ -457,11 +462,15 @@ public class APIManager {
|
||||||
|
|
||||||
HashMap<String, Feed> existingFeeds = getExistingFeeds();
|
HashMap<String, Feed> existingFeeds = getExistingFeeds();
|
||||||
|
|
||||||
|
List<ContentValues> feedValues = new ArrayList<ContentValues>();
|
||||||
for (String newFeedId : feedUpdate.feeds.keySet()) {
|
for (String newFeedId : feedUpdate.feeds.keySet()) {
|
||||||
if (existingFeeds.get(newFeedId) == null || !feedUpdate.feeds.get(newFeedId).equals(existingFeeds.get(newFeedId))) {
|
if (existingFeeds.get(newFeedId) == null || !feedUpdate.feeds.get(newFeedId).equals(existingFeeds.get(newFeedId))) {
|
||||||
contentResolver.insert(FeedProvider.FEEDS_URI, feedUpdate.feeds.get(newFeedId).getValues());
|
feedValues.add(feedUpdate.feeds.get(newFeedId).getValues());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(feedValues.size() > 0) {
|
||||||
|
contentResolver.bulkInsert(FeedProvider.FEEDS_URI, feedValues.toArray(new ContentValues[feedValues.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
for (String olderFeedId : existingFeeds.keySet()) {
|
for (String olderFeedId : existingFeeds.keySet()) {
|
||||||
if (feedUpdate.feeds.get(olderFeedId) == null) {
|
if (feedUpdate.feeds.get(olderFeedId) == null) {
|
||||||
|
@ -470,10 +479,13 @@ public class APIManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ContentValues> socialFeedValues = new ArrayList<ContentValues>();
|
||||||
for (final SocialFeed feed : feedUpdate.socialFeeds) {
|
for (final SocialFeed feed : feedUpdate.socialFeeds) {
|
||||||
contentResolver.insert(FeedProvider.SOCIAL_FEEDS_URI, feed.getValues());
|
socialFeedValues.add(feed.getValues());
|
||||||
|
}
|
||||||
|
if(socialFeedValues.size() > 0) {
|
||||||
|
contentResolver.bulkInsert(FeedProvider.SOCIAL_FEEDS_URI, socialFeedValues.toArray(new ContentValues[socialFeedValues.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Cursor folderCursor = contentResolver.query(FeedProvider.FOLDERS_URI, null, null, null, null);
|
Cursor folderCursor = contentResolver.query(FeedProvider.FOLDERS_URI, null, null, null, null);
|
||||||
folderCursor.moveToFirst();
|
folderCursor.moveToFirst();
|
||||||
|
|
|
@ -16,6 +16,10 @@ public class MarkStoryAsReadTask extends AsyncTask<Void, Void, Void> {
|
||||||
private final String feedId;
|
private final String feedId;
|
||||||
private final ArrayList<String> storyIds;
|
private final ArrayList<String> storyIds;
|
||||||
|
|
||||||
|
public MarkStoryAsReadTask(final Context context, final ArrayList<String> storyIds, final String feedId) {
|
||||||
|
this(context, null, storyIds, feedId);
|
||||||
|
}
|
||||||
|
|
||||||
public MarkStoryAsReadTask(final Context context, final SyncUpdateFragment fragment, final ArrayList<String> storyIds, final String feedId) {
|
public MarkStoryAsReadTask(final Context context, final SyncUpdateFragment fragment, final ArrayList<String> storyIds, final String feedId) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.receiver = fragment;
|
this.receiver = fragment;
|
||||||
|
@ -26,7 +30,9 @@ public class MarkStoryAsReadTask extends AsyncTask<Void, Void, Void> {
|
||||||
protected Void doInBackground(Void... stories) {
|
protected Void doInBackground(Void... stories) {
|
||||||
|
|
||||||
final Intent intent = new Intent(Intent.ACTION_SYNC, null, context, SyncService.class);
|
final Intent intent = new Intent(Intent.ACTION_SYNC, null, context, SyncService.class);
|
||||||
|
if(receiver != null) {
|
||||||
intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, receiver.receiver);
|
intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, receiver.receiver);
|
||||||
|
}
|
||||||
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_MARK_STORY_READ);
|
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_MARK_STORY_READ);
|
||||||
intent.putExtra(SyncService.EXTRA_TASK_FEED_ID, feedId);
|
intent.putExtra(SyncService.EXTRA_TASK_FEED_ID, feedId);
|
||||||
intent.putStringArrayListExtra(SyncService.EXTRA_TASK_STORY_ID, storyIds);
|
intent.putStringArrayListExtra(SyncService.EXTRA_TASK_STORY_ID, storyIds);
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
package com.newsblur.network.domain;
|
package com.newsblur.network.domain;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.domain.SocialFeed;
|
import com.newsblur.domain.SocialFeed;
|
||||||
|
@ -21,5 +31,88 @@ public class FeedFolderResponse {
|
||||||
@SerializedName("social_feeds")
|
@SerializedName("social_feeds")
|
||||||
public SocialFeed[] socialFeeds;
|
public SocialFeed[] socialFeeds;
|
||||||
|
|
||||||
|
public FeedFolderResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public FeedFolderResponse(String json, Gson gson) {
|
||||||
|
// This is a mess but I don't see a way to parse the mixed content in
|
||||||
|
// folders w/o going to low level Gson API
|
||||||
|
JsonParser parser = new JsonParser();
|
||||||
|
JsonObject asJsonObject = parser.parse(json).getAsJsonObject();
|
||||||
|
JsonArray jsonFoldersArray = (JsonArray) asJsonObject.get("folders");
|
||||||
|
ArrayList<String> nestedFolderList = new ArrayList<String>();
|
||||||
|
folders = new HashMap<String, List<Long>>();
|
||||||
|
parseFeedArray(nestedFolderList, folders, null, jsonFoldersArray);
|
||||||
|
|
||||||
|
JsonElement starredCountElement = asJsonObject.get("starred_count");
|
||||||
|
if(starredCountElement != null) {
|
||||||
|
starredCount = gson.fromJson(starredCountElement, int.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject feedsElement = (JsonObject) asJsonObject.get("feeds");
|
||||||
|
if(feedsElement != null) {
|
||||||
|
feeds = new HashMap<String, Feed>();
|
||||||
|
Set<Entry<String, JsonElement>> entrySet = feedsElement.entrySet();
|
||||||
|
Iterator<Entry<String, JsonElement>> iterator = entrySet.iterator();
|
||||||
|
while(iterator.hasNext()) {
|
||||||
|
Entry<String, JsonElement> feedElement = iterator.next();
|
||||||
|
Feed feed = gson.fromJson(feedElement.getValue(), Feed.class);
|
||||||
|
feeds.put(feedElement.getKey(), feed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArray socialFeedsArray = (JsonArray) asJsonObject.get("social_feeds");
|
||||||
|
if(socialFeedsArray != null) {
|
||||||
|
List<SocialFeed> socialFeedsList = new ArrayList<SocialFeed>();
|
||||||
|
for(int i=0;i<socialFeedsArray.size();i++) {
|
||||||
|
JsonElement jsonElement = socialFeedsArray.get(i);
|
||||||
|
SocialFeed socialFeed = gson.fromJson(jsonElement, SocialFeed.class);
|
||||||
|
socialFeedsList.add(socialFeed);
|
||||||
|
}
|
||||||
|
socialFeeds = socialFeedsList.toArray(new SocialFeed[socialFeedsArray.size()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFeed(JsonObject asJsonObject2, List<String> parentFeedNames, Map<String, List<Long>> folders) {
|
||||||
|
Set<Entry<String, JsonElement>> entrySet = asJsonObject2.entrySet();
|
||||||
|
Iterator<Entry<String, JsonElement>> iterator = entrySet.iterator();
|
||||||
|
while(iterator.hasNext()) {
|
||||||
|
Entry<String, JsonElement> next = iterator.next();
|
||||||
|
String key = next.getKey();
|
||||||
|
JsonArray value = (JsonArray) next.getValue();
|
||||||
|
parseFeedArray(parentFeedNames, folders, key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFeedArray(List<String> nestedFolderList,
|
||||||
|
Map<String, List<Long>> folders, String name, JsonArray arrayValue) {
|
||||||
|
String fullFolderName = getFolderName(name, nestedFolderList);
|
||||||
|
ArrayList<Long> feedIds = new ArrayList<Long>();
|
||||||
|
for(int k=0;k<arrayValue.size();k++) {
|
||||||
|
JsonElement jsonElement = arrayValue.get(k);
|
||||||
|
if(jsonElement.isJsonPrimitive()) {
|
||||||
|
feedIds.add(jsonElement.getAsLong());
|
||||||
|
} else {
|
||||||
|
List<String> nestedFolerListCopy = new ArrayList<String>(nestedFolderList);
|
||||||
|
if(name != null) {
|
||||||
|
nestedFolerListCopy.add(name);
|
||||||
|
}
|
||||||
|
parseFeed((JsonObject) jsonElement, nestedFolerListCopy, folders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
folders.put(fullFolderName, feedIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFolderName(String key, List<String> parentFeedNames) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for(String parentFolder: parentFeedNames) {
|
||||||
|
builder.append(parentFolder);
|
||||||
|
builder.append(" - ");
|
||||||
|
}
|
||||||
|
if(key != null) {
|
||||||
|
builder.append(key);
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
36
media/android/NewsBlur/src/com/newsblur/util/FeedUtils.java
Normal file
36
media/android/NewsBlur/src/com/newsblur/util/FeedUtils.java
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package com.newsblur.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.domain.Story;
|
||||||
|
import com.newsblur.network.APIManager;
|
||||||
|
|
||||||
|
public class FeedUtils {
|
||||||
|
|
||||||
|
public static void saveStory(final Story story, final Context context, final APIManager apiManager) {
|
||||||
|
if (story != null) {
|
||||||
|
final String feedId = story.feedId;
|
||||||
|
final String storyId = story.id;
|
||||||
|
new AsyncTask<Void, Void, Boolean>() {
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... arg) {
|
||||||
|
return apiManager.markStoryAsStarred(feedId, storyId);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
if (result) {
|
||||||
|
Toast.makeText(context, R.string.toast_story_saved, Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, R.string.toast_story_save_error, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
} else {
|
||||||
|
Log.w(FeedUtils.class.getName(), "Couldn't save story, no selection found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
|
import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Base64;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
@ -17,24 +16,28 @@ import com.newsblur.R;
|
||||||
import com.newsblur.activity.FolderItemsList;
|
import com.newsblur.activity.FolderItemsList;
|
||||||
import com.newsblur.database.DatabaseConstants;
|
import com.newsblur.database.DatabaseConstants;
|
||||||
import com.newsblur.util.AppConstants;
|
import com.newsblur.util.AppConstants;
|
||||||
|
import com.newsblur.util.ImageLoader;
|
||||||
|
|
||||||
public class FolderTreeViewBinder implements ViewBinder {
|
public class FolderTreeViewBinder implements ViewBinder {
|
||||||
|
|
||||||
private int currentState = AppConstants.STATE_SOME;
|
private int currentState = AppConstants.STATE_SOME;
|
||||||
private int READING_RETURNED = 0x02;
|
private int READING_RETURNED = 0x02;
|
||||||
|
private final ImageLoader imageLoader;
|
||||||
|
|
||||||
|
public FolderTreeViewBinder(ImageLoader imageLoader) {
|
||||||
|
this.imageLoader = imageLoader;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
|
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
|
||||||
if (TextUtils.equals(cursor.getColumnName(columnIndex), DatabaseConstants.FEED_FAVICON)) {
|
if (TextUtils.equals(cursor.getColumnName(columnIndex), DatabaseConstants.FEED_FAVICON_URL)) {
|
||||||
Bitmap bitmap = null;
|
if (cursor.getString(columnIndex) != null) {
|
||||||
if (cursor.getBlob(columnIndex) != null) {
|
String imageUrl = cursor.getString(columnIndex);
|
||||||
final byte[] data = Base64.decode(cursor.getBlob(columnIndex), Base64.DEFAULT);
|
imageLoader.displayImage(imageUrl, (ImageView)view);
|
||||||
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
} else {
|
||||||
}
|
Bitmap bitmap = BitmapFactory.decodeResource(view.getContext().getResources(), R.drawable.world);
|
||||||
if (bitmap == null) {
|
|
||||||
bitmap = BitmapFactory.decodeResource(view.getContext().getResources(), R.drawable.world);
|
|
||||||
}
|
|
||||||
((ImageView) view).setImageBitmap(bitmap);
|
((ImageView) view).setImageBitmap(bitmap);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (TextUtils.equals(cursor.getColumnName(columnIndex), DatabaseConstants.FEED_POSITIVE_COUNT) || TextUtils.equals(cursor.getColumnName(columnIndex), DatabaseConstants.SUM_POS)) {
|
} else if (TextUtils.equals(cursor.getColumnName(columnIndex), DatabaseConstants.FEED_POSITIVE_COUNT) || TextUtils.equals(cursor.getColumnName(columnIndex), DatabaseConstants.SUM_POS)) {
|
||||||
int feedPositive = cursor.getInt(columnIndex);
|
int feedPositive = cursor.getInt(columnIndex);
|
||||||
|
|
|
@ -64,25 +64,21 @@ public class StateToggleButton extends LinearLayout implements OnClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setState(final int state) {
|
public void setState(final int state) {
|
||||||
switch (state) {
|
if (state == R.id.toggle_all) {
|
||||||
case R.id.toggle_all:
|
|
||||||
allButton.setEnabled(false);
|
allButton.setEnabled(false);
|
||||||
someButton.setEnabled(true);
|
someButton.setEnabled(true);
|
||||||
focusButton.setEnabled(true);
|
focusButton.setEnabled(true);
|
||||||
CURRENT_STATE = AppConstants.STATE_ALL;
|
CURRENT_STATE = AppConstants.STATE_ALL;
|
||||||
break;
|
} else if (state == R.id.toggle_some) {
|
||||||
case R.id.toggle_some:
|
|
||||||
allButton.setEnabled(true);
|
allButton.setEnabled(true);
|
||||||
someButton.setEnabled(false);
|
someButton.setEnabled(false);
|
||||||
focusButton.setEnabled(true);
|
focusButton.setEnabled(true);
|
||||||
CURRENT_STATE = AppConstants.STATE_SOME;
|
CURRENT_STATE = AppConstants.STATE_SOME;
|
||||||
break;
|
} else if (state == R.id.toggle_focus) {
|
||||||
case R.id.toggle_focus:
|
|
||||||
allButton.setEnabled(true);
|
allButton.setEnabled(true);
|
||||||
someButton.setEnabled(true);
|
someButton.setEnabled(true);
|
||||||
focusButton.setEnabled(false);
|
focusButton.setEnabled(false);
|
||||||
CURRENT_STATE = AppConstants.STATE_BEST;
|
CURRENT_STATE = AppConstants.STATE_BEST;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue