improved gap

improved features for fanfou
This commit is contained in:
Mariotaku Lee 2016-03-11 17:14:50 +08:00
parent ef5901f3e0
commit 5a96097e10
68 changed files with 1480 additions and 954 deletions

View File

@ -1,5 +1,8 @@
package org.mariotaku.twidere.api.fanfou;
import org.mariotaku.twidere.api.fanfou.api.BlocksResources;
import org.mariotaku.twidere.api.fanfou.api.FavoritesResources;
import org.mariotaku.twidere.api.fanfou.api.FriendshipsResources;
import org.mariotaku.twidere.api.fanfou.api.PhotosResources;
import org.mariotaku.twidere.api.fanfou.api.SearchResources;
import org.mariotaku.twidere.api.fanfou.api.TimelineResources;
@ -8,5 +11,6 @@ import org.mariotaku.twidere.api.fanfou.api.UsersResources;
/**
* Created by mariotaku on 16/3/10.
*/
public interface Fanfou extends TimelineResources, SearchResources, UsersResources, PhotosResources {
public interface Fanfou extends TimelineResources, SearchResources, UsersResources, PhotosResources,
FriendshipsResources, BlocksResources, FavoritesResources {
}

View File

@ -0,0 +1,19 @@
package org.mariotaku.twidere.api.fanfou.api;
import org.mariotaku.restfu.annotation.method.POST;
import org.mariotaku.restfu.annotation.param.Param;
import org.mariotaku.restfu.http.BodyType;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
/**
* Created by mariotaku on 16/3/11.
*/
public interface BlocksResources {
@POST("/blocks/create.json")
User createFanfouBlock(@Param("id") String userId) throws TwitterException;
@POST("/blocks/destroy.json")
User destroyFanfouBlock(@Param("id") String userId) throws TwitterException;
}

View File

@ -0,0 +1,18 @@
package org.mariotaku.twidere.api.fanfou.api;
import org.mariotaku.restfu.annotation.method.POST;
import org.mariotaku.restfu.annotation.param.Path;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Status;
/**
* Created by mariotaku on 16/3/11.
*/
public interface FavoritesResources {
@POST("/favorites/create/{id}.json")
Status createFanfouFavorite(@Path("id") String id) throws TwitterException;
@POST("/favorites/destroy/{id}.json")
Status destroyFanfouFavorite(@Path("id") String id) throws TwitterException;
}

View File

@ -0,0 +1,32 @@
package org.mariotaku.twidere.api.fanfou.api;
import org.mariotaku.restfu.annotation.method.GET;
import org.mariotaku.restfu.annotation.method.POST;
import org.mariotaku.restfu.annotation.param.Param;
import org.mariotaku.restfu.annotation.param.Query;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
import org.mariotaku.twidere.api.twitter.model.User;
/**
* Created by mariotaku on 16/3/11.
*/
public interface FriendshipsResources {
@POST("/friendships/create.json")
User createFanfouFriendship(@Param("id") String id) throws TwitterException;
@POST("/friendships/destroy.json")
User destroyFanfouFriendship(@Param("id") String id) throws TwitterException;
@POST("/friendships/accept.json")
User acceptFanfouFriendship(@Param("id") String id) throws TwitterException;
@POST("/friendships/deny.json")
User denyFanfouFriendship(@Param("id") String id) throws TwitterException;
@GET("/friendships/requests.json")
ResponseList<User> getFriendshipsRequests(@Query Paging paging) throws TwitterException;
}

View File

@ -258,6 +258,9 @@ public class TwitterException extends Exception implements TwitterResponse, Http
return getMessage();
}
public String getErrorMessage() {
return errorMessage;
}
void setNested() {
nested = true;

View File

@ -42,11 +42,9 @@ import org.mariotaku.twidere.api.twitter.model.Status;
public interface FavoritesResources {
@POST("/favorites/create.json")
@BodyType(BodyType.FORM)
Status createFavorite(@Param("id") String id) throws TwitterException;
@POST("/favorites/destroy.json")
@BodyType(BodyType.FORM)
Status destroyFavorite(@Param("id") String id) throws TwitterException;
@GET("/favorites/list.json")

View File

@ -46,35 +46,27 @@ import org.mariotaku.twidere.api.twitter.model.User;
public interface UsersResources {
@POST("/blocks/create.json")
@BodyType(BodyType.FORM)
User createBlock(@Param("user_id") String userId) throws TwitterException;
@POST("/blocks/create.json")
@BodyType(BodyType.FORM)
User createBlockByScreenName(@Query("screen_name") String screenName) throws TwitterException;
@POST("/mutes/users/create.json")
@BodyType(BodyType.FORM)
User createMute(@Param("user_id") String userId) throws TwitterException;
@POST("/mutes/users/create.json")
@BodyType(BodyType.FORM)
User createMuteByScreenName(@Query("screen_name") String screenName) throws TwitterException;
@POST("/blocks/destroy.json")
@BodyType(BodyType.FORM)
User destroyBlock(@Param("user_id") String userId) throws TwitterException;
@POST("/blocks/destroy.json")
@BodyType(BodyType.FORM)
User destroyBlockByScreenName(@Query("screen_name") String screenName) throws TwitterException;
@POST("/mutes/users/destroy.json")
@BodyType(BodyType.FORM)
User destroyMute(@Param("user_id") String userId) throws TwitterException;
@POST("/mutes/users/destroy.json")
@BodyType(BodyType.FORM)
User destroyMuteByScreenName(@Query("screen_name") String screenName) throws TwitterException;
@GET("/account/settings.json")

View File

@ -102,6 +102,10 @@ public class ParcelableUser implements Parcelable, Comparable<ParcelableUser> {
@CursorField(CachedUsers.PROFILE_BANNER_URL)
public String profile_banner_url;
@ParcelableThisPlease
@JsonField(name = "profile_background_url")
@CursorField(CachedUsers.PROFILE_BACKGROUND_URL)
public String profile_background_url;
@ParcelableThisPlease
@JsonField(name = "url")
@CursorField(CachedUsers.URL)
public String url;

View File

@ -263,6 +263,8 @@ public interface TwidereDataStore {
String PROFILE_BANNER_URL = "profile_banner_url";
String PROFILE_BACKGROUND_URL = "profile_background_url";
String FOLLOWERS_COUNT = "followers_count";
String FRIENDS_COUNT = "friends_count";
@ -301,18 +303,19 @@ public interface TwidereDataStore {
String USER_HOST = "user_host";
String[] COLUMNS = {_ID, USER_KEY, CREATED_AT, NAME, SCREEN_NAME, DESCRIPTION_PLAIN, LOCATION,
URL, PROFILE_IMAGE_URL, PROFILE_BANNER_URL, IS_PROTECTED, IS_VERIFIED, IS_FOLLOWING,
FOLLOWERS_COUNT, FRIENDS_COUNT, STATUSES_COUNT, FAVORITES_COUNT, LISTED_COUNT,
MEDIA_COUNT, DESCRIPTION_HTML, DESCRIPTION_EXPANDED, URL_EXPANDED, BACKGROUND_COLOR,
LINK_COLOR, TEXT_COLOR, LAST_SEEN, DESCRIPTION_UNESCAPED, EXTRAS, USER_HOST};
URL, PROFILE_IMAGE_URL, PROFILE_BANNER_URL, PROFILE_BACKGROUND_URL, IS_PROTECTED,
IS_VERIFIED, IS_FOLLOWING, FOLLOWERS_COUNT, FRIENDS_COUNT, STATUSES_COUNT,
FAVORITES_COUNT, LISTED_COUNT, MEDIA_COUNT, DESCRIPTION_HTML, DESCRIPTION_EXPANDED,
URL_EXPANDED, BACKGROUND_COLOR, LINK_COLOR, TEXT_COLOR, LAST_SEEN,
DESCRIPTION_UNESCAPED, EXTRAS, USER_HOST};
String[] BASIC_COLUMNS = {_ID, USER_KEY, NAME, SCREEN_NAME, PROFILE_IMAGE_URL};
String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT_NOT_NULL, TYPE_INT, TYPE_TEXT, TYPE_TEXT,
TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_BOOLEAN, TYPE_BOOLEAN,
TYPE_BOOLEAN, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_TEXT,
TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_TEXT,
TYPE_TEXT};
TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_BOOLEAN,
TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
TYPE_TEXT, TYPE_TEXT, TYPE_TEXT};
}

View File

@ -34,7 +34,7 @@ import static org.mariotaku.twidere.annotation.PreferenceType.STRING;
public interface Constants extends TwidereConstants {
String DATABASES_NAME = "twidere.sqlite";
int DATABASES_VERSION = 132;
int DATABASES_VERSION = 133;
int MENU_GROUP_STATUS_EXTENSION = 10;
int MENU_GROUP_COMPOSE_EXTENSION = 11;

View File

@ -75,12 +75,13 @@ import org.mariotaku.twidere.fragment.support.AccountsDashboardFragment;
import org.mariotaku.twidere.fragment.support.DirectMessagesFragment;
import org.mariotaku.twidere.fragment.support.TrendsSuggestionsFragment;
import org.mariotaku.twidere.graphic.EmptyDrawable;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.SupportTabSpec;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.TaskStateChangedEvent;
import org.mariotaku.twidere.model.message.UnreadCountUpdatedEvent;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
import org.mariotaku.twidere.service.StreamingService;
import org.mariotaku.twidere.task.AbstractTask;
@ -929,7 +930,7 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
true, ReadPositionTag.HOME_TIMELINE, accountKeys);
final long position = mReadStateManager.getPosition(tagWithAccounts);
final int count = DataStoreUtils.getStatusesCount(mContext, Statuses.CONTENT_URI,
position, accountKeys);
position, Statuses.STATUS_TIMESTAMP, accountKeys);
result.put(i, count);
publishProgress(new TabBadge(i, count));
break;
@ -940,7 +941,7 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
true, ReadPositionTag.ACTIVITIES_ABOUT_ME, accountIds);
final long position = mReadStateManager.getPosition(tagWithAccounts);
final int count = DataStoreUtils.getInteractionsCount(mContext, spec.args,
accountIds, position);
accountIds, position, Activities.TIMESTAMP);
publishProgress(new TabBadge(i, count));
result.put(i, count);
break;

View File

