fixed crashes for tweets quoting yourself
This commit is contained in:
parent
5db3522433
commit
3d75fbbfd0
|
@ -151,7 +151,7 @@ public interface SharedPreferenceConstants {
|
|||
String KEY_DISPLAY_PROFILE_IMAGE = "display_profile_image";
|
||||
@Preference(type = BOOLEAN)
|
||||
String KEY_LEFTSIDE_COMPOSE_BUTTON = "leftside_compose_button";
|
||||
@Preference(type = BOOLEAN)
|
||||
@Preference(type = BOOLEAN, exportable = false, hasDefault = true, defaultBoolean = false)
|
||||
String KEY_ATTACH_LOCATION = "attach_location";
|
||||
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
|
||||
String KEY_GZIP_COMPRESSING = "gzip_compressing";
|
||||
|
|
|
@ -783,8 +783,6 @@ public interface TwidereDataStore {
|
|||
|
||||
String MY_RETWEET_ID = "my_retweet_id";
|
||||
|
||||
String MY_QUOTE_ID = "my_quote_id";
|
||||
|
||||
String MEDIA_LIST = "media_list";
|
||||
|
||||
String MENTIONS_LIST = "mentions_list";
|
||||
|
@ -803,6 +801,7 @@ public interface TwidereDataStore {
|
|||
String QUOTE_TEXT_HTML = "quote_text_html";
|
||||
String QUOTE_TEXT_PLAIN = "quote_text_plain";
|
||||
String QUOTE_TEXT_UNESCAPED = "quote_text_unescaped";
|
||||
String QUOTE_MEDIA_JSON = "quote_media_json";
|
||||
String QUOTE_TIMESTAMP = "quote_timestamp";
|
||||
String QUOTE_SOURCE = "quote_source";
|
||||
String QUOTED_BY_USER_ID = "quoted_by_user_id";
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -231,7 +232,7 @@ public final class ContentValuesCreator implements TwidereConstants {
|
|||
values.put(DirectMessages.SENDER_PROFILE_IMAGE_URL, message.sender_profile_image_url);
|
||||
values.put(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL, message.recipient_profile_image_url);
|
||||
if (message.media != null) {
|
||||
values.put(Statuses.MEDIA_LIST, SimpleValueSerializer.toSerializedString(message.media));
|
||||
values.put(DirectMessages.MEDIA_LIST, SimpleValueSerializer.toSerializedString(message.media));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
@ -302,8 +303,9 @@ public final class ContentValuesCreator implements TwidereConstants {
|
|||
return resultValuesArray;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static ContentValues createStatus(final Status orig, final long accountId) {
|
||||
if (orig == null || orig.getId() <= 0) return null;
|
||||
if (orig == null) throw new NullPointerException();
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(Statuses.ACCOUNT_ID, accountId);
|
||||
values.put(Statuses.STATUS_ID, orig.getId());
|
||||
|
@ -345,11 +347,6 @@ public final class ContentValuesCreator implements TwidereConstants {
|
|||
values.put(Statuses.QUOTED_BY_USER_IS_VERIFIED, quoteUser.isVerified());
|
||||
values.put(Statuses.QUOTED_BY_USER_IS_PROTECTED, quoteUser.isProtected());
|
||||
values.put(Statuses.IS_QUOTE, true);
|
||||
if (quotedById == accountId) {
|
||||
values.put(Statuses.MY_QUOTE_ID, orig.getId());
|
||||
// } else {
|
||||
// values.put(Statuses.MY_QUOTE_ID, orig.getCurrentUserRetweet());
|
||||
}
|
||||
status = quotedStatus;
|
||||
} else {
|
||||
values.put(Statuses.MY_RETWEET_ID, orig.getCurrentUserRetweet());
|
||||
|
|
|
@ -3,31 +3,19 @@ package edu.tsinghua.spice;
|
|||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.os.IBinder;
|
||||
|
||||
import edu.tsinghua.spice.Utilies.NetworkStateUtil;
|
||||
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
|
||||
|
||||
/**
|
||||
* Created by Denny C. Ng on 2/20/15.
|
||||
*
|
||||
* <p/>
|
||||
* Request location ONCE per WAKE_PERIOD_IN_MILLI.
|
||||
*/
|
||||
public class SpiceService extends Service {
|
||||
|
||||
public static final long LOCATION_PERIOD_IN_MILLI = 15 * 60 * 1000;
|
||||
public static final String ACTION_GET_LOCATION = "edu.tsinghua.spice.GET_LOCATION";
|
||||
private LocationManager mLocationManager;
|
||||
private AlarmManager mAlarmManager;
|
||||
private LocationUpdateReceiver mAlarmReceiver;
|
||||
private PendingIntent locationIntent;
|
||||
private PendingIntent uploadIntent;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(final Intent intent) {
|
||||
|
@ -39,51 +27,17 @@ public class SpiceService extends Service {
|
|||
super.onCreate();
|
||||
|
||||
SpiceProfilingUtil.log(this, "onCreate");
|
||||
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
mAlarmManager = (AlarmManager) getSystemService(Service.ALARM_SERVICE);
|
||||
|
||||
mAlarmReceiver = new LocationUpdateReceiver();
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_GET_LOCATION);
|
||||
registerReceiver(mAlarmReceiver, filter);
|
||||
|
||||
final Intent intent = new Intent(ACTION_GET_LOCATION);
|
||||
locationIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
|
||||
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), LOCATION_PERIOD_IN_MILLI,
|
||||
locationIntent);
|
||||
|
||||
// Upload Service
|
||||
final Intent i = new Intent(SpiceUploadReceiver.ACTION_UPLOAD_PROFILE);
|
||||
uploadIntent = PendingIntent.getBroadcast(this, 0, i, 0);
|
||||
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 12 * 60 * 60 * 1000,
|
||||
uploadIntent);
|
||||
final Intent uploadIntent = new Intent(SpiceUploadReceiver.ACTION_UPLOAD_PROFILE);
|
||||
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
|
||||
12 * 60 * 60 * 1000, PendingIntent.getBroadcast(this, 0, uploadIntent, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mAlarmManager.cancel(locationIntent);
|
||||
unregisterReceiver(mAlarmReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private final class LocationUpdateReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
if (mLocationManager == null) return;
|
||||
SpiceProfilingUtil.log(context, "AlarmReceiver");
|
||||
final String provider = LocationManager.NETWORK_PROVIDER;
|
||||
if (mLocationManager.isProviderEnabled(provider)) {
|
||||
final Location location = mLocationManager.getLastKnownLocation(provider);
|
||||
if (location != null) {
|
||||
SpiceProfilingUtil.profile(SpiceService.this, SpiceProfilingUtil.FILE_NAME_LOCATION, location.getTime() + ","
|
||||
+ location.getLatitude() + "," + location.getLongitude() + "," + location.getProvider());
|
||||
SpiceProfilingUtil.log(context,
|
||||
location.getTime() + "," + location.getLatitude() + "," + location.getLongitude() + ","
|
||||
+ location.getProvider());
|
||||
SpiceProfilingUtil.profile(SpiceService.this, SpiceProfilingUtil.FILE_NAME_NETWORK, NetworkStateUtil.getConnectedType(SpiceService.this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import static org.mariotaku.twidere.annotation.Preference.Type.STRING;
|
|||
public interface Constants extends TwidereConstants {
|
||||
|
||||
String DATABASES_NAME = "twidere.sqlite";
|
||||
int DATABASES_VERSION = 96;
|
||||
int DATABASES_VERSION = 97;
|
||||
|
||||
int MENU_GROUP_STATUS_EXTENSION = 10;
|
||||
int MENU_GROUP_COMPOSE_EXTENSION = 11;
|
||||
|
|
|
@ -90,6 +90,7 @@ import com.twitter.Extractor;
|
|||
import org.mariotaku.dynamicgridview.DraggableArrayAdapter;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants;
|
||||
import org.mariotaku.twidere.fragment.support.BaseSupportDialogFragment;
|
||||
import org.mariotaku.twidere.fragment.support.ViewStatusDialogFragment;
|
||||
import org.mariotaku.twidere.model.DraftItem;
|
||||
|
@ -108,6 +109,7 @@ import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
|||
import org.mariotaku.twidere.util.ContentValuesCreator;
|
||||
import org.mariotaku.twidere.util.MathUtils;
|
||||
import org.mariotaku.twidere.util.MediaLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
|
@ -271,97 +273,6 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
public boolean handleMenuItem(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_TAKE_PHOTO:
|
||||
case R.id.take_photo_sub_item: {
|
||||
takePhoto();
|
||||
break;
|
||||
}
|
||||
case MENU_ADD_IMAGE:
|
||||
case R.id.add_image_sub_item: {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || !openDocument()) {
|
||||
pickImage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MENU_ADD_LOCATION: {
|
||||
toggleLocation();
|
||||
break;
|
||||
}
|
||||
case MENU_DRAFTS: {
|
||||
startActivity(new Intent(INTENT_ACTION_DRAFTS));
|
||||
break;
|
||||
}
|
||||
case MENU_DELETE: {
|
||||
AsyncTaskUtils.executeTask(new DeleteImageTask(this));
|
||||
break;
|
||||
}
|
||||
case MENU_TOGGLE_SENSITIVE: {
|
||||
if (!hasMedia()) return false;
|
||||
mIsPossiblySensitive = !mIsPossiblySensitive;
|
||||
setMenu();
|
||||
updateTextCount();
|
||||
break;
|
||||
}
|
||||
case MENU_VIEW: {
|
||||
if (mInReplyToStatus == null) return false;
|
||||
final DialogFragment fragment = new ViewStatusDialogFragment();
|
||||
final Bundle args = new Bundle();
|
||||
args.putParcelable(EXTRA_STATUS, mInReplyToStatus);
|
||||
fragment.setArguments(args);
|
||||
fragment.show(getSupportFragmentManager(), "view_status");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
final Intent intent = item.getIntent();
|
||||
if (intent != null) {
|
||||
try {
|
||||
final String action = intent.getAction();
|
||||
if (INTENT_ACTION_EXTENSION_COMPOSE.equals(action)) {
|
||||
final long[] accountIds = mAccountsAdapter.getSelectedAccountIds();
|
||||
intent.putExtra(EXTRA_TEXT, ParseUtils.parseString(mEditText.getText()));
|
||||
intent.putExtra(EXTRA_ACCOUNT_IDS, accountIds);
|
||||
if (accountIds.length > 0) {
|
||||
final long account_id = accountIds[0];
|
||||
intent.putExtra(EXTRA_NAME, getAccountName(this, account_id));
|
||||
intent.putExtra(EXTRA_SCREEN_NAME, getAccountScreenName(this, account_id));
|
||||
}
|
||||
if (mInReplyToStatusId > 0) {
|
||||
intent.putExtra(EXTRA_IN_REPLY_TO_ID, mInReplyToStatusId);
|
||||
}
|
||||
if (mInReplyToStatus != null) {
|
||||
intent.putExtra(EXTRA_IN_REPLY_TO_NAME, mInReplyToStatus.user_name);
|
||||
intent.putExtra(EXTRA_IN_REPLY_TO_SCREEN_NAME, mInReplyToStatus.user_screen_name);
|
||||
}
|
||||
startActivityForResult(intent, REQUEST_EXTENSION_COMPOSE);
|
||||
} else if (INTENT_ACTION_EXTENSION_EDIT_IMAGE.equals(action)) {
|
||||
// final ComponentName cmp = intent.getComponent();
|
||||
// if (cmp == null || !hasMedia()) return false;
|
||||
// final String name = new
|
||||
// File(mMediaUri.getPath()).getName();
|
||||
// final Uri data =
|
||||
// Uri.withAppendedPath(CacheFiles.CONTENT_URI,
|
||||
// Uri.encode(name));
|
||||
// intent.setData(data);
|
||||
// grantUriPermission(cmp.getPackageName(), data,
|
||||
// Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
// startActivityForResult(intent,
|
||||
// REQUEST_EDIT_IMAGE);
|
||||
} else {
|
||||
startActivity(intent);
|
||||
}
|
||||
} catch (final ActivityNotFoundException e) {
|
||||
Log.w(LOGTAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void toggleLocation() {
|
||||
final boolean attachLocation = mPreferences.getBoolean(KEY_ATTACH_LOCATION, false);
|
||||
|
@ -556,7 +467,100 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
|
||||
@Override
|
||||
public boolean onMenuItemClick(final MenuItem item) {
|
||||
return handleMenuItem(item);
|
||||
switch (item.getItemId()) {
|
||||
case MENU_TAKE_PHOTO:
|
||||
case R.id.take_photo_sub_item: {
|
||||
takePhoto();
|
||||
break;
|
||||
}
|
||||
case MENU_ADD_IMAGE:
|
||||
case R.id.add_image_sub_item: {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || !openDocument()) {
|
||||
pickImage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MENU_ADD_LOCATION: {
|
||||
toggleLocation();
|
||||
break;
|
||||
}
|
||||
case MENU_DRAFTS: {
|
||||
startActivity(new Intent(INTENT_ACTION_DRAFTS));
|
||||
break;
|
||||
}
|
||||
case MENU_DELETE: {
|
||||
AsyncTaskUtils.executeTask(new DeleteImageTask(this));
|
||||
break;
|
||||
}
|
||||
case MENU_TOGGLE_SENSITIVE: {
|
||||
if (!hasMedia()) return false;
|
||||
mIsPossiblySensitive = !mIsPossiblySensitive;
|
||||
setMenu();
|
||||
updateTextCount();
|
||||
break;
|
||||
}
|
||||
case MENU_VIEW: {
|
||||
if (mInReplyToStatus == null) return false;
|
||||
final DialogFragment fragment = new ViewStatusDialogFragment();
|
||||
final Bundle args = new Bundle();
|
||||
args.putParcelable(EXTRA_STATUS, mInReplyToStatus);
|
||||
fragment.setArguments(args);
|
||||
fragment.show(getSupportFragmentManager(), "view_status");
|
||||
break;
|
||||
}
|
||||
case R.id.link_to_quoted_status: {
|
||||
final boolean newValue = !item.isChecked();
|
||||
item.setChecked(newValue);
|
||||
mPreferences.edit().putBoolean(KEY_LINK_TO_QUOTED_TWEET, newValue).apply();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
final Intent intent = item.getIntent();
|
||||
if (intent != null) {
|
||||
try {
|
||||
final String action = intent.getAction();
|
||||
if (INTENT_ACTION_EXTENSION_COMPOSE.equals(action)) {
|
||||
final long[] accountIds = mAccountsAdapter.getSelectedAccountIds();
|
||||
intent.putExtra(EXTRA_TEXT, ParseUtils.parseString(mEditText.getText()));
|
||||
intent.putExtra(EXTRA_ACCOUNT_IDS, accountIds);
|
||||
if (accountIds.length > 0) {
|
||||
final long account_id = accountIds[0];
|
||||
intent.putExtra(EXTRA_NAME, getAccountName(this, account_id));
|
||||
intent.putExtra(EXTRA_SCREEN_NAME, getAccountScreenName(this, account_id));
|
||||
}
|
||||
if (mInReplyToStatusId > 0) {
|
||||
intent.putExtra(EXTRA_IN_REPLY_TO_ID, mInReplyToStatusId);
|
||||
}
|
||||
if (mInReplyToStatus != null) {
|
||||
intent.putExtra(EXTRA_IN_REPLY_TO_NAME, mInReplyToStatus.user_name);
|
||||
intent.putExtra(EXTRA_IN_REPLY_TO_SCREEN_NAME, mInReplyToStatus.user_screen_name);
|
||||
}
|
||||
startActivityForResult(intent, REQUEST_EXTENSION_COMPOSE);
|
||||
} else if (INTENT_ACTION_EXTENSION_EDIT_IMAGE.equals(action)) {
|
||||
// final ComponentName cmp = intent.getComponent();
|
||||
// if (cmp == null || !hasMedia()) return false;
|
||||
// final String name = new
|
||||
// File(mMediaUri.getPath()).getName();
|
||||
// final Uri data =
|
||||
// Uri.withAppendedPath(CacheFiles.CONTENT_URI,
|
||||
// Uri.encode(name));
|
||||
// intent.setData(data);
|
||||
// grantUriPermission(cmp.getPackageName(), data,
|
||||
// Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
// startActivityForResult(intent,
|
||||
// REQUEST_EDIT_IMAGE);
|
||||
} else {
|
||||
startActivity(intent);
|
||||
}
|
||||
} catch (final ActivityNotFoundException e) {
|
||||
Log.w(LOGTAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -618,7 +622,8 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
// requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
super.onCreate(savedInstanceState);
|
||||
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
mPreferences = SharedPreferencesWrapper.getInstance(this, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
mPreferences = SharedPreferencesWrapper.getInstance(this, SHARED_PREFERENCES_NAME,
|
||||
Context.MODE_PRIVATE, SharedPreferenceConstants.class);
|
||||
|
||||
final TwidereApplication app = TwidereApplication.getInstance(this);
|
||||
mTwitterWrapper = app.getTwitterWrapper();
|
||||
|
@ -638,7 +643,7 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
}
|
||||
// mMenuBar.setIsBottomBar(true);
|
||||
mMenuBar.setOnMenuItemClickListener(this);
|
||||
mEditText.setOnEditorActionListener(mPreferences.getBoolean(KEY_QUICK_SEND, false) ? this : null);
|
||||
mEditText.setOnEditorActionListener(mPreferences.getBoolean(KEY_QUICK_SEND) ? this : null);
|
||||
mEditText.addTextChangedListener(this);
|
||||
mEditText.setCustomSelectionActionModeCallback(this);
|
||||
mAccountSelectorContainer.setOnClickListener(this);
|
||||
|
@ -794,7 +799,7 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
*/
|
||||
private boolean startLocationUpdateIfEnabled() {
|
||||
final LocationManager lm = mLocationManager;
|
||||
final boolean attachLocation = mPreferences.getBoolean(KEY_ATTACH_LOCATION, false);
|
||||
final boolean attachLocation = mPreferences.getBoolean(KEY_ATTACH_LOCATION);
|
||||
if (!attachLocation) {
|
||||
lm.removeUpdates(this);
|
||||
return false;
|
||||
|
@ -986,9 +991,8 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
}
|
||||
|
||||
private boolean isQuotingProtectedStatus() {
|
||||
if (INTENT_ACTION_QUOTE.equals(getIntent().getAction()) && mInReplyToStatus != null)
|
||||
return mInReplyToStatus.user_is_protected && mInReplyToStatus.account_id != mInReplyToStatus.user_id;
|
||||
return false;
|
||||
if (!isQuote() || mInReplyToStatus == null) return false;
|
||||
return mInReplyToStatus.user_is_protected && mInReplyToStatus.account_id != mInReplyToStatus.user_id;
|
||||
}
|
||||
|
||||
private boolean noReplyContent(final String text) {
|
||||
|
@ -1076,20 +1080,19 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
* Has media & Not reply: [Take photo][Media menu][Attach location][Drafts]
|
||||
* Is reply: [Media menu][View status][Attach location][Drafts]
|
||||
*/
|
||||
Utils.setMenuItemAvailability(menu, MENU_TAKE_PHOTO, !hasInReplyTo);
|
||||
Utils.setMenuItemAvailability(menu, R.id.take_photo_sub_item, hasInReplyTo);
|
||||
Utils.setMenuItemAvailability(menu, MENU_ADD_IMAGE, !hasMedia && !hasInReplyTo);
|
||||
Utils.setMenuItemAvailability(menu, MENU_VIEW, hasInReplyTo);
|
||||
Utils.setMenuItemAvailability(menu, R.id.media_menu, hasMedia || hasInReplyTo);
|
||||
Utils.setMenuItemAvailability(menu, MENU_TOGGLE_SENSITIVE, hasMedia);
|
||||
Utils.setMenuItemAvailability(menu, MENU_EDIT_MEDIA, hasMedia);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_TAKE_PHOTO, !hasInReplyTo);
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.take_photo_sub_item, hasInReplyTo);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_ADD_IMAGE, !hasMedia && !hasInReplyTo);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_VIEW, hasInReplyTo);
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.media_menu, hasMedia || hasInReplyTo);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_TOGGLE_SENSITIVE, hasMedia);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_EDIT_MEDIA, hasMedia);
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.link_to_quoted_status, isQuote());
|
||||
|
||||
menu.setGroupEnabled(MENU_GROUP_IMAGE_EXTENSION, hasMedia);
|
||||
menu.setGroupVisible(MENU_GROUP_IMAGE_EXTENSION, hasMedia);
|
||||
final MenuItem itemToggleSensitive = menu.findItem(MENU_TOGGLE_SENSITIVE);
|
||||
if (itemToggleSensitive != null) {
|
||||
itemToggleSensitive.setChecked(hasMedia && mIsPossiblySensitive);
|
||||
}
|
||||
MenuUtils.setMenuItemChecked(menu, MENU_TOGGLE_SENSITIVE, hasMedia && mIsPossiblySensitive);
|
||||
MenuUtils.setMenuItemChecked(menu, R.id.link_to_quoted_status, mPreferences.getBoolean(KEY_LINK_TO_QUOTED_TWEET));
|
||||
ThemeUtils.resetCheatSheet(mMenuBar);
|
||||
// mMenuBar.show();
|
||||
}
|
||||
|
@ -1152,7 +1155,7 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
// setRecentLocation();
|
||||
// }
|
||||
final long[] accountIds = mAccountsAdapter.getSelectedAccountIds();
|
||||
final boolean isQuote = INTENT_ACTION_QUOTE.equals(getIntent().getAction());
|
||||
final boolean isQuote = isQuote();
|
||||
final ParcelableLocation statusLocation = attachLocation ? mRecentLocation : null;
|
||||
final boolean linkToQuotedTweet = mPreferences.getBoolean(KEY_LINK_TO_QUOTED_TWEET, true);
|
||||
final long inReplyToStatusId = !isQuote || linkToQuotedTweet ? mInReplyToStatusId : -1;
|
||||
|
@ -1183,6 +1186,10 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isQuote() {
|
||||
return INTENT_ACTION_QUOTE.equals(getIntent().getAction());
|
||||
}
|
||||
|
||||
private void updateTextCount() {
|
||||
if (mSendTextCountView == null || mEditText == null) return;
|
||||
final String textOrig = parseString(mEditText.getText());
|
||||
|
|
|
@ -66,6 +66,7 @@ import org.mariotaku.twidere.loader.support.TileImageLoader.Result;
|
|||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.model.ParcelableMedia.VideoInfo.Variant;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.SaveImageTask;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
@ -370,6 +371,7 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
final MediaViewerActivity activity = (MediaViewerActivity) getActivity();
|
||||
if (activity == null) return;
|
||||
activity.toggleBar();
|
||||
}
|
||||
|
||||
|
@ -440,9 +442,9 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
|
|||
final Object imageTag = mImageView.getTag();
|
||||
final boolean isLoading = getLoaderManager().hasRunningLoaders();
|
||||
final boolean hasImage = imageTag instanceof File;
|
||||
Utils.setMenuItemAvailability(menu, R.id.refresh, !hasImage && !isLoading);
|
||||
Utils.setMenuItemAvailability(menu, R.id.share, hasImage && !isLoading);
|
||||
Utils.setMenuItemAvailability(menu, R.id.save, hasImage && !isLoading);
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.refresh, !hasImage && !isLoading);
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.share, hasImage && !isLoading);
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.save, hasImage && !isLoading);
|
||||
if (hasImage) {
|
||||
final MenuItem shareItem = menu.findItem(R.id.share);
|
||||
final ShareActionProvider shareProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);
|
||||
|
|
|
@ -377,7 +377,8 @@ public class SignInActivity extends BaseActionBarActivity implements TwitterCons
|
|||
cb.setOAuthBaseURL(Utils.getApiUrl(apiUrlFormat, "api", "/oauth/"));
|
||||
cb.setUploadBaseURL(Utils.getApiUrl(apiUrlFormat, "upload", versionSuffix));
|
||||
cb.setOAuthAuthorizationURL(Utils.getApiUrl(apiUrlFormat, null, "/oauth/authorize"));
|
||||
cb.setHttpUserAgent(Utils.generateBrowserUserAgent());
|
||||
final String userAgent = TwidereApplication.getInstance(this).getDefaultUserAgent();
|
||||
cb.setHttpUserAgent(userAgent);
|
||||
if (!mSameOAuthSigningUrl) {
|
||||
cb.setSigningRestBaseURL(DEFAULT_SIGNING_REST_BASE_URL);
|
||||
cb.setSigningOAuthBaseURL(DEFAULT_SIGNING_OAUTH_BASE_URL);
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.mariotaku.twidere.Constants;
|
|||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.iface.IContentCardAdapter;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.fragment.support.DirectMessagesFragment;
|
||||
import org.mariotaku.twidere.model.StringLongPair;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries;
|
||||
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
||||
|
@ -90,6 +89,10 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
|
|||
};
|
||||
}
|
||||
|
||||
public void onUserProfileClick(int position) {
|
||||
mListener.onUserClick(position, getEntry(position));
|
||||
}
|
||||
|
||||
public void updateReadState() {
|
||||
mPositionPairs = mReadStateManager.getPositionPairs(TAB_TYPE_DIRECT_MESSAGES);
|
||||
notifyDataSetChanged();
|
||||
|
@ -284,7 +287,9 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
|
|||
}
|
||||
|
||||
public interface MessageEntriesAdapterListener {
|
||||
public void onEntryClick(int position, DirectMessageEntry entry);
|
||||
void onEntryClick(int position, DirectMessageEntry entry);
|
||||
|
||||
void onUserClick(int position, DirectMessageEntry entry);
|
||||
}
|
||||
|
||||
public static class DirectMessageEntry {
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.mariotaku.twidere.util.MessagesManager;
|
|||
import org.mariotaku.twidere.util.MultiSelectManager;
|
||||
import org.mariotaku.twidere.util.ReadStateManager;
|
||||
import org.mariotaku.twidere.util.StrictModeUtils;
|
||||
import org.mariotaku.twidere.util.UserAgentUtils;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.VideoLoader;
|
||||
import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper;
|
||||
|
@ -97,11 +98,17 @@ public class TwidereApplication extends MultiDexApplication implements Constants
|
|||
private VideoLoader mVideoLoader;
|
||||
private ReadStateManager mReadStateManager;
|
||||
|
||||
private String mDefaultUserAgent;
|
||||
|
||||
public AsyncTaskManager getAsyncTaskManager() {
|
||||
if (mAsyncTaskManager != null) return mAsyncTaskManager;
|
||||
return mAsyncTaskManager = AsyncTaskManager.getInstance();
|
||||
}
|
||||
|
||||
public String getDefaultUserAgent() {
|
||||
return mDefaultUserAgent;
|
||||
}
|
||||
|
||||
public DiskCache getDiskCache() {
|
||||
if (mDiskCache != null) return mDiskCache;
|
||||
return mDiskCache = createDiskCache(DIR_NAME_IMAGE_CACHE);
|
||||
|
@ -204,6 +211,7 @@ public class TwidereApplication extends MultiDexApplication implements Constants
|
|||
StrictModeUtils.detectAllVmPolicy();
|
||||
}
|
||||
super.onCreate();
|
||||
mDefaultUserAgent = UserAgentUtils.getDefaultUserAgentString(this);
|
||||
mHandler = new Handler();
|
||||
mMessageBus = new Bus();
|
||||
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
|
||||
|
@ -234,6 +242,8 @@ public class TwidereApplication extends MultiDexApplication implements Constants
|
|||
migrateUsageStatisticsPreferences();
|
||||
startUsageStatisticsServiceIfNeeded(this);
|
||||
startRefreshServiceIfNeeded(this);
|
||||
|
||||
reloadConnectivitySettings();
|
||||
}
|
||||
|
||||
private void migrateUsageStatisticsPreferences() {
|
||||
|
|
|
@ -39,8 +39,8 @@ import org.mariotaku.twidere.R;
|
|||
import org.mariotaku.twidere.adapter.ExtensionsAdapter;
|
||||
import org.mariotaku.twidere.loader.ExtensionsListLoader;
|
||||
import org.mariotaku.twidere.loader.ExtensionsListLoader.ExtensionInfo;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.PermissionsManager;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -104,9 +104,9 @@ public class ExtensionsListFragment extends BaseListFragment implements Constant
|
|||
if (extensionInfo.pname != null && extensionInfo.settings != null) {
|
||||
final Intent intent = new Intent(INTENT_ACTION_EXTENSION_SETTINGS);
|
||||
intent.setClassName(extensionInfo.pname, extensionInfo.settings);
|
||||
Utils.setMenuItemAvailability(menu, MENU_SETTINGS, mPackageManager.queryIntentActivities(intent, 0).size() == 1);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_SETTINGS, mPackageManager.queryIntentActivities(intent, 0).size() == 1);
|
||||
} else {
|
||||
Utils.setMenuItemAvailability(menu, MENU_SETTINGS, false);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_SETTINGS, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,6 +66,32 @@ public class HostMappingsListFragment extends BaseListFragment implements MultiC
|
|||
private HostMappingAdapter mAdapter;
|
||||
private SharedPreferences mPreferences;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
mPreferences = getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
mPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
mAdapter = new HostMappingAdapter(getActivity());
|
||||
setListAdapter(mAdapter);
|
||||
mListView = getListView();
|
||||
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||
mListView.setMultiChoiceModeListener(this);
|
||||
reloadHostMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
|
||||
mode.getMenuInflater().inflate(R.menu.action_multi_select_items, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
|
||||
updateTitle(mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
|
@ -90,40 +116,14 @@ public class HostMappingsListFragment extends BaseListFragment implements MultiC
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
mPreferences = getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
mPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
mAdapter = new HostMappingAdapter(getActivity());
|
||||
setListAdapter(mAdapter);
|
||||
mListView = getListView();
|
||||
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||
mListView.setMultiChoiceModeListener(this);
|
||||
reloadHostMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
|
||||
mode.getMenuInflater().inflate(R.menu.action_multi_select_items, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_host_mapping, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(final ActionMode mode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemCheckedStateChanged(final ActionMode mode, final int position, final long id,
|
||||
final boolean checked) {
|
||||
updateTitle(mode);
|
||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_host_mapping, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -138,9 +138,9 @@ public class HostMappingsListFragment extends BaseListFragment implements MultiC
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
|
||||
public void onItemCheckedStateChanged(final ActionMode mode, final int position, final long id,
|
||||
final boolean checked) {
|
||||
updateTitle(mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -169,14 +169,25 @@ public class HostMappingsListFragment extends BaseListFragment implements MultiC
|
|||
private EditText mEditHost, mEditAddress;
|
||||
private CheckBox mCheckExclude;
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
updateButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
updateAddressField();
|
||||
updateButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -237,9 +248,8 @@ public class HostMappingsListFragment extends BaseListFragment implements MultiC
|
|||
updateButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
updateButton();
|
||||
private void updateAddressField() {
|
||||
mEditAddress.setVisibility(mCheckExclude.isChecked() ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
private void updateButton() {
|
||||
|
@ -250,16 +260,6 @@ public class HostMappingsListFragment extends BaseListFragment implements MultiC
|
|||
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
positiveButton.setEnabled(hostValid && addressValid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
updateAddressField();
|
||||
updateButton();
|
||||
}
|
||||
|
||||
private void updateAddressField() {
|
||||
mEditAddress.setVisibility(mCheckExclude.isChecked() ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
static class HostMappingAdapter extends ArrayAdapter<String> {
|
||||
|
|
|
@ -19,8 +19,205 @@
|
|||
|
||||
package org.mariotaku.twidere.fragment;
|
||||
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
import android.content.AsyncTaskLoader;
|
||||
import android.content.Context;
|
||||
import android.content.Loader;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Bundle;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.ActionMode;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView.MultiChoiceModeListener;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.ArrayAdapter;
|
||||
import org.mariotaku.twidere.model.KeyboardShortcutSpec;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/10.
|
||||
*/
|
||||
public class KeyboardShortcutsFragment extends BaseListFragment {
|
||||
public class KeyboardShortcutsFragment extends BaseListFragment implements LoaderCallbacks<List<KeyboardShortcutSpec>>, MultiChoiceModeListener {
|
||||
|
||||
private Adapter mAdapter;
|
||||
private ListView mListView;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
mAdapter = new Adapter(getActivity());
|
||||
setListAdapter(mAdapter);
|
||||
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||
mListView.setMultiChoiceModeListener(this);
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
setListShown(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
mode.getMenuInflater().inflate(R.menu.action_multi_select_items, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
updateTitle(mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_DELETE: {
|
||||
final SharedPreferences.Editor editor = getSharedPreferences(KEYBOARD_SHORTCUTS_PREFERENCES_NAME, Context.MODE_PRIVATE).edit();
|
||||
final SparseBooleanArray array = mListView.getCheckedItemPositions();
|
||||
if (array == null) return false;
|
||||
for (int i = 0, size = array.size(); i < size; i++) {
|
||||
if (array.valueAt(i)) {
|
||||
editor.remove(mAdapter.getItem(i).getRawKey());
|
||||
}
|
||||
}
|
||||
editor.apply();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mode.finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<List<KeyboardShortcutSpec>> onCreateLoader(int id, Bundle args) {
|
||||
return new KeyboardShortcutSpecsLoader(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<List<KeyboardShortcutSpec>> loader, List<KeyboardShortcutSpec> data) {
|
||||
mAdapter.clear();
|
||||
mAdapter.addAll(data);
|
||||
setListShown(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<List<KeyboardShortcutSpec>> loader) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_keyboard_shortcuts, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ADD: {
|
||||
final SharedPreferences preferences = getSharedPreferences(KEYBOARD_SHORTCUTS_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
final Editor editor = preferences.edit();
|
||||
editor.putString("ctrl+m", "compose");
|
||||
editor.apply();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mListView = getListView();
|
||||
}
|
||||
|
||||
private void updateTitle(final ActionMode mode) {
|
||||
if (mListView == null || mode == null || getActivity() == null) return;
|
||||
final int count = mListView.getCheckedItemCount();
|
||||
mode.setTitle(getResources().getQuantityString(R.plurals.Nitems_selected, count, count));
|
||||
}
|
||||
|
||||
private static class Adapter extends ArrayAdapter<KeyboardShortcutSpec> {
|
||||
|
||||
public Adapter(Context context) {
|
||||
super(context, android.R.layout.simple_list_item_activated_2);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View getView(final int position, final View convertView, final ViewGroup parent) {
|
||||
final View view = super.getView(position, convertView, parent);
|
||||
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
|
||||
final TextView text2 = (TextView) view.findViewById(android.R.id.text2);
|
||||
final KeyboardShortcutSpec spec = getItem(position);
|
||||
text1.setText(spec.getValueName(getContext()));
|
||||
text2.setText(spec.toKeyString());
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class KeyboardShortcutSpecsLoader extends AsyncTaskLoader<List<KeyboardShortcutSpec>> {
|
||||
private final SharedPreferences preferences;
|
||||
private final OnSharedPreferenceChangeListener changeListener = new OnSharedPreferenceChangeListener() {
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
forceLoad();
|
||||
}
|
||||
};
|
||||
|
||||
public KeyboardShortcutSpecsLoader(Context context) {
|
||||
super(context);
|
||||
preferences = context.getSharedPreferences(KEYBOARD_SHORTCUTS_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
preferences.registerOnSharedPreferenceChangeListener(changeListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyboardShortcutSpec> loadInBackground() {
|
||||
final ArrayList<KeyboardShortcutSpec> list = new ArrayList<>();
|
||||
for (Entry<String, ?> entry : preferences.getAll().entrySet()) {
|
||||
final KeyboardShortcutSpec spec = new KeyboardShortcutSpec(entry.getKey(), ParseUtils.parseString(entry.getValue()));
|
||||
if (spec.isValid()) {
|
||||
list.add(spec);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
if (isAbandoned()) {
|
||||
preferences.unregisterOnSharedPreferenceChangeListener(changeListener);
|
||||
}
|
||||
super.onReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -509,7 +509,7 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
|
|||
final int swipeStart = (mSystemWindowsInsets.top - mControlBarOffsetPixels) - progressCircleDiameter;
|
||||
// 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET
|
||||
final int swipeDistance = Math.round(64 * density);
|
||||
mSwipeRefreshLayout.setProgressViewOffset(true, swipeStart, swipeStart + swipeDistance);
|
||||
mSwipeRefreshLayout.setProgressViewOffset(false, swipeStart, swipeStart + swipeDistance);
|
||||
}
|
||||
|
||||
protected final class StatusesBusCallback {
|
||||
|
|
|
@ -75,7 +75,6 @@ import org.mariotaku.twidere.util.ThemeUtils;
|
|||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver;
|
||||
import org.mariotaku.twidere.util.message.GetMessagesTaskEvent;
|
||||
import org.mariotaku.twidere.util.message.TaskStateChangedEvent;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -157,27 +156,14 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
|
|||
Utils.openMessageConversation(getActivity(), entry.account_id, entry.conversation_id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserClick(int position, DirectMessageEntry entry) {
|
||||
Utils.openUserProfile(getActivity(), entry.account_id, entry.conversation_id, entry.screen_name, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
AsyncTaskUtils.executeTask(new AsyncTask<Object, Object, long[][]>() {
|
||||
|
||||
@Override
|
||||
protected long[][] doInBackground(final Object... params) {
|
||||
final long[][] result = new long[2][];
|
||||
result[0] = Utils.getActivatedAccountIds(getActivity());
|
||||
result[1] = Utils.getNewestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final long[][] result) {
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
if (twitter == null) return;
|
||||
twitter.getReceivedDirectMessagesAsync(result[0], null, result[1]);
|
||||
twitter.getSentDirectMessagesAsync(result[0], null, null);
|
||||
}
|
||||
|
||||
});
|
||||
triggerRefresh();
|
||||
}
|
||||
|
||||
private void setListShown(boolean shown) {
|
||||
|
@ -315,6 +301,25 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
|
|||
|
||||
@Override
|
||||
public boolean triggerRefresh() {
|
||||
AsyncTaskUtils.executeTask(new AsyncTask<Object, Object, long[][]>() {
|
||||
|
||||
@Override
|
||||
protected long[][] doInBackground(final Object... params) {
|
||||
final long[][] result = new long[2][];
|
||||
result[0] = Utils.getActivatedAccountIds(getActivity());
|
||||
result[1] = Utils.getNewestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final long[][] result) {
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
if (twitter == null) return;
|
||||
twitter.getReceivedDirectMessagesAsync(result[0], null, result[1]);
|
||||
twitter.getSentDirectMessagesAsync(result[0], null, null);
|
||||
}
|
||||
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ public class RetweetQuoteDialogFragment extends BaseSupportDialogFragment implem
|
|||
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
|
||||
final Context context = builder.getContext();
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
@SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.dialog_scrollable_status, null);
|
||||
@SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.dialog_status_quote_retweet, null);
|
||||
final StatusViewHolder holder = new StatusViewHolder(new DummyStatusHolderAdapter(context), view.findViewById(R.id.item_content));
|
||||
final ParcelableStatus status = getStatus();
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ import org.mariotaku.twidere.util.CompareUtils;
|
|||
import org.mariotaku.twidere.util.ImageLoadingHandler;
|
||||
import org.mariotaku.twidere.util.LinkCreator;
|
||||
import org.mariotaku.twidere.util.MediaLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
|
||||
import org.mariotaku.twidere.util.StatusAdapterLinkClickHandler;
|
||||
import org.mariotaku.twidere.util.StatusLinkClickHandler;
|
||||
|
@ -792,8 +793,8 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
}
|
||||
case R.id.retweeted_by_container: {
|
||||
if (status.retweet_id > 0) {
|
||||
Utils.openUserProfile(adapter.getContext(), status.account_id, status.user_id,
|
||||
status.user_screen_name, null);
|
||||
Utils.openUserProfile(adapter.getContext(), status.account_id, status.retweeted_by_id,
|
||||
status.retweeted_by_screen_name, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -884,7 +885,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
final SpannableString string = SpannableString.valueOf(textView.getText());
|
||||
final URLSpan[] spans = string.getSpans(start, end, URLSpan.class);
|
||||
final boolean avail = spans.length == 1 && URLUtil.isValidUrl(spans[0].getURL());
|
||||
Utils.setMenuItemAvailability(menu, android.R.id.copyUrl, avail);
|
||||
MenuUtils.setMenuItemAvailability(menu, android.R.id.copyUrl, avail);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ import org.mariotaku.twidere.util.ContentValuesCreator;
|
|||
import org.mariotaku.twidere.util.LinkCreator;
|
||||
import org.mariotaku.twidere.util.MathUtils;
|
||||
import org.mariotaku.twidere.util.MediaLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
import org.mariotaku.twidere.util.TwidereLinkify;
|
||||
|
@ -139,6 +140,7 @@ import twitter4j.Twitter;
|
|||
import twitter4j.TwitterException;
|
||||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
import static org.mariotaku.twidere.util.MenuUtils.setMenuItemAvailability;
|
||||
import static org.mariotaku.twidere.util.ParseUtils.parseLong;
|
||||
import static org.mariotaku.twidere.util.UserColorNameUtils.clearUserColor;
|
||||
import static org.mariotaku.twidere.util.UserColorNameUtils.clearUserNickname;
|
||||
|
@ -162,7 +164,6 @@ import static org.mariotaku.twidere.util.Utils.openUserFollowers;
|
|||
import static org.mariotaku.twidere.util.Utils.openUserFriends;
|
||||
import static org.mariotaku.twidere.util.Utils.openUserLists;
|
||||
import static org.mariotaku.twidere.util.Utils.openUserProfile;
|
||||
import static org.mariotaku.twidere.util.Utils.setMenuItemAvailability;
|
||||
import static org.mariotaku.twidere.util.Utils.showInfoMessage;
|
||||
|
||||
public class UserFragment extends BaseSupportFragment implements OnClickListener,
|
||||
|
@ -794,8 +795,8 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
if (mentionItem != null) {
|
||||
mentionItem.setTitle(getString(R.string.mention_user_name, UserColorNameUtils.getDisplayName(getActivity(), user)));
|
||||
}
|
||||
Utils.setMenuItemAvailability(menu, MENU_MENTION, !isMyself);
|
||||
Utils.setMenuItemAvailability(menu, R.id.incoming_friendships, isMyself);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_MENTION, !isMyself);
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.incoming_friendships, isMyself);
|
||||
// final MenuItem followItem = menu.findItem(MENU_FOLLOW);
|
||||
// followItem.setVisible(!isMyself);
|
||||
// final boolean shouldShowFollowItem = !creatingFriendship && !destroyingFriendship && !isMyself
|
||||
|
|
|
@ -93,7 +93,7 @@ import static org.mariotaku.twidere.util.Utils.getAccountColor;
|
|||
import static org.mariotaku.twidere.util.Utils.getTwitterInstance;
|
||||
import static org.mariotaku.twidere.util.Utils.openUserListDetails;
|
||||
import static org.mariotaku.twidere.util.Utils.openUserProfile;
|
||||
import static org.mariotaku.twidere.util.Utils.setMenuItemAvailability;
|
||||
import static org.mariotaku.twidere.util.MenuUtils.setMenuItemAvailability;
|
||||
|
||||
public class UserListFragment extends BaseSupportFragment implements OnClickListener,
|
||||
LoaderCallbacks<SingleResponse<ParcelableUserList>>, DrawerCallback,
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/11.
|
||||
*/
|
||||
public class KeyboardShortcutSpec {
|
||||
|
||||
private String rawKey;
|
||||
private String value;
|
||||
private String contextTag;
|
||||
private int keyMeta;
|
||||
private String keyName;
|
||||
|
||||
public KeyboardShortcutSpec(String key, String value) {
|
||||
rawKey = key;
|
||||
final int contextDotIdx = key.indexOf('.');
|
||||
if (contextDotIdx != -1) {
|
||||
contextTag = key.substring(0, contextDotIdx);
|
||||
}
|
||||
int idx = contextDotIdx, previousIdx = idx;
|
||||
while ((idx = key.indexOf('+', idx + 1)) != -1) {
|
||||
keyMeta |= KeyboardShortcutsHandler.getKeyEventMeta(key.substring(previousIdx + 1, idx));
|
||||
previousIdx = idx;
|
||||
}
|
||||
if (previousIdx != -1) {
|
||||
keyName = key.substring(previousIdx + 1);
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getContextTag() {
|
||||
return contextTag;
|
||||
}
|
||||
|
||||
public int getKeyMeta() {
|
||||
return keyMeta;
|
||||
}
|
||||
|
||||
public String getKeyName() {
|
||||
return keyName;
|
||||
}
|
||||
|
||||
public String getRawKey() {
|
||||
return rawKey;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getValueName(Context context) {
|
||||
return KeyboardShortcutsHandler.getActionLabel(context, value);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return keyName != null;
|
||||
}
|
||||
|
||||
public String toKeyString() {
|
||||
return KeyboardShortcutsHandler.metaToHumanReadableString(keyMeta) + keyName.toUpperCase(Locale.US);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KeyboardShortcutSpec{" +
|
||||
"value='" + value + '\'' +
|
||||
", contextTag='" + contextTag + '\'' +
|
||||
", keyMeta=" + keyMeta +
|
||||
", keyName='" + keyName + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -64,9 +64,6 @@ public class CacheUsersStatusesTask extends AsyncTask<TwitterListResponse<twitte
|
|||
for (int bulkIdx = 0, totalSize = list.size(); bulkIdx < totalSize; bulkIdx += 100) {
|
||||
for (int idx = bulkIdx, end = Math.min(totalSize, bulkIdx + ContentResolverUtils.MAX_BULK_COUNT); idx < end; idx++) {
|
||||
final twitter4j.Status status = list.get(idx);
|
||||
if (status == null || status.getId() <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Set<ContentValues> usersValues = new HashSet<>();
|
||||
final Set<ContentValues> statusesValues = new HashSet<>();
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.mariotaku.twidere.util;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.util.SparseArrayCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
|
@ -17,16 +18,30 @@ import java.util.Set;
|
|||
public class KeyboardShortcutsHandler implements Constants {
|
||||
|
||||
private static final HashMap<String, Integer> sActionLabelMap = new HashMap<>();
|
||||
private static final SparseArrayCompat<String> sMetaNameMap = new SparseArrayCompat<>();
|
||||
|
||||
static {
|
||||
sActionLabelMap.put("compose", R.string.compose);
|
||||
sActionLabelMap.put("search", R.string.search);
|
||||
|
||||
sMetaNameMap.put(KeyEvent.META_FUNCTION_ON, "fn");
|
||||
sMetaNameMap.put(KeyEvent.META_META_ON, "meta");
|
||||
sMetaNameMap.put(KeyEvent.META_CTRL_ON, "ctrl");
|
||||
sMetaNameMap.put(KeyEvent.META_ALT_ON, "alt");
|
||||
sMetaNameMap.put(KeyEvent.META_SHIFT_ON, "shift");
|
||||
}
|
||||
|
||||
private static final String KEYCODE_STRING_PREFIX = "KEYCODE_";
|
||||
private final Context mContext;
|
||||
private final SharedPreferencesWrapper mPreferences;
|
||||
|
||||
public static int getKeyEventMeta(String name) {
|
||||
for (int i = 0, j = sMetaNameMap.size(); i < j; i++) {
|
||||
if (sMetaNameMap.valueAt(i).equalsIgnoreCase(name)) return sMetaNameMap.keyAt(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public KeyboardShortcutsHandler(final Context context) {
|
||||
mContext = context;
|
||||
mPreferences = SharedPreferencesWrapper.getInstance(context, KEYBOARD_SHORTCUTS_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
|
@ -38,6 +53,19 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
return context.getString(labelRes);
|
||||
}
|
||||
|
||||
public static String metaToHumanReadableString(int metaState) {
|
||||
final StringBuilder keyNameBuilder = new StringBuilder();
|
||||
for (int i = 0, j = sMetaNameMap.size(); i < j; i++) {
|
||||
if ((sMetaNameMap.keyAt(i) & metaState) != 0) {
|
||||
final String value = sMetaNameMap.valueAt(i);
|
||||
keyNameBuilder.append(value.substring(0, 1).toUpperCase(Locale.US));
|
||||
keyNameBuilder.append(value.substring(1));
|
||||
keyNameBuilder.append("+");
|
||||
}
|
||||
}
|
||||
return keyNameBuilder.toString();
|
||||
}
|
||||
|
||||
public static Set<String> getActions() {
|
||||
return sActionLabelMap.keySet();
|
||||
}
|
||||
|
@ -46,16 +74,15 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
final StringBuilder keyNameBuilder = new StringBuilder();
|
||||
if (!TextUtils.isEmpty(contextTag)) {
|
||||
keyNameBuilder.append(contextTag);
|
||||
keyNameBuilder.append("_");
|
||||
keyNameBuilder.append(".");
|
||||
}
|
||||
if (event.isCtrlPressed()) {
|
||||
keyNameBuilder.append("ctrl_");
|
||||
}
|
||||
if (event.isAltPressed()) {
|
||||
keyNameBuilder.append("alt_");
|
||||
}
|
||||
if (event.isShiftPressed()) {
|
||||
keyNameBuilder.append("shift_");
|
||||
final int metaState = KeyEvent.normalizeMetaState(event.getMetaState());
|
||||
|
||||
for (int i = 0, j = sMetaNameMap.size(); i < j; i++) {
|
||||
if ((sMetaNameMap.keyAt(i) & metaState) != 0) {
|
||||
keyNameBuilder.append(sMetaNameMap.valueAt(i));
|
||||
keyNameBuilder.append("+");
|
||||
}
|
||||
}
|
||||
final String keyCodeString = KeyEvent.keyCodeToString(keyCode);
|
||||
if (keyCodeString.startsWith(KEYCODE_STRING_PREFIX)) {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.util;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/12.
|
||||
*/
|
||||
public class MenuUtils {
|
||||
public static void setMenuItemAvailability(final Menu menu, final int id, final boolean available) {
|
||||
if (menu == null) return;
|
||||
final MenuItem item = menu.findItem(id);
|
||||
if (item == null) return;
|
||||
item.setVisible(available);
|
||||
item.setEnabled(available);
|
||||
}
|
||||
|
||||
public static void setMenuItemChecked(final Menu menu, final int id, final boolean checked) {
|
||||
if (menu == null) return;
|
||||
final MenuItem item = menu.findItem(id);
|
||||
if (item == null) return;
|
||||
item.setChecked(checked);
|
||||
}
|
||||
|
||||
public static void setMenuItemIcon(final Menu menu, final int id, final int icon) {
|
||||
if (menu == null) return;
|
||||
final MenuItem item = menu.findItem(id);
|
||||
if (item == null) return;
|
||||
item.setIcon(icon);
|
||||
}
|
||||
|
||||
public static void setMenuItemTitle(final Menu menu, final int id, final int icon) {
|
||||
if (menu == null) return;
|
||||
final MenuItem item = menu.findItem(id);
|
||||
if (item == null) return;
|
||||
item.setTitle(icon);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.util;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/12.
|
||||
*/
|
||||
public class UserAgentUtils {
|
||||
// You may uncomment next line if using Android Annotations library, otherwise just be sure to run it in on the UI thread
|
||||
public static String getDefaultUserAgentString(Context context) {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) throw new IllegalStateException();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return NewApiWrapper.getDefaultUserAgent(context);
|
||||
}
|
||||
|
||||
try {
|
||||
Constructor<WebSettings> constructor = WebSettings.class.getDeclaredConstructor(Context.class, WebView.class);
|
||||
constructor.setAccessible(true);
|
||||
try {
|
||||
WebSettings settings = constructor.newInstance(context, null);
|
||||
return settings.getUserAgentString();
|
||||
} finally {
|
||||
constructor.setAccessible(false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
final WebView webView = new WebView(context);
|
||||
try {
|
||||
return webView.getSettings().getUserAgentString();
|
||||
} finally {
|
||||
webView.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
static class NewApiWrapper {
|
||||
static String getDefaultUserAgent(Context context) {
|
||||
return WebSettings.getDefaultUserAgent(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -281,8 +281,6 @@ import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
|
|||
@SuppressWarnings("unused")
|
||||
public final class Utils implements Constants, TwitterConstants {
|
||||
|
||||
private static final String UA_TEMPLATE = "Mozilla/5.0 (Linux; Android %s; %s Build/%s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.111 Safari/537.36";
|
||||
|
||||
public static final Pattern PATTERN_XML_RESOURCE_IDENTIFIER = Pattern.compile("res/xml/([\\w_]+)\\.xml");
|
||||
|
||||
public static final Pattern PATTERN_RESOURCE_IDENTIFIER = Pattern.compile("@([\\w_]+)/([\\w_]+)");
|
||||
|
@ -1174,8 +1172,7 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
Expression.equals(Statuses.STATUS_ID, statusId)).getSQL();
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
resolver.delete(CachedStatuses.CONTENT_URI, where, null);
|
||||
resolver.insert(CachedStatuses.CONTENT_URI,
|
||||
ContentValuesCreator.createStatus(status, accountId));
|
||||
resolver.insert(CachedStatuses.CONTENT_URI, ContentValuesCreator.createStatus(status, accountId));
|
||||
return new ParcelableStatus(status, accountId, false);
|
||||
}
|
||||
|
||||
|
@ -1252,10 +1249,6 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
return DateUtils.formatDateTime(context, timestamp, format_flags);
|
||||
}
|
||||
|
||||
public static String generateBrowserUserAgent() {
|
||||
return String.format(UA_TEMPLATE, Build.VERSION.RELEASE, Build.MODEL, Build.ID);
|
||||
}
|
||||
|
||||
public static int getAccountColor(final Context context, final long account_id) {
|
||||
if (context == null) return Color.TRANSPARENT;
|
||||
final Integer cached = sAccountColors.get(account_id);
|
||||
|
@ -1586,7 +1579,7 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
|
||||
private static String substituteLegacyApiBaseUrl(@NonNull String format, String domain) {
|
||||
final int startOfHost = format.indexOf("://") + 3, endOfHost = format.indexOf('/', startOfHost);
|
||||
final String host = format.substring(startOfHost, endOfHost);
|
||||
final String host = endOfHost != -1 ? format.substring(startOfHost, endOfHost) : format.substring(startOfHost);
|
||||
if (!host.equalsIgnoreCase("api.twitter.com")) return format;
|
||||
return format.substring(0, startOfHost) + domain + ".twitter.com" + format.substring(endOfHost);
|
||||
}
|
||||
|
@ -1805,7 +1798,7 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
final int timeoutMillis = prefs.getInt(KEY_CONNECTION_TIMEOUT, 10000) * 1000;
|
||||
final Proxy proxy = getProxy(context);
|
||||
final String userAgent = generateBrowserUserAgent();
|
||||
final String userAgent = TwidereApplication.getInstance(context).getDefaultUserAgent();
|
||||
final HostAddressResolverFactory resolverFactory = new TwidereHostResolverFactory(
|
||||
TwidereApplication.getInstance(context));
|
||||
return getHttpClient(context, timeoutMillis, true, proxy, resolverFactory, userAgent, false);
|
||||
|
@ -1816,7 +1809,7 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
final int timeoutMillis = prefs.getInt(KEY_CONNECTION_TIMEOUT, 10000) * 1000;
|
||||
final Proxy proxy = getProxy(context);
|
||||
final String userAgent = generateBrowserUserAgent();
|
||||
final String userAgent = TwidereApplication.getInstance(context).getDefaultUserAgent();
|
||||
final HostAddressResolverFactory resolverFactory = new TwidereHostResolverFactory(
|
||||
TwidereApplication.getInstance(context));
|
||||
return getHttpClient(context, timeoutMillis, true, proxy, resolverFactory, userAgent, false);
|
||||
|
@ -3595,7 +3588,7 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
final boolean isOfficialKey = isOfficialCredentials(context, account);
|
||||
final SharedPreferencesWrapper prefs = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
final boolean forcePrivateApis = prefs.getBoolean(KEY_FORCE_USING_PRIVATE_APIS, false);
|
||||
setMenuItemAvailability(menu, MENU_TRANSLATE, forcePrivateApis || isOfficialKey);
|
||||
MenuUtils.setMenuItemAvailability(menu, MENU_TRANSLATE, forcePrivateApis || isOfficialKey);
|
||||
}
|
||||
menu.removeGroup(MENU_GROUP_STATUS_EXTENSION);
|
||||
addIntentToMenuForExtension(context, menu, MENU_GROUP_STATUS_EXTENSION, INTENT_ACTION_EXTENSION_OPEN_STATUS,
|
||||
|
@ -3616,28 +3609,6 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
|
||||
}
|
||||
|
||||
public static void setMenuItemAvailability(final Menu menu, final int id, final boolean available) {
|
||||
if (menu == null) return;
|
||||
final MenuItem item = menu.findItem(id);
|
||||
if (item == null) return;
|
||||
item.setVisible(available);
|
||||
item.setEnabled(available);
|
||||
}
|
||||
|
||||
public static void setMenuItemIcon(final Menu menu, final int id, final int icon) {
|
||||
if (menu == null) return;
|
||||
final MenuItem item = menu.findItem(id);
|
||||
if (item == null) return;
|
||||
item.setIcon(icon);
|
||||
}
|
||||
|
||||
public static void setMenuItemTitle(final Menu menu, final int id, final int icon) {
|
||||
if (menu == null) return;
|
||||
final MenuItem item = menu.findItem(id);
|
||||
if (item == null) return;
|
||||
item.setTitle(icon);
|
||||
}
|
||||
|
||||
public static void setUserAgent(final Context context, final ConfigurationBuilder cb) {
|
||||
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
final boolean gzipCompressing = prefs.getBoolean(KEY_GZIP_COMPRESSING, true);
|
||||
|
@ -3663,14 +3634,25 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
* @param cb
|
||||
*/
|
||||
public static void setMockOfficialUserAgent(final Context context, final ConfigurationBuilder cb) {
|
||||
cb.setClientVersion("5.32.0");
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
cb.setClientName("TwitterAndroid");
|
||||
cb.setClientURL(null);
|
||||
String versionName;
|
||||
int versionCode;
|
||||
try {
|
||||
final PackageInfo packageInfo = pm.getPackageInfo("com.twitter.android", 0);
|
||||
versionName = packageInfo.versionName;
|
||||
versionCode = packageInfo.versionCode;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
versionName = "5.53.0";
|
||||
versionCode = 4030814;
|
||||
}
|
||||
cb.setClientVersion(versionName);
|
||||
final String deviceInfo = String.format(Locale.ROOT, "%s/%s (%s;%s;%s;%s;)",
|
||||
Build.MODEL, Build.VERSION.RELEASE, Build.MANUFACTURER, Build.MODEL, Build.BRAND,
|
||||
Build.PRODUCT);
|
||||
cb.setHttpUserAgent(String.format(Locale.ROOT, "TwitterAndroid/%s (%d-%c-%d) %s",
|
||||
"5.32.0", 3030745, 'r', 692, deviceInfo));
|
||||
versionName, versionCode, 'r', versionCode / 4200, deviceInfo));
|
||||
}
|
||||
|
||||
public static boolean shouldForceUsingPrivateAPIs(final Context context) {
|
||||
|
|
|
@ -62,6 +62,7 @@ public class MessageEntryViewHolder extends ViewHolder implements OnClickListene
|
|||
|
||||
setTextSize(adapter.getTextSize());
|
||||
itemView.setOnClickListener(this);
|
||||
profileImageView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
public void displayMessage(Cursor cursor, boolean isUnread) {
|
||||
|
@ -101,11 +102,12 @@ public class MessageEntryViewHolder extends ViewHolder implements OnClickListene
|
|||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.profile_image: {
|
||||
adapter.onUserProfileClick(getLayoutPosition());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (v == itemView) {
|
||||
adapter.onMessageClick(getPosition());
|
||||
adapter.onMessageClick(getLayoutPosition());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -183,10 +183,10 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
final int idx = status.quote_text_unescaped.lastIndexOf(" twitter.com");
|
||||
if (adapter.getLinkHighlightingStyle() == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
|
||||
final String text = status.quote_text_unescaped;
|
||||
quoteTextView.setText(idx > 0 ? text.substring(0, idx ) : text);
|
||||
quoteTextView.setText(idx > 0 ? text.substring(0, idx) : text);
|
||||
} else {
|
||||
final Spanned text = Html.fromHtml(status.quote_text_html);
|
||||
quoteTextView.setText(idx > 0 ? text.subSequence(0, idx ) : text);
|
||||
quoteTextView.setText(idx > 0 ? text.subSequence(0, idx) : text);
|
||||
linkify.applyAllLinks(quoteTextView, status.account_id, getLayoutPosition(),
|
||||
status.is_possibly_sensitive, adapter.getLinkHighlightingStyle());
|
||||
quoteTextView.setMovementMethod(null);
|
||||
|
@ -373,10 +373,10 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
final String quote_text_unescaped = cursor.getString(indices.quote_text_unescaped);
|
||||
final int idx = quote_text_unescaped.lastIndexOf(" twitter.com");
|
||||
if (adapter.getLinkHighlightingStyle() == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
|
||||
quoteTextView.setText(idx > 0 ? quote_text_unescaped.substring(0, idx ) : quote_text_unescaped);
|
||||
quoteTextView.setText(idx > 0 ? quote_text_unescaped.substring(0, idx) : quote_text_unescaped);
|
||||
} else {
|
||||
final Spanned text = Html.fromHtml(cursor.getString(indices.quote_text_html));
|
||||
quoteTextView.setText(idx > 0 ? text.subSequence(0, idx ) : text);
|
||||
quoteTextView.setText(idx > 0 ? text.subSequence(0, idx) : text);
|
||||
linkify.applyAllLinks(quoteTextView, account_id, getLayoutPosition(),
|
||||
cursor.getShort(indices.is_possibly_sensitive) == 1,
|
||||
adapter.getLinkHighlightingStyle());
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<menu xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:showAsAction="always"
|
||||
android:id="@id/add"
|
||||
android:icon="@drawable/ic_action_add"
|
||||
android:title="@string/add"
|
||||
tools:ignore="AppCompatResource"/>
|
||||
</menu>
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/status_container"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/element_spacing_normal"
|
||||
android:paddingLeft="@dimen/element_spacing_large"
|
||||
android:paddingRight="@dimen/element_spacing_large">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text"/>
|
||||
|
||||
<include layout="@layout/card_item_status_common"/>
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
|
@ -24,7 +24,8 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:splitMotionEvents="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/retweeted_by_container"
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<item
|
||||
android:id="@id/take_photo"
|
||||
android:icon="@drawable/ic_action_camera"
|
||||
android:title="@string/take_photo"
|
||||
app:showAsAction="always"/>
|
||||
app:showAsAction="always"
|
||||
tools:ignore="AlwaysShowAction"/>
|
||||
<item
|
||||
android:id="@id/add_image"
|
||||
android:icon="@drawable/ic_action_gallery"
|
||||
android:title="@string/add_image"
|
||||
app:showAsAction="always"/>
|
||||
app:showAsAction="always"
|
||||
tools:ignore="AlwaysShowAction"/>
|
||||
<item
|
||||
android:id="@+id/media_menu"
|
||||
android:icon="@drawable/ic_action_gallery"
|
||||
android:title="@string/media"
|
||||
android:visible="false"
|
||||
app:showAsAction="always">
|
||||
app:showAsAction="always"
|
||||
tools:ignore="AlwaysShowAction">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/take_photo_sub_item"
|
||||
|
@ -43,7 +47,8 @@
|
|||
android:icon="@drawable/ic_action_reply"
|
||||
android:title="@string/original_status"
|
||||
android:visible="false"
|
||||
app:showAsAction="always"/>
|
||||
app:showAsAction="always"
|
||||
tools:ignore="AlwaysShowAction"/>
|
||||
<item
|
||||
android:id="@id/add_location"
|
||||
android:checkable="true"
|
||||
|
@ -51,11 +56,19 @@
|
|||
android:icon="@drawable/ic_action_my_location"
|
||||
android:title="@string/location"
|
||||
android:visible="false"
|
||||
app:showAsAction="always"/>
|
||||
app:showAsAction="always"
|
||||
tools:ignore="AlwaysShowAction"/>
|
||||
<item
|
||||
android:id="@id/drafts"
|
||||
android:icon="@drawable/ic_action_draft"
|
||||
android:title="@string/drafts"
|
||||
app:showAsAction="always"/>
|
||||
app:showAsAction="always"
|
||||
tools:ignore="AlwaysShowAction"/>
|
||||
<item
|
||||
android:id="@+id/link_to_quoted_status"
|
||||
android:icon="@drawable/ic_action_link"
|
||||
android:checkable="true"
|
||||
android:title="@string/link_to_quoted_status"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
</menu>
|
|
@ -48,11 +48,6 @@
|
|||
android:summary="@string/quote_format_summary"
|
||||
android:title="@string/quote_format"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="link_to_quoted_tweet"
|
||||
android:title="@string/link_to_quoted_status"/>
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue="[TITLE] - [TEXT]"
|
||||
android:dialogTitle="@string/share_format"
|
||||
|
|
Loading…
Reference in New Issue