fixed fallback intent

This commit is contained in:
Mariotaku Lee 2016-04-01 22:15:53 +08:00
parent 16201b8142
commit 78bc7e6d55
31 changed files with 457 additions and 526 deletions

View File

@ -41,7 +41,7 @@ dependencies {
apt 'com.github.mariotaku.ObjectCursor:processor:0.9.7'
compile 'com.android.support:support-annotations:23.2.1'
compile 'com.bluelinelabs:logansquare:1.3.7'
compile 'com.github.mariotaku.RestFu:library:0.9.25'
compile 'com.github.mariotaku.RestFu:library:0.9.26-SNAPSHOT'
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.2'
compile 'com.github.mariotaku.ObjectCursor:core:0.9.7'
compile fileTree(dir: 'libs', include: ['*.jar'])

View File

@ -98,7 +98,6 @@ public interface UsersResources {
ResponseList<User> lookupUsersByScreenName(@Param(value = "screen_name", arrayDelimiter = ',') String[] screenNames) throws TwitterException;
@POST("/account/remove_profile_banner.json")
@BodyType(BodyType.FORM)
ResponseCode removeProfileBannerImage() throws TwitterException;
@GET("/users/search.json")
@ -111,34 +110,27 @@ public interface UsersResources {
User showUserByScreenName(@Query("screen_name") String screenName) throws TwitterException;
@POST("/account/settings.json")
@BodyType(BodyType.FORM)
AccountSettings updateAccountSettings(@Param SettingsUpdate settingsUpdate) throws TwitterException;
@POST("/account/update_profile.json")
@BodyType(BodyType.FORM)
User updateProfile(@Param ProfileUpdate profileUpdate) throws TwitterException;
@POST("/account/update_profile_background_image.json")
@BodyType(BodyType.MULTIPART)
User updateProfileBackgroundImage(@Param("image") FileBody data, @Param("tile") boolean tile) throws TwitterException;
@POST("/account/update_profile_background_image.json")
@BodyType(BodyType.FORM)
User updateProfileBackgroundImage(@Param("media_id") long mediaId, @Param("tile") boolean tile) throws TwitterException;
@POST("/account/update_profile_banner.json")
@BodyType(BodyType.MULTIPART)
ResponseCode updateProfileBannerImage(@Param("banner") FileBody data, @Param("width") int width,
@Param("height") int height, @Param("offset_left") int offsetLeft,
@Param("offset_top") int offsetTop)
throws TwitterException;
@POST("/account/update_profile_banner.json")
@BodyType(BodyType.MULTIPART)
ResponseCode updateProfileBannerImage(@Param("banner") FileBody data) throws TwitterException;
@POST("/account/update_profile_image.json")
@BodyType(BodyType.MULTIPART)
User updateProfileImage(@Param("image") FileBody data) throws TwitterException;
@GET("/account/verify_credentials.json")

View File

@ -68,7 +68,6 @@ public interface IntentConstants {
String INTENT_ACTION_SEND_DIRECT_MESSAGE = INTENT_PACKAGE_PREFIX + "SEND_DIRECT_MESSAGE";
String INTENT_ACTION_DISCARD_DRAFT = INTENT_PACKAGE_PREFIX + "DISCARD_DRAFT";
String INTENT_ACTION_SEND_DRAFT = INTENT_PACKAGE_PREFIX + "SEND_DRAFT";
String INTENT_ACTION_PICK_ACTIVITY = "org.mariotaku.twidere.PICK_ACTIVITY";
String INTENT_ACTION_PEBBLE_NOTIFICATION = "com.getpebble.action.SEND_NOTIFICATION";

View File

@ -139,8 +139,8 @@ dependencies {
compile 'com.bluelinelabs:logansquare:1.3.7'
compile 'com.soundcloud.android:android-crop:1.0.1@aar'
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.2'
compile 'com.github.mariotaku:PickNCrop:0.9.3'
compile 'com.github.mariotaku.RestFu:okhttp3:0.9.25'
compile 'com.github.mariotaku:PickNCrop:0.9.4-SNAPSHOT'
compile 'com.github.mariotaku.RestFu:okhttp3:0.9.26-SNAPSHOT'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.lnikkila:extendedtouchview:0.1.0'
compile 'com.google.dagger:dagger:2.1'
@ -150,7 +150,7 @@ dependencies {
compile 'com.github.mariotaku.SQLiteQB:library:0.9.6'
compile 'com.github.mariotaku.ObjectCursor:core:0.9.7'
compile 'com.github.mariotaku:MultiValueSwitch:0.9.4'
compile 'com.github.mariotaku:AbstractTask:0.9'
compile 'com.github.mariotaku:AbstractTask:0.9.1'
}
task svgToDrawable(type: SvgDrawableTask) {

View File

@ -387,15 +387,6 @@
android:name=".activity.DataImportActivity"
android:label="@string/import_settings"
android:theme="@style/Theme.Twidere.NoDisplay"/>
<activity
android:name=".activity.ActivityPickerActivity"
android:theme="@style/Theme.Twidere.Dialog">
<intent-filter>
<action android:name="org.mariotaku.twidere.PICK_ACTIVITY"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".activity.TwitterLinkHandlerActivity"
android:excludeFromRecents="true"

View File

@ -1,73 +0,0 @@
package org.mariotaku.twidere.activity;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.ResolveInfoListAdapter;
import org.mariotaku.twidere.loader.IntentActivitiesLoader;
import java.util.List;
public class ActivityPickerActivity extends BaseActivity implements
LoaderCallbacks<List<ResolveInfo>>, OnItemClickListener {
private ResolveInfoListAdapter mAdapter;
private ListView mListView;
@Override
public void onContentChanged() {
super.onContentChanged();
mListView = (ListView) findViewById(android.R.id.list);
}
@Override
public Loader<List<ResolveInfo>> onCreateLoader(final int id, final Bundle args) {
final Intent intent = getIntent();
final Intent extraIntent = intent.getParcelableExtra(EXTRA_INTENT);
final String[] blacklist = intent.getStringArrayExtra(EXTRA_BLACKLIST);
return new IntentActivitiesLoader(this, extraIntent, blacklist, 0);
}
@Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
final Intent intent = getIntent(), data = new Intent();
data.putExtra(EXTRA_DATA, mAdapter.getItem(position));
data.putExtra(EXTRA_INTENT, intent.getParcelableExtra(EXTRA_INTENT));
setResult(RESULT_OK, data);
finish();
}
@Override
public void onLoaderReset(final Loader<List<ResolveInfo>> loader) {
mAdapter.clear();
}
@Override
public void onLoadFinished(final Loader<List<ResolveInfo>> loader, final List<ResolveInfo> data) {
mAdapter.clear();
if (data != null) {
mAdapter.addAll(data);
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity_picker);
mAdapter = new ResolveInfoListAdapter(this);
mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(this);
getSupportLoaderManager().initLoader(0, null, this);
}
}

View File

@ -1914,7 +1914,8 @@ public class ComposeActivity extends BaseActivity implements OnMenuItemClickList
}
@Override
protected void beforeExecute(ParcelableLocation location) {
protected void beforeExecute() {
ParcelableLocation location = getParams();
final TextView textView = getCallback();
if (textView == null) return;

View File

@ -1,6 +1,7 @@
package org.mariotaku.twidere.activity;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
@ -15,8 +16,10 @@ import android.util.Pair;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.BugReporter;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.support.IntentSupport;
import java.util.List;
@ -97,20 +100,20 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
startActivity(handled.first);
} else {
if (!handled.second) {
// BugReporter.error(new TwitterLinkException("Unable to handle twitter uri " + uri));
BugReporter.logException(new TwitterLinkException("Unable to handle twitter uri " + uri));
}
final String packageName = mPreferences.getString(KEY_FALLBACK_TWITTER_LINK_HANDLER, null);
final Intent fallbackIntent = new Intent(Intent.ACTION_VIEW, uri);
IntentSupport.setSelector(intent, new Intent(Intent.ACTION_VIEW).addCategory(IntentSupport.CATEGORY_APP_BROWSER));
fallbackIntent.setPackage(packageName);
if (TextUtils.isEmpty(packageName) || packageManager.queryIntentActivities(fallbackIntent, 0).isEmpty()) {
final Intent pickIntent = new Intent(INTENT_ACTION_PICK_ACTIVITY);
pickIntent.putExtra(EXTRA_INTENT, new Intent(Intent.ACTION_VIEW, uri));
pickIntent.putExtra(EXTRA_BLACKLIST, new String[]{getPackageName()});
startActivityForResult(pickIntent, REQUEST_PICK_ACTIVITY);
return;
} else {
fallbackIntent.addCategory(Intent.CATEGORY_BROWSABLE);
fallbackIntent.setPackage(IntentUtils.getDefaultBrowserPackage(this));
final ComponentName componentName = fallbackIntent.resolveActivity(packageManager);
if (componentName == null) {
final Intent targetIntent = new Intent(Intent.ACTION_VIEW, uri);
targetIntent.addCategory(Intent.CATEGORY_BROWSABLE);
startActivity(Intent.createChooser(targetIntent, getString(R.string.open_in_browser)));
} else if (!TextUtils.equals(getPackageName(), componentName.getPackageName())) {
startActivity(fallbackIntent);
} else {
// TODO show error
}
}
finish();
@ -180,6 +183,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
return Pair.create(null, false);
}
@NonNull
private Pair<Intent, Boolean> handleUserSpecificPageIntent(Uri uri, List<String> pathSegments, String screenName) {
final int segsSize = pathSegments.size();
if (segsSize == 1) {

View File

@ -1,35 +0,0 @@
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.mariotaku.twidere.R;
public class ResolveInfoListAdapter extends ArrayAdapter<ResolveInfo> {
private final PackageManager mPackageManager;
public ResolveInfoListAdapter(final Context context) {
super(context, R.layout.list_item_two_line_small);
mPackageManager = context.getPackageManager();
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final View view = super.getView(position, convertView, parent);
final ResolveInfo info = getItem(position);
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
final TextView text2 = (TextView) view.findViewById(android.R.id.text2);
icon.setImageDrawable(info.loadIcon(mPackageManager));
text1.setText(info.loadLabel(mPackageManager));
text2.setVisibility(View.GONE);
return view;
}
}

View File

@ -48,6 +48,7 @@ import android.widget.TextView;
import com.afollestad.appthemeengine.ATE;
import com.afollestad.appthemeengine.Config;
import com.pnikosis.materialishprogress.ProgressWheel;
import com.rengwuxian.materialedittext.MaterialEditText;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.BuildConfig;
@ -73,6 +74,7 @@ import org.mariotaku.twidere.util.theme.FloatingActionButtonViewProcessor;
import org.mariotaku.twidere.util.theme.FontFamilyTagProcessor;
import org.mariotaku.twidere.util.theme.IconActionButtonTagProcessor;
import org.mariotaku.twidere.util.theme.ImageViewViewProcessor;
import org.mariotaku.twidere.util.theme.MaterialEditTextViewProcessor;
import org.mariotaku.twidere.util.theme.OptimalLinkColorTagProcessor;
import org.mariotaku.twidere.util.theme.ProfileImageViewViewProcessor;
import org.mariotaku.twidere.util.theme.ProgressWheelViewProcessor;
@ -152,6 +154,7 @@ public class TwidereApplication extends Application implements Constants,
ATE.registerViewProcessor(TimelineContentTextView.class, new TimelineContentTextViewViewProcessor());
ATE.registerViewProcessor(TextView.class, new TextViewViewProcessor());
ATE.registerViewProcessor(ImageView.class, new ImageViewViewProcessor());
ATE.registerViewProcessor(MaterialEditText.class, new MaterialEditTextViewProcessor());
ATE.registerViewProcessor(ProgressWheel.class, new ProgressWheelViewProcessor());
ATE.registerViewProcessor(ProfileImageView.class, mProfileImageViewViewProcessor);
ATE.registerTagProcessor(OptimalLinkColorTagProcessor.TAG, new OptimalLinkColorTagProcessor());

View File

@ -22,8 +22,6 @@ package org.mariotaku.twidere.fragment;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.AsyncTask.Status;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
@ -49,6 +47,7 @@ import android.widget.Toast;
import com.rengwuxian.materialedittext.MaterialEditText;
import com.twitter.Validator;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.abstask.library.TaskStarter;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.ColorPickerDialogActivity;
@ -67,8 +66,8 @@ import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.task.UpdateAccountInfoTask;
import org.mariotaku.twidere.task.UpdateProfileBackgroundImageTask;
import org.mariotaku.twidere.task.UpdateProfileBannerImageTask;
import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper.UpdateProfileImageTask;
import org.mariotaku.twidere.util.HtmlEscapeHelper;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
@ -90,15 +89,17 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
private static final int REQUEST_UPLOAD_PROFILE_IMAGE = 1;
private static final int REQUEST_UPLOAD_PROFILE_BANNER_IMAGE = 2;
private static final int REQUEST_PICK_LINK_COLOR = 3;
private static final int REQUEST_PICK_BACKGROUND_COLOR = 4;
private static final int REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE = 3;
private static final int REQUEST_PICK_LINK_COLOR = 11;
private static final int REQUEST_PICK_BACKGROUND_COLOR = 12;
private static final int RESULT_REMOVE_BANNER = 101;
private static final String UPDATE_PROFILE_DIALOG_FRAGMENT_TAG = "update_profile";
private AsyncTask<Object, Object, ?> mTask;
private AbstractTask<?, ?, UserProfileEditorFragment> mTask;
private ImageView mProfileImageView;
private ImageView mProfileBannerView;
private ImageView mProfileBackgroundView;
private MaterialEditText mEditName;
private MaterialEditText mEditDescription;
private MaterialEditText mEditLocation;
@ -106,6 +107,7 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
private View mProgressContainer, mEditProfileContent;
private View mEditProfileImage;
private View mEditProfileBanner;
private View mEditProfileBackground;
private View mSetLinkColor, mSetBackgroundColor;
private ForegroundColorView mLinkColor, mBackgroundColor;
private UserKey mAccountId;
@ -129,7 +131,7 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
@Override
public void onClick(final View view) {
final ParcelableUser user = mUser;
if (user == null || (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING))
if (user == null || (mTask != null && !mTask.isFinished()))
return;
switch (view.getId()) {
case R.id.profile_image: {
@ -150,6 +152,11 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
startActivityForResult(intent, REQUEST_UPLOAD_PROFILE_BANNER_IMAGE);
break;
}
case R.id.edit_profile_background: {
final Intent intent = ThemedImagePickerActivity.withThemed(getActivity()).build();
startActivityForResult(intent, REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE);
break;
}
case R.id.set_link_color: {
final Intent intent = new Intent(getActivity(), ColorPickerDialogActivity.class);
intent.putExtra(EXTRA_COLOR, user.link_color);
@ -206,7 +213,7 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
final int backgroundColor = mBackgroundColor.getColor();
mTask = new UpdateProfileTaskInternal(this, mAccountId, mUser, name, url, location,
description, linkColor, backgroundColor);
AsyncTaskUtils.executeTask(mTask);
TaskStarter.execute(mTask);
return true;
}
}
@ -236,8 +243,12 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
mProfileImageView.setOnClickListener(this);
mProfileBannerView.setOnClickListener(this);
mEditProfileBanner.setOnClickListener(this);
mProfileBackgroundView.setOnClickListener(this);
mEditProfileImage.setOnClickListener(this);
mEditProfileBanner.setOnClickListener(this);
mEditProfileBackground.setOnClickListener(this);
mSetLinkColor.setOnClickListener(this);
mSetBackgroundColor.setOnClickListener(this);
@ -279,14 +290,16 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
super.onViewCreated(view, savedInstanceState);
mProgressContainer = view.findViewById(R.id.progress_container);
mEditProfileContent = view.findViewById(R.id.edit_profile_content);
mProfileBannerView = (ImageView) view.findViewById(R.id.profile_banner);
mProfileImageView = (ImageView) view.findViewById(R.id.profile_image);
mProfileBannerView = (ImageView) view.findViewById(R.id.profile_banner);
mProfileBackgroundView = (ImageView) view.findViewById(R.id.profile_background);
mEditName = (MaterialEditText) view.findViewById(R.id.name);
mEditDescription = (MaterialEditText) view.findViewById(R.id.description);
mEditLocation = (MaterialEditText) view.findViewById(R.id.location);
mEditUrl = (MaterialEditText) view.findViewById(R.id.url);
mEditProfileImage = view.findViewById(R.id.edit_profile_image);
mEditProfileBanner = view.findViewById(R.id.edit_profile_banner);
mEditProfileBackground = view.findViewById(R.id.edit_profile_background);
mLinkColor = (ForegroundColorView) view.findViewById(R.id.link_color);
mBackgroundColor = (ForegroundColorView) view.findViewById(R.id.background_color);
mSetLinkColor = view.findViewById(R.id.set_link_color);
@ -298,17 +311,26 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
if (resultCode == FragmentActivity.RESULT_CANCELED) return;
switch (requestCode) {
case REQUEST_UPLOAD_PROFILE_BANNER_IMAGE: {
if (mTask != null && mTask.getStatus() == Status.RUNNING) return;
if (mTask != null && !mTask.isFinished()) return;
if (resultCode == RESULT_REMOVE_BANNER) {
mTask = new RemoveProfileBannerTaskInternal(mAccountId);
} else {
mTask = new UpdateProfileBannerImageTaskInternal(getActivity(), mAccountId, data.getData(), true);
mTask = new UpdateProfileBannerImageTaskInternal(getActivity(), mAccountId,
data.getData(), true);
}
break;
}
case REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE: {
//TODO upload profile background
if (mTask != null && !mTask.isFinished()) return;
mTask = new UpdateProfileBackgroundImageTaskInternal(getActivity(), mAccountId,
data.getData(), false, true);
break;
}
case REQUEST_UPLOAD_PROFILE_IMAGE: {
if (mTask != null && mTask.getStatus() == Status.RUNNING) return;
mTask = new UpdateProfileImageTaskInternal(getActivity(), mAccountId, data.getData(), true);
if (mTask != null && !mTask.isFinished()) return;
mTask = new UpdateProfileImageTaskInternal(getActivity(), mAccountId,
data.getData(), true);
break;
}
case REQUEST_PICK_LINK_COLOR: {
@ -341,10 +363,16 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
mEditLocation.setText(user.location);
mEditUrl.setText(isEmpty(user.url_expanded) ? user.url : user.url_expanded);
mMediaLoader.displayProfileImage(mProfileImageView, user);
final int def_width = getResources().getDisplayMetrics().widthPixels;
mMediaLoader.displayProfileBanner(mProfileBannerView, user.profile_banner_url, def_width);
final int defWidth = getResources().getDisplayMetrics().widthPixels;
mMediaLoader.displayProfileBanner(mProfileBannerView, user.profile_banner_url, defWidth);
mMediaLoader.displayImage(mProfileBackgroundView, user.profile_background_url);
mLinkColor.setColor(user.link_color);
mBackgroundColor.setColor(user.background_color);
if (USER_TYPE_FANFOU_COM.equals(user.key.getHost())) {
mEditProfileBanner.setVisibility(View.GONE);
} else {
mEditProfileBanner.setVisibility(View.VISIBLE);
}
} else {
mProgressContainer.setVisibility(View.GONE);
mEditProfileContent.setVisibility(View.GONE);
@ -368,8 +396,8 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
@Override
public void onResume() {
super.onResume();
if (mTask != null && mTask.getStatus() == Status.PENDING) {
AsyncTaskUtils.executeTask(mTask);
if (mTask != null && !mTask.isFinished()) {
TaskStarter.execute(mTask);
}
}
@ -415,7 +443,8 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
static class UpdateProfileTaskInternal extends AsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
static class UpdateProfileTaskInternal extends AbstractTask<Object, SingleResponse<ParcelableUser>,
UserProfileEditorFragment> {
private static final String DIALOG_FRAGMENT_TAG = "updating_user_profile";
private final UserProfileEditorFragment mFragment;
@ -449,7 +478,7 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
protected SingleResponse<ParcelableUser> doLongOperation(final Object params) {
final ParcelableCredentials credentials = ParcelableCredentialsUtils.getCredentials(mActivity, mAccountKey);
if (credentials == null) return SingleResponse.getInstance();
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mActivity, credentials,
@ -495,8 +524,8 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
protected void afterExecute(SingleResponse<ParcelableUser> result) {
super.afterExecute(result);
if (result.hasData()) {
final ParcelableAccount account = result.getExtras().getParcelable(EXTRA_ACCOUNT);
if (account != null) {
@ -518,7 +547,8 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
@Override
protected void onPreExecute() {
protected void beforeExecute() {
super.beforeExecute();
mFragment.executeAfterFragmentResumed(new Action() {
@Override
public void execute(IBaseFragment fragment) {
@ -526,12 +556,11 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
df.setCancelable(false);
}
});
super.onPreExecute();
}
}
class RemoveProfileBannerTaskInternal extends AsyncTask<Object, Object, SingleResponse<Boolean>> {
class RemoveProfileBannerTaskInternal extends AbstractTask<Object, SingleResponse<Boolean>, UserProfileEditorFragment> {
private final UserKey mAccountKey;
@ -540,13 +569,13 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
@Override
protected SingleResponse<Boolean> doInBackground(final Object... params) {
protected SingleResponse<Boolean> doLongOperation(final Object params) {
return TwitterWrapper.deleteProfileBannerImage(getActivity(), mAccountKey);
}
@Override
protected void onPostExecute(final SingleResponse<Boolean> result) {
super.onPostExecute(result);
protected void afterExecute(final SingleResponse<Boolean> result) {
super.afterExecute(result);
if (result.getData() != null && result.getData()) {
getUserInfo();
Toast.makeText(getActivity(), R.string.profile_banner_image_updated, Toast.LENGTH_SHORT).show();
@ -558,14 +587,14 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
@Override
protected void onPreExecute() {
super.onPreExecute();
protected void beforeExecute() {
super.beforeExecute();
setUpdateState(true);
}
}
private class UpdateProfileBannerImageTaskInternal extends UpdateProfileBannerImageTask {
private class UpdateProfileBannerImageTaskInternal extends UpdateProfileBannerImageTask<UserProfileEditorFragment> {
public UpdateProfileBannerImageTaskInternal(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean deleteImage) {
@ -573,21 +602,44 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
protected void afterExecute(final SingleResponse<ParcelableUser> result) {
super.afterExecute(result);
setUpdateState(false);
getUserInfo();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
protected void beforeExecute() {
super.beforeExecute();
setUpdateState(true);
}
}
private class UpdateProfileImageTaskInternal extends UpdateProfileImageTask {
private class UpdateProfileBackgroundImageTaskInternal extends UpdateProfileBackgroundImageTask<UserProfileEditorFragment> {
public UpdateProfileBackgroundImageTaskInternal(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean tile,
final boolean deleteImage) {
super(context, accountKey, imageUri, tile, deleteImage);
}
@Override
protected void afterExecute(final SingleResponse<ParcelableUser> result) {
super.afterExecute(result);
setUpdateState(false);
getUserInfo();
}
@Override
protected void beforeExecute() {
super.beforeExecute();
setUpdateState(true);
}
}
private class UpdateProfileImageTaskInternal extends UpdateProfileImageTask<UserProfileEditorFragment> {
public UpdateProfileImageTaskInternal(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean deleteImage) {
@ -595,8 +647,8 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
protected void afterExecute(SingleResponse<ParcelableUser> result) {
super.afterExecute(result);
if (result != null && result.getData() != null) {
displayUser(result.getData());
}
@ -604,8 +656,8 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
}
@Override
protected void onPreExecute() {
super.onPreExecute();
protected void beforeExecute() {
super.beforeExecute();
setUpdateState(true);
}

View File

@ -1,177 +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.loader;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.support.v4.content.AsyncTaskLoader;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.Constants;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class IntentActivitiesLoader extends AsyncTaskLoader<List<ResolveInfo>> implements Constants {
private PackageIntentReceiver mPackageObserver;
private final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
private final PackageManager mPackageManager;
private final Intent mIntent;
private final String[] mPackagesBlacklist;
private final int mFlags;
public IntentActivitiesLoader(final Context context, final Intent intent) {
this(context, intent, null, 0);
}
public IntentActivitiesLoader(final Context context, final Intent intent, final String[] packagesBlacklist,
final int flags) {
super(context);
mPackageManager = context.getPackageManager();
mIntent = intent;
mPackagesBlacklist = packagesBlacklist;
mFlags = flags;
}
@Override
public List<ResolveInfo> loadInBackground() {
if (mIntent == null) return Collections.emptyList();
final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(mIntent, mFlags);
final List<ResolveInfo> result = new ArrayList<>();
for (final ResolveInfo activity : activities) {
final ActivityInfo activityInfo = activity.activityInfo;
if (mPackagesBlacklist == null || !ArrayUtils.contains(mPackagesBlacklist, activityInfo.packageName)) {
result.add(activity);
}
}
return result;
}
/**
* Handles a request to completely reset the Loader.
*/
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// Stop monitoring for changes.
if (mPackageObserver != null) {
getContext().unregisterReceiver(mPackageObserver);
mPackageObserver = null;
}
}
/**
* Handles a request to start the Loader.
*/
@Override
protected void onStartLoading() {
// Start watching for changes in the app data.
if (mPackageObserver == null) {
mPackageObserver = new PackageIntentReceiver(this);
}
// Has something interesting in the configuration changed since we
// last built the app list?
final boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
if (takeContentChanged() || configChange) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Helper for determining if the configuration has changed in an interesting
* way so we need to rebuild the app list.
*/
public static class InterestingConfigChanges {
final Configuration mLastConfiguration = new Configuration();
int mLastDensity;
boolean applyNewConfig(final Resources res) {
final int configChanges = mLastConfiguration.updateFrom(res.getConfiguration());
final boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
if (densityChanged
|| (configChanges & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_SCREEN_LAYOUT)) != 0) {
mLastDensity = res.getDisplayMetrics().densityDpi;
return true;
}
return false;
}
}
/**
* Helper class to look for interesting changes to the installed apps so
* that the loader can be updated.
*/
public static class PackageIntentReceiver extends BroadcastReceiver {
final IntentActivitiesLoader mLoader;
public PackageIntentReceiver(final IntentActivitiesLoader loader) {
mLoader = loader;
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mLoader.getContext().registerReceiver(this, filter);
// Register for events related to sdcard installation.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
final IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mLoader.getContext().registerReceiver(this, sdFilter);
}
}
@Override
public void onReceive(final Context context, final Intent intent) {
// Tell the loader about the change.
mLoader.onContentChanged();
}
}
}

View File

@ -52,7 +52,8 @@ public abstract class AbsFriendshipOperationTask extends AbstractTask<AbsFriends
@Override
protected final void beforeExecute(Arguments params) {
protected final void beforeExecute() {
Arguments params = getParams();
twitter.addUpdatingRelationshipId(params.accountKey, params.userKey);
final FriendshipTaskEvent event = new FriendshipTaskEvent(action, params.accountKey,
params.userKey);

View File

@ -40,6 +40,7 @@ public abstract class ProgressSaveFileTask extends SaveFileTask {
super(context, source, destination, getMimeType);
}
@Override
protected void showProgress() {
final Context context = getContext();
if (context == null) return;
@ -53,6 +54,7 @@ public abstract class ProgressSaveFileTask extends SaveFileTask {
});
}
@Override
protected void dismissProgress() {
final Context context = getContext();
if (context == null) return;

View File

@ -0,0 +1,91 @@
package org.mariotaku.twidere.task;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import com.squareup.otto.Bus;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.twidere.Constants;
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 org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
import java.io.IOException;
import javax.inject.Inject;
/**
* Created by mariotaku on 16/3/11.
*/
public class UpdateProfileBackgroundImageTask<ResultHandler> extends AbstractTask<Object,
SingleResponse<ParcelableUser>, ResultHandler> implements Constants {
@Inject
protected Bus mBus;
private final UserKey mAccountKey;
private final Uri mImageUri;
private boolean mTile;
private final boolean mDeleteImage;
private final Context mContext;
public UpdateProfileBackgroundImageTask(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean tile,
final boolean deleteImage) {
//noinspection unchecked
GeneralComponentHelper.build(context).inject((UpdateProfileBackgroundImageTask<Object>) this);
mContext = context;
mAccountKey = accountKey;
mImageUri = imageUri;
mDeleteImage = deleteImage;
mTile = tile;
}
@Override
protected void afterExecute(SingleResponse<ParcelableUser> result) {
super.afterExecute(result);
if (result.hasData()) {
Utils.showOkMessage(mContext, R.string.profile_banner_image_updated, false);
mBus.post(new ProfileUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_updating_profile_background_image,
result.getException(),
true);
}
}
@Override
protected SingleResponse<ParcelableUser> doLongOperation(final Object params) {
try {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey,
true);
TwitterWrapper.updateProfileBackgroundImage(mContext, twitter, mImageUri, mTile,
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 = twitter.verifyCredentials();
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey));
} catch (TwitterException | IOException e) {
return SingleResponse.getInstance(e);
}
}
}

View File

@ -4,6 +4,10 @@ import android.content.Context;
import android.net.Uri;
import android.util.Log;
import com.squareup.otto.Bus;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
@ -16,13 +20,20 @@ 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 org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.inject.Inject;
/**
* Created by mariotaku on 16/3/11.
*/
public class UpdateProfileBannerImageTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
public class UpdateProfileBannerImageTask<ResultHandler> extends AbstractTask<Object,
SingleResponse<ParcelableUser>, ResultHandler> implements Constants {
@Inject
protected Bus mBus;
private final UserKey mAccountKey;
private final Uri mImageUri;
@ -31,7 +42,8 @@ public class UpdateProfileBannerImageTask extends ManagedAsyncTask<Object, Objec
public UpdateProfileBannerImageTask(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean deleteImage) {
super(context);
//noinspection unchecked
GeneralComponentHelper.build(context).inject((UpdateProfileBannerImageTask<Object>) this);
mContext = context;
mAccountKey = accountKey;
mImageUri = imageUri;
@ -39,11 +51,11 @@ public class UpdateProfileBannerImageTask extends ManagedAsyncTask<Object, Objec
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
protected void afterExecute(final SingleResponse<ParcelableUser> result) {
super.afterExecute(result);
if (result.hasData()) {
Utils.showOkMessage(mContext, R.string.profile_banner_image_updated, false);
bus.post(new ProfileUpdatedEvent(result.getData()));
mBus.post(new ProfileUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_updating_profile_banner_image, result.getException(),
true);
@ -51,7 +63,7 @@ public class UpdateProfileBannerImageTask extends ManagedAsyncTask<Object, Objec
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
protected SingleResponse<ParcelableUser> doLongOperation(final Object params) {
try {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey,
true);
@ -65,7 +77,7 @@ public class UpdateProfileBannerImageTask extends ManagedAsyncTask<Object, Objec
}
final User user = twitter.verifyCredentials();
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey));
} catch (TwitterException | FileNotFoundException e) {
} catch (TwitterException | IOException e) {
return SingleResponse.getInstance(e);
}
}

View File

@ -206,7 +206,7 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
@UiThread
@Override
public void beforeExecute(RefreshTaskParam params) {
public void beforeExecute() {
bus.post(new GetActivitiesTaskEvent(getContentUri(), true, null));
}
}

View File

@ -93,7 +93,7 @@ public abstract class GetStatusesTask extends AbstractTask<RefreshTaskParam,
}
@Override
protected void beforeExecute(RefreshTaskParam refreshTaskParam) {
protected void beforeExecute() {
bus.post(new GetStatusesTaskEvent(getContentUri(), true, null));
}

View File

@ -110,12 +110,15 @@ 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.util.dagger.GeneralComponentHelper;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import edu.tsinghua.hotmobi.HotMobiLogger;
import edu.tsinghua.hotmobi.model.TimelineType;
import edu.tsinghua.hotmobi.model.TweetEvent;
@ -552,7 +555,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mUpdatingRelationshipIds.contains(ParcelableUser.calculateHashCode(accountId, userId));
}
public static class UpdateProfileImageTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
public static class UpdateProfileImageTask<ResultHandler> extends AbstractTask<Object,
SingleResponse<ParcelableUser>, ResultHandler> {
@Inject
protected Bus mBus;
private final UserKey mAccountKey;
private final Uri mImageUri;
@ -561,7 +568,8 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
public UpdateProfileImageTask(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean deleteImage) {
super(context);
//noinspection unchecked
GeneralComponentHelper.build(context).inject((UpdateProfileImageTask<Object>) this);
this.mContext = context;
this.mAccountKey = accountKey;
this.mImageUri = imageUri;
@ -569,7 +577,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
protected SingleResponse<ParcelableUser> doLongOperation(final Object params) {
try {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, true);
TwitterWrapper.updateProfileImage(mContext, twitter, mImageUri, mDeleteImage);
@ -582,17 +590,17 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
final User user = twitter.verifyCredentials();
return SingleResponse.getInstance(ParcelableUserUtils.fromUser(user, mAccountKey));
} catch (TwitterException | FileNotFoundException e) {
} catch (TwitterException | IOException e) {
return SingleResponse.getInstance(e);
}
}
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
protected void afterExecute(SingleResponse<ParcelableUser> result) {
super.afterExecute(result);
if (result.hasData()) {
Utils.showOkMessage(mContext, R.string.profile_image_updated, false);
bus.post(new ProfileUpdatedEvent(result.getData()));
mBus.post(new ProfileUpdatedEvent(result.getData()));
} else {
Utils.showErrorMessage(mContext, R.string.action_updating_profile_image, result.getException(), true);
}

View File

@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -35,6 +36,7 @@ import org.mariotaku.twidere.model.util.ParcelableLocationUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import static android.text.TextUtils.isEmpty;
@ -195,6 +197,27 @@ public class IntentUtils implements Constants {
}
}
public static String getDefaultBrowserPackage(Context context) {
Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_HTTP);
StringBuilder sb = new StringBuilder();
Random random = new Random();
int range = 'z' - 'a';
for (int i = 0; i < 20; i++) {
sb.append((char) ('a' + (Math.abs(random.nextInt()) % range)));
}
sb.append(".com");
builder.authority(sb.toString());
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
intent.addCategory(Intent.CATEGORY_BROWSABLE);
List<ResolveInfo> info = context.getPackageManager().queryIntentActivities(intent, 0);
if (info.isEmpty()) return null;
for (ResolveInfo item : info) {
if (item.isDefault) return item.activityInfo.packageName;
}
return info.get(0).activityInfo.packageName;
}
public static void openMediaDirectly(@NonNull final Context context,
@Nullable final UserKey accountKey,
final ParcelableDirectMessage message, final ParcelableMedia current,

View File

@ -222,12 +222,8 @@ public class MediaLoaderWrapper implements Constants {
}
public void displayImage(final ImageView view, final String url, DisplayImageOptions options) {
mImageLoader.displayImage(url, view, options);
}
public DisplayImageOptions getProfileImageDisplayOptions() {
return mProfileImageDisplayOptions;
public void displayImage(final ImageView view, final String url) {
mImageLoader.displayImage(url, view);
}
public void displayProfileImage(final ImageView view, final String url, final ImageLoadingListener listener) {

View File

@ -19,13 +19,16 @@
package org.mariotaku.twidere.util;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.util.SimpleArrayMap;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;
import org.mariotaku.restfu.http.ContentType;
import org.mariotaku.restfu.http.mime.FileBody;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.api.twitter.Twitter;
@ -44,6 +47,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.UnreadCounts;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Set;
@ -174,13 +178,34 @@ public class TwitterWrapper implements Constants {
public static void updateProfileBannerImage(final Context context, final Twitter twitter,
final Uri imageUri, final boolean deleteImage)
throws FileNotFoundException, TwitterException {
InputStream is = null;
throws IOException, TwitterException {
FileBody fileBody = null;
try {
is = context.getContentResolver().openInputStream(imageUri);
twitter.updateProfileBannerImage(new FileBody(is, "image", -1, null));
fileBody = getFileBody(context, imageUri);
twitter.updateProfileBannerImage(fileBody);
} finally {
Utils.closeSilently(is);
Utils.closeSilently(fileBody);
if (deleteImage && "file".equals(imageUri.getScheme())) {
final File file = new File(imageUri.getPath());
if (!file.delete()) {
Log.w(LOGTAG, String.format("Unable to delete %s", file));
}
}
}
}
public static void updateProfileBackgroundImage(@NonNull final Context context,
@NonNull final Twitter twitter,
@NonNull final Uri imageUri,
final boolean tile,
final boolean deleteImage)
throws IOException, TwitterException {
FileBody fileBody = null;
try {
fileBody = getFileBody(context, imageUri);
twitter.updateProfileBackgroundImage(fileBody, tile);
} finally {
Utils.closeSilently(fileBody);
if (deleteImage && "file".equals(imageUri.getScheme())) {
final File file = new File(imageUri.getPath());
if (!file.delete()) {
@ -192,13 +217,13 @@ public class TwitterWrapper implements Constants {
public static User updateProfileImage(final Context context, final Twitter twitter,
final Uri imageUri, final boolean deleteImage)
throws FileNotFoundException, TwitterException {
InputStream is = null;
throws IOException, TwitterException {
FileBody fileBody = null;
try {
is = context.getContentResolver().openInputStream(imageUri);
return twitter.updateProfileImage(new FileBody(is, "image", -1, null));
fileBody = getFileBody(context, imageUri);
return twitter.updateProfileImage(fileBody);
} finally {
Utils.closeSilently(is);
Utils.closeSilently(fileBody);
if (deleteImage && "file".equals(imageUri.getScheme())) {
final File file = new File(imageUri.getPath());
if (!file.delete()) {
@ -208,6 +233,33 @@ public class TwitterWrapper implements Constants {
}
}
private static FileBody getFileBody(Context context, Uri imageUri) throws IOException {
final ContentResolver cr = context.getContentResolver();
String type = cr.getType(imageUri);
if (type == null) {
type = Utils.getImageMimeType(cr, imageUri);
}
final ContentType contentType;
final String extension;
if (type != null) {
contentType = ContentType.parse(type);
extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type);
} else {
contentType = null;
extension = null;
}
final InputStream is = cr.openInputStream(imageUri);
if (is == null) throw new FileNotFoundException(imageUri.toString());
final String fileName;
if (extension != null) {
fileName = "image." + extension;
} else {
fileName = "image";
}
return new FileBody(is, fileName, is.available(), contentType);
}
public static final class MessageListResponse extends TwitterListResponse<DirectMessage> {
public MessageListResponse(final UserKey accountKey, final Exception exception) {

View File

@ -41,7 +41,6 @@ import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
@ -75,13 +74,10 @@ import android.support.v4.view.GravityCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v7.app.AppCompatActivity;
import android.system.ErrnoException;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.text.style.CharacterStyle;
import android.text.style.StyleSpan;
import android.transition.Transition;
import android.transition.TransitionInflater;
import android.util.Log;
@ -1239,6 +1235,23 @@ public final class Utils implements Constants {
return o.outMimeType;
}
@Nullable
public static String getImageMimeType(ContentResolver cr, final Uri uri) {
if (uri == null) return null;
final BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
InputStream is = null;
try {
is = cr.openInputStream(uri);
BitmapFactory.decodeStream(is, null, o);
return o.outMimeType;
} catch (IOException e) {
return null;
} finally {
closeSilently(is);
}
}
public static String getImagePathFromUri(final Context context, final Uri uri) {
if (context == null || uri == null) return null;
@ -1290,28 +1303,6 @@ public final class Utils implements Constants {
return new File(context.getCacheDir(), cacheDirName);
}
public static CharSequence getKeywordBoldedText(final CharSequence orig, final String... keywords) {
return getKeywordHighlightedText(orig, new StyleSpan(Typeface.BOLD), keywords);
}
public static CharSequence getKeywordHighlightedText(final CharSequence orig, final CharacterStyle style,
final String... keywords) {
if (keywords == null || keywords.length == 0 || orig == null) return orig;
final SpannableStringBuilder sb = SpannableStringBuilder.valueOf(orig);
final StringBuilder patternBuilder = new StringBuilder();
for (int i = 0, j = keywords.length; i < j; i++) {
if (i != 0) {
patternBuilder.append('|');
}
patternBuilder.append(Pattern.quote(keywords[i]));
}
final Matcher m = Pattern.compile(patternBuilder.toString(), Pattern.CASE_INSENSITIVE).matcher(orig);
while (m.find()) {
sb.setSpan(style, m.start(), m.end(), SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
}
return sb;
}
public static String getLinkHighlightingStyleName(final Context context) {
if (context == null) return null;
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
@ -1785,7 +1776,7 @@ public final class Utils implements Constants {
if (absListView == null) return;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
if (absListView instanceof ListView) {
final ListView listView = ((ListView) absListView);
final ListView listView = (ListView) absListView;
listView.setSelectionFromTop(position, offset);
} else {
absListView.setSelection(position);
@ -1794,7 +1785,7 @@ public final class Utils implements Constants {
} else {
stopListView(absListView);
if (absListView instanceof ListView) {
final ListView listView = ((ListView) absListView);
final ListView listView = (ListView) absListView;
listView.setSelectionFromTop(position, offset);
} else {
absListView.setSelection(position);
@ -1929,6 +1920,9 @@ public final class Utils implements Constants {
.getMessage(context, te.getStatusCode(), te.getErrorCode());
message = context.getString(R.string.error_message_with_action, action, msg != null ? msg
: trimLineBreak(te.getMessage()));
} else if (!TextUtils.isEmpty(te.getErrorMessage())) {
message = context.getString(R.string.error_message_with_action, action,
trimLineBreak(te.getErrorMessage()));
} else if (te.getCause() instanceof SSLException) {
final String msg = te.getCause().getMessage();
if (msg != null && msg.contains("!=")) {
@ -2148,8 +2142,8 @@ public final class Utils implements Constants {
public static boolean isCustomConsumerKeySecret(String consumerKey, String consumerSecret) {
if (TextUtils.isEmpty(consumerKey) || TextUtils.isEmpty(consumerSecret)) return false;
return (!TWITTER_CONSUMER_KEY.equals(consumerKey) && !TWITTER_CONSUMER_SECRET.equals(consumerKey))
&& (!TWITTER_CONSUMER_KEY_LEGACY.equals(consumerKey) && !TWITTER_CONSUMER_SECRET_LEGACY.equals(consumerSecret));
return !TWITTER_CONSUMER_KEY.equals(consumerKey) && !TWITTER_CONSUMER_SECRET.equals(consumerKey)
&& !TWITTER_CONSUMER_KEY_LEGACY.equals(consumerKey) && !TWITTER_CONSUMER_SECRET_LEGACY.equals(consumerSecret);
}
public static boolean isStreamingEnabled() {

View File

@ -32,9 +32,9 @@ import org.mariotaku.twidere.adapter.ComposeAutoCompleteAdapter;
import org.mariotaku.twidere.adapter.DraftsAdapter;
import org.mariotaku.twidere.adapter.DummyItemAdapter;
import org.mariotaku.twidere.adapter.UserAutoCompleteAdapter;
import org.mariotaku.twidere.fragment.BaseFiltersFragment;
import org.mariotaku.twidere.fragment.BaseListFragment;
import org.mariotaku.twidere.fragment.BasePreferenceFragment;
import org.mariotaku.twidere.fragment.BaseFiltersFragment;
import org.mariotaku.twidere.fragment.BaseSupportDialogFragment;
import org.mariotaku.twidere.fragment.BaseSupportFragment;
import org.mariotaku.twidere.fragment.MessagesConversationFragment;
@ -51,10 +51,13 @@ import org.mariotaku.twidere.task.AbsFriendshipOperationTask;
import org.mariotaku.twidere.task.GetDirectMessagesTask;
import org.mariotaku.twidere.task.GetTrendsTask;
import org.mariotaku.twidere.task.ManagedAsyncTask;
import org.mariotaku.twidere.task.UpdateProfileBackgroundImageTask;
import org.mariotaku.twidere.task.UpdateProfileBannerImageTask;
import org.mariotaku.twidere.task.twitter.GetActivitiesTask;
import org.mariotaku.twidere.task.twitter.GetStatusesTask;
import org.mariotaku.twidere.text.util.EmojiEditableFactory;
import org.mariotaku.twidere.text.util.EmojiSpannableFactory;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.MultiSelectEventHandler;
import javax.inject.Singleton;
@ -138,4 +141,10 @@ public interface GeneralComponent {
void inject(ParcelableStatusLoader loader);
void inject(GetTrendsTask task);
void inject(UpdateProfileBackgroundImageTask<Object> task);
void inject(UpdateProfileBannerImageTask<Object> task);
void inject(AsyncTwitterWrapper.UpdateProfileImageTask<Object> task);
}

View File

@ -0,0 +1,21 @@
package org.mariotaku.twidere.util.theme;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.viewprocessors.ViewProcessor;
import com.rengwuxian.materialedittext.MaterialEditText;
/**
* Created by mariotaku on 16/4/1.
*/
public class MaterialEditTextViewProcessor implements ViewProcessor<MaterialEditText, Void> {
@Override
public void process(@NonNull Context context, @Nullable String key, @Nullable MaterialEditText target, @Nullable Void extra) {
if (target == null) return;
int accentColor = Config.accentColor(context, key);
target.setPrimaryColor(accentColor);
}
}

View File

@ -40,6 +40,9 @@ public class HomeDrawerLayout extends DrawerLayout implements ViewInterface {
}
private void init(Context context, @Nullable ATEActivity keyContext) {
if (keyContext == null && context instanceof ATEActivity) {
keyContext = (ATEActivity) context;
}
final String key = keyContext != null ? keyContext.getATEKey() : null;
if (Config.coloredStatusBar(context, key)) {
// Sets the status bar overlayed by the DrawerLayout

View File

@ -1,53 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 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.view.themed;
import android.content.Context;
import android.content.res.ColorStateList;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import com.rengwuxian.materialedittext.MaterialEditText;
import org.mariotaku.twidere.view.iface.IThemeBackgroundTintView;
/**
* TextView with tint background support
*/
public class BackgroundTintMaterialEditText extends MaterialEditText implements IThemeBackgroundTintView {
public BackgroundTintMaterialEditText(Context context) {
super(context);
}
public BackgroundTintMaterialEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BackgroundTintMaterialEditText(Context context, AttributeSet attrs, int style) {
super(context, attrs, style);
}
@Override
public void setBackgroundTintColor(@NonNull ColorStateList color) {
setPrimaryColor(color.getDefaultColor());
}
}

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@ -24,7 +24,7 @@
android:layout_height="match_parent"
android:padding="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -39,7 +39,7 @@
app:met_floatingLabelText="@string/name"
app:met_maxCharacters="25"/>
<org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -59,7 +59,8 @@
android:layout_height="@dimen/element_size_mlarge"
android:layout_gravity="center"
android:foreground="?selectableItemBackground"
android:scaleType="centerCrop"/>
android:scaleType="centerCrop"
tools:src="@drawable/ic_launcher_web"/>
<TextView
android:layout_width="wrap_content"
@ -81,7 +82,9 @@
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="@dimen/element_spacing_normal">
android:padding="@dimen/element_spacing_normal"
android:visibility="gone"
tools:visibility="visible">
<org.mariotaku.twidere.view.ForegroundImageView
android:id="@+id/profile_banner"
@ -89,7 +92,8 @@
android:layout_height="@dimen/element_size_mlarge"
android:layout_gravity="center"
android:foreground="?selectableItemBackground"
android:scaleType="centerCrop"/>
android:scaleType="centerCrop"
tools:src="@drawable/nyan_stars_background_tile"/>
<TextView
android:layout_width="wrap_content"
@ -103,6 +107,37 @@
android:textStyle="bold"/>
</LinearLayout>
<LinearLayout
android:id="@+id/edit_profile_background"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.ForegroundImageView
android:id="@+id/profile_background"
android:layout_width="@dimen/element_size_mlarge"
android:layout_height="@dimen/element_size_mlarge"
android:layout_gravity="center"
android:foreground="?selectableItemBackground"
android:scaleType="centerCrop"
tools:src="@drawable/nyan_stars_background_tile"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:text="@string/profile_background"
android:textAllCaps="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
</LinearLayout>
</LinearLayout>
<Space
@ -116,7 +151,7 @@
android:orientation="vertical"
android:padding="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -125,9 +160,11 @@
app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/name"
app:met_maxCharacters="20"/>
app:met_maxCharacters="20"
app:met_primaryColor="?colorAccent"
tools:text="TwidereProject"/>
<org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -137,9 +174,11 @@
app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/description"
app:met_maxCharacters="160"/>
app:met_maxCharacters="160"
app:met_primaryColor="?colorAccent"
tools:text="@string/sample_status_text"/>
<org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -148,9 +187,11 @@
app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/location"
app:met_maxCharacters="30"/>
app:met_maxCharacters="30"
app:met_primaryColor="?colorAccent"
tools:text="Earth"/>
<org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -159,7 +200,9 @@
app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/url"
app:met_maxCharacters="100"/>
app:met_maxCharacters="100"
app:met_primaryColor="?colorAccent"
tools:text="https://github.com/TwidereProject/"/>
</LinearLayout>
<Space
@ -185,7 +228,8 @@
android:id="@+id/link_color"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_weight="0"/>
android:layout_weight="0"
tools:color="@color/branding_color"/>
<TextView
android:layout_width="match_parent"
@ -214,7 +258,8 @@
android:id="@+id/background_color"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_weight="0"/>
android:layout_weight="0"
tools:color="@color/branding_color"/>
<TextView
android:layout_width="match_parent"

View File

@ -303,6 +303,7 @@
<string name="action_updating_profile">updating profile</string>
<string name="action_updating_profile_image">updating profile image</string>
<string name="action_updating_profile_banner_image">updating profile header image</string>
<string name="action_updating_profile_background_image">updating profile background image</string>
<string name="action_removing_profile_banner_image">removing profile header image</string>
<string name="action_updating_details">updating details</string>
<string name="action_blocking">blocking</string>
@ -588,6 +589,7 @@
<string name="function">Function</string>
<string name="replies">Replies</string>
<string name="profile_banner">Profile banner</string>
<string name="profile_background">Profile background</string>
<string name="profile">Profile</string>
<string name="listed">Listed</string>
<string name="state_blocking">Blocking</string>