improved keyboard shortcut - navigate back key
material theme improvements
This commit is contained in:
parent
9eaf596f77
commit
39f55889fa
|
@ -172,7 +172,9 @@ public class SettingsActivity extends BasePreferenceActivity {
|
|||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_HOME: {
|
||||
onBackPressed();
|
||||
if (!isFinishing()) {
|
||||
onBackPressed();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case MENU_IMPORT_SETTINGS: {
|
||||
|
|
|
@ -120,12 +120,12 @@ public class BaseAppCompatActivity extends ThemedAppCompatActivity implements Co
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutRepeat(KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,7 @@ public class ComposeActivity extends ThemedFragmentActivity implements LocationL
|
|||
private boolean mIsPossiblySensitive, mShouldSaveAccounts;
|
||||
private boolean mImageUploaderUsed, mStatusShortenerUsed;
|
||||
private boolean mNavigateBackPressed;
|
||||
private boolean mTextChanged;
|
||||
|
||||
@Override
|
||||
public int getThemeColor() {
|
||||
|
@ -616,6 +617,7 @@ public class ComposeActivity extends ThemedFragmentActivity implements LocationL
|
|||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
mTextChanged = true;
|
||||
setMenu();
|
||||
updateTextCount();
|
||||
}
|
||||
|
@ -707,9 +709,9 @@ public class ComposeActivity extends ThemedFragmentActivity implements LocationL
|
|||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
final String action = handler.getKeyAction("navigation", keyCode, event);
|
||||
if ("navigation.back".equals(action)) {
|
||||
if (mEditText.length() == 0) {
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (ACTION_NAVIGATION_BACK.equals(action)) {
|
||||
if (mEditText.length() == 0 && !mTextChanged) {
|
||||
if (!mNavigateBackPressed) {
|
||||
final SuperToast toast = SuperToast.create(this, getString(R.string.press_again_to_close), Duration.SHORT);
|
||||
toast.setOnDismissListener(new OnDismissListener() {
|
||||
|
@ -723,6 +725,8 @@ public class ComposeActivity extends ThemedFragmentActivity implements LocationL
|
|||
} else {
|
||||
onBackPressed();
|
||||
}
|
||||
} else {
|
||||
mTextChanged = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -261,12 +261,12 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event)) return true;
|
||||
String action = handler.getKeyAction("home", keyCode, event);
|
||||
String action = handler.getKeyAction(CONTEXT_TAG_HOME, keyCode, event);
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case "home.accounts_dashboard": {
|
||||
case ACTION_HOME_ACCOUNTS_DASHBOARD: {
|
||||
if (mSlidingMenu.isMenuShowing()) {
|
||||
mSlidingMenu.showContent(true);
|
||||
} else {
|
||||
|
@ -277,10 +277,10 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
|
|||
}
|
||||
}
|
||||
}
|
||||
action = handler.getKeyAction("navigation", keyCode, event);
|
||||
action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case "navigation.previous_tab": {
|
||||
case ACTION_NAVIGATION_PREVIOUS_TAB: {
|
||||
final int previous = mViewPager.getCurrentItem() - 1;
|
||||
if (previous < 0) {
|
||||
mSlidingMenu.showMenu(true);
|
||||
|
@ -294,7 +294,7 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
|
|||
}
|
||||
return true;
|
||||
}
|
||||
case "navigation.next_tab": {
|
||||
case ACTION_NAVIGATION_NEXT_TAB: {
|
||||
final int next = mViewPager.getCurrentItem() + 1;
|
||||
if (next >= mPagerAdapter.getCount()) {
|
||||
mSlidingMenu.showSecondaryMenu(true);
|
||||
|
@ -326,7 +326,7 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutRepeat(KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
if (handleFragmentKeyboardShortcutRepeat(handler, keyCode, repeatCount, event)) return true;
|
||||
return super.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event);
|
||||
}
|
||||
|
|
|
@ -113,13 +113,13 @@ public class LinkHandlerActivity extends BaseAppCompatActivity implements System
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event)) return true;
|
||||
return handler.handleKey(this, null, keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutRepeat(KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
if (handleFragmentKeyboardShortcutRepeat(handler, keyCode, repeatCount, event)) return true;
|
||||
return super.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event);
|
||||
}
|
||||
|
@ -220,7 +220,14 @@ public class LinkHandlerActivity extends BaseAppCompatActivity implements System
|
|||
@NonNull KeyEvent event) {
|
||||
final Fragment fragment = getCurrentVisibleFragment();
|
||||
if (fragment instanceof KeyboardShortcutCallback) {
|
||||
return ((KeyboardShortcutCallback) fragment).handleKeyboardShortcutSingle(handler, keyCode, event);
|
||||
if (((KeyboardShortcutCallback) fragment).handleKeyboardShortcutSingle(handler, keyCode, event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (ACTION_NAVIGATION_BACK.equals(action)) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.graphics.PorterDuff.Mode;
|
|||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
|
@ -35,6 +36,7 @@ import android.text.Editable;
|
|||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
@ -68,6 +70,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.SavedSearches;
|
|||
import org.mariotaku.twidere.provider.TwidereDataStore.SearchHistory;
|
||||
import org.mariotaku.twidere.util.EditTextEnterHandler;
|
||||
import org.mariotaku.twidere.util.EditTextEnterHandler.EnterListener;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
|
||||
import org.mariotaku.twidere.util.MediaLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
import org.mariotaku.twidere.util.SwipeDismissListViewTouchListener;
|
||||
|
@ -97,6 +100,7 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
private SuggestionsAdapter mUsersSearchAdapter;
|
||||
private ExtendedRelativeLayout mMainContent;
|
||||
private Rect mSystemWindowsInsets = new Rect();
|
||||
private boolean mTextChanged;
|
||||
|
||||
@Override
|
||||
public boolean canDismiss(int position) {
|
||||
|
@ -186,6 +190,20 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (ACTION_NAVIGATION_BACK.equals(action) && mSearchQuery.length() == 0) {
|
||||
if (!mTextChanged) {
|
||||
onBackPressed();
|
||||
} else {
|
||||
mTextChanged = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return super.handleKeyboardShortcutSingle(handler, keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -227,6 +245,7 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
mTextChanged = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -304,6 +323,15 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
mQuery = query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(SuggestionsAdapter adapter, View view, int position) {
|
||||
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
|
||||
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
|
||||
text1.setText(mQuery);
|
||||
icon.setImageResource(R.drawable.ic_action_save);
|
||||
icon.setColorFilter(text1.getCurrentTextColor(), Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getItemLayoutResource() {
|
||||
return R.layout.list_item_suggestion_search;
|
||||
|
@ -314,15 +342,6 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
return ITEM_VIEW_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(SuggestionsAdapter adapter, View view, int position) {
|
||||
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
|
||||
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
|
||||
text1.setText(mQuery);
|
||||
icon.setImageResource(R.drawable.ic_action_save);
|
||||
icon.setColorFilter(text1.getCurrentTextColor(), Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onItemClick(QuickSearchBarActivity activity, int position) {
|
||||
|
@ -342,6 +361,10 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
mQuery = query;
|
||||
}
|
||||
|
||||
public long getCursorId() {
|
||||
return mCursorId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(SuggestionsAdapter adapter, View view, int position) {
|
||||
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
|
||||
|
@ -351,10 +374,6 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
icon.setColorFilter(text1.getCurrentTextColor(), Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
public long getCursorId() {
|
||||
return mCursorId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getItemLayoutResource() {
|
||||
return R.layout.list_item_suggestion_search;
|
||||
|
@ -371,7 +390,6 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
activity.finish();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class SuggestionsAdapter extends BaseAdapter {
|
||||
|
|
|
@ -81,7 +81,7 @@ public class UserHashtagAutoCompleteAdapter extends SimpleCursorAdapter implemen
|
|||
}
|
||||
|
||||
public UserHashtagAutoCompleteAdapter(final Context context, final EditText view) {
|
||||
super(context, R.layout.list_item_two_line_small, null, FROM, TO, 0);
|
||||
super(context, R.layout.list_item_auto_complete, null, FROM, TO, 0);
|
||||
mEditText = view;
|
||||
mPreferences = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
mUserNicknamePreferences = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.constant;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/23.
|
||||
*/
|
||||
public interface KeyboardShortcutConstants {
|
||||
|
||||
String CONTEXT_TAG_NAVIGATION = "navigation";
|
||||
String CONTEXT_TAG_STATUS = "status";
|
||||
String CONTEXT_TAG_HOME = "home";
|
||||
|
||||
String ACTION_NAVIGATION_BACK = "navigation.back";
|
||||
String ACTION_NAVIGATION_NEXT_TAB = "navigation.next_tab";
|
||||
String ACTION_NAVIGATION_PREVIOUS_TAB = "navigation.previous_tab";
|
||||
String ACTION_NAVIGATION_REFRESH = "navigation.refresh";
|
||||
String ACTION_NAVIGATION_NEXT = "navigation.next";
|
||||
String ACTION_NAVIGATION_PREVIOUS = "navigation.previous";
|
||||
String ACTION_STATUS_FAVORITE = "status.favorite";
|
||||
String ACTION_STATUS_RETWEET = "status.retweet";
|
||||
String ACTION_STATUS_REPLY = "status.reply";
|
||||
String ACTION_HOME_ACCOUNTS_DASHBOARD = "home.accounts_dashboard";
|
||||
String ACTION_MESSAGE = "message";
|
||||
String ACTION_SEARCH = "search";
|
||||
String ACTION_COMPOSE = "compose";
|
||||
}
|
|
@ -51,13 +51,14 @@ import android.widget.TextView;
|
|||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.activity.KeyboardShortcutPreferenceCompatActivity;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.constant.KeyboardShortcutConstants;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutSpec;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/10.
|
||||
*/
|
||||
public class KeyboardShortcutsFragment extends BasePreferenceFragment {
|
||||
public class KeyboardShortcutsFragment extends BasePreferenceFragment implements KeyboardShortcutConstants {
|
||||
|
||||
private KeyboardShortcutsHandler mKeyboardShortcutHandler;
|
||||
|
||||
|
@ -102,18 +103,18 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
|
|||
general.addPreference(makePreferences(null, "search"));
|
||||
general.addPreference(makePreferences(null, "message"));
|
||||
final PreferenceCategory home = makeAndAddCategory(getString(R.string.home));
|
||||
home.addPreference(makePreferences("home", "home.accounts_dashboard"));
|
||||
home.addPreference(makePreferences("home", ACTION_HOME_ACCOUNTS_DASHBOARD));
|
||||
final PreferenceCategory navigation = makeAndAddCategory(getString(R.string.navigation));
|
||||
navigation.addPreference(makePreferences("navigation", "navigation.previous"));
|
||||
navigation.addPreference(makePreferences("navigation", "navigation.next"));
|
||||
navigation.addPreference(makePreferences("navigation", "navigation.previous_tab"));
|
||||
navigation.addPreference(makePreferences("navigation", "navigation.next_tab"));
|
||||
navigation.addPreference(makePreferences("navigation", "navigation.refresh"));
|
||||
navigation.addPreference(makePreferences("navigation", "navigation.back"));
|
||||
navigation.addPreference(makePreferences(CONTEXT_TAG_NAVIGATION, ACTION_NAVIGATION_PREVIOUS));
|
||||
navigation.addPreference(makePreferences(CONTEXT_TAG_NAVIGATION, ACTION_NAVIGATION_NEXT));
|
||||
navigation.addPreference(makePreferences(CONTEXT_TAG_NAVIGATION, ACTION_NAVIGATION_PREVIOUS_TAB));
|
||||
navigation.addPreference(makePreferences(CONTEXT_TAG_NAVIGATION, ACTION_NAVIGATION_NEXT_TAB));
|
||||
navigation.addPreference(makePreferences(CONTEXT_TAG_NAVIGATION, ACTION_NAVIGATION_REFRESH));
|
||||
navigation.addPreference(makePreferences(CONTEXT_TAG_NAVIGATION, ACTION_NAVIGATION_BACK));
|
||||
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"));
|
||||
statuses.addPreference(makePreferences(CONTEXT_TAG_STATUS, ACTION_STATUS_REPLY));
|
||||
statuses.addPreference(makePreferences(CONTEXT_TAG_STATUS, ACTION_STATUS_RETWEET));
|
||||
statuses.addPreference(makePreferences(CONTEXT_TAG_STATUS, ACTION_STATUS_FAVORITE));
|
||||
}
|
||||
|
||||
private PreferenceCategory makeAndAddCategory(String title) {
|
||||
|
@ -198,7 +199,9 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
|
|||
builder.setNegativeButton(getContext().getString(android.R.string.cancel), this);
|
||||
builder.setNeutralButton(getContext().getString(R.string.clear), this);
|
||||
builder.setOnKeyListener(this);
|
||||
} @Override
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToActivity() {
|
||||
super.onAttachedToActivity();
|
||||
mKeyboardShortcutHandler.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
|
||||
|
@ -226,7 +229,9 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} @Override
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPrepareForRemoval() {
|
||||
mKeyboardShortcutHandler.unregisterOnSharedPreferenceChangeListener(mPreferencesChangeListener);
|
||||
super.onPrepareForRemoval();
|
||||
|
@ -238,9 +243,6 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static class KeyboardShortcutPreferenceCompat extends Preference {
|
||||
|
@ -279,7 +281,9 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
|
|||
private void updateSummary() {
|
||||
final KeyboardShortcutSpec spec = mKeyboardShortcutHandler.findKey(mAction);
|
||||
setSummary(spec != null ? spec.toKeyString() : null);
|
||||
} @Override
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToActivity() {
|
||||
super.onAttachedToActivity();
|
||||
mKeyboardShortcutHandler.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
|
||||
|
@ -292,8 +296,6 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class ResetKeyboardShortcutConfirmDialogFragment extends DialogFragment implements OnClickListener {
|
||||
|
|
|
@ -88,10 +88,10 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentListFragment<A
|
|||
public abstract int getStatuses(long[] accountIds, long[] maxIds, long[] sinceIds);
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
if (!KeyboardShortcutsHandler.isValidForHotkey(keyCode, event)) return false;
|
||||
String action = handler.getKeyAction("navigation", keyCode, event);
|
||||
if ("navigation.refresh".equals(action)) {
|
||||
String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (ACTION_NAVIGATION_REFRESH.equals(action)) {
|
||||
triggerRefresh();
|
||||
return true;
|
||||
}
|
||||
|
@ -108,21 +108,21 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentListFragment<A
|
|||
final ParcelableStatus status = getAdapter().getStatus(position);
|
||||
if (status == null) return false;
|
||||
if (action == null) {
|
||||
action = handler.getKeyAction("status", keyCode, event);
|
||||
action = handler.getKeyAction(CONTEXT_TAG_STATUS, keyCode, event);
|
||||
}
|
||||
if (action == null) return false;
|
||||
switch (action) {
|
||||
case "status.reply": {
|
||||
case ACTION_STATUS_REPLY: {
|
||||
final Intent intent = new Intent(INTENT_ACTION_REPLY);
|
||||
intent.putExtra(EXTRA_STATUS, status);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
case "status.retweet": {
|
||||
case ACTION_STATUS_RETWEET: {
|
||||
RetweetQuoteDialogFragment.show(getFragmentManager(), status);
|
||||
return true;
|
||||
}
|
||||
case "status.favorite": {
|
||||
case ACTION_STATUS_FAVORITE: {
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
if (status.is_favorite) {
|
||||
twitter.destroyFavoriteAsync(status.account_id, status.id);
|
||||
|
@ -136,7 +136,7 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentListFragment<A
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutRepeat(KeyboardShortcutsHandler handler, final int keyCode, final int repeatCount,
|
||||
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, final int keyCode, final int repeatCount,
|
||||
@NonNull final KeyEvent event) {
|
||||
return mRecyclerViewNavigationHelper.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ import android.view.View;
|
|||
|
||||
import org.mariotaku.twidere.adapter.AbsUsersAdapter;
|
||||
import org.mariotaku.twidere.adapter.AbsUsersAdapter.UserAdapterListener;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
|
||||
import org.mariotaku.twidere.model.ParcelableUser;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
|
||||
|
@ -53,12 +52,12 @@ abstract class AbsUsersFragment<Data> extends AbsContentListFragment<AbsUsersAda
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutRepeat(KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
return mRecyclerViewNavigationHelper.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event);
|
||||
}
|
||||
|
||||
|
@ -67,7 +66,6 @@ abstract class AbsUsersFragment<Data> extends AbsContentListFragment<AbsUsersAda
|
|||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
final FragmentActivity activity = getActivity();
|
||||
final TwidereApplication application = TwidereApplication.getInstance(activity);
|
||||
final AbsUsersAdapter<Data> adapter = getAdapter();
|
||||
final RecyclerView recyclerView = getRecyclerView();
|
||||
final LinearLayoutManager layoutManager = getLayoutManager();
|
||||
|
|
|
@ -164,15 +164,15 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
public boolean handleKeyboardShortcutRepeat(@NonNull final KeyboardShortcutsHandler handler,
|
||||
final int keyCode, final int repeatCount,
|
||||
@NonNull final KeyEvent event) {
|
||||
final String action = handler.getKeyAction("navigation", keyCode, event);
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (action == null) return false;
|
||||
final int offset;
|
||||
switch (action) {
|
||||
case "navigation.previous": {
|
||||
case ACTION_NAVIGATION_PREVIOUS: {
|
||||
offset = -1;
|
||||
break;
|
||||
}
|
||||
case "navigation.next": {
|
||||
case ACTION_NAVIGATION_NEXT: {
|
||||
offset = 1;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import android.graphics.Rect;
|
|||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
|
@ -44,7 +45,7 @@ import android.support.v7.widget.RecyclerView;
|
|||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -62,6 +63,9 @@ import android.widget.ListView;
|
|||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.johnpersano.supertoasts.SuperToast;
|
||||
import com.github.johnpersano.supertoasts.SuperToast.Duration;
|
||||
import com.github.johnpersano.supertoasts.SuperToast.OnDismissListener;
|
||||
import com.squareup.otto.Bus;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
|
@ -87,10 +91,13 @@ import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
|
|||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Conversation;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries;
|
||||
import org.mariotaku.twidere.util.AsyncTaskUtils;
|
||||
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
||||
import org.mariotaku.twidere.util.ClipboardUtils;
|
||||
import org.mariotaku.twidere.util.EditTextEnterHandler;
|
||||
import org.mariotaku.twidere.util.EditTextEnterHandler.EnterListener;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
|
||||
import org.mariotaku.twidere.util.MediaLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
import org.mariotaku.twidere.util.ReadStateManager;
|
||||
|
@ -103,7 +110,6 @@ import org.mariotaku.twidere.view.StatusTextCountView;
|
|||
import org.mariotaku.twidere.view.iface.IColorLabelView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -113,49 +119,14 @@ import static org.mariotaku.twidere.util.Utils.showOkMessage;
|
|||
|
||||
public class MessagesConversationFragment extends BaseSupportFragment implements
|
||||
LoaderCallbacks<Cursor>, OnClickListener, OnItemSelectedListener, MenuButtonClickListener,
|
||||
PopupMenu.OnMenuItemClickListener {
|
||||
PopupMenu.OnMenuItemClickListener, KeyboardShortcutCallback {
|
||||
|
||||
// Constants
|
||||
private static final int LOADER_ID_SEARCH_USERS = 1;
|
||||
|
||||
private static final String EXTRA_FROM_CACHE = "from_cache";
|
||||
|
||||
private TwidereValidator mValidator;
|
||||
private AsyncTwitterWrapper mTwitterWrapper;
|
||||
private SharedPreferences mPreferences;
|
||||
private SharedPreferences mMessageDrafts;
|
||||
private ReadStateManager mReadStateManager;
|
||||
|
||||
private RecyclerView mMessagesListView;
|
||||
private ListView mUsersSearchList;
|
||||
private StatusComposeEditText mEditText;
|
||||
private StatusTextCountView mTextCountView;
|
||||
private View mSendButton;
|
||||
private ImageView mAddImageButton;
|
||||
private View mConversationContainer, mRecipientSelectorContainer;
|
||||
private Spinner mAccountSpinner;
|
||||
private ImageView mRecipientProfileImageView;
|
||||
private EditText mUserQuery;
|
||||
private View mUsersSearchProgress;
|
||||
private View mQueryButton;
|
||||
private View mUsersSearchEmpty;
|
||||
private TextView mUsersSearchEmptyText;
|
||||
|
||||
private PopupMenu mPopupMenu;
|
||||
|
||||
private ParcelableDirectMessage mSelectedDirectMessage;
|
||||
private boolean mLoaderInitialized;
|
||||
private String mImageUri;
|
||||
|
||||
|
||||
private MessageConversationAdapter mAdapter;
|
||||
private SimpleParcelableUsersAdapter mUsersSearchAdapter;
|
||||
|
||||
private ParcelableAccount mAccount;
|
||||
private ParcelableUser mRecipient;
|
||||
|
||||
private MediaLoaderWrapper mImageLoader;
|
||||
private IColorLabelView mProfileImageContainer;
|
||||
|
||||
// Callbacks
|
||||
private LoaderCallbacks<List<ParcelableUser>> mSearchLoadersCallback = new LoaderCallbacks<List<ParcelableUser>>() {
|
||||
@Override
|
||||
public Loader<List<ParcelableUser>> onCreateLoader(int id, Bundle args) {
|
||||
|
@ -184,12 +155,70 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
}
|
||||
};
|
||||
|
||||
// Utility classes
|
||||
private TwidereValidator mValidator;
|
||||
private AsyncTwitterWrapper mTwitterWrapper;
|
||||
private SharedPreferences mPreferences;
|
||||
private SharedPreferences mMessageDrafts;
|
||||
private ReadStateManager mReadStateManager;
|
||||
private MediaLoaderWrapper mImageLoader;
|
||||
|
||||
// Views
|
||||
private RecyclerView mMessagesListView;
|
||||
private ListView mUsersSearchList;
|
||||
private StatusComposeEditText mEditText;
|
||||
private StatusTextCountView mTextCountView;
|
||||
private View mSendButton;
|
||||
private ImageView mAddImageButton;
|
||||
private View mConversationContainer, mRecipientSelectorContainer;
|
||||
private Spinner mAccountSpinner;
|
||||
private ImageView mRecipientProfileImageView;
|
||||
private EditText mEditUserQuery;
|
||||
private View mUsersSearchProgress;
|
||||
private View mQueryButton;
|
||||
private View mUsersSearchEmpty;
|
||||
private TextView mUsersSearchEmptyText;
|
||||
private PopupMenu mPopupMenu;
|
||||
private IColorLabelView mProfileImageContainer;
|
||||
|
||||
// Adapters
|
||||
private MessageConversationAdapter mAdapter;
|
||||
private SimpleParcelableUsersAdapter mUsersSearchAdapter;
|
||||
|
||||
// Data fields
|
||||
private boolean mSearchUsersLoaderInitialized;
|
||||
private boolean mNavigateBackPressed;
|
||||
private ParcelableDirectMessage mSelectedDirectMessage;
|
||||
private boolean mLoaderInitialized;
|
||||
private String mImageUri;
|
||||
private ParcelableAccount mAccount;
|
||||
private ParcelableUser mRecipient;
|
||||
private boolean mTextChanged, mQueryTextChanged;
|
||||
|
||||
@Subscribe
|
||||
public void notifyTaskStateChanged(TaskStateChangedEvent event) {
|
||||
updateRefreshState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_PICK_IMAGE: {
|
||||
if (resultCode != Activity.RESULT_OK || data.getDataString() == null) {
|
||||
break;
|
||||
}
|
||||
mImageUri = data.getDataString();
|
||||
updateAddImageButton();
|
||||
break;
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_messages_conversation, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
|
@ -214,7 +243,7 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
actionBar.setCustomView(R.layout.actionbar_custom_view_message_user_picker);
|
||||
final View actionBarView = actionBar.getCustomView();
|
||||
mAccountSpinner = (Spinner) actionBarView.findViewById(R.id.account_spinner);
|
||||
mUserQuery = (EditText) actionBarView.findViewById(R.id.user_query);
|
||||
mEditUserQuery = (EditText) actionBarView.findViewById(R.id.user_query);
|
||||
mQueryButton = actionBarView.findViewById(R.id.query_button);
|
||||
final List<ParcelableAccount> accounts = ParcelableAccount.getAccountsList(activity, false);
|
||||
final AccountsSpinnerAdapter accountsSpinnerAdapter = new AccountsSpinnerAdapter(
|
||||
|
@ -291,14 +320,322 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
|
||||
bus.register(this);
|
||||
updateTextCount();
|
||||
updateEmptyText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
final String previewScaleType = Utils.getNonEmptyString(mPreferences, KEY_MEDIA_PREVIEW_STYLE,
|
||||
ScaleType.CENTER_CROP.name());
|
||||
mAdapter.setImagePreviewScaleType(previewScaleType);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
updateAddImageButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(final Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (mEditText != null) {
|
||||
outState.putCharSequence(EXTRA_TEXT, mEditText.getText());
|
||||
}
|
||||
outState.putParcelable(EXTRA_ACCOUNT, mAccount);
|
||||
outState.putParcelable(EXTRA_USER, mRecipient);
|
||||
outState.putString(EXTRA_IMAGE_URI, mImageUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
|
||||
bus.unregister(this);
|
||||
if (mPopupMenu != null) {
|
||||
mPopupMenu.dismiss();
|
||||
}
|
||||
|
||||
final ParcelableAccount account = mAccount;
|
||||
final ParcelableUser recipient = mRecipient;
|
||||
if (account != null && recipient != null) {
|
||||
final String key = getDraftsTextKey(account.account_id, recipient.id);
|
||||
final SharedPreferences.Editor editor = mMessageDrafts.edit();
|
||||
editor.putString(key, ParseUtils.parseString(mEditText.getText()));
|
||||
editor.apply();
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_direct_messages_conversation, menu);
|
||||
final View profileImageItemView = MenuItemCompat.getActionView(menu.findItem(R.id.item_profile_image));
|
||||
profileImageItemView.setOnClickListener(this);
|
||||
mProfileImageContainer = (IColorLabelView) profileImageItemView;
|
||||
mRecipientProfileImageView = (ImageView) profileImageItemView.findViewById(R.id.recipient_profile_image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
updateProfileImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBaseViewCreated(final View view, final Bundle savedInstanceState) {
|
||||
super.onBaseViewCreated(view, savedInstanceState);
|
||||
mUsersSearchProgress = view.findViewById(R.id.users_search_progress);
|
||||
mUsersSearchList = (ListView) view.findViewById(R.id.users_search_list);
|
||||
mUsersSearchEmpty = view.findViewById(R.id.users_search_empty);
|
||||
mUsersSearchEmptyText = (TextView) view.findViewById(R.id.users_search_empty_text);
|
||||
mMessagesListView = (RecyclerView) view.findViewById(R.id.recycler_view);
|
||||
final View inputSendContainer = view.findViewById(R.id.input_send_container);
|
||||
mConversationContainer = view.findViewById(R.id.conversation_container);
|
||||
mRecipientSelectorContainer = view.findViewById(R.id.recipient_selector_container);
|
||||
mEditText = (StatusComposeEditText) inputSendContainer.findViewById(R.id.edit_text);
|
||||
mTextCountView = (StatusTextCountView) inputSendContainer.findViewById(R.id.text_count);
|
||||
mSendButton = inputSendContainer.findViewById(R.id.send);
|
||||
mAddImageButton = (ImageView) inputSendContainer.findViewById(R.id.add_image);
|
||||
mUsersSearchList = (ListView) view.findViewById(R.id.users_search_list);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fitSystemWindows(Rect insets) {
|
||||
final View view = getView();
|
||||
if (view == null) return;
|
||||
view.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
|
||||
final long accountId = args != null ? args.getLong(EXTRA_ACCOUNT_ID, -1) : -1;
|
||||
final long recipientId = args != null ? args.getLong(EXTRA_RECIPIENT_ID, -1) : -1;
|
||||
final String[] cols = DirectMessages.COLUMNS;
|
||||
final boolean isValid = accountId > 0 && recipientId > 0;
|
||||
mConversationContainer.setVisibility(isValid ? View.VISIBLE : View.GONE);
|
||||
mRecipientSelectorContainer.setVisibility(isValid ? View.GONE : View.VISIBLE);
|
||||
if (!isValid)
|
||||
return new CursorLoader(getActivity(), TwidereDataStore.CONTENT_URI_NULL, cols, null, null, null);
|
||||
final Uri uri = buildDirectMessageConversationUri(accountId, recipientId, null);
|
||||
return new CursorLoader(getActivity(), uri, cols, null, null, Conversation.DEFAULT_SORT_ORDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.send: {
|
||||
sendDirectMessage();
|
||||
break;
|
||||
}
|
||||
case R.id.add_image: {
|
||||
final Intent intent = new Intent(getActivity(), ImagePickerActivity.class);
|
||||
startActivityForResult(intent, REQUEST_PICK_IMAGE);
|
||||
break;
|
||||
}
|
||||
case R.id.item_profile_image: {
|
||||
final ParcelableUser recipient = mRecipient;
|
||||
if (recipient == null) return;
|
||||
final Bundle options = Utils.makeSceneTransitionOption(getActivity(),
|
||||
new Pair<View, String>(mRecipientProfileImageView,
|
||||
UserFragment.TRANSITION_NAME_PROFILE_IMAGE));
|
||||
Utils.openUserProfile(getActivity(), recipient.account_id, recipient.id,
|
||||
recipient.screen_name, options);
|
||||
break;
|
||||
}
|
||||
case R.id.query_button: {
|
||||
final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem();
|
||||
searchUsers(account.account_id, ParseUtils.parseString(mEditUserQuery.getText()), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(final AdapterView<?> parent, final View view, final int pos, final long id) {
|
||||
final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem();
|
||||
if (account != null) {
|
||||
mAccount = account;
|
||||
updateProfileImage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(final AdapterView<?> view) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMenuButtonClick(final View button, final int position, final long id) {
|
||||
mSelectedDirectMessage = mAdapter.findItem(id);
|
||||
showMenu(button, mSelectedDirectMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(final Loader<Cursor> loader) {
|
||||
mAdapter.setCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(final MenuItem item) {
|
||||
if (mSelectedDirectMessage != null) {
|
||||
final long message_id = mSelectedDirectMessage.id;
|
||||
final long account_id = mSelectedDirectMessage.account_id;
|
||||
switch (item.getItemId()) {
|
||||
case MENU_DELETE: {
|
||||
mTwitterWrapper.destroyDirectMessageAsync(account_id, message_id);
|
||||
break;
|
||||
}
|
||||
case MENU_COPY: {
|
||||
if (ClipboardUtils.setText(getActivity(), mSelectedDirectMessage.text_plain)) {
|
||||
showOkMessage(getActivity(), R.string.text_copied, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) {
|
||||
mAdapter.setCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (ACTION_NAVIGATION_BACK.equals(action)) {
|
||||
final boolean showingConversation = isShowingConversation();
|
||||
final EditText editText = showingConversation ? mEditText : mEditUserQuery;
|
||||
final boolean textChanged = showingConversation ? mTextChanged : mQueryTextChanged;
|
||||
if (editText.length() == 0 && !textChanged) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (!mNavigateBackPressed) {
|
||||
final SuperToast toast = SuperToast.create(activity, getString(R.string.press_again_to_close), Duration.SHORT);
|
||||
toast.setOnDismissListener(new OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(View view) {
|
||||
mNavigateBackPressed = false;
|
||||
}
|
||||
});
|
||||
toast.show();
|
||||
mNavigateBackPressed = true;
|
||||
} else {
|
||||
activity.onBackPressed();
|
||||
}
|
||||
} else {
|
||||
mQueryTextChanged = false;
|
||||
mTextChanged = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void showConversation(final ParcelableAccount account, final ParcelableUser recipient) {
|
||||
mAccount = account;
|
||||
mRecipient = recipient;
|
||||
if (account == null || recipient == null) return;
|
||||
final LoaderManager lm = getLoaderManager();
|
||||
final Bundle args = new Bundle();
|
||||
args.putLong(EXTRA_ACCOUNT_ID, account.account_id);
|
||||
args.putLong(EXTRA_RECIPIENT_ID, recipient.id);
|
||||
if (mLoaderInitialized) {
|
||||
lm.restartLoader(0, args, this);
|
||||
} else {
|
||||
mLoaderInitialized = true;
|
||||
lm.initLoader(0, args, this);
|
||||
}
|
||||
AsyncTaskUtils.executeTask(new SetReadStateTask(getActivity(), account, recipient));
|
||||
updateActionBar();
|
||||
updateProfileImage();
|
||||
}
|
||||
|
||||
public boolean isShowingConversation() {
|
||||
return mConversationContainer.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
|
||||
private String getDraftsTextKey(long accountId, long userId) {
|
||||
return String.format(Locale.ROOT, "text_%d_to_%d", accountId, userId);
|
||||
}
|
||||
|
||||
private void searchUsers(long accountId, String query, boolean fromCache) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putLong(EXTRA_ACCOUNT_ID, accountId);
|
||||
args.putString(EXTRA_QUERY, query);
|
||||
args.putBoolean(EXTRA_FROM_CACHE, fromCache);
|
||||
final LoaderManager lm = getLoaderManager();
|
||||
if (mSearchUsersLoaderInitialized) {
|
||||
lm.restartLoader(LOADER_ID_SEARCH_USERS, args, mSearchLoadersCallback);
|
||||
} else {
|
||||
mSearchUsersLoaderInitialized = true;
|
||||
lm.initLoader(LOADER_ID_SEARCH_USERS, args, mSearchLoadersCallback);
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void onRefreshFromEnd() {
|
||||
// new TwidereAsyncTask<Object, Object, long[][]>() {
|
||||
//
|
||||
// @Override
|
||||
// protected long[][] doInBackground(final Object... params) {
|
||||
// final long[][] result = new long[2][];
|
||||
// result[0] = getActivatedAccountIds(getActivity());
|
||||
// result[1] = getNewestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onPostExecute(final long[][] result) {
|
||||
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
// if (twitter == null) return;
|
||||
// twitter.getReceivedDirectMessagesAsync(result[0], null, result[1]);
|
||||
// twitter.getSentDirectMessagesAsync(result[0], null, null);
|
||||
// }
|
||||
//
|
||||
// }.executeTask();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onRefresh() {
|
||||
// loadMoreMessages();
|
||||
// }
|
||||
|
||||
private void sendDirectMessage() {
|
||||
final ParcelableAccount account = mAccount;
|
||||
final ParcelableUser recipient = mRecipient;
|
||||
if (mAccount == null || mRecipient == null) return;
|
||||
final String message = mEditText.getText().toString();
|
||||
if (TextUtils.isEmpty(message)) {
|
||||
mEditText.setError(getString(R.string.error_message_no_content));
|
||||
} else if (mValidator.getTweetLength(message) > mValidator.getMaxTweetLength()) {
|
||||
mEditText.setError(getString(R.string.error_message_message_too_long));
|
||||
} else {
|
||||
mTwitterWrapper.sendDirectMessageAsync(account.account_id, recipient.id, message, mImageUri);
|
||||
mEditText.setText(null);
|
||||
mImageUri = null;
|
||||
updateAddImageButton();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupEditQuery() {
|
||||
final EditTextEnterHandler queryEnterHandler = EditTextEnterHandler.attach(mUserQuery, new EnterListener() {
|
||||
final EditTextEnterHandler queryEnterHandler = EditTextEnterHandler.attach(mEditUserQuery, new EnterListener() {
|
||||
@Override
|
||||
public void onHitEnter() {
|
||||
final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem();
|
||||
if (account == null) return;
|
||||
mEditText.setAccountId(account.account_id);
|
||||
searchUsers(account.account_id, ParseUtils.parseString(mUserQuery.getText()), false);
|
||||
searchUsers(account.account_id, ParseUtils.parseString(mEditUserQuery.getText()), false);
|
||||
}
|
||||
}, true);
|
||||
queryEnterHandler.addTextChangedListener(new TextWatcher() {
|
||||
|
@ -309,6 +646,7 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
mQueryTextChanged = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -319,7 +657,7 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
searchUsers(account.account_id, ParseUtils.parseString(s), true);
|
||||
}
|
||||
});
|
||||
mUserQuery.addTextChangedListener(new TextWatcher() {
|
||||
mEditUserQuery.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
|
@ -358,6 +696,7 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
mTextChanged = true;
|
||||
updateTextCount();
|
||||
if (mSendButton == null || s == null) return;
|
||||
mSendButton.setEnabled(mValidator.isValidTweet(s.toString()));
|
||||
|
@ -365,29 +704,48 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
});
|
||||
}
|
||||
|
||||
private String getDraftsTextKey(long accountId, long userId) {
|
||||
return String.format(Locale.ROOT, "text_%d_to_%d", accountId, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_PICK_IMAGE: {
|
||||
if (resultCode != Activity.RESULT_OK || data.getDataString() == null) {
|
||||
break;
|
||||
}
|
||||
mImageUri = data.getDataString();
|
||||
updateAddImageButton();
|
||||
break;
|
||||
}
|
||||
private void showMenu(final View view, final ParcelableDirectMessage dm) {
|
||||
if (mPopupMenu != null) {
|
||||
mPopupMenu.dismiss();
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
final Context context = getActivity();
|
||||
mPopupMenu = new PopupMenu(context, view);
|
||||
mPopupMenu.inflate(R.menu.action_direct_message);
|
||||
final Menu menu = mPopupMenu.getMenu();
|
||||
final MenuItem view_profile_item = menu.findItem(MENU_VIEW_PROFILE);
|
||||
if (view_profile_item != null && dm != null) {
|
||||
view_profile_item.setVisible(dm.account_id != dm.sender_id);
|
||||
}
|
||||
mPopupMenu.setOnMenuItemClickListener(this);
|
||||
mPopupMenu.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
updateProfileImage();
|
||||
private void updateActionBar() {
|
||||
final BaseAppCompatActivity activity = (BaseAppCompatActivity) getActivity();
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (actionBar == null) return;
|
||||
actionBar.setDisplayOptions(mRecipient != null ? ActionBar.DISPLAY_SHOW_TITLE : ActionBar.DISPLAY_SHOW_CUSTOM,
|
||||
ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
|
||||
}
|
||||
|
||||
private void updateAddImageButton() {
|
||||
mAddImageButton.setActivated(mImageUri != null);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean scrollToStart() {
|
||||
// if (mAdapter == null || mAdapter.isEmpty()) return false;
|
||||
// setSelection(mAdapter.getCount() - 1);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
private void updateEmptyText() {
|
||||
final boolean noQuery = mEditUserQuery.length() <= 0;
|
||||
if (noQuery) {
|
||||
mUsersSearchEmptyText.setText(R.string.type_name_to_search);
|
||||
} else {
|
||||
mUsersSearchEmptyText.setText(R.string.no_user_found);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProfileImage() {
|
||||
|
@ -409,285 +767,6 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_direct_messages_conversation, menu);
|
||||
final View profileImageItemView = MenuItemCompat.getActionView(menu.findItem(R.id.item_profile_image));
|
||||
profileImageItemView.setOnClickListener(this);
|
||||
mProfileImageContainer = (IColorLabelView) profileImageItemView;
|
||||
mRecipientProfileImageView = (ImageView) profileImageItemView.findViewById(R.id.recipient_profile_image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.send: {
|
||||
sendDirectMessage();
|
||||
break;
|
||||
}
|
||||
case R.id.add_image: {
|
||||
final Intent intent = new Intent(getActivity(), ImagePickerActivity.class);
|
||||
startActivityForResult(intent, REQUEST_PICK_IMAGE);
|
||||
break;
|
||||
}
|
||||
case R.id.item_profile_image: {
|
||||
final ParcelableUser recipient = mRecipient;
|
||||
if (recipient == null) return;
|
||||
final Bundle options = Utils.makeSceneTransitionOption(getActivity(),
|
||||
new Pair<View, String>(mRecipientProfileImageView,
|
||||
UserFragment.TRANSITION_NAME_PROFILE_IMAGE));
|
||||
Utils.openUserProfile(getActivity(), recipient.account_id, recipient.id,
|
||||
recipient.screen_name, options);
|
||||
break;
|
||||
}
|
||||
case R.id.query_button: {
|
||||
final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem();
|
||||
searchUsers(account.account_id, ParseUtils.parseString(mUserQuery.getText()), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mSearchUsersLoaderInitialized;
|
||||
|
||||
private void searchUsers(long accountId, String query, boolean fromCache) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putLong(EXTRA_ACCOUNT_ID, accountId);
|
||||
args.putString(EXTRA_QUERY, query);
|
||||
args.putBoolean(EXTRA_FROM_CACHE, fromCache);
|
||||
final LoaderManager lm = getLoaderManager();
|
||||
if (mSearchUsersLoaderInitialized) {
|
||||
lm.restartLoader(LOADER_ID_SEARCH_USERS, args, mSearchLoadersCallback);
|
||||
} else {
|
||||
mSearchUsersLoaderInitialized = true;
|
||||
lm.initLoader(LOADER_ID_SEARCH_USERS, args, mSearchLoadersCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
|
||||
final long accountId = args != null ? args.getLong(EXTRA_ACCOUNT_ID, -1) : -1;
|
||||
final long recipientId = args != null ? args.getLong(EXTRA_RECIPIENT_ID, -1) : -1;
|
||||
final String[] cols = DirectMessages.COLUMNS;
|
||||
final boolean isValid = accountId > 0 && recipientId > 0;
|
||||
mConversationContainer.setVisibility(isValid ? View.VISIBLE : View.GONE);
|
||||
mRecipientSelectorContainer.setVisibility(isValid ? View.GONE : View.VISIBLE);
|
||||
if (!isValid)
|
||||
return new CursorLoader(getActivity(), TwidereDataStore.CONTENT_URI_NULL, cols, null, null, null);
|
||||
final Uri uri = buildDirectMessageConversationUri(accountId, recipientId, null);
|
||||
return new CursorLoader(getActivity(), uri, cols, null, null, Conversation.DEFAULT_SORT_ORDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_messages_conversation, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fitSystemWindows(Rect insets) {
|
||||
final View view = getView();
|
||||
if (view == null) return;
|
||||
view.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(final AdapterView<?> parent, final View view, final int pos, final long id) {
|
||||
final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem();
|
||||
if (account != null) {
|
||||
mAccount = account;
|
||||
updateProfileImage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(final Loader<Cursor> loader) {
|
||||
mAdapter.setCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) {
|
||||
mAdapter.setCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMenuButtonClick(final View button, final int position, final long id) {
|
||||
mSelectedDirectMessage = mAdapter.findItem(id);
|
||||
showMenu(button, mSelectedDirectMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(final MenuItem item) {
|
||||
if (mSelectedDirectMessage != null) {
|
||||
final long message_id = mSelectedDirectMessage.id;
|
||||
final long account_id = mSelectedDirectMessage.account_id;
|
||||
switch (item.getItemId()) {
|
||||
case MENU_DELETE: {
|
||||
mTwitterWrapper.destroyDirectMessageAsync(account_id, message_id);
|
||||
break;
|
||||
}
|
||||
case MENU_COPY: {
|
||||
if (ClipboardUtils.setText(getActivity(), mSelectedDirectMessage.text_plain)) {
|
||||
showOkMessage(getActivity(), R.string.text_copied, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(final AdapterView<?> view) {
|
||||
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void onRefreshFromEnd() {
|
||||
// new TwidereAsyncTask<Object, Object, long[][]>() {
|
||||
//
|
||||
// @Override
|
||||
// protected long[][] doInBackground(final Object... params) {
|
||||
// final long[][] result = new long[2][];
|
||||
// result[0] = getActivatedAccountIds(getActivity());
|
||||
// result[1] = getNewestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onPostExecute(final long[][] result) {
|
||||
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
// if (twitter == null) return;
|
||||
// twitter.getReceivedDirectMessagesAsync(result[0], null, result[1]);
|
||||
// twitter.getSentDirectMessagesAsync(result[0], null, null);
|
||||
// }
|
||||
//
|
||||
// }.executeTask();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onRefresh() {
|
||||
// loadMoreMessages();
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
final String previewScaleType = Utils.getNonEmptyString(mPreferences, KEY_MEDIA_PREVIEW_STYLE,
|
||||
ScaleType.CENTER_CROP.name());
|
||||
mAdapter.setImagePreviewScaleType(previewScaleType);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
updateAddImageButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(final Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (mEditText != null) {
|
||||
outState.putCharSequence(EXTRA_TEXT, mEditText.getText());
|
||||
}
|
||||
outState.putParcelable(EXTRA_ACCOUNT, mAccount);
|
||||
outState.putParcelable(EXTRA_USER, mRecipient);
|
||||
outState.putString(EXTRA_IMAGE_URI, mImageUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
|
||||
bus.register(this);
|
||||
updateTextCount();
|
||||
updateEmptyText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
|
||||
bus.unregister(this);
|
||||
if (mPopupMenu != null) {
|
||||
mPopupMenu.dismiss();
|
||||
}
|
||||
|
||||
final ParcelableAccount account = mAccount;
|
||||
final ParcelableUser recipient = mRecipient;
|
||||
if (account != null && recipient != null) {
|
||||
final String key = getDraftsTextKey(account.account_id, recipient.id);
|
||||
final SharedPreferences.Editor editor = mMessageDrafts.edit();
|
||||
editor.putString(key, ParseUtils.parseString(mEditText.getText()));
|
||||
editor.apply();
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
|
||||
private void updateEmptyText() {
|
||||
final boolean noQuery = mUserQuery.length() <= 0;
|
||||
if (noQuery) {
|
||||
mUsersSearchEmptyText.setText(R.string.type_name_to_search);
|
||||
} else {
|
||||
mUsersSearchEmptyText.setText(R.string.no_user_found);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBaseViewCreated(final View view, final Bundle savedInstanceState) {
|
||||
super.onBaseViewCreated(view, savedInstanceState);
|
||||
mUsersSearchProgress = view.findViewById(R.id.users_search_progress);
|
||||
mUsersSearchList = (ListView) view.findViewById(R.id.users_search_list);
|
||||
mUsersSearchEmpty = view.findViewById(R.id.users_search_empty);
|
||||
mUsersSearchEmptyText = (TextView) view.findViewById(R.id.users_search_empty_text);
|
||||
mMessagesListView = (RecyclerView) view.findViewById(R.id.recycler_view);
|
||||
final View inputSendContainer = view.findViewById(R.id.input_send_container);
|
||||
mConversationContainer = view.findViewById(R.id.conversation_container);
|
||||
mRecipientSelectorContainer = view.findViewById(R.id.recipient_selector_container);
|
||||
mEditText = (StatusComposeEditText) inputSendContainer.findViewById(R.id.edit_text);
|
||||
mTextCountView = (StatusTextCountView) inputSendContainer.findViewById(R.id.text_count);
|
||||
mSendButton = inputSendContainer.findViewById(R.id.send);
|
||||
mAddImageButton = (ImageView) inputSendContainer.findViewById(R.id.add_image);
|
||||
mUsersSearchList = (ListView) view.findViewById(R.id.users_search_list);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean scrollToStart() {
|
||||
// if (mAdapter == null || mAdapter.isEmpty()) return false;
|
||||
// setSelection(mAdapter.getCount() - 1);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
public void showConversation(final ParcelableAccount account, final ParcelableUser recipient) {
|
||||
mAccount = account;
|
||||
mRecipient = recipient;
|
||||
if (account == null || recipient == null) return;
|
||||
final LoaderManager lm = getLoaderManager();
|
||||
final Bundle args = new Bundle();
|
||||
args.putLong(EXTRA_ACCOUNT_ID, account.account_id);
|
||||
args.putLong(EXTRA_RECIPIENT_ID, recipient.id);
|
||||
if (mLoaderInitialized) {
|
||||
lm.restartLoader(0, args, this);
|
||||
} else {
|
||||
mLoaderInitialized = true;
|
||||
lm.initLoader(0, args, this);
|
||||
}
|
||||
AsyncTask.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
}
|
||||
});
|
||||
new SetReadStateTask(getActivity(), account, recipient).execute();
|
||||
updateActionBar();
|
||||
updateProfileImage();
|
||||
}
|
||||
|
||||
private void updateActionBar() {
|
||||
final BaseAppCompatActivity activity = (BaseAppCompatActivity) getActivity();
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (actionBar == null) return;
|
||||
actionBar.setDisplayOptions(mRecipient != null ? ActionBar.DISPLAY_SHOW_TITLE : ActionBar.DISPLAY_SHOW_CUSTOM,
|
||||
ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void onReachedTop() {
|
||||
// if (!mLoadMoreAutomatically) return;
|
||||
|
@ -727,43 +806,6 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
// }.executeTask();
|
||||
// }
|
||||
|
||||
private void sendDirectMessage() {
|
||||
final ParcelableAccount account = mAccount;
|
||||
final ParcelableUser recipient = mRecipient;
|
||||
if (mAccount == null || mRecipient == null) return;
|
||||
final String message = mEditText.getText().toString();
|
||||
if (TextUtils.isEmpty(message)) {
|
||||
mEditText.setError(getString(R.string.error_message_no_content));
|
||||
} else if (mValidator.getTweetLength(message) > mValidator.getMaxTweetLength()) {
|
||||
mEditText.setError(getString(R.string.error_message_message_too_long));
|
||||
} else {
|
||||
mTwitterWrapper.sendDirectMessageAsync(account.account_id, recipient.id, message, mImageUri);
|
||||
mEditText.setText(null);
|
||||
mImageUri = null;
|
||||
updateAddImageButton();
|
||||
}
|
||||
}
|
||||
|
||||
private void showMenu(final View view, final ParcelableDirectMessage dm) {
|
||||
if (mPopupMenu != null) {
|
||||
mPopupMenu.dismiss();
|
||||
}
|
||||
final Context context = getActivity();
|
||||
mPopupMenu = new PopupMenu(context, view);
|
||||
mPopupMenu.inflate(R.menu.action_direct_message);
|
||||
final Menu menu = mPopupMenu.getMenu();
|
||||
final MenuItem view_profile_item = menu.findItem(MENU_VIEW_PROFILE);
|
||||
if (view_profile_item != null && dm != null) {
|
||||
view_profile_item.setVisible(dm.account_id != dm.sender_id);
|
||||
}
|
||||
mPopupMenu.setOnMenuItemClickListener(this);
|
||||
mPopupMenu.show();
|
||||
}
|
||||
|
||||
private void updateAddImageButton() {
|
||||
mAddImageButton.setActivated(mImageUri != null);
|
||||
}
|
||||
|
||||
private void updateTextCount() {
|
||||
if (mTextCountView == null || mEditText == null) return;
|
||||
final int count = mValidator.getTweetLength(ParseUtils.parseString(mEditText.getText()));
|
||||
|
@ -831,17 +873,6 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
mRecipient = recipient;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Cursor cursor) {
|
||||
if (cursor.moveToFirst()) {
|
||||
final int messageIdIdx = cursor.getColumnIndex(ConversationEntries.MESSAGE_ID);
|
||||
final String key = mAccount.account_id + "-" + mRecipient.id;
|
||||
mReadStateManager.setPosition(TAB_TYPE_DIRECT_MESSAGES, key, cursor.getLong(messageIdIdx), false);
|
||||
}
|
||||
Log.d(LOGTAG, Arrays.toString(mReadStateManager.getPositionPairs(TAB_TYPE_DIRECT_MESSAGES)));
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cursor doInBackground(Object... params) {
|
||||
final ContentResolver resolver = mContext.getContentResolver();
|
||||
|
@ -853,5 +884,17 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
final String orderBy = new OrderBy(ConversationEntries.MESSAGE_ID, false).getSQL();
|
||||
return resolver.query(ConversationEntries.CONTENT_URI, projection, selection, null, orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Cursor cursor) {
|
||||
if (cursor.moveToFirst()) {
|
||||
final int messageIdIdx = cursor.getColumnIndex(ConversationEntries.MESSAGE_ID);
|
||||
final String key = mAccount.account_id + "-" + mRecipient.id;
|
||||
mReadStateManager.setPosition(TAB_TYPE_DIRECT_MESSAGES, key, cursor.getLong(messageIdIdx), false);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -108,17 +108,17 @@ public class SearchFragment extends BaseSupportFragment implements RefreshScroll
|
|||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event)) return true;
|
||||
final String action = handler.getKeyAction("navigation", keyCode, event);
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case "navigation.previous_tab": {
|
||||
case ACTION_NAVIGATION_PREVIOUS_TAB: {
|
||||
final int previous = mViewPager.getCurrentItem() - 1;
|
||||
if (previous >= 0 && previous < mPagerAdapter.getCount()) {
|
||||
mViewPager.setCurrentItem(previous, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case "navigation.next_tab": {
|
||||
case ACTION_NAVIGATION_NEXT_TAB: {
|
||||
final int next = mViewPager.getCurrentItem() + 1;
|
||||
if (next >= 0 && next < mPagerAdapter.getCount()) {
|
||||
mViewPager.setCurrentItem(next, true);
|
||||
|
|
|
@ -415,7 +415,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
if (!KeyboardShortcutsHandler.isValidForHotkey(keyCode, event)) return false;
|
||||
final View focusedChild = RecyclerViewUtils.findRecyclerViewChild(mRecyclerView, mLayoutManager.getFocusedChild());
|
||||
final int position;
|
||||
|
@ -427,20 +427,20 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
if (position == -1) return false;
|
||||
final ParcelableStatus status = getAdapter().getStatus(position);
|
||||
if (status == null) return false;
|
||||
String action = handler.getKeyAction("status", keyCode, event);
|
||||
String action = handler.getKeyAction(CONTEXT_TAG_STATUS, keyCode, event);
|
||||
if (action == null) return false;
|
||||
switch (action) {
|
||||
case "status.reply": {
|
||||
case ACTION_STATUS_REPLY: {
|
||||
final Intent intent = new Intent(INTENT_ACTION_REPLY);
|
||||
intent.putExtra(EXTRA_STATUS, status);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
case "status.retweet": {
|
||||
case ACTION_STATUS_RETWEET: {
|
||||
RetweetQuoteDialogFragment.show(getFragmentManager(), status);
|
||||
return true;
|
||||
}
|
||||
case "status.favorite": {
|
||||
case ACTION_STATUS_FAVORITE: {
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
if (status.is_favorite) {
|
||||
twitter.destroyFavoriteAsync(status.account_id, status.id);
|
||||
|
|
|
@ -1068,19 +1068,19 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event)) return true;
|
||||
final String action = handler.getKeyAction("navigation", keyCode, event);
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case "navigation.previous_tab": {
|
||||
case ACTION_NAVIGATION_PREVIOUS_TAB: {
|
||||
final int previous = mViewPager.getCurrentItem() - 1;
|
||||
if (previous >= 0 && previous < mPagerAdapter.getCount()) {
|
||||
mViewPager.setCurrentItem(previous, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case "navigation.next_tab": {
|
||||
case ACTION_NAVIGATION_NEXT_TAB: {
|
||||
final int next = mViewPager.getCurrentItem() + 1;
|
||||
if (next >= 0 && next < mPagerAdapter.getCount()) {
|
||||
mViewPager.setCurrentItem(next, true);
|
||||
|
|
|
@ -15,43 +15,34 @@ 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 org.mariotaku.twidere.constant.KeyboardShortcutConstants;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class KeyboardShortcutsHandler implements Constants {
|
||||
public class KeyboardShortcutsHandler implements Constants, KeyboardShortcutConstants {
|
||||
|
||||
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 String KEYCODE_STRING_PREFIX = "KEYCODE_";
|
||||
|
||||
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("home.accounts_dashboard", R.string.open_accounts_dashboard);
|
||||
sActionLabelMap.put("status.reply", R.string.reply);
|
||||
sActionLabelMap.put("status.retweet", R.string.retweet);
|
||||
sActionLabelMap.put("status.favorite", R.string.favorite);
|
||||
sActionLabelMap.put("navigation.previous", R.string.previous_item);
|
||||
sActionLabelMap.put("navigation.next", R.string.next_item);
|
||||
sActionLabelMap.put("navigation.refresh", R.string.refresh);
|
||||
sActionLabelMap.put("navigation.previous_tab", R.string.previous_tab);
|
||||
sActionLabelMap.put("navigation.next_tab", R.string.next_tab);
|
||||
sActionLabelMap.put("navigation.back", R.string.keyboard_shortcut_back);
|
||||
sActionLabelMap.put(ACTION_COMPOSE, R.string.compose);
|
||||
sActionLabelMap.put(ACTION_SEARCH, R.string.search);
|
||||
sActionLabelMap.put(ACTION_MESSAGE, R.string.new_direct_message);
|
||||
sActionLabelMap.put(ACTION_HOME_ACCOUNTS_DASHBOARD, R.string.open_accounts_dashboard);
|
||||
sActionLabelMap.put(ACTION_STATUS_REPLY, R.string.reply);
|
||||
sActionLabelMap.put(ACTION_STATUS_RETWEET, R.string.retweet);
|
||||
sActionLabelMap.put(ACTION_STATUS_FAVORITE, R.string.favorite);
|
||||
sActionLabelMap.put(ACTION_NAVIGATION_PREVIOUS, R.string.previous_item);
|
||||
sActionLabelMap.put(ACTION_NAVIGATION_NEXT, R.string.next_item);
|
||||
sActionLabelMap.put(ACTION_NAVIGATION_REFRESH, R.string.refresh);
|
||||
sActionLabelMap.put(ACTION_NAVIGATION_PREVIOUS_TAB, R.string.previous_tab);
|
||||
sActionLabelMap.put(ACTION_NAVIGATION_NEXT_TAB, R.string.next_tab);
|
||||
sActionLabelMap.put(ACTION_NAVIGATION_BACK, R.string.keyboard_shortcut_back);
|
||||
|
||||
sMetaNameMap.put(KeyEvent.META_FUNCTION_ON, "fn");
|
||||
sMetaNameMap.put(KeyEvent.META_META_ON, "meta");
|
||||
|
@ -60,10 +51,16 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
sMetaNameMap.put(KeyEvent.META_SHIFT_ON, "shift");
|
||||
}
|
||||
|
||||
private static final String KEYCODE_STRING_PREFIX = "KEYCODE_";
|
||||
private final Context mContext;
|
||||
private final SharedPreferencesWrapper mPreferences;
|
||||
|
||||
public KeyboardShortcutsHandler(final TwidereApplication context) {
|
||||
mPreferences = SharedPreferencesWrapper.getInstance(context, KEYBOARD_SHORTCUTS_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public String findAction(@NonNull KeyboardShortcutSpec spec) {
|
||||
return mPreferences.getString(spec.getRawKey(), null);
|
||||
}
|
||||
|
||||
public KeyboardShortcutSpec findKey(String action) {
|
||||
for (Entry<String, ?> entry : mPreferences.getAll().entrySet()) {
|
||||
if (action.equals(entry.getValue())) {
|
||||
|
@ -74,41 +71,23 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public KeyboardShortcutsHandler(final TwidereApplication context) {
|
||||
mContext = context;
|
||||
mPreferences = SharedPreferencesWrapper.getInstance(context, KEYBOARD_SHORTCUTS_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static String getActionLabel(Context context, String action) {
|
||||
if (!sActionLabelMap.containsKey(action)) return null;
|
||||
final int labelRes = sActionLabelMap.get(action);
|
||||
return context.getString(labelRes);
|
||||
}
|
||||
|
||||
public static String metaToFriendlyString(int metaState) {
|
||||
final StringBuilder keyNameBuilder = new StringBuilder();
|
||||
for (int i = 0, j = sMetaNameMap.size(); i < j; i++) {
|
||||
if ((sMetaNameMap.keyAt(i) & metaState) != 0) {
|
||||
final String value = sMetaNameMap.valueAt(i);
|
||||
keyNameBuilder.append(value.substring(0, 1).toUpperCase(Locale.US));
|
||||
keyNameBuilder.append(value.substring(1));
|
||||
keyNameBuilder.append("+");
|
||||
}
|
||||
}
|
||||
return keyNameBuilder.toString();
|
||||
}
|
||||
|
||||
public static Set<String> getActions() {
|
||||
return sActionLabelMap.keySet();
|
||||
}
|
||||
|
||||
@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 String getKeyEventKey(String contextTag, int keyCode, KeyEvent event) {
|
||||
if (!isValidForHotkey(keyCode, event)) return null;
|
||||
final StringBuilder keyNameBuilder = new StringBuilder();
|
||||
|
@ -148,6 +127,13 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
return keyNameBuilder.toString();
|
||||
}
|
||||
|
||||
public static int getKeyEventMeta(String name) {
|
||||
for (int i = 0, j = sMetaNameMap.size(); i < j; i++) {
|
||||
if (sMetaNameMap.valueAt(i).equalsIgnoreCase(name)) return sMetaNameMap.keyAt(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static KeyboardShortcutSpec getKeyboardShortcutSpec(String contextTag, int keyCode, KeyEvent event) {
|
||||
if (!isValidForHotkey(keyCode, event)) return null;
|
||||
final int metaState = KeyEvent.normalizeMetaState(event.getMetaState());
|
||||
|
@ -169,15 +155,15 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
final String action = getKeyAction(contextTag, keyCode, event);
|
||||
if (action == null) return false;
|
||||
switch (action) {
|
||||
case "compose": {
|
||||
case ACTION_COMPOSE: {
|
||||
context.startActivity(new Intent(context, ComposeActivity.class).setAction(INTENT_ACTION_COMPOSE));
|
||||
return true;
|
||||
}
|
||||
case "search": {
|
||||
case ACTION_SEARCH: {
|
||||
context.startActivity(new Intent(context, QuickSearchBarActivity.class).setAction(INTENT_ACTION_QUICK_SEARCH));
|
||||
return true;
|
||||
}
|
||||
case "message": {
|
||||
case ACTION_MESSAGE: {
|
||||
Utils.openMessageConversation(context, -1, -1);
|
||||
return true;
|
||||
}
|
||||
|
@ -185,11 +171,8 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
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 boolean isEmpty() {
|
||||
return mPreferences.getAll().isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isValidForHotkey(int keyCode, KeyEvent event) {
|
||||
|
@ -210,26 +193,17 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
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("home.q", "home.accounts_dashboard");
|
||||
editor.putString("navigation.period", "navigation.refresh");
|
||||
editor.putString("navigation.j", "navigation.next");
|
||||
editor.putString("navigation.k", "navigation.previous");
|
||||
editor.putString("navigation.h", "navigation.previous_tab");
|
||||
editor.putString("navigation.l", "navigation.next_tab");
|
||||
editor.putString("status.f", "status.favorite");
|
||||
editor.putString("status.r", "status.reply");
|
||||
editor.putString("status.t", "status.retweet");
|
||||
editor.apply();
|
||||
public static String metaToFriendlyString(int metaState) {
|
||||
final StringBuilder keyNameBuilder = new StringBuilder();
|
||||
for (int i = 0, j = sMetaNameMap.size(); i < j; i++) {
|
||||
if ((sMetaNameMap.keyAt(i) & metaState) != 0) {
|
||||
final String value = sMetaNameMap.valueAt(i);
|
||||
keyNameBuilder.append(value.substring(0, 1).toUpperCase(Locale.US));
|
||||
keyNameBuilder.append(value.substring(1));
|
||||
keyNameBuilder.append("+");
|
||||
}
|
||||
}
|
||||
return keyNameBuilder.toString();
|
||||
}
|
||||
|
||||
public void register(KeyboardShortcutSpec spec, String action) {
|
||||
|
@ -237,6 +211,28 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
mPreferences.edit().putString(spec.getRawKey(), action).apply();
|
||||
}
|
||||
|
||||
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
|
||||
mPreferences.registerOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
final Editor editor = mPreferences.edit();
|
||||
editor.clear();
|
||||
editor.putString("n", ACTION_COMPOSE);
|
||||
editor.putString("m", ACTION_MESSAGE);
|
||||
editor.putString("slash", ACTION_SEARCH);
|
||||
editor.putString("home.q", ACTION_HOME_ACCOUNTS_DASHBOARD);
|
||||
editor.putString("navigation.period", ACTION_NAVIGATION_REFRESH);
|
||||
editor.putString("navigation.j", ACTION_NAVIGATION_NEXT);
|
||||
editor.putString("navigation.k", ACTION_NAVIGATION_PREVIOUS);
|
||||
editor.putString("navigation.h", ACTION_NAVIGATION_PREVIOUS_TAB);
|
||||
editor.putString("navigation.l", ACTION_NAVIGATION_NEXT_TAB);
|
||||
editor.putString("status.f", ACTION_STATUS_FAVORITE);
|
||||
editor.putString("status.r", ACTION_STATUS_REPLY);
|
||||
editor.putString("status.t", ACTION_STATUS_RETWEET);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public void unregister(String action) {
|
||||
final Editor editor = mPreferences.edit();
|
||||
for (Entry<String, ?> entry : mPreferences.getAll().entrySet()) {
|
||||
|
@ -250,16 +246,21 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
editor.apply();
|
||||
}
|
||||
|
||||
public static interface KeyboardShortcutCallback {
|
||||
boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event);
|
||||
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
|
||||
mPreferences.unregisterOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
|
||||
public static interface KeyboardShortcutCallback extends KeyboardShortcutConstants {
|
||||
|
||||
boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event);
|
||||
|
||||
boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/11.
|
||||
*/
|
||||
public static class KeyboardShortcutSpec {
|
||||
public static final class KeyboardShortcutSpec {
|
||||
|
||||
private String action;
|
||||
private String contextTag;
|
||||
|
@ -291,10 +292,18 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
return new KeyboardShortcutSpec(contextTag, keyMeta, keyName, action);
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public String getContextTag() {
|
||||
return contextTag;
|
||||
}
|
||||
|
||||
public void setContextTag(String contextTag) {
|
||||
this.contextTag = contextTag;
|
||||
}
|
||||
|
||||
public int getKeyMeta() {
|
||||
return keyMeta;
|
||||
}
|
||||
|
@ -307,10 +316,6 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
return getKeyEventKey(contextTag, keyMeta, keyName);
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public String getValueName(Context context) {
|
||||
return getActionLabel(context, action);
|
||||
}
|
||||
|
@ -319,24 +324,10 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
return keyName != null;
|
||||
}
|
||||
|
||||
public void setContextTag(String contextTag) {
|
||||
this.contextTag = contextTag;
|
||||
}
|
||||
|
||||
public String toKeyString() {
|
||||
return metaToFriendlyString(keyMeta) + keyToFriendlyString(keyName);
|
||||
}
|
||||
|
||||
private static String keyToFriendlyString(String keyName) {
|
||||
if (keyName == null) return null;
|
||||
final String upperName = keyName.toUpperCase(Locale.US);
|
||||
final int keyCode = KeyEvent.keyCodeFromString(KEYCODE_STRING_PREFIX + upperName);
|
||||
if (keyCode == KeyEvent.KEYCODE_UNKNOWN) return upperName;
|
||||
if (keyCode == KeyEvent.KEYCODE_DEL) return "Backspace";
|
||||
if (keyCode == KeyEvent.KEYCODE_FORWARD_DEL) return "Delete";
|
||||
return String.valueOf(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode).getDisplayLabel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KeyboardShortcutSpec{" +
|
||||
|
@ -346,5 +337,15 @@ public class KeyboardShortcutsHandler implements Constants {
|
|||
", keyName='" + keyName + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
private static String keyToFriendlyString(String keyName) {
|
||||
if (keyName == null) return null;
|
||||
final String upperName = keyName.toUpperCase(Locale.US);
|
||||
final int keyCode = KeyEvent.keyCodeFromString(KEYCODE_STRING_PREFIX + upperName);
|
||||
if (keyCode == KeyEvent.KEYCODE_UNKNOWN) return upperName;
|
||||
if (keyCode == KeyEvent.KEYCODE_DEL) return "Backspace";
|
||||
if (keyCode == KeyEvent.KEYCODE_FORWARD_DEL) return "Delete";
|
||||
return String.valueOf(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode).getDisplayLabel());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,12 @@ import android.support.v7.widget.RecyclerView.ViewHolder;
|
|||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/21.
|
||||
*/
|
||||
public class RecyclerViewNavigationHelper {
|
||||
public class RecyclerViewNavigationHelper implements KeyboardShortcutCallback {
|
||||
|
||||
private int positionBackup;
|
||||
@NonNull
|
||||
|
@ -48,18 +50,19 @@ public class RecyclerViewNavigationHelper {
|
|||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutRepeat(@NonNull final KeyboardShortcutsHandler handler,
|
||||
final int keyCode, final int repeatCount,
|
||||
@NonNull final KeyEvent event) {
|
||||
final String action = handler.getKeyAction("navigation", keyCode, event);
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event);
|
||||
if (action == null) return false;
|
||||
final int direction;
|
||||
switch (action) {
|
||||
case "navigation.previous": {
|
||||
case ACTION_NAVIGATION_PREVIOUS: {
|
||||
direction = -1;
|
||||
break;
|
||||
}
|
||||
case "navigation.next": {
|
||||
case ACTION_NAVIGATION_NEXT: {
|
||||
direction = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -90,4 +93,9 @@ public class RecyclerViewNavigationHelper {
|
|||
RecyclerViewUtils.focusNavigate(view, layoutManager, position, direction);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.text.TextUtils;
|
|||
import android.text.method.ArrowKeyMovementMethod;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.UserHashtagAutoCompleteAdapter;
|
||||
|
||||
public class StatusComposeEditText extends AppCompatMultiAutoCompleteTextView {
|
||||
|
@ -40,7 +41,7 @@ public class StatusComposeEditText extends AppCompatMultiAutoCompleteTextView {
|
|||
}
|
||||
|
||||
public StatusComposeEditText(final Context context, final AttributeSet attrs) {
|
||||
this(context, attrs, android.R.attr.autoCompleteTextViewStyle);
|
||||
this(context, attrs, R.attr.autoCompleteTextViewStyle);
|
||||
}
|
||||
|
||||
public StatusComposeEditText(final Context context, final AttributeSet attrs, final int defStyle) {
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.mariotaku.twidere.view;
|
|||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.support.v7.widget.AppCompatTextView;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
@ -32,7 +33,7 @@ import java.util.Locale;
|
|||
|
||||
import static org.mariotaku.twidere.util.Utils.getLocalizedNumber;
|
||||
|
||||
public class StatusTextCountView extends TextView {
|
||||
public class StatusTextCountView extends AppCompatTextView {
|
||||
|
||||
private final int mTextColor;
|
||||
private final Locale mLocale;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
android:id="@+id/account_spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:layout_weight="0"
|
||||
tools:listitem="@layout/spinner_item_account_icon"/>
|
||||
|
||||
|
|
|
@ -49,14 +49,76 @@
|
|||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:id="@+id/input_send_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:layout_weight="0">
|
||||
|
||||
<include layout="@layout/fragment_messages_conversation_input_send"/>
|
||||
</FrameLayout>
|
||||
<org.mariotaku.twidere.view.ActionIconView
|
||||
android:id="@+id/add_image"
|
||||
style="?android:borderlessButtonStyle"
|
||||
android:layout_width="?android:actionBarSize"
|
||||
android:layout_height="?android:actionBarSize"
|
||||
android:layout_weight="0"
|
||||
android:color="?android:textColorSecondary"
|
||||
android:contentDescription="@string/add_image"
|
||||
android:padding="0dp"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_action_gallery"/>
|
||||
|
||||
<org.mariotaku.twidere.view.StatusComposeEditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:completionThreshold="1"
|
||||
android:focusable="true"
|
||||
android:gravity="left|bottom"
|
||||
android:hint="@string/type_to_compose"
|
||||
android:inputType="textShortMessage|textMultiLine"
|
||||
android:maxHeight="140dp"
|
||||
android:minHeight="?android:actionBarSize"
|
||||
android:singleLine="false">
|
||||
|
||||
<requestFocus/>
|
||||
</org.mariotaku.twidere.view.StatusComposeEditText>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/send"
|
||||
style="?android:borderlessButtonStyle"
|
||||
android:layout_width="?android:actionBarSize"
|
||||
android:layout_height="?android:actionBarSize"
|
||||
android:layout_weight="0"
|
||||
android:padding="0dp">
|
||||
|
||||
<org.mariotaku.twidere.view.ActionIconView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:color="?android:textColorSecondary"
|
||||
android:contentDescription="@string/send"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_action_send"/>
|
||||
|
||||
<org.mariotaku.twidere.view.StatusTextCountView
|
||||
android:id="@+id/text_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginBottom="@dimen/element_spacing_small"
|
||||
android:layout_marginRight="@dimen/element_spacing_small"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:singleLine="true"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:text="140"/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
tools:showIn="@layout/fragment_messages_conversation">
|
||||
|
||||
<org.mariotaku.twidere.view.ActionIconView
|
||||
android:id="@+id/add_image"
|
||||
style="?android:borderlessButtonStyle"
|
||||
android:layout_width="?android:actionBarSize"
|
||||
android:layout_height="?android:actionBarSize"
|
||||
android:layout_weight="0"
|
||||
android:color="?android:textColorSecondary"
|
||||
android:contentDescription="@string/add_image"
|
||||
android:padding="0dp"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_action_gallery"/>
|
||||
|
||||
<org.mariotaku.twidere.view.StatusComposeEditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:completionThreshold="1"
|
||||
android:gravity="left|bottom"
|
||||
android:hint="@string/type_to_compose"
|
||||
android:inputType="textShortMessage|textMultiLine"
|
||||
android:maxHeight="140dp"
|
||||
android:minHeight="?android:actionBarSize"
|
||||
android:singleLine="false"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/send"
|
||||
style="?android:borderlessButtonStyle"
|
||||
android:layout_width="?android:actionBarSize"
|
||||
android:layout_height="?android:actionBarSize"
|
||||
android:layout_weight="0"
|
||||
android:padding="0dp">
|
||||
|
||||
<org.mariotaku.twidere.view.ActionIconView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:color="?android:textColorSecondary"
|
||||
android:contentDescription="@string/send"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_action_send"/>
|
||||
|
||||
<org.mariotaku.twidere.view.StatusTextCountView
|
||||
android:id="@+id/text_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginBottom="@dimen/element_spacing_small"
|
||||
android:layout_marginRight="@dimen/element_spacing_small"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:singleLine="true"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:text="140"/>
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:listPreferredItemHeightSmall"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/element_spacing_small">
|
||||
|
||||
<org.mariotaku.twidere.view.ShapedImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="@dimen/icon_size_list_item_small"
|
||||
style="?profileImageStyle"
|
||||
android:layout_height="@dimen/icon_size_list_item_small"
|
||||
android:contentDescription="@string/icon"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/element_spacing_small">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/text2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -27,10 +27,9 @@
|
|||
android:orientation="horizontal"
|
||||
android:padding="@dimen/element_spacing_small">
|
||||
|
||||
<org.mariotaku.twidere.view.ShapedImageView
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="@dimen/icon_size_list_item_small"
|
||||
style="?profileImageStyle"
|
||||
android:layout_height="@dimen/icon_size_list_item_small"
|
||||
android:contentDescription="@string/icon"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="@dimen/element_spacing_small"
|
||||
tools:layout_height="?android:actionBarSize">
|
||||
android:padding="@dimen/element_spacing_small">
|
||||
|
||||
<org.mariotaku.twidere.view.SquareShapedImageView
|
||||
android:id="@android:id/icon"
|
||||
|
|
Loading…
Reference in New Issue