@ -20,9 +20,9 @@
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -52,6 +52,7 @@ public class ParcelableUsersAdapter extends LoadMoreSupportAdapter<RecyclerView.
private List<ParcelableUser> mData;
private UserAdapterListener mUserAdapterListener;
private RequestClickListener mRequestClickListener;
private FollowClickListener mFollowClickListener;
public ParcelableUsersAdapter(Context context) {
@ -131,11 +132,11 @@ public class ParcelableUsersAdapter extends LoadMoreSupportAdapter<RecyclerView.
return true;
}
public int findPosition(UserKey accountKey, String userId) {
public int findPosition(@NonNull final UserKey accountKey, @NonNull final UserKey userKey) {
if (mData == null) return RecyclerView.NO_POSITION;
for (int i = getUserStartIndex(), j = i + getUserCount(); i < j; i++) {
final ParcelableUser user = mData.get(i);
if (user.account_key.equals(accountKey) && TextUtils.equals(user.key.getId(), userId)) {
if (accountKey.equals(user.account_key) && userKey.equals(user.key)) {
return i;
}
}
@ -223,6 +224,15 @@ public class ParcelableUsersAdapter extends LoadMoreSupportAdapter<RecyclerView.
mRequestClickListener = requestClickListener;
}
@Override
public FollowClickListener getFollowClickListener() {
return mFollowClickListener;
}
public void setFollowClickListener(FollowClickListener followClickListener) {
mFollowClickListener = followClickListener;
}
@Override
public boolean shouldShowAccountsColor() {
return false;

View File

@ -45,6 +45,8 @@ public interface IUsersAdapter<Data> extends IContentCardAdapter {
RequestClickListener getRequestClickListener();
FollowClickListener getFollowClickListener();
boolean shouldShowAccountsColor();
@NonNull
@ -65,4 +67,8 @@ public interface IUsersAdapter<Data> extends IContentCardAdapter {
void onDenyClicked(UserViewHolder holder, int position);
}
interface FollowClickListener {
void onFollowClicked(UserViewHolder holder, int position);
}
}

View File

@ -445,7 +445,7 @@ public abstract class AbsActivitiesFragment extends AbsContentListRecyclerViewFr
}
@Override
public void afterExecute(RecyclerView recyclerView, Boolean result) {
public void afterExecute(RecyclerView recyclerView, Object params, Boolean result) {
if (result) {
recyclerView.addOnScrollListener(mActiveHotMobiScrollTracker = mHotMobiScrollTracker);
}

View File

@ -441,7 +441,7 @@ public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFrag
}
@Override
public void afterExecute(RecyclerView recyclerView, Boolean result) {
public void afterExecute(RecyclerView recyclerView, Object params, Boolean result) {
if (result) {
recyclerView.addOnScrollListener(mActiveHotMobiScrollTracker = mHotMobiScrollTracker);
}

View File

@ -91,11 +91,11 @@ import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.SupportTabSpec;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.util.CompareUtils;
import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.InternalTwitterContentUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.ListViewUtils;
@ -734,10 +734,15 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo
final Resources res = getResources();
final int defWidth = res.getDisplayMetrics().widthPixels;
final int width = bannerWidth > 0 ? bannerWidth : defWidth;
final String bannerUrl = InternalTwitterContentUtils.getBestBannerUrl(account.profile_banner_url, width);
String bannerUrl = account.profile_banner_url;
if (bannerUrl == null && ParcelableAccount.Type.FANFOU.equals(account.account_type)) {
if (account.account_user != null) {
bannerUrl = ParcelableUserUtils.getProfileBannerUrl(account.account_user);
}
}
final ImageView bannerView = mAccountProfileBannerView;
if (bannerView.getDrawable() == null || !CompareUtils.objectEquals(bannerUrl, bannerView.getTag())) {
mMediaLoader.displayProfileBanner(mAccountProfileBannerView, bannerUrl, this);
mMediaLoader.displayProfileBanner(mAccountProfileBannerView, bannerUrl, width, this);
} else {
mMediaLoader.cancelDisplayTask(mAccountProfileBannerView);
}

View File

@ -40,7 +40,6 @@ import com.squareup.otto.Bus;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.activity.iface.IThemedActivity;
import org.mariotaku.twidere.activity.support.BaseAppCompatActivity;
import org.mariotaku.twidere.fragment.iface.IBaseFragment;
import org.mariotaku.twidere.util.AsyncTaskManager;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
@ -84,7 +83,7 @@ public class BaseSupportFragment extends Fragment implements IBaseFragment, Cons
@Inject
protected ErrorInfoStore mErrorInfoStore;
@Inject
TwidereValidator mValidator;
protected TwidereValidator mValidator;
private final ActionHelper mActionHelper = new ActionHelper(this);
@ -123,13 +122,6 @@ public class BaseSupportFragment extends Fragment implements IBaseFragment, Cons
activity.registerReceiver(receiver, filter);
}
public void setProgressBarIndeterminateVisibility(final boolean visible) {
final Activity activity = getActivity();
if (activity instanceof BaseAppCompatActivity) {
activity.setProgressBarIndeterminateVisibility(visible);
}
}
public void unregisterReceiver(final BroadcastReceiver receiver) {
final Activity activity = getActivity();
if (activity == null) return;

View File

@ -44,7 +44,7 @@ public class CreateUserBlockDialogFragment extends BaseSupportDialogFragment imp
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
twitter.createBlockAsync(user.account_key, user.key.getId());
twitter.createBlockAsync(user.account_key, user.key);
break;
default:
break;

View File

@ -44,7 +44,7 @@ public class CreateUserMuteDialogFragment extends BaseSupportDialogFragment impl
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
twitter.createMuteAsync(user.account_key, user.key.getId());
twitter.createMuteAsync(user.account_key, user.key);
break;
default:
break;

View File

@ -45,7 +45,7 @@ public class DestroyFriendshipDialogFragment extends BaseSupportDialogFragment i
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
twitter.destroyFriendshipAsync(user.account_key, user.key.getId());
twitter.destroyFriendshipAsync(user.account_key, user.key);
break;
default:
break;

View File

@ -23,38 +23,26 @@ import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import com.squareup.otto.Subscribe;
import org.mariotaku.twidere.adapter.ParcelableUsersAdapter;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.loader.support.CursorSupportUsersLoader;
import org.mariotaku.twidere.loader.support.IncomingFriendshipsLoader;
import org.mariotaku.twidere.loader.support.UserFriendsLoader;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FollowRequestTaskEvent;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.view.holder.UserViewHolder;
public class IncomingFriendshipsFragment extends CursorSupportUsersListFragment implements IUsersAdapter.RequestClickListener {
@Override
public void onStart() {
super.onStart();
mBus.register(this);
}
@Override
public void onStop() {
mBus.unregister(this);
super.onStop();
}
public class IncomingFriendshipsFragment extends CursorSupportUsersListFragment implements
IUsersAdapter.RequestClickListener {
@Override
public CursorSupportUsersLoader onCreateUsersLoader(final Context context, @NonNull final Bundle args,
final boolean fromUser) {
final boolean fromUser) {
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final IncomingFriendshipsLoader loader = new IncomingFriendshipsLoader(context, accountKey,
getData(), fromUser);
loader.setCursor(getNextCursor());
loader.setPage(getNextPage());
return loader;
}
@ -82,14 +70,16 @@ public class IncomingFriendshipsFragment extends CursorSupportUsersListFragment
mTwitterWrapper.denyFriendshipAsync(user.account_key, user.key);
}
@Subscribe
public void onFollowRequestTaskEvent(FollowRequestTaskEvent event) {
final ParcelableUsersAdapter adapter = getAdapter();
final int position = adapter.findPosition(event.getAccountKey(), event.getUserId());
if (event.isFinished() && event.isSucceeded()) {
adapter.removeUserAt(position);
} else {
adapter.notifyItemChanged(position);
@Override
protected boolean shouldRemoveUser(int position, FriendshipTaskEvent event) {
if (!event.isSucceeded()) return false;
switch (event.getAction()) {
case FriendshipTaskEvent.Action.BLOCK:
case FriendshipTaskEvent.Action.ACCEPT:
case FriendshipTaskEvent.Action.DENY: {
return true;
}
}
return false;
}
}

View File

@ -37,6 +37,7 @@ public class MutesUsersListFragment extends CursorSupportUsersListFragment {
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final MutesUsersLoader loader = new MutesUsersLoader(context, accountKey, getData(), fromUser);
loader.setCursor(getNextCursor());
loader.setPage(getNextPage());
return loader;
}

View File

@ -33,26 +33,68 @@ import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import com.squareup.otto.Subscribe;
import org.mariotaku.twidere.adapter.ParcelableUsersAdapter;
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter.UserAdapterListener;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.util.UserKeyUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.ParcelUtils;
import org.mariotaku.twidere.util.RecyclerViewNavigationHelper;
import org.mariotaku.twidere.view.holder.UserViewHolder;
import java.util.List;
public abstract class ParcelableUsersFragment extends AbsContentListRecyclerViewFragment<ParcelableUsersAdapter>
implements LoaderCallbacks<List<ParcelableUser>>, UserAdapterListener, KeyboardShortcutCallback {
implements LoaderCallbacks<List<ParcelableUser>>, UserAdapterListener, KeyboardShortcutCallback,
IUsersAdapter.FollowClickListener {
@NonNull
private final Object mUsersBusCallback;
private RecyclerViewNavigationHelper mNavigationHelper;
protected ParcelableUsersFragment() {
mUsersBusCallback = createMessageBusCallback();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ParcelableUsersAdapter adapter = getAdapter();
final RecyclerView recyclerView = getRecyclerView();
final LinearLayoutManager layoutManager = getLayoutManager();
adapter.setUserAdapterListener(this);
mNavigationHelper = new RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter,
this);
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().initLoader(0, loaderArgs, this);
}
@Override
public void onStart() {
super.onStart();
mBus.register(mUsersBusCallback);
}
@Override
public void onStop() {
mBus.unregister(mUsersBusCallback);
super.onStop();
}
@Override
public boolean isRefreshing() {
if (getContext() == null || isDetached()) return false;
@ -63,7 +105,9 @@ public abstract class ParcelableUsersFragment extends AbsContentListRecyclerView
@NonNull
@Override
protected ParcelableUsersAdapter onCreateAdapter(Context context, boolean compact) {
return new ParcelableUsersAdapter(context);
final ParcelableUsersAdapter adapter = new ParcelableUsersAdapter(context);
adapter.setFollowClickListener(this);
return adapter;
}
@NonNull
@ -72,10 +116,7 @@ public abstract class ParcelableUsersFragment extends AbsContentListRecyclerView
return super.getAdapter();
}
protected boolean hasMoreData(List<ParcelableUser> data) {
return data == null || !data.isEmpty();
}
@Override
public void onLoadFinished(Loader<List<ParcelableUser>> loader, List<ParcelableUser> data) {
final ParcelableUsersAdapter adapter = getAdapter();
adapter.setData(data);
@ -92,14 +133,6 @@ public abstract class ParcelableUsersFragment extends AbsContentListRecyclerView
setLoadMoreIndicatorPosition(IndicatorPosition.NONE);
}
protected void removeUsers(String... ids) {
//TODO remove from adapter
}
public final List<ParcelableUser> getData() {
return getAdapter().getData();
}
@Override
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
return mNavigationHelper.handleKeyboardShortcutSingle(handler, keyCode, event, metaState);
@ -115,21 +148,6 @@ public abstract class ParcelableUsersFragment extends AbsContentListRecyclerView
return mNavigationHelper.isKeyboardShortcutHandled(handler, keyCode, event, metaState);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ParcelableUsersAdapter adapter = getAdapter();
final RecyclerView recyclerView = getRecyclerView();
final LinearLayoutManager layoutManager = getLayoutManager();
adapter.setUserAdapterListener(this);
mNavigationHelper = new RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter,
this);
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().initLoader(0, loaderArgs, this);
}
@Override
public final Loader<List<ParcelableUser>> onCreateLoader(int id, Bundle args) {
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
@ -161,6 +179,20 @@ public abstract class ParcelableUsersFragment extends AbsContentListRecyclerView
}
}
@Override
public void onFollowClicked(UserViewHolder holder, int position) {
final AsyncTwitterWrapper twitter = mTwitterWrapper;
final ParcelableUsersAdapter adapter = getAdapter();
final ParcelableUser user = adapter.getUser(position);
if (user == null || twitter == null) return;
if (twitter.isUpdatingRelationship(user.account_key, user.key)) return;
if (user.is_following) {
DestroyFriendshipDialogFragment.show(getFragmentManager(), user);
} else {
twitter.createFriendshipAsync(user.account_key, user.key);
}
}
@UserFragment.Referral
protected String getUserReferral() {
return null;
@ -179,4 +211,55 @@ public abstract class ParcelableUsersFragment extends AbsContentListRecyclerView
protected void setupRecyclerView(Context context, boolean compact) {
super.setupRecyclerView(context, true);
}
private int findPosition(ParcelableUsersAdapter adapter, UserKey accountKey, UserKey userKey) {
return adapter.findPosition(accountKey, userKey);
}
protected boolean shouldRemoveUser(int position, FriendshipTaskEvent event) {
return false;
}
protected boolean hasMoreData(List<ParcelableUser> data) {
return data == null || !data.isEmpty();
}
protected void removeUsers(String... ids) {
//TODO remove from adapter
}
public final List<ParcelableUser> getData() {
return getAdapter().getData();
}
@NonNull
protected Object createMessageBusCallback() {
return new UsersBusCallback();
}
protected class UsersBusCallback {
@Subscribe
public void onFriendshipTaskEvent(FriendshipTaskEvent event) {
final ParcelableUsersAdapter adapter = getAdapter();
final int position = findPosition(adapter, event.getAccountKey(), event.getUserKey());
final List<ParcelableUser> data = adapter.getData();
if (shouldRemoveUser(position, event)) {
data.remove(position);
adapter.notifyItemRemoved(position);
} else {
ParcelableUser adapterUser = data.get(position);
ParcelableUser eventUser = event.getUser();
if (eventUser != null) {
if (adapterUser.account_key.equals(eventUser.account_key)) {
ParcelableUser clone = ParcelUtils.clone(eventUser);
clone.position = adapterUser.position;
data.set(position, clone);
}
}
adapter.notifyItemChanged(position);
}
}
}
}

View File

@ -44,7 +44,7 @@ public class ReportSpamDialogFragment extends BaseSupportDialogFragment implemen
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
twitter.reportSpamAsync(user.account_key, user.key.getId());
twitter.reportSpamAsync(user.account_key, user.key);
break;
default:
break;

View File

@ -37,6 +37,7 @@ public class StatusFavoritersListFragment extends CursorSupportUsersListFragment
final StatusFavoritersLoader loader = new StatusFavoritersLoader(context, accountKey,
statusId, getData(), false);
loader.setCursor(getNextCursor());
loader.setPage(getNextPage());
return loader;
}

View File

@ -39,6 +39,7 @@ public class StatusRetweetersListFragment extends CursorSupportUsersListFragment
final StatusRetweetersLoader loader = new StatusRetweetersLoader(context, accountKey, statusId,
getData(), fromUser);
loader.setCursor(getNextCursor());
loader.setPage(getNextPage());
return loader;
}

View File

@ -26,6 +26,7 @@ import android.support.annotation.NonNull;
import org.mariotaku.twidere.loader.support.CursorSupportUsersLoader;
import org.mariotaku.twidere.loader.support.UserBlocksLoader;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
public class UserBlocksListFragment extends CursorSupportUsersListFragment {
@ -36,7 +37,20 @@ public class UserBlocksListFragment extends CursorSupportUsersListFragment {
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final UserBlocksLoader loader = new UserBlocksLoader(context, accountKey, getData(), fromUser);
loader.setCursor(getNextCursor());
loader.setPage(getNextPage());
return loader;
}
@Override
protected boolean shouldRemoveUser(int position, FriendshipTaskEvent event) {
if (!event.isSucceeded()) return false;
switch (event.getAction()) {
case FriendshipTaskEvent.Action.FOLLOW:
case FriendshipTaskEvent.Action.UNBLOCK: {
return true;
}
}
return false;
}
}

View File

@ -22,32 +22,14 @@ package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.squareup.otto.Subscribe;
import org.mariotaku.twidere.loader.support.CursorSupportUsersLoader;
import org.mariotaku.twidere.loader.support.UserFollowersLoader;
import org.mariotaku.twidere.loader.support.UserFriendsLoader;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.UsersBlockedEvent;
import static org.mariotaku.twidere.util.DataStoreUtils.getAccountScreenName;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
public class UserFollowersFragment extends CursorSupportUsersListFragment {
@Override
public void onStart() {
super.onStart();
mBus.register(this);
}
@Override
public void onStop() {
mBus.unregister(this);
super.onStop();
}
@Override
public CursorSupportUsersLoader onCreateUsersLoader(final Context context,
@NonNull final Bundle args,
@ -62,16 +44,15 @@ public class UserFollowersFragment extends CursorSupportUsersListFragment {
return loader;
}
@Subscribe
public void onUsersBlocked(UsersBlockedEvent event) {
final UserKey accountKey = event.getAccountKey();
final String screenName = getAccountScreenName(getActivity(), accountKey);
final Bundle args = getArguments();
if (args == null) return;
if (accountKey != null && TextUtils.equals(accountKey.getId(), args.getString(EXTRA_USER_ID))
|| screenName != null && screenName.equalsIgnoreCase(args.getString(EXTRA_SCREEN_NAME))) {
removeUsers(event.getUserIds());
@Override
protected boolean shouldRemoveUser(int position, FriendshipTaskEvent event) {
if (!event.isSucceeded()) return false;
switch (event.getAction()) {
case FriendshipTaskEvent.Action.BLOCK: {
return true;
}
}
return false;
}
}

View File

@ -111,12 +111,13 @@ import org.mariotaku.twidere.model.ParcelableUserValuesCreator;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.SupportTabSpec;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.message.FriendshipUpdatedEvent;
import org.mariotaku.twidere.model.message.FriendshipUserUpdatedEvent;
import org.mariotaku.twidere.model.message.ProfileUpdatedEvent;
import org.mariotaku.twidere.model.message.TaskStateChangedEvent;
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils;
import org.mariotaku.twidere.model.util.ParcelableMediaUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
@ -127,6 +128,7 @@ import org.mariotaku.twidere.util.ContentValuesCreator;
import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.HtmlSpanBuilder;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.InternalTwitterContentUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.LinkCreator;
@ -271,9 +273,8 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mHeaderErrorTextView.setVisibility(View.GONE);
setListShown(false);
}
setProgressBarIndeterminateVisibility(true);
final ParcelableUser user = mUser;
final boolean loadFromCache = user == null || !user.is_cache && userId != user.key.getId();
final boolean loadFromCache = user == null || !user.is_cache && user.key.check(userId, null);
return new ParcelableUserLoader(getActivity(), accountKey, userId, screenName, getArguments(),
omitIntentExtra, loadFromCache);
}
@ -317,7 +318,6 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mHeaderErrorContainer.setVisibility(View.VISIBLE);
mProgressContainer.setVisibility(View.GONE);
}
setProgressBarIndeterminateVisibility(false);
}
};
@ -569,10 +569,11 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
}
final int defWidth = resources.getDisplayMetrics().widthPixels;
final int width = mBannerWidth > 0 ? mBannerWidth : defWidth;
if (ObjectUtils.notEqual(mProfileBannerView.getTag(), user.profile_banner_url) ||
final String bannerUrl = ParcelableUserUtils.getProfileBannerUrl(user);
if (ObjectUtils.notEqual(mProfileBannerView.getTag(), bannerUrl) ||
mProfileBannerView.getDrawable() == null) {
mProfileBannerView.setTag(user.profile_banner_url);
mMediaLoader.displayProfileBanner(mProfileBannerView, user.profile_banner_url, width);
mProfileBannerView.setTag(bannerUrl);
mMediaLoader.displayProfileBanner(mProfileBannerView, bannerUrl, width);
}
final UserRelationship relationship = mRelationship;
if (relationship == null) {
@ -646,9 +647,9 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
}
@Subscribe
public void notifyFriendshipUserUpdated(FriendshipUserUpdatedEvent event) {
public void notifyFriendshipUserUpdated(FriendshipTaskEvent event) {
final ParcelableUser user = getUser();
if (user == null || !event.user.equals(user)) return;
if (user == null || !event.isSucceeded() || !event.isUser(user)) return;
getFriendship();
}
@ -661,7 +662,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
@Subscribe
public void notifyTaskStateChanged(TaskStateChangedEvent event) {
updateRefreshState();
invalidateOptionsMenu();
}
@Override
@ -977,7 +978,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
case R.id.block: {
if (userRelationship == null) return true;
if (userRelationship.relationship.isSourceBlockingTarget()) {
twitter.destroyBlockAsync(user.account_key, user.key.getId());
twitter.destroyBlockAsync(user.account_key, user.key);
} else {
CreateUserBlockDialogFragment.show(getFragmentManager(), user);
}
@ -1004,7 +1005,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
case R.id.mute_user: {
if (userRelationship == null) return true;
if (userRelationship.relationship.isSourceMutingTarget()) {
twitter.destroyMuteAsync(user.account_key, user.key.getId());
twitter.destroyMuteAsync(user.account_key, user.key);
} else {
CreateUserMuteDialogFragment.show(getFragmentManager(), user);
}
@ -1066,15 +1067,13 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
case R.id.follow: {
if (userRelationship == null) return true;
final boolean isFollowing = userRelationship.relationship.isSourceFollowingTarget();
final boolean isCreatingFriendship = twitter.isCreatingFriendship(user.account_key,
user.key.getId());
final boolean isDestroyingFriendship = twitter.isDestroyingFriendship(user.account_key,
user.key.getId());
if (!isCreatingFriendship && !isDestroyingFriendship) {
final boolean updatingRelationship = twitter.isUpdatingRelationship(user.account_key,
user.key);
if (!updatingRelationship) {
if (isFollowing) {
DestroyFriendshipDialogFragment.show(getFragmentManager(), user);
} else {
twitter.createFriendshipAsync(user.account_key, user.key.getId());
twitter.createFriendshipAsync(user.account_key, user.key);
}
}
return true;
@ -1293,11 +1292,11 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (userRelationship == null || twitter == null) return;
if (userRelationship.relationship.isSourceBlockingTarget()) {
twitter.destroyBlockAsync(user.account_key, user.key.getId());
twitter.destroyBlockAsync(user.account_key, user.key);
} else if (userRelationship.relationship.isSourceFollowingTarget()) {
DestroyFriendshipDialogFragment.show(getFragmentManager(), user);
} else {
twitter.createFriendshipAsync(user.account_key, user.key.getId());
twitter.createFriendshipAsync(user.account_key, user.key);
}
break;
}
@ -1310,8 +1309,10 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
break;
}
case R.id.profile_banner: {
if (user.profile_banner_url == null) return;
final String url = user.profile_banner_url + "/ipad_retina";
final String bannerUrl = ParcelableUserUtils.getProfileBannerUrl(user);
if (bannerUrl == null) return;
final String url = InternalTwitterContentUtils.getBestBannerUrl(bannerUrl,
Integer.MAX_VALUE);
ParcelableMedia profileBanner = ParcelableMediaUtils.image(url);
profileBanner.type = ParcelableMedia.Type.IMAGE;
final ParcelableMedia[] media = {profileBanner};
@ -1564,11 +1565,8 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final LoaderManager lm = getLoaderManager();
final boolean loadingRelationship = lm.getLoader(LOADER_ID_FRIENDSHIP) != null;
final UserKey accountKey = user.account_key;
final boolean creatingFriendship = twitter.isCreatingFriendship(accountKey, user.key.getId());
final boolean destroyingFriendship = twitter.isDestroyingFriendship(accountKey, user.key.getId());
final boolean creatingBlock = twitter.isCreatingFriendship(accountKey, user.key.getId());
final boolean destroyingBlock = twitter.isDestroyingFriendship(accountKey, user.key.getId());
if (loadingRelationship || creatingFriendship || destroyingFriendship || creatingBlock || destroyingBlock) {
final boolean updatingRelationship = twitter.isUpdatingRelationship(accountKey, user.key);
if (loadingRelationship || updatingRelationship) {
mFollowButton.setVisibility(View.GONE);
mFollowProgress.setVisibility(View.VISIBLE);
} else if (mRelationship != null) {
@ -1580,17 +1578,6 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
}
}
private void updateRefreshState() {
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
final UserKey accountKey = user.account_key;
final boolean isCreatingFriendship = twitter.isCreatingFriendship(accountKey, user.key.getId());
final boolean destroyingFriendship = twitter.isDestroyingFriendship(accountKey, user.key.getId());
setProgressBarIndeterminateVisibility(isCreatingFriendship || destroyingFriendship);
invalidateOptionsMenu();
}
private void updateScrollOffset(int offset) {
final View space = mProfileBannerSpace;
final ProfileBannerImageView profileBannerView = mProfileBannerView;

View File

@ -26,6 +26,7 @@ import android.support.annotation.NonNull;
import org.mariotaku.twidere.loader.support.CursorSupportUsersLoader;
import org.mariotaku.twidere.loader.support.UserFriendsLoader;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
public class UserFriendsFragment extends CursorSupportUsersListFragment {
@ -38,7 +39,19 @@ public class UserFriendsFragment extends CursorSupportUsersListFragment {
final UserFriendsLoader loader = new UserFriendsLoader(context, accountKey, userId,
screenName, getData(), fromUser);
loader.setCursor(getNextCursor());
loader.setPage(getNextPage());
return loader;
}
@Override
protected boolean shouldRemoveUser(int position, FriendshipTaskEvent event) {
if (!event.isSucceeded()) return false;
switch (event.getAction()) {
case FriendshipTaskEvent.Action.UNFOLLOW:
case FriendshipTaskEvent.Action.BLOCK: {
return true;
}
}
return false;
}
}

View File

@ -363,7 +363,6 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
@Override
public Loader<SingleResponse<ParcelableUserList>> onCreateLoader(final int id, final Bundle args) {
setProgressBarIndeterminateVisibility(true);
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final String userId = args.getString(EXTRA_USER_ID);
final long listId = args.getLong(EXTRA_LIST_ID, -1);
@ -384,7 +383,6 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
displayUserList(list);
} else if (data.hasException()) {
}
setProgressBarIndeterminateVisibility(false);
}
@Override

View File

@ -70,6 +70,7 @@ public class UserListMembersFragment extends CursorSupportUsersListFragment {
final UserListMembersLoader loader = new UserListMembersLoader(context, accountId, listId,
userId, screenName, listName, getData(), fromUser);
loader.setCursor(getNextCursor());
loader.setPage(getNextPage());
return loader;
}

View File

@ -40,6 +40,7 @@ public class UserListSubscribersFragment extends CursorSupportUsersListFragment
final UserListSubscribersLoader loader = new UserListSubscribersLoader(context, accountKey,
listId, userId, screenName, listName, getData(), fromUser);
loader.setCursor(getNextCursor());
loader.setPage(getNextPage());
return loader;
}

View File

@ -63,7 +63,7 @@ import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper.UpdateProfileBannerImageTask;
import org.mariotaku.twidere.task.UpdateProfileBannerImageTask;
import org.mariotaku.twidere.util.AsyncTwitterWrapper.UpdateProfileImageTask;
import org.mariotaku.twidere.util.HtmlEscapeHelper;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;

View File

@ -169,7 +169,7 @@ public class CardPollFragment extends BaseSupportFragment implements
= new AbstractTask<CardDataMap, ParcelableCardEntity, CardPollFragment>() {
@Override
public void afterExecute(CardPollFragment handler, ParcelableCardEntity result) {
public void afterExecute(CardPollFragment handler, CardDataMap params, ParcelableCardEntity result) {
handler.displayAndReloadPoll(result, status);
}

View File

@ -90,6 +90,13 @@ public abstract class CursorSupportUsersLoader extends TwitterAPIUsersLoader
if (cursor == null) return;
mNextCursor = cursor.getNextCursor();
mPrevCursor = cursor.getPreviousCursor();
}
protected final void incrementPage(ResponseList<User> users) {
if (users.isEmpty()) return;
if (mPage == -1) {
mPage = 1;
}
mNextPage = mPage + 1;
}
@ -122,17 +129,19 @@ public abstract class CursorSupportUsersLoader extends TwitterAPIUsersLoader
} else if (getPage() > 1) {
paging.setPage(getPage());
}
final ResponseList<User> users;
if (useIDs(credentials)) {
final IDs ids = getIDs(twitter, credentials, paging);
setCursors(ids);
return twitter.lookupUsers(ids.getIDs());
users = twitter.lookupUsers(ids.getIDs());
} else {
final List<User> users = getCursoredUsers(twitter, credentials, paging);
users = getCursoredUsers(twitter, credentials, paging);
if (users instanceof CursorSupport) {
setCursors(((CursorSupport) users));
}
return users;
}
incrementPage(users);
return users;
}
protected boolean useIDs(@NonNull ParcelableCredentials credentials) {

View File

@ -26,9 +26,13 @@ import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.IDs;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import java.util.List;
@ -45,8 +49,19 @@ public class IncomingFriendshipsLoader extends CursorSupportUsersLoader {
return twitter.getIncomingFriendships(paging);
}
@NonNull
@Override
protected ResponseList<User> getCursoredUsers(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Paging paging) throws TwitterException {
return twitter.getFriendshipsRequests(paging);
}
@Override
protected boolean useIDs(@NonNull ParcelableCredentials credentials) {
switch (ParcelableAccountUtils.getAccountType(credentials)) {
case ParcelableAccount.Type.FANFOU: {
return false;
}
}
return true;
}
}

View File

@ -1,69 +0,0 @@
package org.mariotaku.twidere.model.message;
import android.support.annotation.IntDef;
import org.mariotaku.twidere.model.UserKey;
/**
* Created by mariotaku on 16/2/15.
*/
public class FollowRequestTaskEvent {
@Action
private int action;
private boolean finished;
private boolean succeeded;
private UserKey mAccountKey;
private String userId;
public FollowRequestTaskEvent(@Action int action, UserKey accountKey, String userId) {
this.action = action;
this.mAccountKey = accountKey;
this.userId = userId;
}
@Action
public int getAction() {
return action;
}
public boolean isFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
public UserKey getAccountKey() {
return mAccountKey;
}
public String getUserId() {
return userId;
}
public boolean isSucceeded() {
return succeeded;
}
public void setSucceeded(boolean succeeded) {
this.succeeded = succeeded;
}
@Override
public String toString() {
return "FollowRequestTaskEvent{" +
"action=" + action +
", finished=" + finished +
", mAccountKey=" + mAccountKey +
", userId=" + userId +
'}';
}
@IntDef({Action.ACCEPT, Action.DENY})
public @interface Action {
int ACCEPT = 1;
int DENY = 2;
}
}

View File

@ -0,0 +1,95 @@
package org.mariotaku.twidere.model.message;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.UserKey;
/**
* Created by mariotaku on 16/2/15.
*/
public class FriendshipTaskEvent {
@Action
private int action;
private boolean finished;
private boolean succeeded;
@NonNull
private UserKey accountKey;
@NonNull
private UserKey userKey;
private ParcelableUser user;
public FriendshipTaskEvent(@Action int action, @NonNull UserKey accountKey, @NonNull UserKey userKey) {
this.action = action;
this.accountKey = accountKey;
this.userKey = userKey;
}
@Action
public int getAction() {
return action;
}
public boolean isFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
@NonNull
public UserKey getAccountKey() {
return accountKey;
}
@NonNull
public UserKey getUserKey() {
return userKey;
}
public boolean isSucceeded() {
return succeeded;
}
public void setSucceeded(boolean succeeded) {
this.succeeded = succeeded;
}
public ParcelableUser getUser() {
return user;
}
public void setUser(ParcelableUser user) {
this.user = user;
}
public final boolean isUser(@NonNull ParcelableUser user) {
return userKey.equals(user.key);
}
@Override
public String toString() {
return "FriendshipTaskEvent{" +
"action=" + action +
", finished=" + finished +
", mAccountKey=" + accountKey +
", userId=" + userKey +
'}';
}
@IntDef({Action.ACCEPT, Action.DENY, Action.FOLLOW, Action.UNFOLLOW, Action.BLOCK,
Action.UNBLOCK, Action.MUTE, Action.UNMUTE})
public @interface Action {
int ACCEPT = 1;
int DENY = 2;
int FOLLOW = 3;
int UNFOLLOW = 4;
int BLOCK = 5;
int UNBLOCK = 6;
int MUTE = 7;
int UNMUTE = 8;
}
}

View File

@ -1,37 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.model.message;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.model.ParcelableUser;
/**
* Created by mariotaku on 14/12/7.
*/
public class FriendshipUserUpdatedEvent {
@NonNull
public final ParcelableUser user;
public FriendshipUserUpdatedEvent(@NonNull ParcelableUser user) {
this.user = user;
}
}

View File

@ -8,9 +8,9 @@ import android.support.annotation.Nullable;
import org.mariotaku.sqliteqb.library.ArgsArray;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccountCursorIndices;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.TwidereArrayUtils;
@ -96,7 +96,7 @@ public class ParcelableAccountUtils {
@NonNull
@ParcelableAccount.Type
public static String getAccountType(ParcelableAccount account) {
public static String getAccountType(@NonNull ParcelableAccount account) {
if (account.account_type == null) return ParcelableAccount.Type.TWITTER;
return account.account_type;
}

View File

@ -3,6 +3,7 @@ package org.mariotaku.twidere.model.util;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.api.twitter.model.UrlEntity;
@ -44,6 +45,10 @@ public class ParcelableUserUtils implements TwidereConstants {
obj.location = user.getLocation();
obj.profile_image_url = TwitterContentUtils.getProfileImageUrl(user);
obj.profile_banner_url = user.getProfileBannerImageUrl();
obj.profile_background_url = user.getProfileBackgroundImageUrlHttps();
if (TextUtils.isEmpty(obj.profile_background_url)) {
obj.profile_background_url = user.getProfileBackgroundImageUrl();
}
obj.url = user.getUrl();
if (obj.url != null && urlEntities != null && urlEntities.length > 0) {
obj.url_expanded = urlEntities[0].getExpandedUrl();
@ -56,9 +61,9 @@ public class ParcelableUserUtils implements TwidereConstants {
obj.listed_count = user.getListedCount();
obj.media_count = user.getMediaCount();
obj.is_following = user.isFollowing();
obj.background_color = ParseUtils.parseColor("#" + user.getProfileBackgroundColor(), 0);
obj.link_color = ParseUtils.parseColor("#" + user.getProfileLinkColor(), 0);
obj.text_color = ParseUtils.parseColor("#" + user.getProfileTextColor(), 0);
obj.background_color = parseColor(user.getProfileBackgroundColor());
obj.link_color = parseColor(user.getProfileLinkColor());
obj.text_color = parseColor(user.getProfileTextColor());
obj.is_cache = false;
obj.is_basic = false;
@ -93,4 +98,21 @@ public class ParcelableUserUtils implements TwidereConstants {
}
return result;
}
private static int parseColor(@Nullable String colorString) {
if (colorString == null) return 0;
if (!colorString.startsWith("#")) {
colorString = "#" + colorString;
}
return ParseUtils.parseColor(colorString, 0);
}
@Nullable
public static String getProfileBannerUrl(@NonNull ParcelableUser user) {
if (!TextUtils.isEmpty(user.profile_banner_url)) return user.profile_banner_url;
if (USER_TYPE_FANFOU_COM.equals(user.key.getHost())) {
return user.profile_background_url;
}
return null;
}
}

View File

@ -0,0 +1,126 @@
package org.mariotaku.twidere.task;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.squareup.otto.Bus;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import org.mariotaku.twidere.util.UserColorNameManager;
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
import javax.inject.Inject;
/**
* Created by mariotaku on 16/3/11.
*/
public abstract class AbsFriendshipOperationTask extends AbstractTask<AbsFriendshipOperationTask.Arguments,
SingleResponse<ParcelableUser>, Object> implements Constants {
protected final Context context;
@FriendshipTaskEvent.Action
protected final int action;
@Inject
protected Bus bus;
@Inject
protected AsyncTwitterWrapper twitter;
@Inject
protected SharedPreferencesWrapper preferences;
@Inject
protected UserColorNameManager manager;
public AbsFriendshipOperationTask(Context context, @FriendshipTaskEvent.Action int action) {
this.context = context;
this.action = action;
GeneralComponentHelper.build(context).inject(this);
}
@Override
protected final void beforeExecute(Arguments params) {
twitter.addUpdatingRelationshipId(params.accountKey, params.userKey);
final FriendshipTaskEvent event = new FriendshipTaskEvent(action, params.accountKey,
params.userKey);
event.setFinished(false);
bus.post(event);
}
@Override
protected final void afterExecute(Arguments params, SingleResponse<ParcelableUser> result) {
twitter.removeUpdatingRelationshipId(params.accountKey, params.userKey);
final FriendshipTaskEvent event = new FriendshipTaskEvent(action, params.accountKey,
params.userKey);
event.setFinished(true);
if (result.hasData()) {
final ParcelableUser user = result.getData();
showSucceededMessage(params, user);
event.setSucceeded(true);
event.setUser(result.getData());
} else {
showErrorMessage(params, result.getException());
}
bus.post(event);
}
@Override
public final SingleResponse<ParcelableUser> doLongOperation(final Arguments args) {
final ParcelableCredentials credentials = ParcelableCredentialsUtils.getCredentials(context,
args.accountKey);
if (credentials == null) return SingleResponse.getInstance();
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(context, credentials, false, false);
if (twitter == null) return SingleResponse.getInstance();
try {
final User user = perform(twitter, credentials, args);
final ParcelableUser parcelableUser = ParcelableUserUtils.fromUser(user, args.accountKey);
succeededWorker(twitter, credentials, args, parcelableUser);
return SingleResponse.getInstance(parcelableUser, null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
@NonNull
protected abstract User perform(@NonNull Twitter twitter,
@NonNull ParcelableCredentials credentials,
@NonNull Arguments args) throws TwitterException;
protected abstract void succeededWorker(@NonNull Twitter twitter,
@NonNull ParcelableCredentials credentials,
@NonNull Arguments args,
@NonNull ParcelableUser user);
protected abstract void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user);
protected abstract void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception);
public final void setup(@NonNull UserKey accountKey, @NonNull UserKey userKey) {
setParams(new Arguments(accountKey, userKey));
}
protected static class Arguments {
@NonNull
protected final UserKey accountKey;
@NonNull
protected final UserKey userKey;
protected Arguments(@NonNull UserKey accountKey, @NonNull UserKey userKey) {
this.accountKey = accountKey;
this.userKey = userKey;
}
}
}

View File

@ -16,17 +16,17 @@ public abstract class AbstractTask<Params, Result, Callback> {
protected abstract Result doLongOperation(Params params);
@MainThread
protected void beforeExecute() {
protected void beforeExecute(Params params) {
}
@MainThread
protected void afterExecute(Result result) {
protected void afterExecute(Params params, Result result) {
}
@MainThread
protected void afterExecute(Callback callback, Result result) {
protected void afterExecute(Callback callback, Params params, Result result) {
}
@ -42,9 +42,9 @@ public abstract class AbstractTask<Params, Result, Callback> {
@MainThread
public void invokeAfterExecute(Result result) {
if (mCallback != null) {
afterExecute(mCallback, result);
afterExecute(mCallback, mParams, result);
} else {
afterExecute(result);
afterExecute(mParams, result);
}
}
@ -53,6 +53,6 @@ public abstract class AbstractTask<Params, Result, Callback> {
}
public void invokeBeforeExecute() {
beforeExecute();
beforeExecute(mParams);
}
}

View File

@ -0,0 +1,56 @@
package org.mariotaku.twidere.task;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/11.
*/
public class AcceptFriendshipTask extends AbsFriendshipOperationTask {
public AcceptFriendshipTask(final Context context) {
super(context, FriendshipTaskEvent.Action.ACCEPT);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Arguments args) throws TwitterException {
switch (ParcelableAccountUtils.getAccountType(credentials)) {
case ParcelableAccount.Type.FANFOU: {
return twitter.acceptFanfouFriendship(args.userKey.getId());
}
}
return twitter.acceptFriendship(args.userKey.getId());
}
@Override
protected void succeededWorker(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Arguments args, @NonNull ParcelableUser user) {
Utils.setLastSeen(context, user.key, System.currentTimeMillis());
}
@Override
protected void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception) {
Utils.showErrorMessage(context, R.string.action_accepting_follow_request, exception, false);
}
@Override
protected void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user) {
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
final String message = context.getString(R.string.accepted_users_follow_request,
manager.getDisplayName(user, nameFirst, true));
Utils.showOkMessage(context, message, false);
}
}

View File

@ -0,0 +1,73 @@
package org.mariotaku.twidere.task;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/11.
*/
public class CreateFriendshipTask extends AbsFriendshipOperationTask {
public CreateFriendshipTask(final Context context) {
super(context, FriendshipTaskEvent.Action.FOLLOW);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Arguments args) throws TwitterException {
switch (ParcelableAccountUtils.getAccountType(credentials)) {
case ParcelableAccount.Type.FANFOU: {
return twitter.createFanfouFriendship(args.userKey.getId());
}
}
return twitter.createFriendship(args.userKey.getId());
}
@Override
protected void succeededWorker(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Arguments args, @NonNull ParcelableUser user) {
Utils.setLastSeen(context, user.key, System.currentTimeMillis());
}
@Override
protected void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception) {
if (USER_TYPE_FANFOU_COM.equals(params.accountKey.getHost())) {
// Fanfou returns 403 for follow request
if (exception instanceof TwitterException) {
TwitterException te = (TwitterException) exception;
if (te.getStatusCode() == 403 && !TextUtils.isEmpty(te.getErrorMessage())) {
Utils.showErrorMessage(context, te.getErrorMessage(), false);
return;
}
}
}
Utils.showErrorMessage(context, R.string.action_following, exception, false);
}
@Override
protected void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user) {
final String message;
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
if (user.is_protected) {
message = context.getString(R.string.sent_follow_request_to_user,
manager.getDisplayName(user, nameFirst, true));
} else {
message = context.getString(R.string.followed_user,
manager.getDisplayName(user, nameFirst, true));
}
Utils.showOkMessage(context, message, false);
}
}

View File

@ -0,0 +1,82 @@
package org.mariotaku.twidere.task;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/11.
*/
public class CreateUserBlockTask extends AbsFriendshipOperationTask {
public CreateUserBlockTask(Context context) {
super(context, FriendshipTaskEvent.Action.BLOCK);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials,
@NonNull Arguments args) throws TwitterException {
switch (ParcelableAccountUtils.getAccountType(credentials)) {
case ParcelableAccount.Type.FANFOU: {
return twitter.createFanfouBlock(args.userKey.getId());
}
}
return twitter.createBlock(args.userKey.getId());
}
@Override
protected void succeededWorker(@NonNull Twitter twitter,
@NonNull ParcelableCredentials credentials,
@NonNull Arguments args, @NonNull ParcelableUser user) {
final ContentResolver resolver = context.getContentResolver();
Utils.setLastSeen(context, args.userKey, -1);
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
final Expression where = Expression.and(
Expression.equalsArgs(TwidereDataStore.AccountSupportColumns.ACCOUNT_KEY),
Expression.equalsArgs(TwidereDataStore.Statuses.USER_ID)
);
final String[] whereArgs = {args.accountKey.toString(), args.userKey.toString()};
resolver.delete(uri, where.getSQL(), whereArgs);
}
// I bet you don't want to see this user in your auto complete list.
final ContentValues values = new ContentValues();
values.put(CachedRelationships.ACCOUNT_KEY, args.accountKey.toString());
values.put(CachedRelationships.USER_ID, args.userKey.toString());
values.put(CachedRelationships.BLOCKING, true);
values.put(CachedRelationships.FOLLOWING, false);
values.put(CachedRelationships.FOLLOWED_BY, false);
resolver.insert(CachedRelationships.CONTENT_URI, values);
}
@Override
protected void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user) {
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
final String message = context.getString(R.string.blocked_user, manager.getDisplayName(user,
nameFirst, true));
Utils.showInfoMessage(context, message, false);
}
@Override
protected void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception) {
Utils.showErrorMessage(context, R.string.action_blocking, exception, true);
}
}

View File

@ -0,0 +1,74 @@
package org.mariotaku.twidere.task;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/11.
*/
public class CreateUserMuteTask extends AbsFriendshipOperationTask {
public CreateUserMuteTask(Context context) {
super(context, FriendshipTaskEvent.Action.MUTE);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials,
@NonNull Arguments args) throws TwitterException {
return twitter.createMute(args.userKey.getId());
}
@Override
protected void succeededWorker(@NonNull Twitter twitter,
@NonNull ParcelableCredentials credentials,
@NonNull Arguments args, @NonNull ParcelableUser user) {
final ContentResolver resolver = context.getContentResolver();
Utils.setLastSeen(context, args.userKey, -1);
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
final Expression where = Expression.and(
Expression.equalsArgs(Statuses.ACCOUNT_KEY),
Expression.equalsArgs(Statuses.USER_ID)
);
final String[] whereArgs = {args.accountKey.toString(), args.userKey.toString()};
resolver.delete(uri, where.getSQL(), whereArgs);
}
// I bet you don't want to see this user in your auto complete list.
final ContentValues values = new ContentValues();
values.put(CachedRelationships.ACCOUNT_KEY, args.accountKey.toString());
values.put(CachedRelationships.USER_ID, args.userKey.toString());
values.put(CachedRelationships.MUTING, true);
resolver.insert(CachedRelationships.CONTENT_URI, values);
}
@Override
protected void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user) {
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
final String message = context.getString(R.string.muted_user, manager.getDisplayName(user,
nameFirst, true));
Utils.showInfoMessage(context, message, false);
}
@Override
protected void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception) {
Utils.showErrorMessage(context, R.string.action_muting, exception, true);
}
}

View File

@ -0,0 +1,56 @@
package org.mariotaku.twidere.task;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/11.
*/
public class DenyFriendshipTask extends AbsFriendshipOperationTask {
public DenyFriendshipTask(final Context context) {
super(context, FriendshipTaskEvent.Action.DENY);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Arguments args) throws TwitterException {
switch (ParcelableAccountUtils.getAccountType(credentials)) {
case ParcelableAccount.Type.FANFOU: {
return twitter.denyFanfouFriendship(args.userKey.getId());
}
}
return twitter.denyFriendship(args.userKey.getId());
}
@Override
protected void succeededWorker(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Arguments args, @NonNull ParcelableUser user) {
Utils.setLastSeen(context, user.key, -1);
}
@Override
protected void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception) {
Utils.showErrorMessage(context, R.string.action_denying_follow_request, exception, false);
}
@Override
protected void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user) {
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
final String message = context.getString(R.string.denied_users_follow_request,
manager.getDisplayName(user, nameFirst, true));
Utils.showOkMessage(context, message, false);
}
}

