implementing keyboard shortcut

removed some unused sources
This commit is contained in:
Mariotaku Lee 2015-04-13 00:37:54 +08:00
parent 3d75fbbfd0
commit 809876c050
45 changed files with 792 additions and 1390 deletions

View File

@ -34,4 +34,18 @@
<!--Twitter for Google TV-->
<item>56d8f9ff</item>
</string-array>
<string-array name="names_official_consumer_secret_crc32">
<!--Twitter for Android-->
<item>Twitter for Android</item>
<!--Twitter for iPhone-->
<item>Twitter for iPhone</item>
<!--Twitter for iPad-->
<item>Twitter for iPad</item>
<!--Twitter for Mac-->
<item>Twitter for Mac</item>
<!--Twitter for Windows Phone-->
<item>Twitter for Windows Phone</item>
<!--Twitter for Google TV-->
<item>Twitter for Google TV</item>
</string-array>
</resources>

View File

@ -33,7 +33,7 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback;
import org.mariotaku.twidere.fragment.iface.IBasePullToRefreshFragment;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback;
import org.mariotaku.twidere.util.MessagesManager;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.view.iface.IExtendedView.OnFitSystemWindowsListener;
@ -42,7 +42,8 @@ import java.util.ArrayList;
@SuppressLint("Registered")
public class BaseActionBarActivity extends ThemedActionBarActivity implements Constants,
OnFitSystemWindowsListener, SystemWindowsInsetsCallback, IControlBarActivity {
OnFitSystemWindowsListener, SystemWindowsInsetsCallback, IControlBarActivity,
ShortcutCallback {
private boolean mInstanceStateSaved, mIsVisible, mIsOnTop;
@ -118,7 +119,8 @@ public class BaseActionBarActivity extends ThemedActionBarActivity implements Co
return null;
}
protected boolean handleKeyboardShortcut(int keyCode,@NonNull KeyEvent event) {
@Override
public boolean handleKeyboardShortcut(int keyCode, @NonNull KeyEvent event) {
return false;
}

View File

@ -93,6 +93,7 @@ import org.mariotaku.twidere.util.ColorUtils;
import org.mariotaku.twidere.util.CustomTabUtils;
import org.mariotaku.twidere.util.FlymeUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.MultiSelectEventHandler;
import org.mariotaku.twidere.util.ParseUtils;
@ -279,9 +280,16 @@ public class HomeActivity extends BaseActionBarActivity implements OnClickListen
}
@Override
protected boolean handleKeyboardShortcut(int keyCode, @NonNull KeyEvent event) {
mKeyboardShortcutsHandler.handleKey(null, keyCode, event);
return super.handleKeyboardShortcut(keyCode, event);
public boolean handleKeyboardShortcut(int keyCode, @NonNull KeyEvent event) {
if (handleCurrentFragmentKeyboardShortcut(keyCode, event)) return true;
return mKeyboardShortcutsHandler.handleKey(this, null, keyCode, event);
}
private boolean handleCurrentFragmentKeyboardShortcut(int keyCode, @NonNull KeyEvent event) {
if (mCurrentVisibleFragment instanceof ShortcutCallback) {
return ((ShortcutCallback) mCurrentVisibleFragment).handleKeyboardShortcut(keyCode, event);
}
return false;
}
/**
@ -301,10 +309,11 @@ public class HomeActivity extends BaseActionBarActivity implements OnClickListen
}
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mTwitterWrapper = getTwitterWrapper();
mReadStateManager = TwidereApplication.getInstance(this).getReadStateManager();
final TwidereApplication app = TwidereApplication.getInstance(this);
mReadStateManager = app.getReadStateManager();
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mMultiSelectHandler = new MultiSelectEventHandler(this);
mKeyboardShortcutsHandler = new KeyboardShortcutsHandler(this);
mKeyboardShortcutsHandler = app.getKeyboardShortcutsHandler();
mMultiSelectHandler.dispatchOnCreate();
final long[] accountIds = getAccountIds(this);
if (accountIds.length == 0) {

View File

@ -25,26 +25,26 @@ import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.support.v4.view.WindowCompat;
import android.support.v7.app.ActionBar;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IControlBarActivity;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.iface.IBaseFragment;
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback;
import org.mariotaku.twidere.fragment.iface.IBasePullToRefreshFragment;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback;
import org.mariotaku.twidere.fragment.support.SearchFragment;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback;
import org.mariotaku.twidere.util.MultiSelectEventHandler;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
@ -55,13 +55,16 @@ import org.mariotaku.twidere.view.TintedStatusFrameLayout;
import static org.mariotaku.twidere.util.Utils.createFragmentForIntent;
import static org.mariotaku.twidere.util.Utils.matchLinkId;
public class LinkHandlerActivity extends BaseActionBarActivity implements OnClickListener,
OnLongClickListener, SystemWindowsInsetsCallback, IControlBarActivity, SupportFragmentCallback {
public class LinkHandlerActivity extends BaseActionBarActivity implements SystemWindowsInsetsCallback,
IControlBarActivity, SupportFragmentCallback {
private ControlBarShowHideHelper mControlBarShowHideHelper = new ControlBarShowHideHelper(this);
private MultiSelectEventHandler mMultiSelectHandler;
private KeyboardShortcutsHandler mKeyboardShortcutsHandler;
private TintedStatusFrameLayout mMainContent;
private boolean mFinishOnly;
@Override
@ -84,35 +87,6 @@ public class LinkHandlerActivity extends BaseActionBarActivity implements OnClic
return false;
}
@Override
public void onClick(final View v) {
switch (v.getId()) {
case R.id.go_top: {
final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_content);
if (fragment instanceof RefreshScrollTopInterface) {
((RefreshScrollTopInterface) fragment).scrollToStart();
} else if (fragment instanceof ListFragment) {
((ListFragment) fragment).setSelection(0);
}
break;
}
}
}
@Override
public boolean onLongClick(final View v) {
switch (v.getId()) {
case R.id.go_top: {
final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_content);
if (fragment instanceof RefreshScrollTopInterface) {
((RefreshScrollTopInterface) fragment).triggerRefresh();
}
return true;
}
}
return false;
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
@ -150,6 +124,7 @@ public class LinkHandlerActivity extends BaseActionBarActivity implements OnClic
final int linkId = matchLinkId(data);
requestWindowFeatures(getWindow(), linkId, data);
super.onCreate(savedInstanceState);
mKeyboardShortcutsHandler = TwidereApplication.getInstance(this).getKeyboardShortcutsHandler();
final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
@ -411,6 +386,19 @@ public class LinkHandlerActivity extends BaseActionBarActivity implements OnClic
mControlBarShowHideHelper.setControlBarVisibleAnimate(visible);
}
@Override
public boolean handleKeyboardShortcut(int keyCode, @NonNull KeyEvent event) {
if (handleCurrentFragmentKeyboardShortcut(keyCode, event)) return true;
return mKeyboardShortcutsHandler.handleKey(this, null, keyCode, event);
}
private boolean handleCurrentFragmentKeyboardShortcut(int keyCode, @NonNull KeyEvent event) {
final Fragment fragment = getCurrentVisibleFragment();
if (fragment instanceof ShortcutCallback) {
return ((ShortcutCallback) fragment).handleKeyboardShortcut(keyCode, event);
}
return false;
}
@Override
public void setControlBarOffset(float offset) {

View File

@ -72,6 +72,7 @@ import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.VideoLoader;
import org.mariotaku.twidere.util.VideoLoader.VideoLoadingListener;
import org.mariotaku.twidere.view.LinePageIndicator;
import java.io.File;
@ -82,6 +83,7 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
private MediaPagerAdapter mAdapter;
private ActionBar mActionBar;
private View mMediaStatusContainer;
private LinePageIndicator mIndicator;
@Override
@ -124,6 +126,7 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
public void onSupportContentChanged() {
super.onSupportContentChanged();
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mIndicator = (LinePageIndicator) findViewById(R.id.pager_indicator);
mMediaStatusContainer = findViewById(R.id.media_status_container);
}
@ -137,16 +140,19 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
mViewPager.setAdapter(mAdapter);
mViewPager.setPageMargin(getResources().getDimensionPixelSize(R.dimen.element_spacing_normal));
mViewPager.setOnPageChangeListener(this);
mIndicator.setSelectedColor(getCurrentThemeColor());
mIndicator.setViewPager(mViewPager);
final Intent intent = getIntent();
final long accountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1);
final ParcelableMedia[] media = Utils.newParcelableArray(intent.getParcelableArrayExtra(EXTRA_MEDIA), ParcelableMedia.CREATOR);
final ParcelableMedia currentMedia = intent.getParcelableExtra(EXTRA_CURRENT_MEDIA);
mAdapter.setMedia(accountId, media);
mIndicator.notifyDataSetChanged();
final int currentIndex = ArrayUtils.indexOf(media, currentMedia);
if (currentIndex != -1) {
mViewPager.setCurrentItem(currentIndex, false);
}
if (intent.hasExtra(EXTRA_STATUS)) {
if (isMediaStatusEnabled() && intent.hasExtra(EXTRA_STATUS)) {
mMediaStatusContainer.setVisibility(View.VISIBLE);
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
final Fragment f = new ViewStatusDialogFragment();
@ -175,9 +181,15 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
mActionBar.hide();
}
mMediaStatusContainer.setVisibility(visible ? View.VISIBLE : View.GONE);
mIndicator.setVisibility(visible ? View.VISIBLE : View.GONE);
mMediaStatusContainer.setVisibility(isMediaStatusEnabled() && visible ? View.VISIBLE : View.GONE);
}
private boolean isMediaStatusEnabled() {
return false;
}
private void toggleBar() {
setBarVisibility(!isBarShowing());
}

View File

@ -49,6 +49,7 @@ import org.mariotaku.twidere.activity.MainHondaJOJOActivity;
import org.mariotaku.twidere.service.RefreshService;
import org.mariotaku.twidere.util.AsyncTaskManager;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MessagesManager;
import org.mariotaku.twidere.util.MultiSelectManager;
@ -97,6 +98,7 @@ public class TwidereApplication extends MultiDexApplication implements Constants
private Bus mMessageBus;
private VideoLoader mVideoLoader;
private ReadStateManager mReadStateManager;
private KeyboardShortcutsHandler mKeyboardShortcutsHandler;
private String mDefaultUserAgent;
@ -138,6 +140,15 @@ public class TwidereApplication extends MultiDexApplication implements Constants
return mReadStateManager = new ReadStateManager(this);
}
public KeyboardShortcutsHandler getKeyboardShortcutsHandler() {
if (mKeyboardShortcutsHandler != null) return mKeyboardShortcutsHandler;
mKeyboardShortcutsHandler = new KeyboardShortcutsHandler(this);
if (mKeyboardShortcutsHandler.isEmpty()) {
mKeyboardShortcutsHandler.reset();
}
return mKeyboardShortcutsHandler;
}
public ImageDownloader getImageDownloader() {
if (mImageDownloader != null) return mImageDownloader;
return mImageDownloader = new TwidereImageDownloader(this, false, true);

View File

@ -19,109 +19,55 @@
package org.mariotaku.twidere.fragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.AsyncTaskLoader;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.Context;
import android.content.Loader;
import android.content.DialogInterface;
import android.content.DialogInterface.OnKeyListener;
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.preference.DialogPreference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.KeyEvent;
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;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutSpec;
/**
* Created by mariotaku on 15/4/10.
*/
public class KeyboardShortcutsFragment extends BaseListFragment implements LoaderCallbacks<List<KeyboardShortcutSpec>>, MultiChoiceModeListener {
public class KeyboardShortcutsFragment extends BasePreferenceFragment {
private Adapter mAdapter;
private ListView mListView;
private KeyboardShortcutsHandler mKeyboardShortcutHandler;
@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;
}
final Activity activity = getActivity();
mKeyboardShortcutHandler = TwidereApplication.getInstance(activity).getKeyboardShortcutsHandler();
final PreferenceScreen defaultScreen = getPreferenceScreen();
final PreferenceScreen preferenceScreen;
if (defaultScreen != null) {
defaultScreen.removeAll();
preferenceScreen = defaultScreen;
} else {
preferenceScreen = getPreferenceManager().createPreferenceScreen(activity);
}
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) {
setPreferenceScreen(preferenceScreen);
addPreferences();
}
@Override
@ -129,95 +75,138 @@ public class KeyboardShortcutsFragment extends BaseListFragment implements Loade
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);
private void addPreferences() {
final PreferenceCategory general = makeAndAddCategory(getString(R.string.general));
general.addPreference(makePreferences(null, "compose"));
general.addPreference(makePreferences(null, "search"));
general.addPreference(makePreferences(null, "message"));
final PreferenceCategory statuses = makeAndAddCategory(getString(R.string.statuses));
statuses.addPreference(makePreferences("status", "status.reply"));
statuses.addPreference(makePreferences("status", "status.retweet"));
statuses.addPreference(makePreferences("status", "status.favorite"));
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
private PreferenceCategory makeAndAddCategory(String title) {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
final Context context = preferenceScreen.getContext();
//noinspection ConstantConditions
final PreferenceCategory category = new PreferenceCategory(context, null);
category.setTitle(title);
preferenceScreen.addPreference(category);
return category;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mListView = getListView();
private KeyboardShortcutPreferences makePreferences(String contextTag, String action) {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
final Context context = preferenceScreen.getContext();
return new KeyboardShortcutPreferences(context, mKeyboardShortcutHandler, contextTag, action);
}
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 KeyboardShortcutPreferences extends DialogPreference implements OnKeyListener {
private static class Adapter extends ArrayAdapter<KeyboardShortcutSpec> {
private final KeyboardShortcutsHandler mKeyboardShortcutHandler;
private final String mContextTag, mAction;
private final OnSharedPreferenceChangeListener mPreferencesChangeListener;
private TextView mKeysLabel, mConflictLabel;
private KeyboardShortcutSpec mKeySpec;
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);
public KeyboardShortcutPreferences(final Context context, final KeyboardShortcutsHandler handler,
@Nullable final String contextTag, @NonNull final String action) {
//noinspection ConstantConditions
super(context, null);
mKeyboardShortcutHandler = handler;
mContextTag = contextTag;
mAction = action;
setDialogLayoutResource(R.layout.dialog_keyboard_shortcut_input);
setPersistent(false);
setDialogTitle(KeyboardShortcutsHandler.getActionLabel(context, action));
setTitle(KeyboardShortcutsHandler.getActionLabel(context, action));
mPreferencesChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
updateSummary();
}
};
updateSummary();
}
@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);
protected void onAttachedToActivity() {
super.onAttachedToActivity();
mKeyboardShortcutHandler.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
}
@Override
protected void onPrepareForRemoval() {
mKeyboardShortcutHandler.unregisterOnSharedPreferenceChangeListener(mPreferencesChangeListener);
super.onPrepareForRemoval();
}
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
if (mKeySpec == null) return;
mKeyboardShortcutHandler.register(mKeySpec, mAction);
break;
}
case DialogInterface.BUTTON_NEUTRAL: {
mKeyboardShortcutHandler.unregister(mAction);
break;
}
}
return list;
}
@Override
protected void onStartLoading() {
forceLoad();
protected void onPrepareDialogBuilder(Builder builder) {
builder.setPositiveButton(getContext().getString(android.R.string.ok), this);
builder.setNegativeButton(getContext().getString(android.R.string.cancel), this);
builder.setNeutralButton(getContext().getString(R.string.clear), this);
}
@Override
protected void onReset() {
if (isAbandoned()) {
preferences.unregisterOnSharedPreferenceChangeListener(changeListener);
protected void showDialog(Bundle state) {
super.showDialog(state);
final Dialog dialog = getDialog();
dialog.setOnKeyListener(this);
mKeysLabel = (TextView) dialog.findViewById(R.id.keys_label);
mConflictLabel = (TextView) dialog.findViewById(R.id.conflict_label);
mConflictLabel.setVisibility(View.GONE);
}
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_UP) return false;
if (event.hasNoModifiers() && keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
mKeyboardShortcutHandler.unregister(mAction);
return true;
}
super.onReset();
final KeyboardShortcutSpec spec = KeyboardShortcutsHandler.getKeyboardShortcutSpec(mContextTag, keyCode, event);
if (spec == null || !spec.isValid()) return false;
mKeySpec = spec;
mKeysLabel.setText(spec.toKeyString());
final String oldAction = mKeyboardShortcutHandler.findAction(spec);
final Context context = getContext();
if (mAction.equals(oldAction) || TextUtils.isEmpty(oldAction)) {
mConflictLabel.setVisibility(View.GONE);
if (dialog instanceof AlertDialog) {
((AlertDialog) dialog).setButton(DialogInterface.BUTTON_POSITIVE, context.getString(android.R.string.ok), this);
}
} else {
mConflictLabel.setVisibility(View.VISIBLE);
final String label = KeyboardShortcutsHandler.getActionLabel(context, oldAction);
mConflictLabel.setText(context.getString(R.string.conflicts_with_name, label));
if (dialog instanceof AlertDialog) {
((AlertDialog) dialog).setButton(DialogInterface.BUTTON_POSITIVE, context.getString(R.string.overwrite), this);
}
}
return true;
}
private void updateSummary() {
final KeyboardShortcutSpec spec = mKeyboardShortcutHandler.findKey(mAction);
setSummary(spec != null ? spec.toKeyString() : null);
}
}
}

