package com.gettingmobile.goodnews.itemlist; import android.content.Context; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.util.Log; import android.view.ContextMenu; import android.view.View; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.gettingmobile.android.widget.ListItem; import com.gettingmobile.goodnews.AutomaticallyClosingElementListActivity; import com.gettingmobile.goodnews.R; import com.gettingmobile.goodnews.itemview.ItemViewActivity; import com.gettingmobile.goodnews.settings.ItemDisplayType; import com.gettingmobile.goodnews.settings.ItemListSettingsHandler; import com.gettingmobile.goodnews.settings.SettingsHandler; import com.gettingmobile.google.reader.*; import com.gettingmobile.google.reader.db.ItemCursor; import com.gettingmobile.google.reader.db.ItemDatabaseAdapter; import com.gettingmobile.google.reader.db.ItemTagChangeDatabaseAdapter; import com.gettingmobile.google.reader.db.SortOrder; import java.util.Arrays; public final class ItemListActivity extends AutomaticallyClosingElementListActivity implements OnItemClickListener, AbsListView.OnScrollListener { private static final String LOG_TAG = "goodnews.ItemListActivity"; private static final String EXTRA_KEY_ITEM_KEYS = EXTRA_KEY_BASE + "ITEM_KEYS"; protected final ItemTagChangeDatabaseAdapter itemTagChangeAdapter = new ItemTagChangeDatabaseAdapter(); private ItemListView listView = null; private ItemRowViewType itemRowViewType = new ItemRowViewType(this); protected final ItemListAdapter itemListAdapter = new ItemListAdapter(this, itemTagChangeAdapter, itemRowViewType); private long[] itemKeys = null; private ItemListProvider itemListProvider = null; public ItemListActivity() { super(R.integer.tip_group_item_list); setViewLoader(new ItemListLoader()); setViewUpdater(new ItemListUpdater()); } protected ItemListProvider createItemListProvider() { final ElementId elementId = getIntentElementId(); if (elementId.equals(ItemState.STARRED.getId()) || elementId.equals(getApp().getSettings().getLabelReadListId())) { return new SpecialTagItemsListProvider(getApp(), elementId, getIntentElementKey(), getIntentElementTitle()); } else if (elementId.equals(ItemState.READING_LIST.getId())) { return new AllItemsListProvider(getApp(), elementId, getIntentElementTitle()); } else if (elementId.getType() == ElementType.FEED) { return new FeedItemsListProvider(getApp(), elementId, getIntentElementTitle()); } else if (getIntentElementIsStateOrLabel()) { return new LabelItemsListProvider(getApp(), elementId, getIntentElementKey(), getIntentElementTitle()); } else { return new FolderItemsListProvider(getApp(), elementId, getIntentElementKey(), getIntentElementTitle()); } } /* * life cycle management */ @Override public void onCreate() { itemListProvider = createItemListProvider(); setContentView(R.layout.item_list); super.onCreate(); listView = (ItemListView) findViewById(R.id.items); listView.setOnItemClickListener(this); registerForContextMenu(listView); listView.setOnScrollListener(this); listView.setAdapter(itemListAdapter); } @Override protected void onPause() { commitTagChanges(); super.onPause(); } @Override protected void onSaveInstanceState(Bundle outState) { Log.d(LOG_TAG, "Saving instance state. itemKeys = " + Arrays.toString(itemKeys)); outState.putLongArray(EXTRA_KEY_ITEM_KEYS, itemKeys); super.onSaveInstanceState(outState); } @Override protected void onPostCreateRestoreSavedInstanceState(Bundle savedInstanceState) { itemKeys = savedInstanceState.getLongArray(EXTRA_KEY_ITEM_KEYS); Log.d(LOG_TAG, "Restoring instance state. itemKeys = " + Arrays.toString(itemKeys)); super.onPostCreateRestoreSavedInstanceState(savedInstanceState); } protected void commitTagChanges() { if (itemTagChangeAdapter.commitChanges(getDb())) { getApp().onItemTagsChanged(); } } @Override protected void closeCursor() { itemListAdapter.close(); } /* * helpers */ public static Intent createItemListIntent(Context context, Tag tag) { return createIntent(ItemListActivity.class, context, tag); } @Override protected ListView getListView() { return listView; } @Override protected boolean isUnreadListRead() { return itemListAdapter.isRead(); } /* * click events */ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (parent.getId() == R.id.items) { final ListItem listItem = (ListItem) itemListAdapter.getItem(position); if (listItem.getViewType() == ItemListAdapter.VIEW_TYPE_DEFAULT) { onItemClick((Item) listItem.getItem()); } } } public void openItem(Item item) { ItemViewActivity.startItemViewActivity(this, getIntentElementTitle(), item.getKey(), itemKeys); } public void openItemInBrowser(Item item) { startActivity(new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(item.getAlternate().getHref()))); /* * mark item as read and remove it from read list */ if (getApp().getSettings().markReadOnView()) { itemTagChangeAdapter.markItemRead(item, true); } if (getApp().getSettings().removeFromReadListOnView()) { itemTagChangeAdapter.removeItemTag(item, getApp().getSettings().getLabelReadListId()); } } public void onItemClick(Item item) { Log.d(LOG_TAG, "Clicked item " + item.getId()); boolean openInBrowser = getApp().getSettings().getItemDisplayType(item) == ItemDisplayType.BROWSER; if (openInBrowser && item.getAlternate() != null) { openItemInBrowser(item); } else { openItem(item); } } /* * mark read handling */ @Override protected boolean requiresMarkReadConfirmationDialog() { return getApp().getSettings().confirmMarkAllReadInItemList(); } @Override protected void markAllRead(SQLiteDatabase db) { final ItemDatabaseAdapter itemAdapter = new ItemDatabaseAdapter(); final ElementId id = getIntentElementId(); if (ItemState.READING_LIST.getId().equals(getIntentElementId())) { itemAdapter.markAllRead(db); } else if (id.getType() == ElementType.FEED) { itemAdapter.markReadByFeed(db, id); } else if (getIntentElementIsStateOrLabel()) { itemAdapter.markReadByLabel(db, id); } else { itemAdapter.markReadByFolder(db, id); } itemListAdapter.markAllRead(); } @Override protected void onMarkedRead() { if (automaticallyCloseWhenRead()) { finish(); } else { listView.updateVisibleItems(); } } protected void onMarkedItemRead() { if (automaticallyCloseWhenRead() && isUnreadListRead()) { finish(); } } protected void markReadTo(int lastIndex) { itemTagChangeAdapter.markItemsReadByKey(itemListAdapter.getUnreadKeysToPosition(lastIndex)); } @Override public void onScrollStateChanged(AbsListView absListView, int i) { // not interested } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (firstVisibleItem > 0 && getApp().getSettings().markReadOnScrollOver()) { markReadTo(firstVisibleItem - 1); } } /* * options menus */ @Override protected int getOptionsMenuResourceId() { return R.menu.item_list_options; } @Override protected Class<? extends SettingsHandler> getViewSettingsHandlerClass() { return ItemListSettingsHandler.class; } @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.findItem(R.id.menu_sort_ascending).setVisible(SortOrder.DESCENDING.equals(getSortOrder())); menu.findItem(R.id.menu_sort_descending).setVisible(SortOrder.ASCENDING.equals(getSortOrder())); /* * handle grouping items */ final boolean supportsGrouping = supportsGroupingByFeed(); menu.findItem(R.id.menu_grouped_feed).setVisible(supportsGrouping && !getGroupByFeeds()); menu.findItem(R.id.menu_grouped_flat).setVisible(supportsGrouping && getGroupByFeeds()); /* * enable feed options if applicable */ menu.findItem(R.id.menu_feed_preferences).setVisible(isFeedsList()); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.menu_sort_ascending) { setSortOrder(SortOrder.ASCENDING); } else if (item.getItemId() == R.id.menu_sort_descending) { setSortOrder(SortOrder.DESCENDING); }else if (item.getItemId() == R.id.menu_grouped_feed) { setGroupByFeeds(true); } else if (item.getItemId() == R.id.menu_grouped_flat) { setGroupByFeeds(false); } else if (item.getItemId() == R.id.menu_feed_preferences) { showFeedOptions(); } else { return super.onOptionsItemSelected(item); } return true; } /* * context menu handling */ protected ItemRowViewHandler getItemRowViewHandler(ContextMenu.ContextMenuInfo menuInfo) { ItemRowViewHandler rowViewHandler = null; if (menuInfo instanceof ListView.AdapterContextMenuInfo) { final ListView.AdapterContextMenuInfo cmi = (ListView.AdapterContextMenuInfo) menuInfo; if (cmi.targetView != null) { rowViewHandler = (ItemRowViewHandler) cmi.targetView.getTag(); } } return rowViewHandler; } protected int getItemIndex(ContextMenu.ContextMenuInfo menuInfo) { return (menuInfo instanceof ListView.AdapterContextMenuInfo) ? ((ListView.AdapterContextMenuInfo) menuInfo).position : -1; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); if (v.getId() == R.id.items) { final ItemRowViewHandler rowViewHandler = getItemRowViewHandler(menuInfo); if (rowViewHandler != null) { getMenuInflater().inflate(R.menu.item_context, menu); menu.setHeaderTitle(R.string.contextmenu_item); rowViewHandler.onPrepareContextMenu(menu); } } } @Override public boolean onContextItemSelected(android.view.MenuItem item) { final ItemRowViewHandler rowViewHandler = getItemRowViewHandler(item.getMenuInfo()); if (rowViewHandler != null) { if (item.getItemId() == R.id.menu_item_mark_read_until_here) { markReadTo(getItemIndex(item.getMenuInfo())); return true; } else { return rowViewHandler.onContextItemSelected(item.getItemId()); } } else { return super.onContextItemSelected(item); } } /* * command handling */ protected boolean isFeedsList() { final ElementId id = getIntentElementId(); return id.getType() == ElementType.FEED; } protected boolean supportsGroupingByFeed() { return !isFeedsList(); } protected boolean getGroupByFeeds() { return supportsGroupingByFeed() && (getIntentElementIsStateOrLabel() ? getApp().getSettings().groupByFeedsInLabels() : getApp().getSettings().groupByFeedsInFolders()); } protected void setGroupByFeeds(boolean groupByFeeds) { if (getIntentElementIsStateOrLabel()) { getApp().getSettings().setGroupByFeedsInLabels(groupByFeeds); } else { getApp().getSettings().setGroupByFeedsInFolders(groupByFeeds); } if (itemKeys != null) { updateView(); } else { loadView(); } } @Override protected boolean getHideRead() { return getIntentElementIsStateOrLabel() ? getApp().getSettings().hideReadInLabelItemList() : getApp().getSettings().hideRead(); } @Override protected void setHideReadSetting(boolean hideRead) { if (getIntentElementIsStateOrLabel()) { getApp().getSettings().setHideReadInLabelItemList(hideRead); } else { getApp().getSettings().setHideRead(hideRead); } } protected SortOrder getSortOrder() { return getApp().getSettings().getItemSortOrder(); } protected void setSortOrder(SortOrder sortOrder) { getApp().getSettings().setItemSortOrder(sortOrder); if (itemKeys != null) { updateView(); } else { loadView(); } } private void showFeedOptions() { startActivity(settingsIntentFactory.createFeedSettingsIntent(getIntentElementId())); } /* * inner classes */ private class ItemListUpdater extends ViewOperation<ItemCursor> { @Override protected ItemCursor fetchData(SQLiteDatabase readOnlyDb) { Log.d(LOG_TAG, "committing tag changes"); commitTagChanges(); Log.d(LOG_TAG, "done committing tag changes"); return itemKeys != null ? loadItemsByKey(readOnlyDb) : loadItemsByList(readOnlyDb); } private ItemCursor loadItemsByKey(SQLiteDatabase readOnlyDb) { Log.d(LOG_TAG, "loading items by key; itemKeys = " + Arrays.toString(itemKeys)); final ItemCursor c = itemListProvider.readListItemsByKeys(readOnlyDb, itemKeys, getGroupByFeeds(), getSortOrder()); Log.d(LOG_TAG, "number of keys: " + itemKeys.length + "; number of entries: " + c.getCount()); return c; } private ItemCursor loadItemsByList(SQLiteDatabase readOnlyDb) { Log.d(LOG_TAG, "loading item list using " + itemListProvider.getClass() + "; group=" + getGroupByFeeds() + "; sortOrder=" + getSortOrder() + "; itemKeys=" + Arrays.toString(itemKeys)); final ItemCursor itemCursor = itemListProvider.readListItems(readOnlyDb, getGroupByFeeds(), getHideRead(), getSortOrder()); Log.d(LOG_TAG, "received item cursor for " + itemCursor.getCount() + " entries"); return itemCursor; } @Override protected boolean updateView(ItemCursor items) { Log.d(LOG_TAG, "applying item cursor to adapter"); itemListAdapter.changeCursor(items); itemKeys = itemListAdapter.getItemKeys(); Log.d(LOG_TAG, "Received itemKeys = " + Arrays.toString(itemKeys)); return items.getCount() > 0; } } final private class ItemListLoader extends ItemListUpdater { @Override protected ItemCursor fetchData(SQLiteDatabase readOnlyDb) { itemKeys = null; return super.fetchData(readOnlyDb); } } }