View File

@ -0,0 +1,66 @@
package org.mariotaku.twidere.task;
import android.content.ContentResolver;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/11.
*/
public class DestroyFriendshipTask extends AbsFriendshipOperationTask {
public DestroyFriendshipTask(final Context context) {
super(context, FriendshipTaskEvent.Action.UNFOLLOW);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Arguments args) throws TwitterException {
switch (ParcelableAccountUtils.getAccountType(credentials)) {
case ParcelableAccount.Type.FANFOU: {
return twitter.destroyFanfouFriendship(args.userKey.getId());
}
}
return twitter.destroyFriendship(args.userKey.getId());
}
@Override
protected void succeededWorker(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull Arguments args, @NonNull ParcelableUser user) {
Utils.setLastSeen(context, user.key, -1);
final Expression where = Expression.and(Expression.equalsArgs(TwidereDataStore.Statuses.ACCOUNT_KEY),
Expression.or(Expression.equalsArgs(TwidereDataStore.Statuses.USER_ID),
Expression.equalsArgs(TwidereDataStore.Statuses.RETWEETED_BY_USER_ID)));
final String[] whereArgs = {args.userKey.toString(), args.userKey.toString(),
args.userKey.toString()};
final ContentResolver resolver = context.getContentResolver();
resolver.delete(TwidereDataStore.Statuses.CONTENT_URI, where.getSQL(), whereArgs);
}
@Override
protected void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception) {
Utils.showErrorMessage(context, R.string.action_unfollowing, exception, false);
}
@Override
protected void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user) {
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
final String message = context.getString(R.string.unfollowed_user,
manager.getDisplayName(user, nameFirst, true));
Utils.showInfoMessage(context, message, false);
}
}