View File

@ -6,6 +6,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
@ -19,6 +20,7 @@ import android.support.v7.widget.PopupMenu.OnMenuItemClickListener;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@ -44,6 +46,8 @@ import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ColorUtils;
import org.mariotaku.twidere.util.ContentListScrollListener;
import org.mariotaku.twidere.util.ContentListScrollListener.ContentListSupport;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback;
import org.mariotaku.twidere.util.ReadStateManager;
import org.mariotaku.twidere.util.SimpleDrawerCallback;
import org.mariotaku.twidere.util.ThemeUtils;
@ -63,7 +67,7 @@ import static org.mariotaku.twidere.util.Utils.setMenuForStatus;
*/
public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment implements LoaderCallbacks<Data>,
OnRefreshListener, DrawerCallback, RefreshScrollTopInterface, StatusAdapterListener,
ControlBarOffsetListener, ContentListSupport {
ControlBarOffsetListener, ContentListSupport, ShortcutCallback {
private final Object mStatusesBusCallback;
private AbsStatusesAdapter<Data> mAdapter;
@ -77,6 +81,7 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
private int mControlBarOffsetPixels;
private PopupMenu mPopupMenu;
private ReadStateManager mReadStateManager;
private KeyboardShortcutsHandler mKeyboardShortcutsHandler;
private ParcelableStatus mSelectedStatus;
private OnMenuItemClickListener mOnStatusMenuItemClickListener = new OnMenuItemClickListener() {
@Override
@ -117,6 +122,40 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
return mDrawerCallback.isScrollContent(x, y);
}
@Override
public boolean handleKeyboardShortcut(int keyCode, @NonNull KeyEvent event) {
if (!KeyboardShortcutsHandler.isValidForHotkey(keyCode, event)) return false;
final View focusedChild = mLayoutManager.getFocusedChild();
final int position = mRecyclerView.getChildLayoutPosition(focusedChild);
if (position == -1) return false;
final ParcelableStatus status = mAdapter.getStatus(position);
if (status == null) return false;
final String action = mKeyboardShortcutsHandler.getKeyAction("status", keyCode, event);
if (action == null) return false;
switch (action) {
case "status.reply": {
final Intent intent = new Intent(INTENT_ACTION_REPLY);
intent.putExtra(EXTRA_STATUS, status);
startActivity(intent);
return true;
}
case "status.retweet": {
RetweetQuoteDialogFragment.show(getFragmentManager(), status);
return true;
}
case "status.favorite": {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (status.is_favorite) {
twitter.destroyFavoriteAsync(status);
} else {
twitter.createFavoriteAsync(status);
}
return true;
}
}
return false;
}
@Override
public void scrollBy(float dy) {
mDrawerCallback.scrollBy(dy);
@ -175,6 +214,9 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mReadStateManager = getReadStateManager();
final FragmentActivity activity = getActivity();
final TwidereApplication application = TwidereApplication.getInstance(activity);
mKeyboardShortcutsHandler = application.getKeyboardShortcutsHandler();
final View view = getView();
if (view == null) throw new AssertionError();
final Context context = view.getContext();

View File

@ -1,97 +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.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 + '\'' +
'}';
}
}

View File

@ -196,6 +196,21 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int createFavoriteAsync(final ParcelableStatus status) {
//spice
final Context context = getContext();
SpiceProfilingUtil.profile(context,
status.account_id, status.id + ",Favor,"
+ status.account_id + "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
SpiceProfilingUtil.log(context, status.id + ",Favor,"
+ status.account_id + "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count + "," + status.timestamp);
//end
return createFavoriteAsync(status.account_id, status.id);
}
public int createFriendshipAsync(final long accountId, final long userId) {
final CreateFriendshipTask task = new CreateFriendshipTask(accountId, userId);
return mAsyncTaskManager.add(task, true);
@ -252,6 +267,22 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int destroyFavoriteAsync(final ParcelableStatus status) {
//spice
final Context context = getContext();
SpiceProfilingUtil.profile(context,
status.account_id, status.id + ",Unfavor," + status.account_id
+ "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
SpiceProfilingUtil.log(context, status.id + ",Unfavor," + status.account_id
+ "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
//end
return destroyFavoriteAsync(status.account_id, status.id);
}
public int destroyFriendshipAsync(final long accountId, final long user_id) {
final DestroyFriendshipTask task = new DestroyFriendshipTask(accountId, user_id);
return mAsyncTaskManager.add(task, true);
@ -579,7 +610,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
Utils.showErrorMessage(mContext, R.string.action_updating_profile_banner_image, result.getException(),
true);
}
} @Override
}
@Override
protected SingleResponse<ParcelableUser> doInBackground(final Object... params) {
try {
final Twitter twitter = getTwitterInstance(mContext, mAccountId, true);
@ -599,7 +632,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
}
public static class UpdateProfileImageTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUser>> {
@ -1379,7 +1411,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final TwitterException te = (TwitterException) e;
return te.getErrorCode() == StatusCodeMessageUtils.PAGE_NOT_FOUND
|| te.getStatusCode() == HttpResponseCode.NOT_FOUND;
} @Override
}
@Override
protected SingleResponse<DirectMessage> doInBackground(final Object... args) {
final Twitter twitter = getTwitterInstance(mContext, account_id, false);
if (twitter == null) return SingleResponse.getInstance();
@ -1396,7 +1430,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
@Override
protected void onPostExecute(final SingleResponse<DirectMessage> result) {
super.onPostExecute(result);
@ -1769,7 +1802,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected abstract Uri getDatabaseUri();
protected abstract boolean isOutgoing(); @Override
protected abstract boolean isOutgoing();
@Override
protected List<MessageListResponse> doInBackground(final Object... params) {
final List<MessageListResponse> result = new ArrayList<>();
@ -1843,7 +1878,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
@Override
protected void onPreExecute() {
super.onPreExecute();
@ -1871,14 +1905,15 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
public ResponseList<twitter4j.Status> getStatuses(final Twitter twitter, final Paging paging)
throws TwitterException {
return twitter.getHomeTimeline(paging);
} @NonNull
}
@NonNull
@Override
protected Uri getDatabaseUri() {
return Statuses.CONTENT_URI;
}
@Override
protected void onPostExecute(final List<StatusListResponse> result) {
super.onPostExecute(result);
@ -1966,13 +2001,14 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
public ResponseList<DirectMessage> getDirectMessages(final Twitter twitter, final Paging paging)
throws TwitterException {
return twitter.getDirectMessages(paging);
} @Override
}
@Override
protected Uri getDatabaseUri() {
return Inbox.CONTENT_URI;
}
@Override
protected boolean isOutgoing() {
return false;
@ -2044,7 +2080,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean isMaxIdsValid() {
return mMaxIds != null && mMaxIds.length == mAccountIds.length;
} @SafeVarargs
}
@SafeVarargs
@Override
protected final void onProgressUpdate(TwitterListResponse<twitter4j.Status>... values) {
AsyncTaskUtils.executeTask(new CacheUsersStatusesTask(mContext), values);

View File

@ -42,22 +42,13 @@ public class ContentListScrollListener extends OnScrollListener {
mContentListSupport = contentListSupport;
}
public void setOnScrollListener(OnScrollListener listener) {
mOnScrollListener = listener;
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(recyclerView, newState);
}
final IContentCardAdapter adapter = mContentListSupport.getAdapter();
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!mContentListSupport.isRefreshing() && adapter.isLoadMoreSupported()
&& !adapter.isLoadMoreIndicatorVisible() && mScrollState != RecyclerView.SCROLL_STATE_IDLE
&& layoutManager.findLastVisibleItemPosition() == adapter.getItemCount() - 1) {
mContentListSupport.onLoadMoreContents();
if (mScrollState != RecyclerView.SCROLL_STATE_IDLE) {
notifyScrollStateChanged(recyclerView);
}
mScrollState = newState;
}
@ -76,22 +67,37 @@ public class ContentListScrollListener extends OnScrollListener {
mContentListSupport.setControlVisible(dy < 0);
mScrollSum = 0;
}
if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
notifyScrollStateChanged(recyclerView);
}
}
public void setOnScrollListener(OnScrollListener listener) {
mOnScrollListener = listener;
}
public void setTouchSlop(int touchSlop) {
mTouchSlop = touchSlop;
}
public static interface ContentListSupport {
private void notifyScrollStateChanged(RecyclerView recyclerView) {
final IContentCardAdapter adapter = mContentListSupport.getAdapter();
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!mContentListSupport.isRefreshing() && adapter.isLoadMoreSupported() && !adapter.isLoadMoreIndicatorVisible()
&& layoutManager.findLastVisibleItemPosition() == adapter.getItemCount() - 1) {
mContentListSupport.onLoadMoreContents();
}
}
boolean isRefreshing();
public static interface ContentListSupport {
IContentCardAdapter getAdapter();
void setControlVisible(boolean visible);
boolean isRefreshing();
void onLoadMoreContents();
void setControlVisible(boolean visible);
}
}

View File

@ -2,6 +2,10 @@ package org.mariotaku.twidere.util;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.SparseArrayCompat;
import android.text.TextUtils;
import android.view.KeyEvent;
@ -10,19 +14,37 @@ import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.ComposeActivity;
import org.mariotaku.twidere.activity.support.QuickSearchBarActivity;
import org.mariotaku.twidere.app.TwidereApplication;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Set;
public class KeyboardShortcutsHandler implements Constants {
public String findAction(@NonNull KeyboardShortcutSpec spec) {
return mPreferences.getString(spec.getRawKey(), null);
}
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
mPreferences.registerOnSharedPreferenceChangeListener(listener);
}
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
mPreferences.unregisterOnSharedPreferenceChangeListener(listener);
}
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);
sActionLabelMap.put("message", R.string.new_direct_message);
sActionLabelMap.put("status.reply", R.string.reply);
sActionLabelMap.put("status.retweet", R.string.retweet);
sActionLabelMap.put("status.favorite", R.string.favorite);
sMetaNameMap.put(KeyEvent.META_FUNCTION_ON, "fn");
sMetaNameMap.put(KeyEvent.META_META_ON, "meta");
@ -35,6 +57,16 @@ public class KeyboardShortcutsHandler implements Constants {
private final Context mContext;
private final SharedPreferencesWrapper mPreferences;
public KeyboardShortcutSpec findKey(String action) {
for (Entry<String, ?> entry : mPreferences.getAll().entrySet()) {
if (action.equals(entry.getValue())) {
final KeyboardShortcutSpec spec = new KeyboardShortcutSpec(entry.getKey(), action);
if (spec.isValid()) return spec;
}
}
return null;
}
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);
@ -42,7 +74,7 @@ public class KeyboardShortcutsHandler implements Constants {
return 0;
}
public KeyboardShortcutsHandler(final Context context) {
public KeyboardShortcutsHandler(final TwidereApplication context) {
mContext = context;
mPreferences = SharedPreferencesWrapper.getInstance(context, KEYBOARD_SHORTCUTS_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
@ -71,6 +103,7 @@ public class KeyboardShortcutsHandler implements Constants {
}
public static String getKeyEventKey(String contextTag, int keyCode, KeyEvent event) {
if (!isValidForHotkey(keyCode, event)) return null;
final StringBuilder keyNameBuilder = new StringBuilder();
if (!TextUtils.isEmpty(contextTag)) {
keyNameBuilder.append(contextTag);
@ -91,26 +124,196 @@ public class KeyboardShortcutsHandler implements Constants {
return keyNameBuilder.toString();
}
public boolean handleKey(final String contextTag, final int keyCode, final KeyEvent event) {
public static String getKeyEventKey(String contextTag, int metaState, String keyName) {
final StringBuilder keyNameBuilder = new StringBuilder();
if (!TextUtils.isEmpty(contextTag)) {
keyNameBuilder.append(contextTag);
keyNameBuilder.append(".");
}
for (int i = 0, j = sMetaNameMap.size(); i < j; i++) {
if ((sMetaNameMap.keyAt(i) & metaState) != 0) {
keyNameBuilder.append(sMetaNameMap.valueAt(i));
keyNameBuilder.append("+");
}
}
keyNameBuilder.append(keyName);
return keyNameBuilder.toString();
}
public static KeyboardShortcutSpec getKeyboardShortcutSpec(String contextTag, int keyCode, KeyEvent event) {
if (!isValidForHotkey(keyCode, event)) return null;
final int metaState = KeyEvent.normalizeMetaState(event.getMetaState());
int metaStateNormalized = 0;
for (int i = 0, j = sMetaNameMap.size(); i < j; i++) {
if ((sMetaNameMap.keyAt(i) & metaState) != 0) {
metaStateNormalized |= sMetaNameMap.keyAt(i);
}
}
final String keyCodeString = KeyEvent.keyCodeToString(keyCode);
if (keyCodeString.startsWith(KEYCODE_STRING_PREFIX)) {
final String keyName = keyCodeString.substring(KEYCODE_STRING_PREFIX.length()).toLowerCase(Locale.US);
return new KeyboardShortcutSpec(contextTag, metaStateNormalized, keyName, null);
}
return null;
}
public boolean handleKey(final Context context, final String contextTag, final int keyCode, final KeyEvent event) {
if (!isValidForHotkey(keyCode, event)) return false;
final String key = getKeyEventKey(contextTag, keyCode, event);
final String action = mPreferences.getString(key, null);
if (action == null) return false;
switch (action) {
case "compose": {
mContext.startActivity(new Intent(mContext, ComposeActivity.class).setAction(INTENT_ACTION_COMPOSE));
context.startActivity(new Intent(context, ComposeActivity.class).setAction(INTENT_ACTION_COMPOSE));
return true;
}
case "search": {
mContext.startActivity(new Intent(mContext, QuickSearchBarActivity.class).setAction(INTENT_ACTION_QUICK_SEARCH));
context.startActivity(new Intent(context, QuickSearchBarActivity.class).setAction(INTENT_ACTION_QUICK_SEARCH));
return true;
}
case "message": {
Utils.openMessageConversation(context, -1, -1);
return true;
}
}
return false;
}
@Nullable
public String getKeyAction(final String contextTag, final int keyCode, final KeyEvent event) {
if (!isValidForHotkey(keyCode, event)) return null;
final String key = getKeyEventKey(contextTag, keyCode, event);
return mPreferences.getString(key, null);
}
public static boolean isValidForHotkey(int keyCode, KeyEvent event) {
// These keys must use with modifiers
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_NUMPAD_ENTER:
case KeyEvent.KEYCODE_TAB: {
if (event.hasNoModifiers()) return false;
break;
}
}
return !event.isSystem() && !KeyEvent.isModifierKey(keyCode) && keyCode != KeyEvent.KEYCODE_UNKNOWN;
}
public boolean isEmpty() {
return mPreferences.getAll().isEmpty();
}
public void reset() {
final Editor editor = mPreferences.edit();
editor.clear();
editor.putString("n", "compose");
editor.putString("m", "message");
editor.putString("slash", "search");
editor.putString("status.f", "status.favorite");
editor.putString("status.r", "status.reply");
editor.putString("status.t", "status.retweet");
editor.apply();
}
public void register(KeyboardShortcutSpec spec, String action) {
unregister(action);
mPreferences.edit().putString(spec.getRawKey(), action).apply();
}
public void unregister(String action) {
final Editor editor = mPreferences.edit();
for (Entry<String, ?> entry : mPreferences.getAll().entrySet()) {
if (action.equals(entry.getValue())) {
final KeyboardShortcutSpec spec = new KeyboardShortcutSpec(entry.getKey(), action);
if (spec.isValid()) {
editor.remove(spec.getRawKey());
}
}
}
editor.apply();
}
public static interface ShortcutCallback {
boolean handleKeyboardShortcut(int keyCode, @NonNull KeyEvent event);
}
/**
* Created by mariotaku on 15/4/11.
*/
public static class KeyboardShortcutSpec {
private String action;
private String contextTag;
private int keyMeta;
private String keyName;
public KeyboardShortcutSpec(String contextTag, int keyMeta, String keyName, String action) {
this.contextTag = contextTag;
this.keyMeta = keyMeta;
this.keyName = keyName;
this.action = action;
}
public KeyboardShortcutSpec(String key, String action) {
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 |= getKeyEventMeta(key.substring(previousIdx + 1, idx));
previousIdx = idx;
}
keyName = key.substring(previousIdx + 1);
this.action = action;
}
public String getContextTag() {
return contextTag;
}
public int getKeyMeta() {
return keyMeta;
}
public String getKeyName() {
return keyName;
}
public String getRawKey() {
return getKeyEventKey(contextTag, keyMeta, keyName);
}
public String getAction() {
return action;
}
public String getValueName(Context context) {
return getActionLabel(context, action);
}
public boolean isValid() {
return keyName != null;
}
public String toKeyString() {
return metaToHumanReadableString(keyMeta) + keyName.toUpperCase(Locale.US);
}
@Override
public String toString() {
return "KeyboardShortcutSpec{" +
"action='" + action + '\'' +
", contextTag='" + contextTag + '\'' +
", keyMeta=" + keyMeta +
", keyName='" + keyName + '\'' +
'}';
}
}
}

View File

@ -243,7 +243,6 @@ import java.util.zip.CRC32;
import javax.net.ssl.SSLException;
import edu.tsinghua.spice.SpiceService;
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
import edu.ucdavis.earlybird.UCDService;
import twitter4j.DirectMessage;
import twitter4j.RateLimitStatus;
@ -2925,9 +2924,9 @@ public final class Utils implements Constants, TwitterConstants {
return null;
}
public static void openMessageConversation(final FragmentActivity activity, final long accountId,
public static void openMessageConversation(final Context context, final long accountId,
final long recipientId) {
if (activity == null) return;
if (context == null) return;
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_DIRECT_MESSAGES_CONVERSATION);
@ -2936,7 +2935,7 @@ public final class Utils implements Constants, TwitterConstants {
builder.appendQueryParameter(QUERY_PARAM_RECIPIENT_ID, String.valueOf(recipientId));
}
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
activity.startActivity(intent);
context.startActivity(intent);
}
public static void openMedia(final Context context, final ParcelableDirectMessage message, final ParcelableMedia current) {
@ -3569,15 +3568,9 @@ public final class Utils implements Constants, TwitterConstants {
}
final MenuItem retweet = menu.findItem(MENU_RETWEET);
if (retweet != null) {
retweet.setVisible(!status.user_is_protected || isMyRetweet);
ActionIconDrawable.setMenuHighlight(retweet, new TwidereMenuInfo(isMyRetweet, retweetHighlight));
retweet.setTitle(isMyRetweet ? R.string.cancel_retweet : R.string.retweet);
}
// final MenuItem retweetSubItem = menu.findItem(R.id.retweet_submenu);
// if (retweetSubItem != null) {
// ActionIconDrawable.setMenuHighlight(retweetSubItem, new TwidereMenuInfo(isMyRetweet,
// retweetHighlight));
// }
final MenuItem favorite = menu.findItem(MENU_FAVORITE);
if (favorite != null) {
ActionIconDrawable.setMenuHighlight(favorite, new TwidereMenuInfo(status.is_favorite, favoriteHighlight));
@ -3950,30 +3943,9 @@ public final class Utils implements Constants, TwitterConstants {
}
case MENU_FAVORITE: {
if (status.is_favorite) {
twitter.destroyFavoriteAsync(status.account_id, status.id);
//spice
SpiceProfilingUtil.profile(context,
status.account_id, status.id + ",Unfavor," + status.account_id
+ "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
SpiceProfilingUtil.log(context, status.id + ",Unfavor," + status.account_id
+ "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
//end
twitter.destroyFavoriteAsync(status);
} else {
twitter.createFavoriteAsync(status.account_id, status.id);
//spice
SpiceProfilingUtil.profile(context,
status.account_id, status.id + ",Favor,"
+ status.account_id + "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
SpiceProfilingUtil.log(context, status.id + ",Favor,"
+ status.account_id + "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count + "," + status.timestamp);
//end
twitter.createFavoriteAsync(status);
}
break;
}

View File

@ -1,47 +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.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class ActionBarHomeAsUpIndicator extends ImageView {
public ActionBarHomeAsUpIndicator(final Context context) {
this(context, null);
}
public ActionBarHomeAsUpIndicator(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public ActionBarHomeAsUpIndicator(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(new int[]{android.R.attr.homeAsUpIndicator});
final Drawable d = a.getDrawable(0);
a.recycle();
setImageDrawable(d);
setScaleType(ScaleType.CENTER);
}
}

View File

@ -1,59 +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.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.accessor.ViewAccessor;
public class ActionBarSplitThemedContainer extends FrameLayout {
public ActionBarSplitThemedContainer(final Context context) {
this(context, null);
}
public ActionBarSplitThemedContainer(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public ActionBarSplitThemedContainer(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.layout});
final int resId = a.getResourceId(0, 0);
a.recycle();
if (resId == 0)
throw new IllegalArgumentException("You must specify a layout resource in layout XML file.");
final View view = LayoutInflater.from(getThemedContext(context)).inflate(resId, this, false);
final int themeResId = ThemeUtils.getThemeResource(context);
ViewAccessor.setBackground(view, ThemeUtils.getActionBarSplitBackground(context, themeResId));
addView(view);
}
private static Context getThemedContext(final Context context) {
return ThemeUtils.getActionBarContext(context);
}
}

View File

@ -1,46 +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.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.TextView;
public class ActionBarSubtitleView extends TextView {
public ActionBarSubtitleView(final Context context) {
this(context, null);
}
public ActionBarSubtitleView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public ActionBarSubtitleView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(null, new int[]{android.R.attr.subtitleTextStyle},
android.R.attr.actionBarStyle, android.R.style.Widget_Holo_ActionBar);
final int textAppearance = a.getResourceId(0, android.R.style.Widget_Holo_ActionBar);
a.recycle();
setTextAppearance(context, textAppearance);
}
}

View File

@ -1,91 +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.view;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import org.mariotaku.twidere.R;
public class ActionBarTabView extends FrameLayout {
private CharSequence mTitle;
private Drawable mIcon;
public ActionBarTabView(final Context context) {
this(context, null);
}
public ActionBarTabView(final Context context, final AttributeSet attrs) {
this(context, attrs, android.R.attr.actionBarTabStyle);
}
public ActionBarTabView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
inflate(context, R.layout.tab_item_ab, this);
}
public void setIcon(final Drawable icon) {
mIcon = icon;
setIconView(icon);
}
public void setIcon(final int iconRes) {
setIcon(getResources().getDrawable(iconRes));
}
public void setIconView(final Drawable icon) {
final ImageView iconView = (ImageView) findViewById(android.R.id.icon);
if (iconView == null) return;
iconView.setVisibility(icon != null ? GONE : VISIBLE);
iconView.setImageDrawable(icon);
}
public void setTitle(final CharSequence title) {
mTitle = title;
setTitleView(title);
}
public void setTitle(final int titleRes) {
setTitle(getResources().getText(titleRes));
}
public void setTitleView(final CharSequence title) {
final TextView titleView = (TextView) findViewById(android.R.id.title);
final ImageView iconView = (ImageView) findViewById(android.R.id.icon);
if (titleView == null || iconView == null) return;
titleView.setVisibility(TextUtils.isEmpty(title) ? GONE : VISIBLE);
titleView.setText(title);
iconView.setContentDescription(title);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
setTitleView(mTitle);
setIconView(mIcon);
}
}

View File

@ -1,53 +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.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import org.mariotaku.twidere.util.ThemeUtils;
public class ActionBarThemedContainer extends FrameLayout {
public ActionBarThemedContainer(final Context context) {
this(context, null);
}
public ActionBarThemedContainer(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public ActionBarThemedContainer(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.layout});
final int resId = a.getResourceId(0, 0);
a.recycle();
if (resId == 0)
throw new IllegalArgumentException("You must specify a layout resource in layout XML file.");
inflate(getThemedContext(context), resId, this);
}
private static Context getThemedContext(final Context context) {
return ThemeUtils.getActionBarContext(context);
}
}

View File

@ -1,46 +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.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.TextView;
public class ActionBarTitleView extends TextView {
public ActionBarTitleView(final Context context) {
this(context, null);
}
public ActionBarTitleView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public ActionBarTitleView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(null, new int[]{android.R.attr.titleTextStyle},
android.R.attr.actionBarStyle, android.R.style.Widget_Holo_ActionBar);
final int textAppearance = a.getResourceId(0, android.R.style.Widget_Holo_TextView);
a.recycle();
setTextAppearance(context, textAppearance);
}
}

View File

@ -1,62 +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;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import org.mariotaku.twidere.Constants;
/**
* Created by mariotaku on 15/3/30.
*/
public class AdvancedRecyclerView extends RecyclerView {
public AdvancedRecyclerView(Context context) {
super(context);
}
public AdvancedRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AdvancedRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {
Log.d(Constants.LOGTAG, event.toString());
return super.dispatchTrackballEvent(event);
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
final LayoutManager lm = getLayoutManager();
if (!(lm instanceof LinearLayoutManager)) return false;
final LinearLayoutManager llm = (LinearLayoutManager) lm;
Log.d(Constants.LOGTAG, event.toString());
return true;
}
}

View File

@ -1,59 +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.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class AutoAdjustHeightImageView extends ImageView {
public AutoAdjustHeightImageView(final Context context) {
this(context, null);
}
public AutoAdjustHeightImageView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoAdjustHeightImageView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
setScaleType(ScaleType.CENTER_CROP);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec);
final Drawable d = getDrawable();
final Bitmap b = d instanceof BitmapDrawable ? ((BitmapDrawable) d).getBitmap() : null;
if (b != null) {
final int height = Math.round((float) width * (float) b.getHeight() / b.getWidth());
setMeasuredDimension(width, height);
} else {
setMeasuredDimension(width, width);
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}

View File

@ -1,71 +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.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* Created by mariotaku on 14/12/4.
*/
public class BottomDividerFrameLayout extends FrameLayout {
private final Drawable mDividerDrawable;
public BottomDividerFrameLayout(Context context) {
this(context, null);
}
public BottomDividerFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BottomDividerFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
TypedArray a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.divider});
mDividerDrawable = a.getDrawable(0);
a.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final Drawable divider = mDividerDrawable;
if (divider != null) {
divider.draw(canvas);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
final Drawable divider = mDividerDrawable;
if (divider != null) {
final int drawableLeft = 0, drawableRight = drawableLeft + getMeasuredWidth();
final int drawableBottom = getMeasuredHeight(), drawableTop = drawableBottom - divider.getIntrinsicHeight();
divider.setBounds(drawableLeft, drawableTop, drawableRight, drawableBottom);
}
}
}

View File

@ -1,29 +0,0 @@
package org.mariotaku.twidere.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* Created by mariotaku on 14/11/5.
*/
public class DrawerAccountHeaderContainer extends RelativeLayout {
public DrawerAccountHeaderContainer(Context context) {
super(context);
}
public DrawerAccountHeaderContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawerAccountHeaderContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec), height = width / 2;
setMeasuredDimension(width, height);
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
}

View File

@ -47,7 +47,7 @@ public class ExtendedFrameLayout extends FrameLayout implements IExtendedView {
}
@Override
public final boolean dispatchTouchEvent(final MotionEvent event) {
public final boolean dispatchTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.dispatchTouchEvent(this, event);
if (ret) return true;
@ -80,39 +80,16 @@ public class ExtendedFrameLayout extends FrameLayout implements IExtendedView {
}
@Override
@SuppressWarnings("deprecation")
protected boolean fitSystemWindows(@NonNull Rect insets) {
// if (mOnFitSystemWindowsListener != null && Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
// mOnFitSystemWindowsListener.onFitSystemWindows(insets);
// }
if (mOnFitSystemWindowsListener != null) {
mOnFitSystemWindowsListener.onFitSystemWindows(insets);
}
return super.fitSystemWindows(insets);
}
Rect insets = new Rect();
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// if (mOnFitSystemWindowsListener != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
// final OnFitSystemWindowsListener l = mOnFitSystemWindowsListener;
// final Activity activity = Utils.findActivity(getContext());
// if (activity instanceof ActionBarActivity) {
// final ActionBarActivity actionBarActivity = (ActionBarActivity) activity;
// insets.top = Utils.getActionBarHeight(actionBarActivity.getSupportActionBar());
// l.onFitSystemWindows(insets);
// } else if (activity != null && activity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR
// | Window.FEATURE_ACTION_BAR_OVERLAY)) {
// insets.top = Utils.getActionBarHeight(activity.getActionBar());
// l.onFitSystemWindows(insets);
// }
// }
}
@Override
public final boolean onTouchEvent(final MotionEvent event) {
public final boolean onTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.onTouchEvent(this, event);
if (ret) return true;
@ -120,6 +97,11 @@ public class ExtendedFrameLayout extends FrameLayout implements IExtendedView {
return super.onTouchEvent(event);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected final void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
super.onSizeChanged(w, h, oldw, oldh);

View File

@ -62,6 +62,7 @@ public class ExtendedImageView extends ImageView implements IExtendedView {
}
@Override
@SuppressWarnings("deprecation")
protected boolean fitSystemWindows(@NonNull Rect insets) {
if (mOnFitSystemWindowsListener != null) {
mOnFitSystemWindowsListener.onFitSystemWindows(insets);
@ -70,7 +71,7 @@ public class ExtendedImageView extends ImageView implements IExtendedView {
}
@Override
public final boolean dispatchTouchEvent(final MotionEvent event) {
public final boolean dispatchTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.dispatchTouchEvent(this, event);
if (ret) return true;
@ -79,7 +80,7 @@ public class ExtendedImageView extends ImageView implements IExtendedView {
}
@Override
public final boolean onTouchEvent(final MotionEvent event) {
public final boolean onTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.onTouchEvent(this, event);
if (ret) return true;

View File

@ -47,7 +47,7 @@ public class ExtendedLinearLayout extends LinearLayout implements IExtendedView
}
@Override
public final boolean dispatchTouchEvent(final MotionEvent event) {
public final boolean dispatchTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.dispatchTouchEvent(this, event);
if (ret) return true;
@ -80,6 +80,7 @@ public class ExtendedLinearLayout extends LinearLayout implements IExtendedView
}
@Override
@SuppressWarnings("deprecation")
protected boolean fitSystemWindows(@NonNull Rect insets) {
if (mOnFitSystemWindowsListener != null) {
mOnFitSystemWindowsListener.onFitSystemWindows(insets);

View File

@ -47,7 +47,7 @@ public class ExtendedRelativeLayout extends RelativeLayout implements IExtendedV
}
@Override
public final boolean dispatchTouchEvent(final MotionEvent event) {
public final boolean dispatchTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.dispatchTouchEvent(this, event);
if (ret) return true;
@ -80,6 +80,7 @@ public class ExtendedRelativeLayout extends RelativeLayout implements IExtendedV
}
@Override
@SuppressWarnings("deprecation")
protected boolean fitSystemWindows(@NonNull Rect insets) {
if (mOnFitSystemWindowsListener != null) {
mOnFitSystemWindowsListener.onFitSystemWindows(insets);
@ -88,7 +89,7 @@ public class ExtendedRelativeLayout extends RelativeLayout implements IExtendedV
}
@Override
public final boolean onTouchEvent(final MotionEvent event) {
public final boolean onTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.onTouchEvent(this, event);
if (ret) return true;

View File

@ -1,47 +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.view;
import android.content.Context;
import android.util.AttributeSet;
public class MapImageView extends ForegroundImageView {
public MapImageView(final Context context) {
this(context, null);
}
public MapImageView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public MapImageView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec), height = width / 2;
final int hSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, hSpec);
setMeasuredDimension(width, height);
}
}

View File

@ -1,66 +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.view;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.util.AttributeSet;
import android.view.ViewConfiguration;
import android.widget.FrameLayout;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.util.ThemeUtils;
public class MessageCardItemFrameLayout extends FrameLayout {
public MessageCardItemFrameLayout(final Context context) {
this(context, null);
}
public MessageCardItemFrameLayout(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public MessageCardItemFrameLayout(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
if (isInEditMode()) return;
ThemeUtils.applyThemeAlphaToDrawable(context, getBackground());
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
final Drawable d = getBackground();
if (d != null && d.isStateful()) {
final int[] state = getDrawableState();
d.setState(state);
final Drawable current = d.getCurrent();
if (current instanceof TransitionDrawable) {
final TransitionDrawable td = (TransitionDrawable) current;
if (ArrayUtils.contains(state, android.R.attr.state_pressed)) {
td.startTransition(ViewConfiguration.getLongPressTimeout());
} else {
td.resetTransition();
}
}
}
}
}

View File

@ -1,60 +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.view;
import android.content.Context;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.widget.ImageButton;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.util.ThemeUtils;
public class NavigationArrowButton extends ImageButton {
private final int mHighlightColor;
public NavigationArrowButton(final Context context) {
this(context, null);
}
public NavigationArrowButton(final Context context, final AttributeSet attrs) {
this(context, attrs, android.R.attr.imageButtonStyle);
}
public NavigationArrowButton(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
mHighlightColor = isInEditMode() ? 0 : ThemeUtils.getUserAccentColor(context);
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
updateColorFilter();
}
private void updateColorFilter() {
if (isClickable() && isEnabled() && ArrayUtils.contains(getDrawableState(), android.R.attr.state_pressed)) {
setColorFilter(mHighlightColor, Mode.MULTIPLY);
} else {
clearColorFilter();
}
}
}

View File

@ -0,0 +1,100 @@
/*
* 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;
import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.InputDevice;
import android.view.MotionEvent;
import org.mariotaku.twidere.Constants;
/**
* Created by mariotaku on 15/3/30.
*/
public class RecyclerViewBackport extends RecyclerView {
// This value is used when handling generic motion events.
private float mScrollFactor = Float.MIN_VALUE;
public RecyclerViewBackport(Context context) {
super(context);
}
public RecyclerViewBackport(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RecyclerViewBackport(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
final LayoutManager lm = getLayoutManager();
if (lm == null) {
return false;
}
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
if (event.getAction() == MotionEventCompat.ACTION_SCROLL) {
final float vScroll, hScroll;
if (lm.canScrollVertically()) {
vScroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
} else {
vScroll = 0f;
}
if (lm.canScrollHorizontally()) {
hScroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
} else {
hScroll = 0f;
}
if (vScroll != 0 || hScroll != 0) {
final float scrollFactor = getScrollFactorBackport();
scrollBy((int) (hScroll * scrollFactor), (int) (vScroll * scrollFactor));
}
}
}
return false;
}
/**
* Ported from View.getVerticalScrollFactor.
*/
private float getScrollFactorBackport() {
if (mScrollFactor == Float.MIN_VALUE) {
TypedValue outValue = new TypedValue();
if (getContext().getTheme().resolveAttribute(
android.R.attr.listPreferredItemHeight, outValue, true)) {
mScrollFactor = outValue.getDimension(
getContext().getResources().getDisplayMetrics());
} else {
return 0; //listPreferredItemHeight is not defined, no generic scrolling
}
}
return mScrollFactor;
}
}

View File

@ -1,62 +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.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class SquareView extends View {
public SquareView(final Context context) {
this(context, null);
}
public SquareView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public SquareView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec), height = MeasureSpec.getSize(heightMeasureSpec);
final ViewGroup.LayoutParams lp = getLayoutParams();
if (lp.height == ViewGroup.LayoutParams.MATCH_PARENT && lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
setMeasuredDimension(height, height);
} else if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT && lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
setMeasuredDimension(width, width);
} else {
if (width > height) {
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
setMeasuredDimension(height, height);
} else {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
setMeasuredDimension(width, width);
}
}
}
}

View File

@ -1,58 +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.view;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.ViewGroup;
public class SquareViewPager extends ViewPager {
public SquareViewPager(final Context context) {
super(context);
}
public SquareViewPager(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec), height = MeasureSpec.getSize(heightMeasureSpec);
final ViewGroup.LayoutParams lp = getLayoutParams();
if (lp.height == ViewGroup.LayoutParams.MATCH_PARENT && lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
setMeasuredDimension(height, height);
} else if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT && lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
setMeasuredDimension(width, width);
} else {
if (width > height) {
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
setMeasuredDimension(height, height);
} else {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
setMeasuredDimension(width, width);
}
}
}
}

View File

@ -25,6 +25,7 @@ public class StatusTextView extends ThemedTextView implements IExtendedView {
super(context, attrs);
}
public StatusTextView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@ -48,6 +49,32 @@ public class StatusTextView extends ThemedTextView implements IExtendedView {
mOnSelectionChangeListener = l;
}
@Override
public void setText(CharSequence text, BufferType type) {
if (text == null) {
super.setText(null, type);
return;
}
super.setText(new SafeSpannableStringWrapper(text), type);
}
@Override
protected void onSelectionChanged(final int selStart, final int selEnd) {
super.onSelectionChanged(selStart, selEnd);
if (mOnSelectionChangeListener != null) {
mOnSelectionChangeListener.onSelectionChanged(selStart, selEnd);
}
}
@Override
public final boolean onTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.onTouchEvent(this, event);
if (ret) return true;
}
return super.onTouchEvent(event);
}
@Override
protected boolean fitSystemWindows(@NonNull Rect insets) {
if (mOnFitSystemWindowsListener != null) {
@ -73,21 +100,8 @@ public class StatusTextView extends ThemedTextView implements IExtendedView {
}
}
@Override
protected void onSelectionChanged(final int selStart, final int selEnd) {
super.onSelectionChanged(selStart, selEnd);
if (mOnSelectionChangeListener != null) {
mOnSelectionChangeListener.onSelectionChanged(selStart, selEnd);
}
}
@Override
public void setText(CharSequence text, BufferType type) {
if (text == null) {
super.setText(null, type);
return;
}
super.setText(new SafeSpannableStringWrapper(text), type);
public interface OnSelectionChangeListener {
void onSelectionChanged(int selStart, int selEnd);
}
private static class SafeSpannableStringWrapper extends SpannableString {
@ -106,17 +120,4 @@ public class StatusTextView extends ThemedTextView implements IExtendedView {
}
}
@Override
public final boolean onTouchEvent(@NonNull final MotionEvent event) {
if (mTouchInterceptor != null) {
final boolean ret = mTouchInterceptor.onTouchEvent(this, event);
if (ret) return true;
}
return super.onTouchEvent(event);
}
public interface OnSelectionChangeListener {
void onSelectionChanged(int selStart, int selEnd);
}
}

View File

@ -164,14 +164,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
replyRetweetIcon.setVisibility(View.GONE);
}
final int typeIconRes = getUserTypeIconRes(status.user_is_verified, status.user_is_protected);
if (typeIconRes != 0) {
profileTypeView.setImageResource(typeIconRes);
profileTypeView.setVisibility(View.VISIBLE);
} else {
profileTypeView.setImageDrawable(null);
profileTypeView.setVisibility(View.GONE);
}
final int typeIconRes;
if (status.is_quote) {
quotedNameView.setText(getUserNickname(context, status.user_id, status.user_name, true));
@ -202,10 +195,14 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, status.quoted_by_user_profile_image);
typeIconRes = getUserTypeIconRes(status.quoted_by_user_is_verified, status.quoted_by_user_is_protected);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
typeIconRes = 0;
}
final int userColor = UserColorNameUtils.getUserColor(context, status.quoted_by_user_id);
@ -220,19 +217,30 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
quoteIndicator.setVisibility(View.GONE);
if (adapter.isProfileImageEnabled()) {
final String user_profile_image_url = status.user_profile_image_url;
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
final String user_profile_image_url = status.user_profile_image_url;
loader.displayProfileImage(profileImageView, user_profile_image_url);
typeIconRes = getUserTypeIconRes(status.user_is_verified, status.user_is_protected);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
typeIconRes = 0;
}
final int userColor = UserColorNameUtils.getUserColor(context, status.user_id);
itemContent.drawStart(userColor);
}
if (typeIconRes != 0) {
profileTypeView.setImageResource(typeIconRes);
profileTypeView.setVisibility(View.VISIBLE);
} else {
profileTypeView.setImageDrawable(null);
profileTypeView.setVisibility(View.GONE);
}
if (adapter.shouldShowAccountsColor()) {
itemContent.drawEnd(Utils.getAccountColor(context, status.account_id));
@ -390,20 +398,21 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
quoteIndicator.setColor(UserColorNameUtils.getUserColor(context, user_id));
if (adapter.isProfileImageEnabled()) {
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, cursor.getString(indices.quoted_by_user_profile_image));
typeIconRes = getUserTypeIconRes(cursor.getShort(indices.quoted_by_user_is_verified) == 1,
cursor.getShort(indices.quoted_by_user_is_protected) == 1);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
typeIconRes = 0;
}
final int userColor = UserColorNameUtils.getUserColor(context, cursor.getLong(indices.quoted_by_user_id));
itemContent.drawStart(userColor);
typeIconRes = getUserTypeIconRes(cursor.getShort(indices.quoted_by_user_is_verified) == 1,
cursor.getShort(indices.quoted_by_user_is_protected) == 1);
} else {
nameView.setText(user_name);
screenNameView.setText("@" + user_screen_name);
@ -414,20 +423,21 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
quoteIndicator.setVisibility(View.GONE);
if (adapter.isProfileImageEnabled()) {
final String user_profile_image_url = cursor.getString(indices.user_profile_image_url);
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
final String user_profile_image_url = cursor.getString(indices.user_profile_image_url);
loader.displayProfileImage(profileImageView, user_profile_image_url);
typeIconRes = getUserTypeIconRes(cursor.getShort(indices.is_verified) == 1,
cursor.getShort(indices.is_protected) == 1);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
typeIconRes = 0;
}
final int userColor = UserColorNameUtils.getUserColor(context, user_id);
itemContent.drawStart(userColor);
typeIconRes = getUserTypeIconRes(cursor.getShort(indices.is_verified) == 1,
cursor.getShort(indices.is_protected) == 1);
}
if (typeIconRes != 0) {

View File

@ -20,6 +20,7 @@
package org.mariotaku.twidere.view.iface;
import android.graphics.Rect;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;

View File

@ -2,7 +2,7 @@
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
~ 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
@ -18,27 +18,26 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout
android:id="@+id/go_top"
style="?android:actionButtonStyle"
<org.mariotaku.twidere.view.ExtendedLinearLayout
android:id="@+id/keyboard_shortcut_input"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:padding="4dp">
android:gravity="center"
android:padding="@dimen/element_spacing_xlarge">
<org.mariotaku.twidere.view.ActionBarTitleView
android:id="@+id/actionbar_title"
<TextView
android:id="@+id/keys_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"/>
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/keyboard_shortcut_hint"/>
<org.mariotaku.twidere.view.ActionBarSubtitleView
android:id="@+id/actionbar_subtitle"
<TextView
android:id="@+id/conflict_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:visibility="gone"/>
android:layout_height="wrap_content"/>
</LinearLayout>
</org.mariotaku.twidere.view.ExtendedLinearLayout>

View File

@ -20,6 +20,7 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -36,7 +37,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
android:orientation="vertical"
android:visibility="gone">
<View
android:layout_width="match_parent"
@ -49,4 +51,14 @@
android:layout_height="wrap_content"
android:background="#80000000"/>
</LinearLayout>
<org.mariotaku.twidere.view.LinePageIndicator
android:id="@+id/pager_indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="@dimen/element_spacing_normal"
app:lineWidth="@dimen/line_indicator_line_width_wizard"
app:selectedColor="?android:colorActivatedHighlight"
app:strokeWidth="@dimen/line_indicator_stroke_width_wizard"/>
</FrameLayout>

View File

@ -19,12 +19,12 @@
-->
<org.mariotaku.twidere.view.ExtendedRelativeLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_content"
android:padding="@dimen/element_spacing_normal">
<android.support.v7.widget.CardView
@ -61,11 +61,15 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@android:color/transparent"
android:focusable="true"
android:hint="@string/search_hint"
android:imeActionLabel="@android:string/search_go"
android:imeOptions="actionSearch"
android:inputType="text"
android:singleLine="true"/>
android:singleLine="true">
<requestFocus/>
</EditText>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/search_submit"
@ -86,8 +90,8 @@
android:id="@+id/suggestions_list"
android:layout_width="match_parent"
android:layout_height="0dp"
tools:listitem="@layout/list_item_user"
android:layout_weight="1"/>
android:layout_weight="1"
tools:listitem="@layout/list_item_user"/>
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@ -35,7 +35,6 @@
android:layout_gravity="top"
android:padding="@dimen/element_spacing_normal"
app:lineWidth="@dimen/line_indicator_line_width_wizard"
app:selectedColor="?android:colorActivatedHighlight"
app:strokeWidth="@dimen/line_indicator_stroke_width_wizard"/>
</merge>

View File

@ -21,6 +21,7 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
@ -36,7 +37,8 @@
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
@ -213,87 +215,52 @@
android:orientation="vertical"
android:padding="@dimen/element_spacing_normal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/element_spacing_small"
android:text="@string/name"
android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
<EditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:inputType="textPersonName"
android:maxLength="20"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"/>
app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/name"
app:met_maxCharacters="20"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/element_spacing_small"
android:text="@string/description"
android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
<EditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:inputType="textMultiLine"
android:maxLength="160"
android:minLines="4"
android:singleLine="false"
android:textAppearance="?android:attr/textAppearanceMedium"/>
app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/description"
app:met_maxCharacters="160"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/element_spacing_small"
android:singleLine="true"
android:text="@string/location"
android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
<EditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPostalAddress"
android:maxLength="30"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"/>
app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/location"
app:met_maxCharacters="30"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/element_spacing_small"
android:singleLine="true"
android:text="@string/url"
android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
<EditText
<com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri"
android:maxLength="100"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"/>
app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/url"
app:met_maxCharacters="100"/>
</LinearLayout>
</android.support.v7.widget.CardView>
@ -378,24 +345,18 @@
<FrameLayout
android:id="@+id/progress_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:visibility="visible"
tools:visibility="gone">
<ProgressBar
style="?android:attr/progressBarStyleLarge"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
</FrameLayout>
<!--<org.mariotaku.twidere.view.ActionBarThemedContainer-->
<!--android:id="@+id/done_bar_container"-->
<!--style="?actionBarStyle"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="?actionBarSize"-->
<!--android:layout="@layout/actionbar_custom_view_done_cancel"/>-->
<org.mariotaku.twidere.view.TwidereToolbar
android:id="@+id/done_bar"
style="?actionBarStyle"

View File

@ -31,7 +31,7 @@
android:layout_height="match_parent"
android:clipToPadding="false">
<android.support.v7.widget.RecyclerView
<org.mariotaku.twidere.view.RecyclerViewBackport
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -31,12 +31,6 @@
android:text="@string/phishing_link_warning_message_1"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<!--<org.mariotaku.twidere.view.AutoAdjustHeightImageView-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_marginBottom="8dp"-->
<!--android:layout_marginTop="8dp"/>-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -27,7 +27,7 @@
<color name="unread_color">@color/material_red</color>
<color name="branding_color">@color/material_cyan</color>
<color name="bg_color_tab_pressed">#40808080</color>
<color name="bg_color_media_viewer">#a0000000</color>
<color name="bg_color_media_viewer">#cc000000</color>
<color name="background_color_card_item_dark">#1a1a1a</color>
<color name="background_color_card_item_light">#fafafa</color>
<color name="background_color_action_bar_dark">#212121</color>

View File

@ -738,5 +738,8 @@
<string name="N_favorites_quantity_other"><xliff:g id="count">%d</xliff:g> favorites</string>
<string name="drafts_hint_messages">Your unsent tweets will goes here</string>
<string name="keyboard_shortcuts">Keyboard shortcuts</string>
<string name="keyboard_shortcut_hint">Press keys</string>
<string name="conflicts_with_name">Conflicts with <xliff:g id="name">%s</xliff:g></string>
<string name="overwrite">Overwrite</string>
</resources>