/*
* Copyright (C) 2013 Chris Lacy Licensed under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
* or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package com.tweetlanes.android.core.view;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ViewSwitcher;
import com.tweetlanes.android.core.AppSettings;
import com.tweetlanes.android.core.Constant;
import com.tweetlanes.android.core.Constant.SystemEvent;
import com.tweetlanes.android.core.Notifier;
import com.tweetlanes.android.core.R;
import com.tweetlanes.android.core.SharedPreferencesConstants;
import com.tweetlanes.android.core.model.AccountDescriptor;
import com.tweetlanes.android.core.model.ComposeTweetDefault;
import com.tweetlanes.android.core.util.LazyImageLoader;
import com.tweetlanes.android.core.widget.pulltorefresh.PullToRefreshBase.OnLastItemVisibleListener;
import com.tweetlanes.android.core.widget.pulltorefresh.PullToRefreshBase.OnRefreshListener;
import com.tweetlanes.android.core.widget.pulltorefresh.PullToRefreshListView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.socialnetlib.android.SocialNetConstant;
import org.tweetalib.android.TwitterConstant;
import org.tweetalib.android.TwitterConstant.StatusesType;
import org.tweetalib.android.TwitterContentHandle;
import org.tweetalib.android.TwitterContentHandleBase;
import org.tweetalib.android.TwitterFetchResult;
import org.tweetalib.android.TwitterFetchStatus;
import org.tweetalib.android.TwitterFetchUsers;
import org.tweetalib.android.TwitterManager;
import org.tweetalib.android.TwitterModifyStatuses;
import org.tweetalib.android.TwitterPaging;
import org.tweetalib.android.callback.TwitterFetchStatusesFinishedCallback;
import org.tweetalib.android.model.TwitterStatus;
import org.tweetalib.android.model.TwitterStatuses;
import org.tweetalib.android.model.TwitterUsers;
import java.util.ArrayList;
import java.util.Calendar;
public final class TweetFeedFragment extends BaseLaneFragment {
public static TweetFeedFragment newInstance(int laneIndex, final TwitterContentHandleBase handleBase,
final String screenName, final String laneIdentifier, final String currentAccountKey) {
TweetFeedFragment fragment = new TweetFeedFragment();
fragment.mContentHandle =
TwitterManager.get().getContentHandle(handleBase, screenName, laneIdentifier, currentAccountKey);
fragment.configureBaseLaneFragment(laneIndex, fragment.mContentHandle.getTypeAsString(),
new ConfigureBundleListener() {
@Override
public void addValues(Bundle args) {
// TODO: serializing is a slow way of doing this...
args.putSerializable(KEY_HANDLE_BASE, handleBase);
args.putString(KEY_SCREEN_NAME, screenName);
args.putString(KEY_LANE_IDENTIFIER, laneIdentifier);
}
});
return fragment;
}
private PullToRefreshListView mTweetFeedListView;
private TweetFeedListAdapter mTweetFeedListAdapter;
private TextView mListHeadingTextView;
private ImageView mListHeadingHideImage;
private boolean mHidingListHeading = false;
private boolean mDetached = false;
private TwitterContentHandle mContentHandle;
private TwitterStatuses _mStatusFeed; // Don't touch me directly. Use the
// accessors
private TwitterStatuses _mCachedStatusFeed;
private TwitterFetchStatusesFinishedCallback mTweetDataRefreshCallback;
private int mTimesFetchCalled;
private TwitterFetchStatusesFinishedCallback mTweetDataLoadMoreCallback;
private ViewSwitcher mViewSwitcher;
private final ArrayList<TweetFeedItemView> mSelectedItems = new ArrayList<TweetFeedItemView>();
private final ArrayList<Long> mConverstaionViewIds = new ArrayList<Long>();
private MultipleTweetSelectionCallback mMultipleTweetSelectionCallback;
private Long mNewestTweetId;
private Long mOldestTweetId;
private Long mRefreshingOldestTweetId;
private boolean mMoreStatusesAvailable = true;
private Long mResumeStatusId;
private LazyImageLoader mProfileImageLoader;
private LazyImageLoader mPreviewImageLoader;
private Calendar mLastRefreshTime = null;
/*
* (non-Javadoc)
*
* @see
* android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater,
* android.view.ViewGroup, android.os.Bundle)
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
mProfileImageLoader = getApp().getProfileImageLoader();
mPreviewImageLoader = getApp().getPreviewImageLoader();
mContentHandle = TwitterManager.get()
.getContentHandle(getContentHandleBase(), getScreenName(), getLaneIdentifier(),
getApp().getCurrentAccountKey());
View resultView = inflater.inflate(R.layout.lane, null);
configureLaneWidth(resultView);
mViewSwitcher = (ViewSwitcher) resultView.findViewById(R.id.profileSwitcher);
mListHeadingTextView = (TextView) resultView.findViewById(R.id.list_heading);
mListHeadingHideImage = (ImageView) resultView.findViewById(R.id.list_hide);
mListHeadingHideImage.setOnClickListener(mListHeadingHideImageOnClickListener);
mMultipleTweetSelectionCallback = new MultipleTweetSelectionCallback();
mTweetFeedListAdapter = new TweetFeedListAdapter(inflater);
mTweetFeedListView = (PullToRefreshListView) resultView.findViewById(R.id.pull_to_refresh_listview);
mTweetFeedListView.getRefreshableView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mTweetFeedListView.getRefreshableView().setMultiChoiceModeListener(mMultipleTweetSelectionCallback);
mTweetFeedListView.getRefreshableView().setOnScrollListener(mTweetFeedOnScrollListener);
mTweetFeedListView.getRefreshableView().setAdapter(mTweetFeedListAdapter);
mTweetFeedListView.setOnRefreshListener(mTweetFeedOnRefreshListener);
mTweetFeedListView.setOnLastItemVisibleListener(mTweetFeedOnLastItemVisibleListener);
mRefreshTimestampsHandler.removeCallbacks(mRefreshTimestampsTask);
mRefreshTimestampsHandler.postDelayed(mRefreshTimestampsTask, REFRESH_TIMESTAMPS_INTERVAL);
LocalBroadcastManager.getInstance(getActivity())
.registerReceiver(mVolumeUpKeyDownReceiver, new IntentFilter("" + SystemEvent.VOLUME_UP_KEY_DOWN));
LocalBroadcastManager.getInstance(getActivity())
.registerReceiver(mVolumeDownKeyDownReceiver, new IntentFilter("" + SystemEvent.VOLUME_DOWN_KEY_DOWN));
if (savedInstanceState != null) {
mTwitterStatusIdWhenRefreshed = savedInstanceState.containsKey("TwitterStatusIdWhenRefreshed") ? savedInstanceState.getLong("TwitterStatusIdWhenRefreshed") : 0L;
mLastTwitterStatusIdSeen = savedInstanceState.containsKey("LastTwitterStatusIdSeen") ? savedInstanceState.getLong("LastTwitterStatusIdSeen") : 0L;
mNewStatuses = savedInstanceState.getInt("NewStatuses", 0);
mHidingListHeading = savedInstanceState.getBoolean("HidingListHeading", false);
}
configureInitialStatuses();
return resultView;
}
@Override
public void onResume() {
super.onResume();
if (getLaneIndex() == getApp().getCurrentAccount().getCurrentLaneIndex(Constant.LaneType.USER_MENTIONS)) {
String cacheKey = "mentions_" + getApp().getCurrentAccountKey();
String mentionCachedData = getApp().getCachedData(cacheKey);
try {
if (mentionCachedData != null) {
TwitterStatuses mentionStatuses = new TwitterStatuses();
JSONArray jsonArray = new JSONArray(mentionCachedData);
for (int i = 0; i < jsonArray.length(); i++) {
String statusString = jsonArray.getString(i);
TwitterStatus status = new TwitterStatus(statusString);
mentionStatuses.add(status);
}
getApp().removeCachedData(cacheKey);
TwitterManager.get().getFetchStatusesInstance().cacheHashtags(mentionStatuses);
TwitterStatuses cachedFeed = TwitterManager.get().setContentFeed(mContentHandle, mentionStatuses);
beginListHeadingCount();
onRefreshFinished(cachedFeed);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (AppSettings.get().isAutoRefreshEnabled()) {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, -2);
if (mLastRefreshTime == null) {
fetchNewestTweets();
} else if (mLastRefreshTime.before(cal)) {
fetchNewestTweets();
}
}
}
@Override
public void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
if (mTwitterStatusIdWhenRefreshed != null)
state.putLong("TwitterStatusIdWhenRefreshed", mTwitterStatusIdWhenRefreshed);
if (mLastTwitterStatusIdSeen != null)
state.putLong("LastTwitterStatusIdSeen", mLastTwitterStatusIdSeen);
state.putInt("NewStatuses", mNewStatuses);
state.putBoolean("HidingListHeading", mHidingListHeading);
mSelectedItems.clear();
android.util.SparseBooleanArray items = mTweetFeedListView.getRefreshableView().getCheckedItemPositions();
for (int i = 0; i < items.size(); i++) {
int key = items.keyAt(i);
mTweetFeedListView.getRefreshableView().setItemChecked(key, false);
}
}
@Override
public void onDetach() {
super.onDetach();
mDetached = true;
}
/*
*
*/
private void configureInitialStatuses() {
boolean autoUpdateStatuses = false;
boolean configuredCachedStatuses = configureCachedStatuses();
TwitterStatuses cachedFeed = TwitterManager.get().getContentFeed(mContentHandle);
if (cachedFeed != null && cachedFeed.getStatusCount(getBaseLaneActivity().mStatusesFilter) > 0) {
setStatusFeed(cachedFeed, true);
} else if (!configuredCachedStatuses) {
autoUpdateStatuses = true;
setStatusFeed(null, true);
}
if (getStatusFeed() == null || getFilteredStatusCount() == 0) {
updateViewVisibility(false);
setInitialDownloadState(InitialDownloadState.WAITING);
} else {
setInitialDownloadState(InitialDownloadState.DOWNLOADED);
updateViewVisibility(true);
if (autoUpdateStatuses || AppSettings.get().isAutoRefreshEnabled()) {
fetchNewestTweets();
}
}
}
/*
*
*/
@Override
public void fetchNewestTweets() {
super.fetchNewestTweets();
if (mNewestTweetId != null) {
fetchNewestTweets(mNewestTweetId.longValue(), null);
}
}
private void lockScreenRotation() {
if (getActivity() != null) {
switch (getActivity().getResources().getConfiguration().orientation) {
case Configuration.ORIENTATION_PORTRAIT:
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
break;
case Configuration.ORIENTATION_LANDSCAPE:
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
break;
}
}
}
private void resetScreenRotation() {
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}
/*
*
*/
void fetchNewestTweets(final long sinceStatusId, Long maxStatusId) {
mTweetFeedListView.setRefreshing(false);
if (mTweetDataRefreshCallback == null) {
if (maxStatusId == null) {
lockScreenRotation();
mTimesFetchCalled = 0;
TwitterStatus visibleStatus = getVisibleStatus();
if (visibleStatus != null && mLastTwitterStatusIdSeen < visibleStatus.mId) {
mLastTwitterStatusIdSeen = visibleStatus.mId;
}
}
mTweetDataRefreshCallback = new TwitterFetchStatusesFinishedCallback() {
@Override
public void finished(TwitterFetchResult fetchResult, TwitterStatuses feed,
TwitterContentHandle contentHandle) {
if (!contentHandle.getCurrentAccountKey().equals(getApp().getCurrentAccountKey())) {
Log.e("Statuses", "account changed, don't display statuses");
return;
}
mTweetDataRefreshCallback = null;
if (fetchResult.isSuccessful()) {
// If there are more statuses to get, go get 'em
boolean doneGettingStatus = true;
if (feed != null && feed.getNewStatusesMaxId() != null) {
doneGettingStatus = false;
}
if (doneGettingStatus || mTimesFetchCalled > 8) {
beginListHeadingCount();
onRefreshFinished(feed);
} else {
fetchNewestTweets(sinceStatusId, feed.getNewStatusesMaxId());
}
} else {
onRefreshFinished(null);
}
}
};
if (mLastTwitterStatusIdSeen == null || mLastTwitterStatusIdSeen == 0) {
showToast(getString(R.string.pottential_lost_position));
onRefreshFinished(null);
}
mTimesFetchCalled++;
Log.d("api-call", "--fetchNewestTweets(" + mContentHandle.getStatusesType().toString() + ") --page: " + mTimesFetchCalled);
int pageSize = (TwitterPaging.INCREMENTING_STATUS_COUNT_START * mTimesFetchCalled);
if (pageSize > TwitterPaging.INCREMENTING_STATUS_COUNT_MAX) {
pageSize = TwitterPaging.INCREMENTING_STATUS_COUNT_MAX;
}
TwitterPaging paging = new TwitterPaging(null, pageSize, sinceStatusId, maxStatusId);
TwitterManager.get().triggerFetchStatuses(mContentHandle, paging, mTweetDataRefreshCallback,
getAsyncTaskPriorityOffset());
if (!getBaseLaneActivity().isComposing() &&
!(mSelectedItems == null || mSelectedItems.size() == 0)) {
getBaseLaneActivity().finishCurrentActionMode();
}
}
}
/*
* (non-Javadoc)
*
* @see com.tweetlanes.android.core.view.BaseLaneFragment#UpdateTweetCache()
*/
@Override
public void UpdateTweetCache(TwitterStatus status, boolean deleteStatus) {
TwitterStatuses statusFeed = getStatusFeed();
if (statusFeed != null) {
TwitterStatus cachedStatus = statusFeed.findByStatusId(status.mId);
if (cachedStatus != null) {
if (deleteStatus) {
TwitterStatuses selectedStatuses = new TwitterStatuses(cachedStatus);
if (statusFeed != null) statusFeed.remove(selectedStatuses);
if (_mCachedStatusFeed != null) _mCachedStatusFeed.remove(selectedStatuses);
TwitterManager.get().removeFromHashMap(selectedStatuses);
setStatusFeed(getStatusFeed(), true);
mTweetFeedListAdapter.notifyDataSetChanged();
mTweetFeedListView.onRefreshComplete();
updateViewVisibility(true);
} else {
cachedStatus.setFavorite(status.mIsFavorited);
cachedStatus.setRetweet(status.mIsRetweetedByMe);
cachedStatus.mFavoriteCount = status.mFavoriteCount;
cachedStatus.mRetweetCount = status.mRetweetCount;
}
}
}
}
/*
* (non-Javadoc)
*
* @see com.tweetlanes.android.core.view.BaseLaneFragment#onJumpToTop()
*/
@Override
public void onJumpToTop() {
if (mTweetFeedListView != null) {
ListView listView = mTweetFeedListView.getRefreshableView();
if (listView != null && listView.getAdapter() != null && !listView.getAdapter().isEmpty()) {
listView.setSelection(0);
}
}
}
private static final String KEY_VISIBLE_STATUS_ID = "visibleStatusId";
private static final String KEY_LAST_SEEN_STATUS_ID = "lastSeenStatusId";
private static final String KEY_HIDE_LIST_HEADING = "hideListHeading";
private static final String KEY_REFRESH_STATUS_ID = "refreshStatusId";
private static final String KEY_STATUSES = "statuses";
/*
* (non-Javadoc)
*
* @see com.tweetlanes.android.core.view.BaseLaneFragment#clearLocalCache()
*/
@Override
public void clearLocalCache() {
_mStatusFeed = null;
_mCachedStatusFeed = null;
}
/*
* (non-Javadoc)
*
* @see com.tweetlanes.android.core.view.BaseLaneFragment#getContentToCache()
*/
@Override
public String getDataToCache() {
TwitterStatuses feed = getStatusFeed();
if (feed == null || feed.getStatusCount() == 0) {
return null;
}
if (mTweetFeedListAdapter != null && mTweetFeedListView != null) {
ListView listView = mTweetFeedListView.getRefreshableView();
int visibleIndex = Math.max(listView.getFirstVisiblePosition() - 1, 0);
try {
visibleIndex = feed.getStatusIndex(mLastTwitterStatusIdSeen);
} catch (Exception e) {
}
// View view = (View)listView.getItemAtPosition(visible);
int startIndex = 0;
// int endIndex = Math.min(visibleIndex + 5,
// Math.min(getStatusFeed().getStatusCount(),
// mTweetFeedListAdapter.getCount()));
int endIndex = Math.min(visibleIndex + 10, feed.getStatusCount());
int cacheSize = AppSettings.get().getCacheSize();
if (cacheSize > 0) {
if (endIndex > cacheSize) {
startIndex = endIndex - cacheSize;
}
}
TwitterStatuses statuses = new TwitterStatuses();
for (int i = startIndex; i < endIndex; i++) {
TwitterStatus status = feed.getStatus(i);
if (status == null) {
break;
}
statuses.add(status);
}
Long visibleStatusId = null;
TwitterStatus visibleStatus = getVisibleStatus();
if (visibleStatus != null) {
visibleStatusId = visibleStatus.mId;
} else if (mLastTwitterStatusIdSeen != null && mLastTwitterStatusIdSeen > 0) {
visibleStatusId = mLastTwitterStatusIdSeen;
}
if (visibleStatusId != null) {
if (statuses.getStatusIndex(visibleStatusId) == null) {
Integer index = feed.getStatusIndex(visibleStatusId);
if (index != null) {
statuses.add(feed.getStatus(index.intValue()));
}
}
}
if (statuses.getStatusCount() > 0 && visibleStatusId != null) {
JSONObject object = new JSONObject();
try {
object.put(KEY_VISIBLE_STATUS_ID, visibleStatusId);
object.put(KEY_LAST_SEEN_STATUS_ID, mLastTwitterStatusIdSeen);
object.put(KEY_REFRESH_STATUS_ID, mTwitterStatusIdWhenRefreshed);
object.put(KEY_HIDE_LIST_HEADING, mHidingListHeading);
JSONArray statusArray = new JSONArray();
int statusCount = statuses.getStatusCount();
for (int i = 0; i < statusCount; ++i) {
TwitterStatus status = statuses.getStatus(i);
statusArray.put(status.toString());
}
object.put(KEY_STATUSES, statusArray);
} catch (JSONException e) {
e.printStackTrace();
}
return object.toString();
}
}
return null;
}
/*
*
*/
boolean configureCachedStatuses() {
String cachedData = getCachedData();
if (cachedData != null) {
JSONObject object;
try {
object = new JSONObject(cachedData);
if (object.has(KEY_VISIBLE_STATUS_ID)) {
mResumeStatusId = object.getLong(KEY_VISIBLE_STATUS_ID);
if (object.has(KEY_LAST_SEEN_STATUS_ID)) {
mLastTwitterStatusIdSeen = object.getLong(KEY_LAST_SEEN_STATUS_ID);
}
if (object.has(KEY_HIDE_LIST_HEADING)) {
mHidingListHeading = object.getBoolean(KEY_HIDE_LIST_HEADING);
}
if (object.has(KEY_REFRESH_STATUS_ID)) {
mTwitterStatusIdWhenRefreshed = object.getLong(KEY_REFRESH_STATUS_ID);
}
if (object.has(KEY_STATUSES)) {
String statusesAsString = object.getString(KEY_STATUSES);
if (statusesAsString != null) {
_mCachedStatusFeed = new TwitterStatuses();
JSONArray jsonArray = new JSONArray(statusesAsString);
for (int i = 0; i < jsonArray.length(); i++) {
String statusString = jsonArray.getString(i);
TwitterStatus status = new TwitterStatus(statusString);
_mCachedStatusFeed.add(status);
}
TwitterManager.get().getFetchStatusesInstance().cacheHashtags(_mCachedStatusFeed);
setStatusFeed(_mCachedStatusFeed, false);
if (getStatusFeed() != null && mLastTwitterStatusIdSeen != null) {
Integer index = getStatusFeed().getStatusIndex(mLastTwitterStatusIdSeen);
if (index != null) {
updateListHeading(index);
}
}
return true;
}
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OutOfMemoryError e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* com.tweetlanes.android.core.view.BaseLaneFragment#triggerInitialDownload()
*/
public void triggerInitialDownload() {
mTweetDataRefreshCallback = new TwitterFetchStatusesFinishedCallback() {
@Override
public void finished(TwitterFetchResult fetchResult, TwitterStatuses feed, TwitterContentHandle handle) {
if (!handle.getCurrentAccountKey().equals(getApp().getCurrentAccountKey())) {
Log.e("Statuses", "account changed, don't display statuses");
return;
}
if (feed != null) {
setStatusFeed(feed, true);
}
updateViewVisibility(true);
setInitialDownloadState(InitialDownloadState.DOWNLOADED);
mTweetDataRefreshCallback = null;
mTweetFeedListView.onRefreshComplete();
}
};
Log.d("api-call", "--triggerInitialDownload((" + mContentHandle.getStatusesType().toString() + ")");
TwitterManager.get()
.triggerFetchStatuses(mContentHandle, null, mTweetDataRefreshCallback, getAsyncTaskPriorityOffset());
setInitialDownloadState(InitialDownloadState.DOWNLOADING);
mTweetFeedListView.setRefreshing(true);
}
/*
*
*/
private final BroadcastReceiver mVolumeUpKeyDownReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (AppSettings.get().isVolScrollEnabled()) {
ListView listView = mTweetFeedListView.getRefreshableView();
int firstPos = listView.getFirstVisiblePosition();
int nextPos = firstPos - 1;
// Greater than 0 so we ignore the pullToRefresh
if (nextPos > 0) {
listView.setSelection(nextPos);
// listView.smoothScrollToPosition(nextPos);
listView.setScrollbarFadingEnabled(false);
}
}
}
};
/*
*
*/
private final BroadcastReceiver mVolumeDownKeyDownReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (AppSettings.get().isVolScrollEnabled()) {
ListView listView = mTweetFeedListView.getRefreshableView();
int nextPos = Math.max(1, listView.getFirstVisiblePosition()) + 1;
int last = listView.getLastVisiblePosition();
if (nextPos < last) {
listView.setSelection(nextPos);
// listView.smoothScrollToPosition(nextPos);
listView.setScrollbarFadingEnabled(false);
}
}
}
};
/*
*
*/
enum ScrollDirection {
UNKNOWN,
TO_NEWER,
TO_OLDER,
}
/*
*
*/
private class ScrollTracker {
private ScrollDirection mLastScrollDirection = ScrollDirection.UNKNOWN;
private int mFirstVisibleYOffset = 0;
private int mOldFirstVisibleYOffset = 0;
private int mOldFirstVisibleItem = 0;
private int mOldTotalItemCount = 0;
ScrollTracker() {
mLastScrollDirection = ScrollDirection.UNKNOWN;
mFirstVisibleYOffset = 0;
mOldFirstVisibleYOffset = 0;
mOldFirstVisibleItem = 0;
mOldTotalItemCount = 0;
}
void update(int firstVisibleItem, int totalItemCount, Integer yOffset) {
if (yOffset != null) {
mOldFirstVisibleYOffset = mFirstVisibleYOffset;
mFirstVisibleYOffset = yOffset;
}
if (mOldTotalItemCount != totalItemCount) {
// mLastScrollDirection = ScrollDirection.UNKNOWN;
} else {
if (mOldFirstVisibleItem == firstVisibleItem) {
if (mOldFirstVisibleYOffset > mFirstVisibleYOffset) {
mLastScrollDirection = ScrollDirection.TO_OLDER;
} else if (mOldFirstVisibleYOffset < mFirstVisibleYOffset) {
mLastScrollDirection = ScrollDirection.TO_NEWER;
}
} else {
if (mOldFirstVisibleItem > firstVisibleItem) {
mLastScrollDirection = ScrollDirection.TO_NEWER;
} else if (mOldFirstVisibleItem < firstVisibleItem) {
mLastScrollDirection = ScrollDirection.TO_OLDER;
}
}
}
mOldTotalItemCount = totalItemCount;
mOldFirstVisibleItem = firstVisibleItem;
}
int getFirstVisibleYOffset() {
return mFirstVisibleYOffset;
}
ScrollDirection getLastScrollDirection() {
return mLastScrollDirection;
}
}
private final ScrollTracker mScrollTracker = new ScrollTracker();
/*
*
*/
private final OnScrollListener mTweetFeedOnScrollListener = new OnScrollListener() {
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
Integer yOffset = null;
if (view != null && view.getChildAt(0) != null) {
yOffset = view.getChildAt(0).getTop();
}
if (firstVisibleItem == 1 && view != null && view.getChildAt(firstVisibleItem - 1) != null) {
int previousTop = view.getChildAt(firstVisibleItem - 1).getTop();
int previousBottom = view.getChildAt(firstVisibleItem - 1).getBottom();
if (previousBottom > 0 && previousTop >= -10) {
firstVisibleItem--;
}
}
mTweetFeedListView.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
mScrollTracker.update(firstVisibleItem, totalItemCount, yOffset);
updateListHeading(firstVisibleItem);
Long visibleStatusId = null;
TwitterStatus visibleStatus = getVisibleStatus();
if (visibleStatus != null) {
visibleStatusId = visibleStatus.mId;
} else if (mLastTwitterStatusIdSeen != null && mLastTwitterStatusIdSeen > 0) {
visibleStatusId = mLastTwitterStatusIdSeen;
}
mResumeStatusId = visibleStatusId;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == 0) {
// Restore scrollbar fading, which may have been set to false
// when scrolling through items via the volume keys
view.setScrollbarFadingEnabled(true);
}
mTweetFeedListView.onScrollStateChanged(view, scrollState);
}
};
/*
*
*/
private final OnLastItemVisibleListener mTweetFeedOnLastItemVisibleListener = new OnLastItemVisibleListener() {
@Override
public void onLastItemVisible() {
if (mOldestTweetId != null) {
if (mRefreshingOldestTweetId == null) {
if (mTweetDataLoadMoreCallback == null) {
mTweetDataLoadMoreCallback = new TwitterFetchStatusesFinishedCallback() {
@Override
public void finished(TwitterFetchResult result, TwitterStatuses feed,
TwitterContentHandle handle) {
if (!handle.getCurrentAccountKey().equals(getApp().getCurrentAccountKey())) {
Log.e("Statuses", "account changed, don't display statuses");
return;
}
if (feed != null) {
setStatusFeed(feed, true);
}
if (mRefreshingOldestTweetId != null && mOldestTweetId != null &&
mRefreshingOldestTweetId.longValue() == mOldestTweetId.longValue()) {
mMoreStatusesAvailable = false;
}
mRefreshingOldestTweetId = null;
mTweetDataLoadMoreCallback = null;
if (mTweetFeedListAdapter != null) {
mTweetFeedListAdapter.notifyDataSetChanged();
}
}
};
Log.d("api-call",
"--OnLastItemVisibleListener((" + mContentHandle.getStatusesType().toString() + ")");
TwitterManager.get()
.triggerFetchStatuses(mContentHandle, TwitterPaging.createGetOlder(mOldestTweetId),
mTweetDataLoadMoreCallback, getAsyncTaskPriorityOffset());
mRefreshingOldestTweetId = mOldestTweetId;
}
}
}
}
};
private Long mTwitterStatusIdWhenRefreshed = 0L;
private Long mLastTwitterStatusIdSeen = 0L;
private int mCurrentFirstVisibleItem = 0;
private int mNewStatuses = 0;
/*
*
*/
void beginListHeadingCount() {
if (mTwitterStatusIdWhenRefreshed == null) {
if (getStatusFeed() != null && mCurrentFirstVisibleItem < getStatusFeed().getStatusCount()) {
TwitterStatus status = getStatusFeed().getStatus(mCurrentFirstVisibleItem);
TwitterStatus visibleStatus = getVisibleStatus();
mTwitterStatusIdWhenRefreshed = status.mId;
mHidingListHeading = false;
if (visibleStatus != null && mLastTwitterStatusIdSeen < visibleStatus.mId) {
mLastTwitterStatusIdSeen = visibleStatus.mId;
}
}
}
}
/*
*
*/ private final OnClickListener mListHeadingHideImageOnClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
mHidingListHeading = true;
setListHeadingVisiblilty(View.GONE);
}
};
/*
*
*/
void setListHeadingVisiblilty(int value) {
mListHeadingTextView.setVisibility(value);
mListHeadingHideImage.setVisibility(value);
}
/*
*
*/
void updateListHeading(int firstVisibleItem) {
SocialNetConstant.Type socialNetType = getApp().getCurrentAccount().getSocialNetType();
TwitterStatuses twitterStatuses = getStatusFeed();
TwitterStatus status = null;
if (twitterStatuses != null) {
status = twitterStatuses.getStatus(firstVisibleItem);
}
if (mTwitterStatusIdWhenRefreshed != null && mTwitterStatusIdWhenRefreshed > 0 && firstVisibleItem > 0) {
if (!mHidingListHeading) {
if (status != null && (mNewStatuses == 0 || status.mId >= mTwitterStatusIdWhenRefreshed) && status.mId >= mLastTwitterStatusIdSeen) {
mNewStatuses = firstVisibleItem;
mLastTwitterStatusIdSeen = status.mId;
}
if (mNewStatuses > 0) {
setListHeadingVisiblilty(View.VISIBLE);
mListHeadingTextView.setText(mNewStatuses + " " + getString(mNewStatuses == 1 ?
socialNetType == SocialNetConstant.Type.Twitter ? R.string.new_tweet : R.string.new_post :
socialNetType == SocialNetConstant.Type.Twitter ? R.string.new_tweets :
R.string.new_posts));
} else {
if (status != null && status.mId >= mLastTwitterStatusIdSeen) {
mLastTwitterStatusIdSeen = status.mId;
}
setListHeadingVisiblilty(View.GONE);
mTwitterStatusIdWhenRefreshed = null;
}
}
} else {
if (status != null && status.mId >= mLastTwitterStatusIdSeen) {
mLastTwitterStatusIdSeen = status.mId;
}
setListHeadingVisiblilty(View.GONE);
mTwitterStatusIdWhenRefreshed = null;
}
mCurrentFirstVisibleItem = firstVisibleItem;
}
/*
*
*/
private TwitterStatus getVisibleStatus() {
TwitterStatus visibleStatus = null;
if (getStatusFeed() != null && mTweetFeedListView != null && mTweetFeedListView.getRefreshableView() != null) {
AdapterView view = mTweetFeedListView.getRefreshableView();
int visiblePosition = view.getFirstVisiblePosition();
if (visiblePosition == 1 && view != null && view.getChildAt(visiblePosition - 1) != null) {
int previousTop = view.getChildAt(visiblePosition - 1).getTop();
int previousBottom = view.getChildAt(visiblePosition - 1).getBottom();
if (previousBottom > 0 && previousTop >= -10) {
visiblePosition--;
}
}
if (visiblePosition < getStatusFeed().getStatusCount()) {
visibleStatus = getStatusFeed().getStatus(visiblePosition);
if (visibleStatus != null) {
String notifcationType = null;
String pref = null;
if (getLaneIndex() == getApp().getCurrentAccount().getCurrentLaneIndex(Constant.LaneType.USER_MENTIONS)) {
notifcationType = SharedPreferencesConstants.NOTIFICATION_TYPE_MENTION;
pref = SharedPreferencesConstants.NOTIFICATION_LAST_DISPLAYED_MENTION_ID;
} else if (getLaneIndex() == getApp().getCurrentAccount().getCurrentLaneIndex(Constant.LaneType.DIRECT_MESSAGES)) {
notifcationType = SharedPreferencesConstants.NOTIFICATION_TYPE_DIRECT_MESSAGE;
pref = SharedPreferencesConstants.NOTIFICATION_LAST_DISPLAYED_DIRECT_MESSAGE_ID;
}
if (notifcationType != null && pref != null) {
Notifier.saveLastNotificationActioned(getBaseLaneActivity(),
getApp().getCurrentAccountKey(), notifcationType, visibleStatus.mId);
Notifier.cancel(getBaseLaneActivity(), getApp().getCurrentAccountKey(), notifcationType);
}
}
}
}
return visibleStatus;
}
/*
*
*/
private void onRefreshFinished(TwitterStatuses feed) {
if (mTweetFeedListView == null || mTweetFeedListView.getRefreshableView() == null) {
return;
}
if (feed == null || feed.getStatusCount() == 0) {
mTweetFeedListView.onRefreshComplete();
mTweetFeedListAdapter.notifyDataSetChanged();
mTweetDataRefreshCallback = null;
resetScreenRotation();
return;
}
mLastRefreshTime = Calendar.getInstance();
TwitterStatus visibleStatus = getVisibleStatus();
setStatusFeed(feed, true);
mTweetFeedListView.onRefreshComplete();
mTweetFeedListAdapter.notifyDataSetChanged();
int total = getStatusFeed().getStatusCount();
int newStatuses = 0;
for (int i = 0; i < total; i++) {
TwitterStatus status = getStatusFeed().getStatus(i);
if (status != null && status.mId > mLastTwitterStatusIdSeen) {
newStatuses++;
}
}
mNewStatuses = newStatuses;
Integer statusIndex = null;
if (visibleStatus != null) {
statusIndex = getStatusFeed().getStatusIndex(visibleStatus.mId);
} else if (mLastTwitterStatusIdSeen != null && mLastTwitterStatusIdSeen > 0) {
statusIndex = getStatusFeed().getStatusIndex(mLastTwitterStatusIdSeen);
}
if (statusIndex != null) {
int newIndex = statusIndex.intValue() + 1;
if (mNewStatuses == 1 && getStatusFeed() != null) {
TwitterStatus firstStatus = getStatusFeed().getStatus(0);
if (firstStatus != null && firstStatus.getAuthorScreenName().equals(getApp().getCurrentAccount().getScreenName())) {
newIndex = statusIndex.intValue();
}
}
mTweetFeedListView.getRefreshableView().setSelectionFromTop(newIndex, mScrollTracker.getFirstVisibleYOffset());
if (visibleStatus != null && mLastTwitterStatusIdSeen < visibleStatus.mId) {
mLastTwitterStatusIdSeen = visibleStatus.mId;
}
if (!mDetached) {
updateListHeading(newIndex);
}
} else {
showToast(getString(R.string.lost_position));
}
if (mNewStatuses == 0) {
mTweetFeedListView.getRefreshableView().setSelectionFromTop(0, mScrollTracker.getFirstVisibleYOffset());
}
mTweetDataRefreshCallback = null;
resetScreenRotation();
}
/*
*
*/
private final OnRefreshListener mTweetFeedOnRefreshListener = new OnRefreshListener() {
@Override
public void onRefresh() {
fetchNewestTweets();
}
};
/*
* (non-Javadoc)
*
* @see
* android.support.v4.app.Fragment#onOptionsItemSelected(android.view.MenuItem
* )
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int i = item.getItemId();
if (i == R.id.action_replies_visibility) {
getBaseLaneActivity().mStatusesFilter
.setShowReplies(!getBaseLaneActivity().mStatusesFilter.getShowReplies());
item.setTitle(getString(
getBaseLaneActivity().mStatusesFilter.getShowReplies() ? R.string.action_hide_replies :
R.string.action_show_replies));
mTweetFeedListAdapter.notifyDataSetChanged();
return false;
} else if (i == R.id.action_retweets_visibility) {
getBaseLaneActivity().mStatusesFilter
.setShowRetweets(!getBaseLaneActivity().mStatusesFilter.getShowRetweets());
item.setTitle(getString(
getBaseLaneActivity().mStatusesFilter.getShowRetweets() ? R.string.action_hide_retweets :
R.string.action_show_retweets));
mTweetFeedListAdapter.notifyDataSetChanged();
return false;
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* com.tweetlanes.android.core.view.BaseLaneFragment#configureOptionsMenu(android
* .view.Menu)
*/
@Override
public boolean configureOptionsMenu(MenuInflater inflater, Menu menu) {
if (inflater != null && mContentHandle != null &&
(mContentHandle.getStatusesType() == StatusesType.USER_TIMELINE ||
mContentHandle.getStatusesType() == StatusesType.USER_HOME_TIMELINE ||
mContentHandle.getStatusesType() == StatusesType.USER_LIST_TIMELINE)) {
if (getBaseLaneActivity() instanceof HomeActivity) {
inflater.inflate(R.menu.home_tweet_feed_action_bar, menu);
} else {
inflater.inflate(R.menu.tweet_feed_action_bar, menu);
}
for (int i = 0; i < menu.size(); i++) {
MenuItem menuItem = menu.getItem(i);
if (menuItem.getItemId() == R.id.action_feed_filter) {
SubMenu subMenu = menuItem.getSubMenu();
if (subMenu != null) {
SocialNetConstant.Type socialNetType = getApp().getCurrentAccount().getSocialNetType();
int subMenuSize = subMenu.size();
for (int j = 0; j < subMenuSize; j++) {
MenuItem subMenuItem = subMenu.getItem(j);
int i1 = subMenuItem.getItemId();
if (i1 == R.id.action_replies_visibility) {
subMenuItem.setTitle(getString(getBaseLaneActivity().mStatusesFilter.getShowReplies() ?
R.string.action_hide_replies : R.string.action_show_replies));
} else if (i1 == R.id.action_retweets_visibility) {
subMenuItem.setTitle(getString(getBaseLaneActivity().mStatusesFilter.getShowRetweets() ?
socialNetType == SocialNetConstant.Type.Twitter ?
R.string.action_hide_retweets : R.string.action_hide_retweets_adn :
socialNetType == SocialNetConstant.Type.Twitter ?
R.string.action_show_retweets : R.string.action_show_retweets_adn));
} else {
}
}
}
}
}
return true;
}
return false;
}
/*
* (non-Javadoc)
*
* @see android.support.v4.app.Fragment#onDestroy()
*/
@Override
public void onDestroy() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mVolumeUpKeyDownReceiver);
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mVolumeDownKeyDownReceiver);
super.onDestroy();
}
/*
*
*/
private void updateViewVisibility(boolean loadHasFinished) {
mViewSwitcher.reset();
if (!loadHasFinished && (getStatusFeed() == null || getFilteredStatusCount() == 0)) {
mViewSwitcher.setDisplayedChild(0);
} else {
mViewSwitcher.setDisplayedChild(1);
mTweetFeedListAdapter.notifyDataSetChanged();
if (mResumeStatusId != null && getStatusFeed() != null) {
Integer statusIndex = getStatusFeed().getStatusIndex(mResumeStatusId);
if (statusIndex != null) {
mTweetFeedListView.getRefreshableView().setSelectionFromTop(statusIndex.intValue() + 1, 0);
}
}
}
}
private static final String KEY_HANDLE_BASE = "handleBase";
private static final String KEY_SCREEN_NAME = "screenName";
private static final String KEY_LANE_IDENTIFIER = "laneIdentifier";
private TwitterContentHandleBase getContentHandleBase() {
return (TwitterContentHandleBase) getArguments().getSerializable(KEY_HANDLE_BASE);
}
private String getScreenName() {
return getArguments().getString(KEY_SCREEN_NAME);
}
private String getLaneIdentifier() {
return getArguments().getString(KEY_LANE_IDENTIFIER);
}
private void setStatusFeed(TwitterStatuses statuses, boolean addCachedStatuses) {
mNewestTweetId = null;
mOldestTweetId = null;
if (statuses == null) {
_mStatusFeed = null;
} else {
_mStatusFeed = new TwitterStatuses(statuses);
}
if (addCachedStatuses && _mCachedStatusFeed != null && _mCachedStatusFeed.getStatusCount() > 0) {
if (_mStatusFeed == null) {
_mStatusFeed = new TwitterStatuses();
}
_mStatusFeed.insert(_mCachedStatusFeed);
}
if (_mStatusFeed != null && _mStatusFeed.getStatusCount() > 0) {
mNewestTweetId = _mStatusFeed.getStatus(0).mId;
mOldestTweetId = _mStatusFeed.getStatus(_mStatusFeed.getStatusCount() - 1).mId;
}
}
private TwitterStatuses getStatusFeed() {
return _mStatusFeed;
}
private int getFilteredStatusCount() {
return getStatusFeed() != null ? getStatusFeed().getStatusCount(getBaseLaneActivity().mStatusesFilter) : 0;
}
private final int REFRESH_TIMESTAMPS_INTERVAL = 1000 * 30;
private final Handler mRefreshTimestampsHandler = new Handler();
private final Runnable mRefreshTimestampsTask = new Runnable() {
public void run() {
if (getFilteredStatusCount() > 0) {
mTweetFeedListAdapter.notifyDataSetChanged();
}
mRefreshTimestampsHandler.postDelayed(this, REFRESH_TIMESTAMPS_INTERVAL);
}
};
/*
*
*/
private void onTweetFeedItemSingleTap(View view, int position) {
if (mSelectedItems.size() == 0) {
TweetFeedItemView tweetFeedItemView = (TweetFeedItemView) (view);
TwitterStatus status = tweetFeedItemView.getTwitterStatus();
FragmentActivity activity = getActivity();
if (activity != null) {
Intent tweetSpotlightIntent = new Intent(activity, TweetSpotlightActivity.class);
tweetSpotlightIntent.putExtra("statusId", Long.toString(status.mId));
tweetSpotlightIntent.putExtra("status", status.toString());
tweetSpotlightIntent.putExtra("clearCompose", "true");
activity.startActivityForResult(tweetSpotlightIntent, Constant.REQUEST_CODE_SPOTLIGHT);
}
} else {
onTweetFeedItemLongPress(view, position);
}
}
/*
*
*/
private void onTweetFeedItemLongPress(View view, int position) {
boolean isChecked = mTweetFeedListView.getRefreshableView().getCheckedItemPositions().get(position);
TweetFeedItemView tweetFeedItemView = (TweetFeedItemView) (view);
for (int index = 0; index < mSelectedItems.size(); index++) {
TweetFeedItemView item = mSelectedItems.get(index);
if (item.getTwitterStatus() != null && tweetFeedItemView.getTwitterStatus() != null) {
if (item.getTwitterStatus().mId == tweetFeedItemView.getTwitterStatus().mId) {
mSelectedItems.remove(index);
break;
}
}
}
if (!isChecked) {
mSelectedItems.add(tweetFeedItemView);
}
mTweetFeedListView.getRefreshableView().setItemChecked(position, !isChecked);
if (mSelectedItems.size() > 0 && getApp() != null) {
mMultipleTweetSelectionCallback
.setIsFavorited(getSelectedFavoriteState() == ItemSelectedState.ALL);
TwitterStatus firstItem = getFirstSelectedStatus();
if (firstItem != null) {
mMultipleTweetSelectionCallback.setIsRetweet(firstItem.mIsRetweetedByMe);
}
getBaseLaneActivity().setComposeTweetDefault(
new ComposeTweetDefault(getApp().getCurrentAccountScreenName(), getSelectedStatuses()));
} else {
mMultipleTweetSelectionCallback.setIsFavorited(false);
mMultipleTweetSelectionCallback.setIsRetweet(false);
getBaseLaneActivity().clearCompose();
getBaseLaneActivity().setComposeDefault();
}
}
/*
*
*/
private TwitterStatuses getSelectedStatuses() {
TwitterStatuses selectedList = new TwitterStatuses();
for (int i = 0; i < mSelectedItems.size(); i++) {
TweetFeedItemView tweetFeedItemView = mSelectedItems.get(i);
TwitterStatus status = tweetFeedItemView.getTwitterStatus();
if (status != null) {
selectedList.add(status);
}
}
return selectedList.getStatusCount() > 0 ? selectedList : null;
}
/*
*
*/
private TwitterStatus getFirstSelectedStatus() {
for (int i = 0; i < mSelectedItems.size(); i++) {
TweetFeedItemView tweetFeedItemView = mSelectedItems.get(i);
TwitterStatus status = tweetFeedItemView.getTwitterStatus();
if (status != null) {
return status;
}
}
return null;
}
/*
*
*/
enum ItemSelectedState {
NONE,
SOME,
ALL
}
/*
*
*/
private ItemSelectedState getSelectedFavoriteState() {
int favoriteCount = 0;
int selectedCount = mSelectedItems.size();
for (int i = 0; i < selectedCount; i++) {
TwitterStatus status = mSelectedItems.get(i).getTwitterStatus();
if (status != null) {
if (status.mIsFavorited) {
favoriteCount++;
}
}
}
if (favoriteCount == selectedCount) {
return ItemSelectedState.ALL;
} else if (favoriteCount != 0) {
return ItemSelectedState.SOME;
}
return ItemSelectedState.NONE;
}
/**
* Checks if the status supplied belongs to the user or not by comparing the IDs
* between the ID of the current AccountDescriptor and the User ID of the status
*
* @param status the TwitterStatus that needs to be checked
*/
private boolean doesTwitterStatusBelongToMe(TwitterStatus status) {
AccountDescriptor currentAccount = getApp().getCurrentAccount();
if (currentAccount != null && status != null) {
if (currentAccount.getId() == status.mUserId) {
return true;
}
}
return false;
}
/*
*
*/
private class MultipleTweetSelectionCallback implements ListView.MultiChoiceModeListener {
private MenuItem mFavoriteMenuItem;
private MenuItem mRetweetMenuItem;
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
configure(mode);
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return true;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (item == null || mode == null) {
return true;
}
final int itemId = item.getItemId();
if (itemId == R.id.action_share) {
getBaseLaneActivity().shareSelected(getFirstSelectedStatus());
mode.finish();
} else if (itemId == R.id.action_retweet) {
final TwitterStatus statusSelected = getFirstSelectedStatus();
if (statusSelected.mIsRetweetedByMe) {
showToast(getString(R.string.cannot_unretweet));
mode.finish();
} else {
TwitterFetchStatus.FinishedCallback callback = TwitterManager.get()
.getFetchStatusInstance().new FinishedCallback() {
@Override
public void finished(TwitterFetchResult result, TwitterStatus status) {
boolean showUnsuccessful = false;
if (result != null && result.isSuccessful()) {
if (status == null || status.mOriginalRetweetId == 0) {
if (result.getErrorMessage() == null) {
showUnsuccessful = true;
} else if (!result.getErrorMessage().equals("CancelPressed") && !result.getErrorMessage().equals("QutotePressed")) {
showUnsuccessful = true;
}
}
} else {
showUnsuccessful = true;
}
if (showUnsuccessful) {
if (!mDetached) {
showToast(getString(R.string.retweeted_un_successful));
}
TwitterStatuses cachedStatuses = getStatusFeed();
TwitterStatus cachedStatus = cachedStatuses.findByStatusId(statusSelected.mId);
if (cachedStatus != null) {
cachedStatus.setRetweet(false);
setIsRetweet(false);
mTweetFeedListAdapter.notifyDataSetChanged();
updateViewVisibility(true);
} else {
if (!mDetached) {
showToast(getString(R.string.retweeted_marking_un_successful));
}
}
}
}
};
TwitterFetchStatus.FinishedCallback showRTcallback = TwitterManager.get()
.getFetchStatusInstance().new FinishedCallback() {
@Override
public void finished(TwitterFetchResult result, TwitterStatus status) {
TwitterStatuses cachedStatuses = getStatusFeed();
TwitterStatus cachedStatus = cachedStatuses.findByStatusId(statusSelected.mId);
if (cachedStatus != null) {
cachedStatus.setRetweet(true);
setIsRetweet(true);
mTweetFeedListAdapter.notifyDataSetChanged();
updateViewVisibility(true);
} else {
if (!mDetached) {
showToast(getString(R.string.retweeted_marking_un_successful));
}
}
}
};
getBaseLaneActivity().retweetSelected(statusSelected, callback, showRTcallback);
mode.finish();
}
} else if (itemId == R.id.action_favorite) {
final TwitterStatuses selected = getSelectedStatuses();
final boolean newState = getSelectedFavoriteState() != ItemSelectedState.ALL;
TwitterModifyStatuses.FinishedCallback callback =
TwitterManager.get().getSetStatusesInstance().new FinishedCallback() {
@Override
public void finished(boolean successful, TwitterStatuses statuses, Integer value) {
if (!successful) {
TwitterStatuses cachedStatuses = getStatusFeed();
if (selected != null && selected.getStatusCount() > 0) {
for (int i = 0; i < selected.getStatusCount(); i++) {
TwitterStatus updatedStatus = selected.getStatus(i);
TwitterStatus cachedStatus = cachedStatuses.findByStatusId(updatedStatus.mId);
if (cachedStatus != null) {
cachedStatus.setFavorite(!newState);
} else {
showToast(getString(R.string.favorite_marking_un_successful));
}
}
mTweetFeedListAdapter.notifyDataSetChanged();
updateViewVisibility(true);
}
setIsFavorited(!newState);
if (!mDetached) {
showToast(getString(newState ? R.string.favorited_un_successfully : R.string
.unfavorited_un_successfully));
}
}
}
};
TwitterManager.get().setFavorite(selected, newState, callback);
TwitterStatuses cachedStatuses = getStatusFeed();
if (selected != null && selected.getStatusCount() > 0) {
for (int i = 0; i < selected.getStatusCount(); i++) {
TwitterStatus updatedStatus = selected.getStatus(i);
TwitterStatus cachedStatus = cachedStatuses.findByStatusId(updatedStatus.mId);
if (cachedStatus != null) {
cachedStatus.setFavorite(newState);
} else {
showToast(getString(R.string.favorite_marking_un_successful));
}
}
mTweetFeedListAdapter.notifyDataSetChanged();
updateViewVisibility(true);
}
setIsFavorited(newState);
mode.finish();
} else if (itemId == R.id.action_manage_friendship) {
showToast(getString(R.string.functionality_not_implemented));
mode.finish();
} else if (itemId == R.id.action_delete_status) {
final TwitterStatuses selected = getSelectedStatuses();
TwitterModifyStatuses.FinishedDeleteCallback callback =
TwitterManager.get().getSetStatusesInstance().new FinishedDeleteCallback(selected) {
@Override
public void finished(boolean successful, TwitterStatuses statuses, Integer value) {
if (!successful) {
if (!mDetached) {
showToast(getString(R.string.deleted_un_successfully));
}
TwitterStatuses statusFeed = getStatusFeed();
statusFeed.add(selected);
setStatusFeed(statusFeed, true);
mTweetFeedListAdapter.notifyDataSetChanged();
mTweetFeedListView.onRefreshComplete();
updateViewVisibility(true);
}
}
};
TwitterManager.get().deleteTweet(selected, callback);
if (getStatusFeed() != null) {
getStatusFeed().remove(selected);
}
if (_mCachedStatusFeed != null) {
_mCachedStatusFeed.remove(selected);
}
TwitterManager.get().removeFromHashMap(selected);
setStatusFeed(getStatusFeed(), true);
mTweetFeedListAdapter.notifyDataSetChanged();
mTweetFeedListView.onRefreshComplete();
updateViewVisibility(true);
mode.finish();
} else if (itemId == R.id.action_report_for_spam || itemId == R.id.action_block) {
AccountDescriptor account = getApp().getCurrentAccount();
if (account != null) {
final TwitterStatuses selected = getSelectedStatuses();
if (selected != null && selected.getStatusCount() > 0) {
ArrayList<Long> userIds = new ArrayList<Long>();
for (int i = 0; i < selected.getStatusCount(); i++) {
if (!doesTwitterStatusBelongToMe(selected.getStatus(i))) {
userIds.add(selected.getStatus(i).mUserId);
}
}
TwitterFetchUsers.FinishedCallback callback =
TwitterManager.get().getFetchUsersInstance().new FinishedCallback() {
@Override
public void finished(TwitterFetchResult result, TwitterUsers users) {
if (result.isSuccessful() && users != null && users.getUserCount() > 0) {
int userCount = users.getUserCount();
String notice;
if (!mDetached) {
if (itemId == R.id.action_report_for_spam) {
if (userCount == 1) {
notice = "Reported @" + users.getUser(0).getScreenName() +
" for Spam.";
} else {
notice = "Reported " + userCount + " users for Spam.";
}
} else {
if (userCount == 1) {
notice = "Blocked @" + users.getUser(0).getScreenName() + ".";
} else {
notice = "Blocked " + userCount + " users.";
}
}
if (notice != null) {
showToast(notice);
}
}
}
}
};
if (item.getItemId() == R.id.action_report_for_spam) {
TwitterManager.get().reportSpam(account.getId(), userIds, callback);
} else {
TwitterManager.get().createBlock(account.getId(), userIds, callback);
}
if (getStatusFeed() != null) {
getStatusFeed().remove(selected);
}
if (_mCachedStatusFeed != null) {
_mCachedStatusFeed.remove(selected);
}
TwitterManager.get().removeFromHashMap(selected);
setStatusFeed(getStatusFeed(), true);
mTweetFeedListAdapter.notifyDataSetChanged();
mTweetFeedListView.onRefreshComplete();
updateViewVisibility(true);
mode.finish();
}
}
} else {
}
return true;
}
public void onDestroyActionMode(ActionMode mode) {
mSelectedItems.clear();
// Don't update the default status when TweetCompose has focus
if (!getBaseLaneActivity().composeHasFocus()) {
getBaseLaneActivity().clearCompose();
getBaseLaneActivity().setComposeDefault();
}
}
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
configure(mode);
}
void configure(ActionMode mode) {
BaseLaneActivity baseLaneActivity = (BaseLaneActivity) getActivity();
if (baseLaneActivity == null || baseLaneActivity.isComposing() || mTweetFeedListView == null ||
mTweetFeedListView.getRefreshableView() == null || mode == null) {
return;
}
final int checkedCount = mTweetFeedListView.getRefreshableView().getCheckedItemCount();
switch (checkedCount) {
case 0:
mode.setSubtitle(null);
break;
case 1: {
mode.getMenu().clear();
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.single_tweet_selected, mode.getMenu());
storeMenuItems(mode.getMenu());
TwitterStatus firstStatus = getFirstSelectedStatus();
if (doesTwitterStatusBelongToMe(firstStatus)) {
mode.getMenu().findItem(R.id.action_block).setVisible(false);
mode.getMenu().findItem(R.id.action_report_for_spam).setVisible(false);
}
mode.setTitle("");
mode.setSubtitle("");
break;
}
case 2: {
mode.getMenu().clear();
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.multiple_tweets_selected, mode.getMenu());
storeMenuItems(mode.getMenu());
mode.setTitle("Select Tweets");
mode.setSubtitle("" + checkedCount + " items selected");
break;
}
default: {
mode.setTitle("Select Tweets");
mode.setSubtitle("" + checkedCount + " items selected");
break;
}
}
}
/*
*
*/
void storeMenuItems(Menu menu) {
for (int i = 0; i < menu.size(); i++) {
MenuItem menuItem = menu.getItem(i);
if (menuItem.getItemId() == R.id.action_favorite) {
mFavoriteMenuItem = menuItem;
} else if (menuItem.getItemId() == R.id.action_retweet) {
mRetweetMenuItem = menuItem;
}
}
}
/*
*
*/
void setIsFavorited(boolean favorited) {
if (mFavoriteMenuItem != null) {
boolean isDarkTheme = AppSettings.get().getCurrentTheme() == AppSettings.Theme.Holo_Dark || AppSettings.get().getCurrentTheme() == AppSettings.Theme.Holo_Light_DarkAction;
if (favorited) {
mFavoriteMenuItem.setIcon(
isDarkTheme ? R.drawable.ic_action_star_on_dark : R.drawable.ic_action_star_on_light);
mFavoriteMenuItem.setTitle(R.string.action_unfavorite);
} else {
mFavoriteMenuItem.setIcon(
isDarkTheme ? R.drawable.ic_action_star_off_dark : R.drawable.ic_action_star_off_light);
mFavoriteMenuItem.setTitle(R.string.action_favorite);
}
}
}
void setIsRetweet(boolean retweet) {
if (mRetweetMenuItem != null) {
boolean isDarkTheme = AppSettings.get().getCurrentTheme() == AppSettings.Theme.Holo_Dark || AppSettings.get().getCurrentTheme() == AppSettings.Theme.Holo_Light_DarkAction;
if (retweet) {
mRetweetMenuItem.setIcon(
isDarkTheme ? R.drawable.ic_action_rt_on_dark : R.drawable.ic_action_rt_on_light);
mRetweetMenuItem.setTitle(R.string.action_retweet_unset);
} else {
mRetweetMenuItem.setIcon(
isDarkTheme ? R.drawable.ic_action_rt_off_dark : R.drawable.ic_action_rt_off_light);
mRetweetMenuItem.setTitle(R.string.action_retweet);
}
}
}
}
/*
*
*/
boolean showConversationView(TwitterStatus status) {
for (Long id : mConverstaionViewIds) {
if (id == status.mId) {
return true;
}
}
return false;
}
/*
*
*/
private class TweetFeedListAdapter extends BaseAdapter {
public TweetFeedListAdapter(LayoutInflater inflater) {
mInflater = inflater;
}
/**
* The number of items in the list is determined by the number of
* speeches in our array.
*
* @see android.widget.ListAdapter#getCount()
*/
public int getCount() {
int count;
if (getStatusFeed() != null) {
count = getFilteredStatusCount() + 1; // +1 for the trailing
// LoadMore view
} else {
count = 1;
}
return count;
}
/**
* Since the data comes from an array, just returning the index is
* sufficent to get at the data. If we were using a more complex data
* structure, we would return whatever object represents one row in the
* list.
*
* @see android.widget.ListAdapter#getItem(int)
*/
public Object getItem(int position) {
return position;
}
/**
* Use the array index as a unique id.
*
* @see android.widget.ListAdapter#getItemId(int)
*/
public long getItemId(int position) {
return position;
}
/**
* Make a TweetFeedItemView to hold each row.
*/
public View getView(int position, View convertView, ViewGroup parent) {
int statusCount = getFilteredStatusCount();
View resultView;
if (statusCount == 0 && position == getCount() - 1) {
resultView = getLoadMoreView();
} else if (position == statusCount) {
resultView = getLoadMoreView();
} else {
resultView = getTweetFeedView(convertView, position);
}
return resultView;
}
View inflateNewTweetFeedItem() {
View view = mInflater.inflate(R.layout.tweet_feed_item_received, null);
ViewHolder holder = new ViewHolder(view);
view.setTag(R.id.tweetFeedItem, holder);
return view;
}
/*
*
*/
View getTweetFeedView(View convertView, int position) {
ViewHolder holder = null;
// Sometimes the convertView comes with type of "LoadMoreView"
// so we check if it contains a holder or not, if not then we inflate
// a new TweetFeedItem cell to replace the LoadMoreView cell.
if (convertView != null) {
holder = (ViewHolder) convertView.getTag(R.id.tweetFeedItem);
if (holder == null) {
convertView = inflateNewTweetFeedItem();
holder = (ViewHolder) convertView.getTag(R.id.tweetFeedItem);
}
} else {
convertView = inflateNewTweetFeedItem();
holder = (ViewHolder) convertView.getTag(R.id.tweetFeedItem);
}
TwitterStatus item = getStatusFeed().getStatus(position, getBaseLaneActivity().mStatusesFilter);
TweetFeedItemView tweetFeedItemView = holder.tweetFeedItemView;
TweetFeedItemView.Callbacks callbacks = new TweetFeedItemView.Callbacks() {
@Override
public boolean onSingleTapConfirmed(View view, int position) {
onTweetFeedItemSingleTap(view, position);
return true;
}
@Override
public void onLongPress(View view, int position) {
onTweetFeedItemLongPress(view, position);
}
@Override
public Activity getActivity() {
return TweetFeedFragment.this.getActivity();
}
@Override
public void onUrlClicked(TwitterStatus status) {
TwitterStatuses selected = getSelectedStatuses();
if (selected != null && selected.getStatusCount() == 1) {
if (selected.getStatus(0).mId == status.mId) {
// HACK ALERT: Finishing the actionMode in this
// callback will cause the link to be unable to be
// clicked.
// Adding a slight delay makes things work just fine
Runnable finishActionModeTask = new Runnable() {
public void run() {
getBaseLaneActivity().finishCurrentActionMode();
}
};
mHandler.postDelayed(finishActionModeTask, 90);
}
}
}
@Override
public void onConversationViewToggle(long statusId, boolean show) {
if (show) {
boolean add = true;
for (int i = 0; i < mConverstaionViewIds.size(); ++i) {
if (mConverstaionViewIds.get(i) == statusId) {
add = false;
break;
}
}
if (add) {
mConverstaionViewIds.add(statusId);
}
} else {
for (int i = 0; i < mConverstaionViewIds.size(); ++i) {
if (mConverstaionViewIds.get(i) == statusId) {
mConverstaionViewIds.remove(i);
break;
}
}
}
}
@Override
public LayoutInflater getLayoutInflater() {
return mInflater;
}
@Override
public LazyImageLoader getProfileImageLoader() {
return mProfileImageLoader;
}
@Override
public LazyImageLoader getPreviewImageLoader() {
return mPreviewImageLoader;
}
};
boolean showRetweetCount = mContentHandle.getStatusesType() == TwitterConstant.StatusesType.RETWEETS_OF_ME;
tweetFeedItemView
.configure(item, position + 1, callbacks, true, showRetweetCount, showConversationView(item), false,
true, getApp().getCurrentAccount().getSocialNetType(), getApp().getCurrentAccountKey());
return tweetFeedItemView;
}
/*
*
*/
View getLoadMoreView() {
View convertView = mInflater.inflate(R.layout.load_more, null);
LoadMoreView loadMoreView = (LoadMoreView) convertView.findViewById(R.id.loadMoreView);
LoadMoreView.Mode mode;
if (getStatusFeed() == null || getFilteredStatusCount() == 0) {
mode = LoadMoreView.Mode.NONE_FOUND;
} else {
mode = mMoreStatusesAvailable ? LoadMoreView.Mode.LOADING : LoadMoreView.Mode.NO_MORE;
}
loadMoreView.configure(mode);
return loadMoreView;
}
private class ViewHolder {
public TweetFeedItemView tweetFeedItemView;
public ViewHolder(View convertView) {
if (convertView != null) {
tweetFeedItemView = (TweetFeedItemView) convertView.findViewById(R.id.tweetFeedItem);
}
}
}
private final LayoutInflater mInflater;
}
private final Handler mHandler = new Handler();
}