View File

@ -0,0 +1,69 @@
package org.mariotaku.twidere.task;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/11.
*/
public class DestroyUserBlockTask extends AbsFriendshipOperationTask {
public DestroyUserBlockTask(Context context) {
super(context, FriendshipTaskEvent.Action.UNBLOCK);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials,
@NonNull Arguments args) throws TwitterException {
switch (ParcelableAccountUtils.getAccountType(credentials)) {
case ParcelableAccount.Type.FANFOU: {
return twitter.destroyFanfouBlock(args.userKey.getId());
}
}
return twitter.destroyBlock(args.userKey.getId());
}
@Override
protected void succeededWorker(@NonNull Twitter twitter,
@NonNull ParcelableCredentials credentials,
@NonNull Arguments args, @NonNull ParcelableUser user) {
final ContentResolver resolver = context.getContentResolver();
// I bet you don't want to see this user in your auto complete list.
final ContentValues values = new ContentValues();
values.put(CachedRelationships.ACCOUNT_KEY, args.accountKey.toString());
values.put(CachedRelationships.USER_ID, args.userKey.toString());
values.put(CachedRelationships.BLOCKING, false);
values.put(CachedRelationships.FOLLOWING, false);
values.put(CachedRelationships.FOLLOWED_BY, false);
resolver.insert(CachedRelationships.CONTENT_URI, values);
}
@Override
protected void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user) {
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
final String message = context.getString(R.string.unblocked_user, manager.getDisplayName(user,
nameFirst, true));
Utils.showInfoMessage(context, message, false);
}
@Override
protected void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception) {
Utils.showErrorMessage(context, R.string.action_unblocking, exception, true);
}
}

View File

@ -0,0 +1,60 @@
package org.mariotaku.twidere.task;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.message.FriendshipTaskEvent;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/11.
*/
public class DestroyUserMuteTask extends AbsFriendshipOperationTask {
public DestroyUserMuteTask(Context context) {
super(context, FriendshipTaskEvent.Action.UNMUTE);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials,
@NonNull Arguments args) throws TwitterException {
return twitter.destroyMute(args.userKey.getId());
}
@Override
protected void succeededWorker(@NonNull Twitter twitter,
@NonNull ParcelableCredentials credentials,
@NonNull Arguments args, @NonNull ParcelableUser user) {
final ContentResolver resolver = context.getContentResolver();
// I bet you don't want to see this user in your auto complete list.
final ContentValues values = new ContentValues();
values.put(CachedRelationships.ACCOUNT_KEY, args.accountKey.toString());
values.put(CachedRelationships.USER_ID, args.userKey.toString());
values.put(CachedRelationships.MUTING, false);
resolver.insert(CachedRelationships.CONTENT_URI, values);
}
@Override
protected void showSucceededMessage(@NonNull Arguments params, @NonNull ParcelableUser user) {
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
final String message = context.getString(R.string.unmuted_user, manager.getDisplayName(user,
nameFirst, true));
Utils.showInfoMessage(context, message, false);
}
@Override
protected void showErrorMessage(@NonNull Arguments params, @Nullable Exception exception) {
Utils.showErrorMessage(context, R.string.action_unmuting, exception, true);
}
}

View File

@ -37,13 +37,18 @@ public class GetActivitiesAboutMeTask extends GetActivitiesTask {
}
@Override
protected void saveReadPosition(@NonNull UserKey accountId, @NonNull Twitter twitter) {
try {
CursorTimestampResponse response = twitter.getActivitiesAboutMeUnread(true);
final String tag = Utils.getReadPositionTagWithAccounts(ReadPositionTag.ACTIVITIES_ABOUT_ME, accountId);
readStateManager.setPosition(tag, response.getCursor(), false);
} catch (TwitterException e) {
// Ignore
protected void saveReadPosition(@NonNull UserKey accountId, ParcelableCredentials credentials, @NonNull Twitter twitter) {
if (ParcelableAccount.Type.TWITTER.equals(ParcelableAccountUtils.getAccountType(credentials))) {
if (Utils.isOfficialCredentials(context, credentials)) {
try {
CursorTimestampResponse response = twitter.getActivitiesAboutMeUnread(true);
final String tag = Utils.getReadPositionTagWithAccounts(ReadPositionTag.ACTIVITIES_ABOUT_ME,
accountId);
readStateManager.setPosition(tag, response.getCursor(), false);
} catch (TwitterException e) {
// Ignore
}
}
}
}

View File

@ -139,12 +139,12 @@ public abstract class GetDirectMessagesTask extends AbstractTask<RefreshTaskPara
}
public void beforeExecute() {
public void beforeExecute(RefreshTaskParam params) {
bus.post(new GetMessagesTaskEvent(getDatabaseUri(), true, null));
}
@Override
protected void afterExecute(List<TwitterWrapper.MessageListResponse> result) {
protected void afterExecute(RefreshTaskParam params, List<TwitterWrapper.MessageListResponse> result) {
bus.post(new GetMessagesTaskEvent(getDatabaseUri(), false, AsyncTwitterWrapper.getException(result)));
}
}

View File

@ -0,0 +1,26 @@
package org.mariotaku.twidere.task;
import android.content.Context;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableCredentials;
/**
* Created by mariotaku on 16/3/11.
*/
public class ReportSpamAndBlockTask extends CreateUserBlockTask {
public ReportSpamAndBlockTask(Context context) {
super(context);
}
@NonNull
@Override
protected User perform(@NonNull Twitter twitter, @NonNull ParcelableCredentials credentials,
@NonNull Arguments args) throws TwitterException {
return twitter.reportSpam(args.userKey.getId());
}
}

View File

@ -0,0 +1,74 @@
package org.mariotaku.twidere.task;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.ProfileUpdatedEvent;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import org.mariotaku.twidere.util.TwitterWrapper;
import org.mariotaku.twidere.util.Utils;
import java.io.FileNotFoundException;
/**
* Created by mariotaku on 16/3/11.
*/
public class UpdateProfileBannerImageTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
private final UserKey mAccountKey;
private final Uri mImageUri;
private final boolean mDeleteImage;
private final Context mContext;
public UpdateProfileBannerImageTask(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean deleteImage) {
super(context);
mContext = context;
mAccountKey = accountKey;
mImageUri = imageUri;
mDeleteImage = deleteImage;
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
if (result.hasData()) {
Utils.showOkMessage(mContext, R.string.profile_banner_image_updated, false);
bus.post(new ProfileUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_updating_profile_banner_image, result.getException(),
true);
}
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
try {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey,
true);
TwitterWrapper.updateProfileBannerImage(mContext, twitter, mImageUri, mDeleteImage);
// Wait for 5 seconds, see
// https://dev.twitter.com/docs/api/1.1/post/account/update_profile_image
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
Log.w(LOGTAG, e);
}
final User user = TwitterWrapper.tryShowUser(twitter, mAccountKey.getId(), null);
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey));
} catch (TwitterException | FileNotFoundException e) {
return SingleResponse.getInstance(e);
}
}
}

View File

@ -106,7 +106,7 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
final ResponseList<Activity> activities = getActivities(twitter, credentials, paging);
storeActivities(cr, loadItemLimit, accountKey, noItemsBefore, activities, sinceId, maxId);
if (saveReadPosition) {
saveReadPosition(accountKey, twitter);
saveReadPosition(accountKey,credentials, twitter);
}
errorInfoStore.remove(getErrorInfoKey(), accountKey);
} catch (TwitterException e) {
@ -180,7 +180,7 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
}
protected abstract void saveReadPosition(@NonNull final UserKey accountId,
@NonNull final Twitter twitter);
ParcelableCredentials credentials, @NonNull final Twitter twitter);
protected abstract ResponseList<Activity> getActivities(@NonNull final Twitter twitter,
@NonNull final ParcelableCredentials credentials,
@ -188,7 +188,7 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
throws TwitterException;
@Override
public void afterExecute(Object result) {
public void afterExecute(RefreshTaskParam params, Object result) {
bus.post(new GetActivitiesTaskEvent(getContentUri(), false, null));
}
@ -196,7 +196,7 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
@UiThread
@Override
public void beforeExecute() {
public void beforeExecute(RefreshTaskParam params) {
bus.post(new GetActivitiesTaskEvent(getContentUri(), true, null));
}
}

View File

@ -83,7 +83,7 @@ public abstract class GetStatusesTask extends AbstractTask<RefreshTaskParam,
protected abstract String getTimelineType();
@Override
public void afterExecute(List<TwitterWrapper.StatusListResponse> result) {
public void afterExecute(RefreshTaskParam params, List<TwitterWrapper.StatusListResponse> result) {
bus.post(new GetStatusesTaskEvent(getContentUri(), false, AsyncTwitterWrapper.getException(result)));
}
@ -222,7 +222,7 @@ public abstract class GetStatusesTask extends AbstractTask<RefreshTaskParam,
final boolean deletedOldGap = rowsDeleted > 0 && ArrayUtils.contains(statusIds, maxId);
final boolean noRowsDeleted = rowsDeleted == 0;
final boolean insertGap = minIdx != -1 && (noRowsDeleted || deletedOldGap) && !noItemsBefore
&& !hasIntersection && statuses.size() >= loadItemLimit;
&& !hasIntersection;
if (insertGap) {
values[minIdx].put(Statuses.IS_GAP, true);
}
@ -230,6 +230,14 @@ public abstract class GetStatusesTask extends AbstractTask<RefreshTaskParam,
final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
ContentResolverUtils.bulkInsert(resolver, insertUri, values);
if (maxId != null && sinceId == null) {
final ContentValues noGapValues = new ContentValues();
noGapValues.put(Statuses.IS_GAP, false);
final String noGapWhere = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY),
Expression.equalsArgs(Statuses.STATUS_ID)).getSQL();
final String[] noGapWhereArgs = {accountKey.toString(), maxId};
resolver.update(getContentUri(), noGapValues, noGapWhere, noGapWhereArgs);
}
}

View File

@ -64,9 +64,7 @@ import org.mariotaku.twidere.model.SimpleRefreshTaskParam;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.FavoriteTaskEvent;
import org.mariotaku.twidere.model.message.FollowRequestTaskEvent;
import org.mariotaku.twidere.model.message.FriendshipUpdatedEvent;
import org.mariotaku.twidere.model.message.FriendshipUserUpdatedEvent;
import org.mariotaku.twidere.model.message.ProfileUpdatedEvent;
import org.mariotaku.twidere.model.message.SavedSearchDestroyedEvent;
import org.mariotaku.twidere.model.message.StatusDestroyedEvent;
@ -78,7 +76,6 @@ import org.mariotaku.twidere.model.message.UsersBlockedEvent;
import org.mariotaku.twidere.model.util.ParcelableStatusUtils;
import org.mariotaku.twidere.model.util.ParcelableUserListUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.model.util.UserKeyUtils;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.provider.TwidereDataStore.AccountSupportColumns;
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
@ -90,12 +87,21 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
import org.mariotaku.twidere.service.BackgroundOperationService;
import org.mariotaku.twidere.task.AbstractTask;
import org.mariotaku.twidere.task.AcceptFriendshipTask;
import org.mariotaku.twidere.task.CreateFriendshipTask;
import org.mariotaku.twidere.task.CreateUserBlockTask;
import org.mariotaku.twidere.task.CreateUserMuteTask;
import org.mariotaku.twidere.task.DenyFriendshipTask;
import org.mariotaku.twidere.task.DestroyFriendshipTask;
import org.mariotaku.twidere.task.DestroyUserBlockTask;
import org.mariotaku.twidere.task.DestroyUserMuteTask;
import org.mariotaku.twidere.task.GetActivitiesAboutMeTask;
import org.mariotaku.twidere.task.GetDirectMessagesTask;
import org.mariotaku.twidere.task.GetHomeTimelineTask;
import org.mariotaku.twidere.task.GetLocalTrendsTask;
import org.mariotaku.twidere.task.GetSavedSearchesTask;
import org.mariotaku.twidere.task.ManagedAsyncTask;
import org.mariotaku.twidere.task.ReportSpamAndBlockTask;
import org.mariotaku.twidere.task.twitter.GetActivitiesTask;
import org.mariotaku.twidere.task.util.TaskStarter;
import org.mariotaku.twidere.util.collection.CompactHashSet;
@ -122,7 +128,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
private Set<Pair<UserKey, String>> mDestroyingFavoriteIds = new CompactHashSet<>();
private Set<Pair<UserKey, String>> mCreatingRetweetIds = new CompactHashSet<>();
private Set<Pair<UserKey, String>> mDestroyingStatusIds = new CompactHashSet<>();
private IntList mProcessingFriendshipRequestIds = new ArrayIntList();
private IntList mUpdatingRelationshipIds = new ArrayIntList();
private final LongList mSendingDraftIds = new ArrayLongList();
@ -135,9 +141,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
mAsyncTaskManager = asyncTaskManager;
}
public int acceptFriendshipAsync(final UserKey accountKey, final UserKey userId) {
final AcceptFriendshipTask task = new AcceptFriendshipTask(mContext, accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void acceptFriendshipAsync(final UserKey accountKey, final UserKey userKey) {
final AcceptFriendshipTask task = new AcceptFriendshipTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public void addSendingDraftId(long id) {
@ -174,9 +181,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
AsyncTaskUtils.executeTask(task);
}
public int createBlockAsync(final UserKey accountKey, final String userId) {
final CreateBlockTask task = new CreateBlockTask(accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void createBlockAsync(final UserKey accountKey, final UserKey userKey) {
final CreateUserBlockTask task = new CreateUserBlockTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public int createFavoriteAsync(final UserKey accountKey, final String statusId) {
@ -184,9 +192,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int createFriendshipAsync(final UserKey accountKey, final String userId) {
final CreateFriendshipTask task = new CreateFriendshipTask(accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void createFriendshipAsync(final UserKey accountKey, final UserKey userKey) {
final CreateFriendshipTask task = new CreateFriendshipTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public int createMultiBlockAsync(final UserKey accountKey, final String[] userIds) {
@ -194,9 +203,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int createMuteAsync(final UserKey accountKey, final String userId) {
final CreateMuteTask task = new CreateMuteTask(accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void createMuteAsync(final UserKey accountKey, final UserKey userKey) {
final CreateUserMuteTask task = new CreateUserMuteTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public int createSavedSearchAsync(final UserKey accountKey, final String query) {
@ -221,14 +231,16 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int denyFriendshipAsync(final UserKey accountKey, final UserKey userId) {
final DenyFriendshipTask task = new DenyFriendshipTask(mContext, accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void denyFriendshipAsync(final UserKey accountKey, final UserKey userKey) {
final DenyFriendshipTask task = new DenyFriendshipTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public int destroyBlockAsync(final UserKey accountKey, final String userId) {
final DestroyBlockTask task = new DestroyBlockTask(accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void destroyBlockAsync(final UserKey accountKey, final UserKey userKey) {
final DestroyUserBlockTask task = new DestroyUserBlockTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public int destroyDirectMessageAsync(final UserKey accountKey, final String messageId) {
@ -246,14 +258,16 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int destroyFriendshipAsync(final UserKey accountKey, final String userId) {
final DestroyFriendshipTask task = new DestroyFriendshipTask(accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void destroyFriendshipAsync(final UserKey accountKey, final UserKey userKey) {
final DestroyFriendshipTask task = new DestroyFriendshipTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public int destroyMuteAsync(final UserKey accountKey, final String userId) {
final DestroyMuteTask task = new DestroyMuteTask(accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void destroyMuteAsync(final UserKey accountKey, final UserKey userKey) {
final DestroyUserMuteTask task = new DestroyUserMuteTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public int destroySavedSearchAsync(final UserKey accountKey, final long searchId) {
@ -320,11 +334,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mCreatingFavoriteIds.contains(Pair.create(accountId, statusId));
}
public boolean isCreatingFriendship(final UserKey accountKey, final String userId) {
// TODO implementation
return false;
}
public boolean isCreatingRetweet(final UserKey accountKey, final String statusId) {
return mCreatingRetweetIds.contains(Pair.create(accountKey, statusId));
}
@ -333,19 +342,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mDestroyingFavoriteIds.contains(Pair.create(accountKey, statusId));
}
public boolean isDestroyingFriendship(final UserKey accountKey, final String userId) {
for (final ManagedAsyncTask<?, ?, ?> task : mAsyncTaskManager.getTaskSpecList()) {
if (task instanceof DestroyFriendshipTask) {
final DestroyFriendshipTask destroyFriendshipTask = (DestroyFriendshipTask) task;
if (destroyFriendshipTask.getStatus() == AsyncTask.Status.RUNNING
&& destroyFriendshipTask.getAccountKey().equals(accountKey)
&& destroyFriendshipTask.getUserId().equals(userId))
return true;
}
}
return false;
}
public boolean isDestroyingStatus(final UserKey accountId, final String statusId) {
return mDestroyingStatusIds.contains(Pair.create(accountId, statusId));
}
@ -449,9 +445,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
// TODO implementation
}
public int reportSpamAsync(final UserKey accountKey, final String userId) {
final ReportSpamTask task = new ReportSpamTask(accountKey, userId);
return mAsyncTaskManager.add(task, true);
public void reportSpamAsync(final UserKey accountKey, final UserKey userKey) {
final ReportSpamAndBlockTask task = new ReportSpamAndBlockTask(mContext);
task.setup(accountKey, userKey);
TaskStarter.execute(task);
}
public int retweetStatusAsync(final UserKey accountKey, final String statusId) {
@ -500,7 +497,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
@Override
public void afterExecute(Bus handler, SingleResponse<Relationship> result) {
public void afterExecute(Bus handler, Object params, SingleResponse<Relationship> result) {
if (result.hasData()) {
handler.post(new FriendshipUpdatedEvent(accountKey, userId, result.getData()));
} else if (result.hasException()) {
@ -540,67 +537,16 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
TaskStarter.execute(task);
}
private void addProcessingFriendshipRequestId(UserKey accountKey, UserKey userId) {
mProcessingFriendshipRequestIds.add(ParcelableUser.calculateHashCode(accountKey, userId));
public void addUpdatingRelationshipId(UserKey accountKey, UserKey userId) {
mUpdatingRelationshipIds.add(ParcelableUser.calculateHashCode(accountKey, userId));
}
private void removeProcessingFriendshipRequestId(UserKey accountKey, UserKey userId) {
mProcessingFriendshipRequestIds.removeElement(ParcelableUser.calculateHashCode(accountKey, userId));
public void removeUpdatingRelationshipId(UserKey accountKey, UserKey userId) {
mUpdatingRelationshipIds.removeElement(ParcelableUser.calculateHashCode(accountKey, userId));
}
public boolean isProcessingFollowRequest(UserKey accountId, UserKey userId) {
return mProcessingFriendshipRequestIds.contains(ParcelableUser.calculateHashCode(accountId, userId));
}
public static class UpdateProfileBannerImageTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
private final UserKey mAccountKey;
private final Uri mImageUri;
private final boolean mDeleteImage;
private final Context mContext;
public UpdateProfileBannerImageTask(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean deleteImage) {
super(context);
mContext = context;
mAccountKey = accountKey;
mImageUri = imageUri;
mDeleteImage = deleteImage;
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
if (result.hasData()) {
Utils.showOkMessage(mContext, R.string.profile_banner_image_updated, false);
bus.post(new ProfileUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_updating_profile_banner_image, result.getException(),
true);
}
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
try {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey,
true);
TwitterWrapper.updateProfileBannerImage(mContext, twitter, mImageUri, mDeleteImage);
// Wait for 5 seconds, see
// https://dev.twitter.com/docs/api/1.1/post/account/update_profile_image
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
Log.w(LOGTAG, e);
}
final User user = TwitterWrapper.tryShowUser(twitter, mAccountKey.getId(), null);
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey));
} catch (TwitterException | FileNotFoundException e) {
return SingleResponse.getInstance(e);
}
}
public boolean isUpdatingRelationship(UserKey accountId, UserKey userId) {
return mUpdatingRelationshipIds.contains(ParcelableUser.calculateHashCode(accountId, userId));
}
public static class UpdateProfileImageTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
@ -651,73 +597,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
static class AcceptFriendshipTask extends ManagedAsyncTask<Object, Object, SingleResponse<User>> {
private final UserKey mAccountKey;
private final UserKey mUserId;
public AcceptFriendshipTask(final Context context, final UserKey accountKey, final UserKey userId) {
super(context);
mAccountKey = accountKey;
mUserId = userId;
}
public UserKey getAccountKey() {
return mAccountKey;
}
public UserKey getUserId() {
return mUserId;
}
@Override
protected void onPreExecute() {
final FollowRequestTaskEvent event = new FollowRequestTaskEvent(FollowRequestTaskEvent.Action.ACCEPT,
mAccountKey, mUserId.getId());
event.setFinished(false);
bus.post(event);
mAsyncTwitterWrapper.addProcessingFriendshipRequestId(mAccountKey, mUserId);
super.onPreExecute();
}
@Override
protected SingleResponse<User> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(getContext(), mAccountKey, false);
if (twitter == null) return SingleResponse.getInstance();
try {
final User user = twitter.acceptFriendship(mUserId.getId());
return SingleResponse.getInstance(user, null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
@Override
protected void onPostExecute(final SingleResponse<User> result) {
final FollowRequestTaskEvent event = new FollowRequestTaskEvent(FollowRequestTaskEvent.Action.ACCEPT,
mAccountKey, mUserId.getId());
event.setFinished(true);
if (result.hasData()) {
final User user = result.getData();
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = getContext().getString(R.string.accepted_users_follow_request,
mUserColorNameManager.getDisplayName(user, nameFirst, true));
Utils.showOkMessage(getContext(), message, false);
event.setSucceeded(true);
} else {
Utils.showErrorMessage(getContext(), R.string.action_accepting_follow_request,
result.getException(), false);
event.setSucceeded(false);
}
mAsyncTwitterWrapper.removeProcessingFriendshipRequestId(mAccountKey, mUserId);
bus.post(event);
super.onPostExecute(result);
}
}
class AddUserListMembersTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUserList>> {
private final UserKey mAccountKey;
@ -807,64 +686,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
class CreateBlockTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
@NonNull
private final UserKey mAccountKey;
private final String mUserId;
public CreateBlockTask(@NonNull final UserKey accountKey, final String userId) {
super(mContext);
this.mAccountKey = accountKey;
this.mUserId = userId;
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter == null) return SingleResponse.getInstance();
try {
final User user = twitter.createBlock(mUserId);
Utils.setLastSeen(mContext, UserKeyUtils.fromUser(user), -1);
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
final Expression where = Expression.and(
Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY),
Expression.equalsArgs(Statuses.USER_ID)
);
final String[] whereArgs = {mAccountKey.toString(), String.valueOf(mUserId)};
mResolver.delete(uri, where.getSQL(), whereArgs);
}
// I bet you don't want to see this user in your auto complete list.
final ContentValues values = new ContentValues();
values.put(CachedRelationships.ACCOUNT_KEY, mAccountKey.toString());
values.put(CachedRelationships.USER_ID, mUserId);
values.put(CachedRelationships.BLOCKING, true);
mResolver.insert(CachedRelationships.CONTENT_URI, values);
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey), null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
if (result.hasData()) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.blocked_user,
mUserColorNameManager.getDisplayName(result.getData(), nameFirst, true));
Utils.showInfoMessage(mContext, message, false);
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_blocking, result.getException(), true);
}
super.onPostExecute(result);
}
}
class CreateFavoriteTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableStatus>> {
private final UserKey mAccountKey;
@ -881,14 +702,14 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, true);
if (twitter == null) return SingleResponse.getInstance();
try {
final ParcelableStatus status = ParcelableStatusUtils.fromStatus(twitter.createFavorite(mStatusId),
final ParcelableStatus result = ParcelableStatusUtils.fromStatus(twitter.createFavorite(mStatusId),
mAccountKey, false);
Utils.setLastSeen(mContext, status.mentions, System.currentTimeMillis());
Utils.setLastSeen(mContext, result.mentions, System.currentTimeMillis());
final ContentValues values = new ContentValues();
values.put(Statuses.IS_FAVORITE, true);
values.put(Statuses.REPLY_COUNT, status.reply_count);
values.put(Statuses.RETWEET_COUNT, status.retweet_count);
values.put(Statuses.FAVORITE_COUNT, status.favorite_count);
values.put(Statuses.REPLY_COUNT, result.reply_count);
values.put(Statuses.RETWEET_COUNT, result.retweet_count);
values.put(Statuses.FAVORITE_COUNT, result.favorite_count);
final Expression where = Expression.and(
Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY),
Expression.or(
@ -901,7 +722,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
mResolver.update(uri, values, where.getSQL(), whereArgs);
}
return SingleResponse.getInstance(status);
return SingleResponse.getInstance(result);
} catch (final TwitterException e) {
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, e);
@ -943,64 +764,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
class CreateFriendshipTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
private final UserKey mAccountKey;
private final String mUserId;
public CreateFriendshipTask(final UserKey accountKey, final String userId) {
super(mContext);
this.mAccountKey = accountKey;
this.mUserId = userId;
}
public UserKey getAccountKey() {
return mAccountKey;
}
public String getUserId() {
return mUserId;
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter == null) return SingleResponse.getInstance();
try {
final User user = twitter.createFriendship(mUserId);
Utils.setLastSeen(mContext, UserKeyUtils.fromUser(user), System.currentTimeMillis());
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey), null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
if (result.hasData()) {
final ParcelableUser user = result.getData();
final String message;
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
if (user.is_protected) {
message = mContext.getString(R.string.sent_follow_request_to_user,
mUserColorNameManager.getDisplayName(user, nameFirst, true));
} else {
message = mContext.getString(R.string.followed_user,
mUserColorNameManager.getDisplayName(user, nameFirst, true));
}
Utils.showOkMessage(mContext, message, false);
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_following, result.getException(), false);
}
super.onPostExecute(result);
}
}
class CreateMultiBlockTask extends ManagedAsyncTask<Object, Object, ListResponse<String>> {
private final UserKey mAccountKey;
@ -1062,53 +825,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
class CreateMuteTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
private final UserKey mAccountKey;
private final String mUserId;
public CreateMuteTask(final UserKey accountKey, final String userId) {
super(mContext);
this.mAccountKey = accountKey;
this.mUserId = userId;
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter == null) return SingleResponse.getInstance();
try {
final User user = twitter.createMute(mUserId);
Utils.setLastSeen(mContext, UserKeyUtils.fromUser(user), -1);
final Expression where = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY),
Expression.equalsArgs(Statuses.USER_ID));
final String[] whereArgs = {mAccountKey.toString(), mUserId};
mResolver.delete(Statuses.CONTENT_URI, where.getSQL(), whereArgs);
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey), null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
if (result.hasData()) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.muted_user,
mUserColorNameManager.getDisplayName(result.getData(), nameFirst, true));
Utils.showInfoMessage(mContext, message, false);
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_muting, result.getException(), true);
}
super.onPostExecute(result);
}
}
class CreateSavedSearchTask extends ManagedAsyncTask<Object, Object, SingleResponse<SavedSearch>> {
private final UserKey mAccountKey;
@ -1300,106 +1016,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
class DenyFriendshipTask extends ManagedAsyncTask<Object, Object, SingleResponse<User>> {
private final UserKey mAccountKey;
private final UserKey mUserId;
public DenyFriendshipTask(final Context context, final UserKey accountKey, final UserKey userId) {
super(context);
mAccountKey = accountKey;
mUserId = userId;
}
@Override
protected SingleResponse<User> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(getContext(), mAccountKey,
false);
if (twitter == null) return SingleResponse.getInstance();
try {
final User user = twitter.denyFriendship(mUserId.getId());
return SingleResponse.getInstance(user, null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
@Override
protected void onPreExecute() {
addProcessingFriendshipRequestId(mAccountKey, mUserId);
final FollowRequestTaskEvent event = new FollowRequestTaskEvent(FollowRequestTaskEvent.Action.ACCEPT,
mAccountKey, mUserId.getId());
event.setFinished(false);
bus.post(event);
super.onPreExecute();
}
@Override
protected void onPostExecute(final SingleResponse<User> result) {
final FollowRequestTaskEvent event = new FollowRequestTaskEvent(FollowRequestTaskEvent.Action.ACCEPT,
mAccountKey, mUserId.getId());
event.setFinished(true);
if (result.hasData()) {
final User user = result.getData();
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.denied_users_follow_request,
mUserColorNameManager.getDisplayName(user, nameFirst, true));
Utils.showOkMessage(mContext, message, false);
event.setSucceeded(true);
} else {
Utils.showErrorMessage(mContext, R.string.action_denying_follow_request, result.getException(), false);
event.setSucceeded(false);
}
super.onPostExecute(result);
removeProcessingFriendshipRequestId(mAccountKey, mUserId);
bus.post(event);
}
}
class DestroyBlockTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
private final UserKey mAccountKey;
private final String mUserId;
public DestroyBlockTask(final UserKey accountKey, final String userId) {
super(mContext);
mAccountKey = accountKey;
mUserId = userId;
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter == null) return SingleResponse.getInstance();
try {
final User user = twitter.destroyBlock(mUserId);
Utils.setLastSeen(mContext, UserKeyUtils.fromUser(user), -1);
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey), null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
if (result.hasData()) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.unblocked_user,
mUserColorNameManager.getDisplayName(result.getData(), nameFirst, true));
Utils.showInfoMessage(mContext, message, false);
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_unblocking, result.getException(), true);
}
super.onPostExecute(result);
}
}
class DestroyDirectMessageTask extends ManagedAsyncTask<Object, Object, SingleResponse<DirectMessage>> {
@ -1593,111 +1209,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
class DestroyFriendshipTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
private final UserKey mAccountKey;
private final String mUserId;
public DestroyFriendshipTask(final UserKey accountKey, final String userId) {
super(mContext);
mAccountKey = accountKey;
mUserId = userId;
}
public UserKey getAccountKey() {
return mAccountKey;
}
public String getUserId() {
return mUserId;
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter != null) {
try {
final User user = twitter.destroyFriendship(mUserId);
// remove user tweets and retweets
Utils.setLastSeen(mContext, UserKeyUtils.fromUser(user), -1);
final Expression where = Expression.and(
Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY),
Expression.or(
Expression.equalsArgs(Statuses.USER_ID),
Expression.equalsArgs(Statuses.RETWEETED_BY_USER_ID)
)
);
final String[] whereArgs = {mAccountKey.toString(), String.valueOf(mUserId),
String.valueOf(mUserId)};
mResolver.delete(Statuses.CONTENT_URI, where.getSQL(), whereArgs);
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey), null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
return SingleResponse.getInstance();
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
if (result.hasData()) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.unfollowed_user,
mUserColorNameManager.getDisplayName(result.getData(), nameFirst, true));
Utils.showInfoMessage(mContext, message, false);
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_unfollowing, result.getException(), true);
}
super.onPostExecute(result);
}
}
class DestroyMuteTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
private final UserKey mAccountKey;
private final String mUserId;
public DestroyMuteTask(final UserKey accountKey, final String userId) {
super(mContext);
mAccountKey = accountKey;
mUserId = userId;
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter == null) return SingleResponse.getInstance();
try {
final User user = twitter.destroyMute(mUserId);
Utils.setLastSeen(mContext, UserKeyUtils.fromUser(user), -1);
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey), null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
if (result.hasData()) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.unmuted_user,
mUserColorNameManager.getDisplayName(result.getData(), nameFirst, true));
Utils.showInfoMessage(mContext, message, false);
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_unmuting, result.getException(), true);
}
super.onPostExecute(result);
}
}
class DestroySavedSearchTask extends ManagedAsyncTask<Object, Object, SingleResponse<SavedSearch>> {
private final UserKey mAccountKey;
@ -1904,10 +1415,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
@Override
public void beforeExecute() {
public void beforeExecute(RefreshTaskParam params) {
final Intent intent = new Intent(BROADCAST_RESCHEDULE_DIRECT_MESSAGES_REFRESHING);
context.sendBroadcast(intent);
super.beforeExecute();
super.beforeExecute(params);
}
}
@ -1955,47 +1466,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
class ReportSpamTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
private final UserKey mAccountKey;
private final String mUserId;
public ReportSpamTask(final UserKey accountKey, final String userId) {
super(mContext);
this.mAccountKey = accountKey;
this.mUserId = userId;
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter != null) {
try {
final User user = twitter.reportSpam(mUserId);
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey), null);
} catch (final TwitterException e) {
return SingleResponse.getInstance(null, e);
}
}
return SingleResponse.getInstance();
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
if (result.hasData()) {
// TODO delete cached status
Utils.showInfoMessage(mContext, R.string.reported_user_for_spam, false);
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_reporting_for_spam, result.getException(), true);
}
super.onPostExecute(result);
}
}
class RetweetStatusTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableStatus>> {
private final UserKey mAccountKey;

View File

@ -463,28 +463,28 @@ public class DataStoreUtils implements Constants {
}
}
public static int getStatusesCount(final Context context, final Uri uri, final long sinceId,
UserKey... accountKeys) {
public static int getStatusesCount(final Context context, final Uri uri, final long since,
String sinceColumn, UserKey... accountKeys) {
if (context == null) return 0;
if (accountKeys == null) {
accountKeys = getActivatedAccountKeys(context);
}
final Expression selection = Expression.and(
Expression.inArgs(new Column(Statuses.ACCOUNT_KEY), accountKeys.length),
Expression.greaterThanArgs(Statuses.STATUS_ID),
Expression.greaterThanArgs(sinceColumn),
buildStatusFilterWhereClause(getTableNameByUri(uri), null)
);
final String[] whereArgs = new String[accountKeys.length + 1];
for (int i = 0; i < accountKeys.length; i++) {
whereArgs[i] = accountKeys[i].toString();
}
whereArgs[accountKeys.length] = String.valueOf(sinceId);
whereArgs[accountKeys.length] = String.valueOf(since);
return queryCount(context, uri, selection.getSQL(), whereArgs);
}
public static int getActivitiesCount(@NonNull final Context context, final Uri uri,
final Expression extraWhere, final String[] extraWhereArgs,
final long sinceTimestamp, boolean followingOnly,
final long since, String sinceColumn, boolean followingOnly,
@Nullable UserKey[] accountKeys) {
if (accountKeys == null) {
accountKeys = getActivatedAccountKeys(context);
@ -497,7 +497,7 @@ public class DataStoreUtils implements Constants {
expressions = new Expression[3];
}
expressions[0] = Expression.inArgs(new Column(Activities.ACCOUNT_KEY), accountKeys.length);
expressions[1] = Expression.greaterThanArgs(Activities.TIMESTAMP);
expressions[1] = Expression.greaterThanArgs(sinceColumn);
expressions[2] = buildActivityFilterWhereClause(getTableNameByUri(uri), null);
final Expression selection = Expression.and(expressions);
String[] selectionArgs;
@ -511,7 +511,7 @@ public class DataStoreUtils implements Constants {
for (int i = 0; i < accountKeys.length; i++) {
selectionArgs[i] = accountKeys[i].toString();
}
selectionArgs[accountKeys.length] = String.valueOf(sinceTimestamp);
selectionArgs[accountKeys.length] = String.valueOf(since);
// If followingOnly option is on, we have to iterate over items
if (followingOnly) {
final ContentResolver resolver = context.getContentResolver();
@ -1069,7 +1069,7 @@ public class DataStoreUtils implements Constants {
}
public static int getInteractionsCount(@NonNull final Context context, @Nullable final Bundle extraArgs,
final UserKey[] accountIds, final long position) {
final UserKey[] accountIds, final long since,final String sinceColumn) {
Expression extraWhere = null;
String[] extraWhereArgs = null;
boolean followingOnly = false;
@ -1088,7 +1088,7 @@ public class DataStoreUtils implements Constants {
}
}
return getActivitiesCount(context, Activities.AboutMe.CONTENT_URI, extraWhere, extraWhereArgs,
position, followingOnly, accountIds);
since, sinceColumn, followingOnly, accountIds);
}
}

View File

@ -130,6 +130,12 @@ public class MediaLoaderWrapper implements Constants {
mImageLoader.displayImage(url, view, mBannerDisplayOptions, listener);
}
public void displayProfileBanner(final ImageView view, final String url, final int width,
final ImageLoadingListener listener) {
mImageLoader.displayImage(getBestBannerUrl(url, width), view, mBannerDisplayOptions,
listener);
}
public void displayProfileBanner(final ImageView view, final String url) {
displayProfileBanner(view, url, null);
}

View File

@ -2,6 +2,7 @@ package org.mariotaku.twidere.util;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.lang.reflect.Field;
@ -11,9 +12,7 @@ import java.lang.reflect.Field;
*/
public class ParcelUtils {
@Nullable
public static <T extends Parcelable> T clone(@Nullable T object) {
if (object == null) return null;
public static <T extends Parcelable> T clone(@NonNull T object) {
final Parcel parcel = Parcel.obtain();
try {
object.writeToParcel(parcel, 0);

View File

@ -314,6 +314,16 @@ public class ThemeUtils implements Constants {
return colors[0];
}
public static int getContrastColor(int color, int darkColor, int lightColor) {
if (TwidereColorUtils.getYIQLuminance(color) <= ACCENT_COLOR_THRESHOLD) {
//return light text color
return lightColor;
}
//return dark text color
return darkColor;
}
public static int getContrastActionBarItemColor(Context context) {
return getColorFromAttribute(context, android.R.attr.colorForeground, 0);
}

View File

@ -50,6 +50,7 @@ import org.mariotaku.twidere.provider.CacheProvider;
import org.mariotaku.twidere.provider.TwidereDataProvider;
import org.mariotaku.twidere.service.BackgroundOperationService;
import org.mariotaku.twidere.service.RefreshService;
import org.mariotaku.twidere.task.AbsFriendshipOperationTask;
import org.mariotaku.twidere.task.GetDirectMessagesTask;
import org.mariotaku.twidere.task.ManagedAsyncTask;
import org.mariotaku.twidere.task.twitter.GetActivitiesTask;
@ -144,4 +145,6 @@ public interface GeneralComponent {
void inject(GetActivitiesTask task);
void inject(GetDirectMessagesTask task);
void inject(AbsFriendshipOperationTask task);
}

View File

@ -1,17 +1,21 @@
package org.mariotaku.twidere.view;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.annotation.ColorInt;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.AppCompatImageButton;
import android.util.AttributeSet;
import android.widget.ImageButton;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.ThemeUtils;
/**
* Created by mariotaku on 14/11/5.
*/
public class ActionIconButton extends ImageButton {
public class ActionIconButton extends AppCompatImageButton {
@ColorInt
private int mDefaultColor, mActivatedColor, mDisabledColor;
@ -37,6 +41,14 @@ public class ActionIconButton extends ImageButton {
@ColorInt
public int getDefaultColor() {
if (mDefaultColor == 0) {
// Return inverse color for background tint
ColorStateList color = ViewCompat.getBackgroundTintList(this);
if (color != null) {
final int currentColor = color.getColorForState(getDrawableState(), 0);
return ThemeUtils.getContrastColor(currentColor, Color.BLACK, Color.WHITE);
}
}
return mDefaultColor;
}

View File

@ -30,6 +30,7 @@ import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter.FollowClickListener;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter.RequestClickListener;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter.UserAdapterListener;
import org.mariotaku.twidere.model.ParcelableUser;
@ -57,12 +58,14 @@ public class UserViewHolder extends ViewHolder implements OnClickListener, OnLon
private final TextView descriptionView, locationView, urlView,
statusesCountView, followersCountView, friendsCountView;
private final View acceptRequestButton, denyRequestButton;
private final View followRequestContainer;
private final View acceptRequestButton, denyRequestButton, followButton;
private final View actionsProgressContainer;
private final View actionsContainer;
private final View processingRequestProgress;
private UserAdapterListener userClickListener;
private RequestClickListener requestClickListener;
private FollowClickListener followClickListener;
public UserViewHolder(final IUsersAdapter<?> adapter, final View itemView) {
super(itemView);
@ -78,9 +81,11 @@ public class UserViewHolder extends ViewHolder implements OnClickListener, OnLon
statusesCountView = (TextView) itemView.findViewById(R.id.statuses_count);
followersCountView = (TextView) itemView.findViewById(R.id.followers_count);
friendsCountView = (TextView) itemView.findViewById(R.id.friends_count);
followRequestContainer = itemView.findViewById(R.id.actions_container);
actionsProgressContainer = itemView.findViewById(R.id.actions_progress_container);
actionsContainer = itemView.findViewById(R.id.actions_container);
acceptRequestButton = itemView.findViewById(R.id.accept_request);
denyRequestButton = itemView.findViewById(R.id.deny_request);
followButton = itemView.findViewById(R.id.follow);
processingRequestProgress = itemView.findViewById(R.id.processing_request);
}
@ -121,14 +126,12 @@ public class UserViewHolder extends ViewHolder implements OnClickListener, OnLon
loader.cancelDisplayTask(profileImageView);
}
if (twitter.isProcessingFollowRequest(user.account_key, user.key)) {
if (twitter.isUpdatingRelationship(user.account_key, user.key)) {
processingRequestProgress.setVisibility(View.VISIBLE);
acceptRequestButton.setVisibility(View.GONE);
denyRequestButton.setVisibility(View.GONE);
actionsContainer.setVisibility(View.GONE);
} else {
processingRequestProgress.setVisibility(View.GONE);
acceptRequestButton.setVisibility(View.VISIBLE);
denyRequestButton.setVisibility(View.VISIBLE);
actionsContainer.setVisibility(View.VISIBLE);
}
if (UserKeyUtils.isSameHost(user.account_key, user.key)) {
externalIndicator.setVisibility(View.GONE);
@ -137,6 +140,23 @@ public class UserViewHolder extends ViewHolder implements OnClickListener, OnLon
externalIndicator.setText(context.getString(R.string.external_user_host_format, user
.key.getHost()));
}
followButton.setActivated(user.is_following);
final boolean isMySelf = user.account_key.equals(user.key);
if (requestClickListener != null && !isMySelf) {
acceptRequestButton.setVisibility(View.VISIBLE);
denyRequestButton.setVisibility(View.VISIBLE);
} else {
acceptRequestButton.setVisibility(View.GONE);
denyRequestButton.setVisibility(View.GONE);
}
if (followClickListener != null && !isMySelf) {
followButton.setVisibility(View.VISIBLE);
} else {
followButton.setVisibility(View.GONE);
}
}
public ImageView getProfileImageView() {
@ -165,6 +185,11 @@ public class UserViewHolder extends ViewHolder implements OnClickListener, OnLon
requestClickListener.onDenyClicked(this, getLayoutPosition());
break;
}
case R.id.follow: {
if (followClickListener == null) return;
followClickListener.onFollowClicked(this, getLayoutPosition());
break;
}
}
}
@ -181,21 +206,24 @@ public class UserViewHolder extends ViewHolder implements OnClickListener, OnLon
public void setOnClickListeners() {
setUserClickListener(adapter.getUserAdapterListener());
setRequestClickListener(adapter.getRequestClickListener());
setActionClickListeners(adapter.getRequestClickListener(), adapter.getFollowClickListener());
}
private void setRequestClickListener(RequestClickListener listener) {
requestClickListener = listener;
if (listener != null) {
private void setActionClickListeners(RequestClickListener requestClickListener,
FollowClickListener followClickListener) {
this.requestClickListener = requestClickListener;
this.followClickListener = followClickListener;
if (requestClickListener != null || followClickListener != null) {
nameView.setTwoLine(true);
followRequestContainer.setVisibility(View.VISIBLE);
actionsProgressContainer.setVisibility(View.VISIBLE);
} else {
nameView.setTwoLine(false);
followRequestContainer.setVisibility(View.GONE);
actionsProgressContainer.setVisibility(View.GONE);
}
nameView.updateText();
acceptRequestButton.setOnClickListener(this);
denyRequestButton.setOnClickListener(this);
followButton.setOnClickListener(this);
}
public void setTextSize(final float textSize) {

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/material_light_blue" android:state_activated="true"/>
<item android:color="@android:color/white"/>
</selector>

View File

@ -34,14 +34,14 @@
android:id="@+id/profile_image_container"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"
android:layout_alignBottom="@+id/actions_container"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignTop="@+id/actions_container"
android:layout_alignTop="@+id/actions_progress_container"
android:layout_marginEnd="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:clipChildren="false">
android:clipChildren="false"
tools:visibility="visible">
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
@ -73,56 +73,78 @@
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/actions_container"
android:layout_alignTop="@+id/actions_container"
android:layout_alignBottom="@+id/actions_progress_container"
android:layout_alignTop="@+id/actions_progress_container"
android:layout_toEndOf="@id/profile_image_container"
android:layout_toLeftOf="@+id/actions_container"
android:layout_toLeftOf="@+id/actions_progress_container"
android:layout_toRightOf="@id/profile_image_container"
android:layout_toStartOf="@+id/actions_container"
android:layout_toStartOf="@+id/actions_progress_container"
android:gravity="center_vertical"
app:nv_primaryTextColor="?android:textColorPrimary"
app:nv_primaryTextStyle="bold"
app:nv_secondaryTextColor="?android:textColorSecondary"
app:nv_twoLine="true"/>
<LinearLayout
android:id="@+id/actions_container"
<FrameLayout
android:id="@+id/actions_progress_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:clipChildren="false"
android:gravity="center"
android:minHeight="@dimen/element_size_normal"
android:minWidth="@dimen/element_size_normal"
android:orientation="horizontal"
tools:visibility="gone">
android:minHeight="@dimen/button_size_content_card"
android:minWidth="@dimen/button_size_content_card">
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/accept_request"
style="?buttonStyleSmall"
<LinearLayout
android:id="@+id/actions_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/accept"
android:src="@drawable/ic_action_confirm"
app:backgroundTint="@color/material_light_green"/>
android:layout_gravity="center"
android:clipChildren="false"
android:orientation="horizontal"
tools:visibility="visible">
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/deny_request"
style="?buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/deny"
android:src="@drawable/ic_action_cancel"
app:backgroundTint="@color/material_red"/>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/follow"
style="?buttonStyleSmall"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:contentDescription="@string/follow"
android:src="@drawable/ic_action_add"
app:backgroundTint="@color/color_stateful_follow"
app:iabColor="@android:color/transparent"/>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/accept_request"
style="?buttonStyleSmall"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:contentDescription="@string/accept"
android:src="@drawable/ic_action_confirm"
app:backgroundTint="@color/material_light_green"
app:iabColor="@android:color/transparent"/>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/deny_request"
style="?buttonStyleSmall"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:contentDescription="@string/deny"
android:src="@drawable/ic_action_cancel"
app:backgroundTint="@color/material_red"
app:iabColor="@android:color/transparent"/>
</LinearLayout>
<ProgressBar
android:id="@+id/processing_request"
style="?android:progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</LinearLayout>
</FrameLayout>
<org.mariotaku.twidere.view.ActionIconThemedTextView
android:id="@+id/external_indicator"