1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-14 10:40:46 +01:00

copy link now work

fixed user auto completion
This commit is contained in:
Mariotaku Lee 2015-04-04 05:12:33 +08:00
parent 8fc291fda5
commit 8d6c2629a1
18 changed files with 285 additions and 116 deletions

View File

@ -0,0 +1,33 @@
/*
* 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 android.support.v7.internal.view;
import android.support.v7.view.ActionMode;
/**
* Created by mariotaku on 15/4/4.
*/
public class SupportActionModeWrapperTrojan {
public static ActionMode getWrappedObject(SupportActionModeWrapper wrapper) {
return wrapper.mWrappedObject;
}
}

View File

@ -34,6 +34,7 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener; import android.support.v4.view.ViewPager.OnPageChangeListener;
@ -65,6 +66,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
import org.mariotaku.twidere.util.ContentValuesCreator; import org.mariotaku.twidere.util.ContentValuesCreator;
import org.mariotaku.twidere.util.ParseUtils; import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import static org.mariotaku.twidere.util.Utils.getDefaultAccountId; import static org.mariotaku.twidere.util.Utils.getDefaultAccountId;
@ -250,7 +252,8 @@ public class FiltersActivity extends BaseActionBarActivity implements TabListene
@NonNull @NonNull
@Override @Override
public Dialog onCreateDialog(final Bundle savedInstanceState) { public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity()); final FragmentActivity activity = getActivity();
final Context wrapped = ThemeUtils.getDialogThemedContext(activity);
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped); final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
buildDialog(builder); buildDialog(builder);
final View view = LayoutInflater.from(wrapped).inflate(R.layout.auto_complete_textview, null); final View view = LayoutInflater.from(wrapped).inflate(R.layout.auto_complete_textview, null);
@ -260,9 +263,11 @@ public class FiltersActivity extends BaseActionBarActivity implements TabListene
final int auto_complete_type = args != null ? args.getInt(EXTRA_AUTO_COMPLETE_TYPE, 0) : 0; final int auto_complete_type = args != null ? args.getInt(EXTRA_AUTO_COMPLETE_TYPE, 0) : 0;
if (auto_complete_type != 0) { if (auto_complete_type != 0) {
if (auto_complete_type == AUTO_COMPLETE_TYPE_SOURCES) { if (auto_complete_type == AUTO_COMPLETE_TYPE_SOURCES) {
mUserAutoCompleteAdapter = new SourceAutoCompleteAdapter(getActivity()); mUserAutoCompleteAdapter = new SourceAutoCompleteAdapter(activity);
} else { } else {
mUserAutoCompleteAdapter = new UserHashtagAutoCompleteAdapter(getActivity()); final UserHashtagAutoCompleteAdapter adapter = new UserHashtagAutoCompleteAdapter(activity);
adapter.setAccountId(Utils.getDefaultAccountId(activity));
mUserAutoCompleteAdapter = adapter;
} }
mEditText.setAdapter(mUserAutoCompleteAdapter); mEditText.setAdapter(mUserAutoCompleteAdapter);
mEditText.setThreshold(1); mEditText.setThreshold(1);

View File

@ -78,7 +78,6 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener; import android.view.View.OnLongClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.widget.EditText;
import android.widget.GridView; import android.widget.GridView;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@ -119,6 +118,7 @@ import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.ActionIconView; import org.mariotaku.twidere.view.ActionIconView;
import org.mariotaku.twidere.view.BadgeView; import org.mariotaku.twidere.view.BadgeView;
import org.mariotaku.twidere.view.ShapedImageView; import org.mariotaku.twidere.view.ShapedImageView;
import org.mariotaku.twidere.view.StatusComposeEditText;
import org.mariotaku.twidere.view.StatusTextCountView; import org.mariotaku.twidere.view.StatusTextCountView;
import java.io.File; import java.io.File;
@ -173,7 +173,7 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
private AsyncTask<Void, Void, ?> mTask; private AsyncTask<Void, Void, ?> mTask;
private GridView mMediaPreviewGrid; private GridView mMediaPreviewGrid;
private ActionMenuView mMenuBar; private ActionMenuView mMenuBar;
private EditText mEditText; private StatusComposeEditText mEditText;
private View mSendView; private View mSendView;
private StatusTextCountView mSendTextCountView; private StatusTextCountView mSendTextCountView;
private RecyclerView mAccountSelector; private RecyclerView mAccountSelector;
@ -577,7 +577,7 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
@Override @Override
public void onContentChanged() { public void onContentChanged() {
super.onContentChanged(); super.onContentChanged();
mEditText = (EditText) findViewById(R.id.edit_text); mEditText = (StatusComposeEditText) findViewById(R.id.edit_text);
mMediaPreviewGrid = (GridView) findViewById(R.id.media_thumbnail_preview); mMediaPreviewGrid = (GridView) findViewById(R.id.media_thumbnail_preview);
mMenuBar = (ActionMenuView) findViewById(R.id.menu_bar); mMenuBar = (ActionMenuView) findViewById(R.id.menu_bar);
mSendView = findViewById(R.id.send); mSendView = findViewById(R.id.send);
@ -1316,7 +1316,9 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
} }
private void notifyAccountSelectionChanged() { private void notifyAccountSelectionChanged() {
setSelectedAccounts(mAccountsAdapter.getSelectedAccounts()); final ParcelableAccount[] accounts = mAccountsAdapter.getSelectedAccounts();
setSelectedAccounts(accounts);
mEditText.setAccountId(accounts.length > 0 ? accounts[0].account_id : Utils.getDefaultAccountId(this));
// mAccountActionProvider.setSelectedAccounts(mAccountsAdapter.getSelectedAccounts()); // mAccountActionProvider.setSelectedAccounts(mAccountsAdapter.getSelectedAccounts());
} }

View File

@ -19,6 +19,7 @@
package org.mariotaku.twidere.activity.support; package org.mariotaku.twidere.activity.support;
import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.graphics.Rect; import android.graphics.Rect;
import android.net.Uri; import android.net.Uri;
@ -224,6 +225,7 @@ public class LinkHandlerActivity extends BaseActionBarActivity implements OnClic
} }
} }
@SuppressLint("AppCompatMethod")
private void setActionBarBackground(ActionBar actionBar, int linkId, Uri data) { private void setActionBarBackground(ActionBar actionBar, int linkId, Uri data) {
switch (linkId) { switch (linkId) {
case LINK_ID_USER: { case LINK_ID_USER: {
@ -233,11 +235,15 @@ public class LinkHandlerActivity extends BaseActionBarActivity implements OnClic
case LINK_ID_USER_LISTS: { case LINK_ID_USER_LISTS: {
ThemeUtils.applyActionBarBackground(actionBar, this, getCurrentThemeResourceId(), ThemeUtils.applyActionBarBackground(actionBar, this, getCurrentThemeResourceId(),
getCurrentThemeColor(), false); getCurrentThemeColor(), false);
ThemeUtils.applyActionBarBackground(getActionBar(), this, getCurrentThemeResourceId(),
getCurrentThemeColor(), true);
break; break;
} }
default: { default: {
ThemeUtils.applyActionBarBackground(actionBar, this, getCurrentThemeResourceId(), ThemeUtils.applyActionBarBackground(actionBar, this, getCurrentThemeResourceId(),
getCurrentThemeColor(), true); getCurrentThemeColor(), true);
ThemeUtils.applyActionBarBackground(getActionBar(), this, getCurrentThemeResourceId(),
getCurrentThemeColor(), true);
break; break;
} }
} }

View File

@ -166,7 +166,9 @@ public class UserListSelectorActivity extends BaseSupportDialogActivity implemen
getUserLists(mScreenName); getUserLists(mScreenName);
} }
} }
mEditScreenName.setAdapter(new UserHashtagAutoCompleteAdapter(this)); final UserHashtagAutoCompleteAdapter adapter = new UserHashtagAutoCompleteAdapter(this);
adapter.setAccountId(getAccountId());
mEditScreenName.setAdapter(adapter);
mEditScreenName.setText(mScreenName); mEditScreenName.setText(mScreenName);
mUserListsListView.setAdapter(mUserListsAdapter = new SimpleParcelableUserListsAdapter(this)); mUserListsListView.setAdapter(mUserListsAdapter = new SimpleParcelableUserListsAdapter(this));
mUsersListView.setAdapter(mUsersAdapter = new SimpleParcelableUsersAdapter(this)); mUsersListView.setAdapter(mUsersAdapter = new SimpleParcelableUsersAdapter(this));

View File

@ -27,7 +27,7 @@ import android.widget.TextView;
import org.mariotaku.twidere.R; import org.mariotaku.twidere.R;
import org.mariotaku.twidere.app.TwidereApplication; import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.support.DirectMessagesConversationFragment; import org.mariotaku.twidere.fragment.support.MessagesConversationFragment;
import org.mariotaku.twidere.model.ParcelableAccount; import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.util.MediaLoaderWrapper; import org.mariotaku.twidere.util.MediaLoaderWrapper;
@ -48,8 +48,8 @@ public class AccountsSpinnerAdapter extends ArrayAdapter<ParcelableAccount> {
super(context, itemViewResource); super(context, itemViewResource);
mContext = context; mContext = context;
mImageLoader = TwidereApplication.getInstance(context).getMediaLoaderWrapper(); mImageLoader = TwidereApplication.getInstance(context).getMediaLoaderWrapper();
mDisplayProfileImage = context.getSharedPreferences(DirectMessagesConversationFragment.SHARED_PREFERENCES_NAME, mDisplayProfileImage = context.getSharedPreferences(MessagesConversationFragment.SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE).getBoolean(DirectMessagesConversationFragment.KEY_DISPLAY_PROFILE_IMAGE, true); Context.MODE_PRIVATE).getBoolean(MessagesConversationFragment.KEY_DISPLAY_PROFILE_IMAGE, true);
} }
public AccountsSpinnerAdapter(final Context context, final Collection<ParcelableAccount> accounts) { public AccountsSpinnerAdapter(final Context context, final Collection<ParcelableAccount> accounts) {

View File

@ -25,6 +25,7 @@ import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuff.Mode;
import android.net.Uri;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.widget.SimpleCursorAdapter; import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View; import android.view.View;
@ -72,6 +73,7 @@ public class UserHashtagAutoCompleteAdapter extends SimpleCursorAdapter implemen
private int mProfileImageUrlIdx, mNameIdx, mScreenNameIdx, mUserIdIdx; private int mProfileImageUrlIdx, mNameIdx, mScreenNameIdx, mUserIdIdx;
private char mToken = '@'; private char mToken = '@';
private long mAccountId;
public UserHashtagAutoCompleteAdapter(final Context context) { public UserHashtagAutoCompleteAdapter(final Context context) {
this(context, null); this(context, null);
@ -172,18 +174,28 @@ public class UserHashtagAutoCompleteAdapter extends SimpleCursorAdapter implemen
selection = null; selection = null;
selectionArgs = null; selectionArgs = null;
} }
final OrderBy orderBy = new OrderBy(CachedUsers.SCREEN_NAME, CachedUsers.NAME); final OrderBy orderBy = new OrderBy(new String[]{CachedUsers.LAST_SEEN, "score", CachedUsers.SCREEN_NAME,
return mResolver.query(CachedUsers.CONTENT_URI, CachedUsers.BASIC_COLUMNS, CachedUsers.NAME}, new boolean[]{false, false, true, true});
selection != null ? selection.getSQL() : null, selectionArgs, orderBy.getSQL()); final Cursor cursor = mResolver.query(Uri.withAppendedPath(CachedUsers.CONTENT_URI_WITH_SCORE, String.valueOf(mAccountId)),
CachedUsers.BASIC_COLUMNS, selection != null ? selection.getSQL() : null, selectionArgs, orderBy.getSQL());
if (Utils.isDebugBuild() && cursor == null) throw new NullPointerException();
return cursor;
} else { } else {
final String selection = constraintEscaped != null ? CachedHashtags.NAME + " LIKE ?||'%' ESCAPE '^'" final String selection = constraintEscaped != null ? CachedHashtags.NAME + " LIKE ?||'%' ESCAPE '^'"
: null; : null;
final String[] selectionArgs = constraintEscaped != null ? new String[]{constraintEscaped} : null; final String[] selectionArgs = constraintEscaped != null ? new String[]{constraintEscaped} : null;
return mDatabase.query(true, CachedHashtags.TABLE_NAME, CachedHashtags.COLUMNS, selection, selectionArgs, final Cursor cursor = mDatabase.query(true, CachedHashtags.TABLE_NAME, CachedHashtags.COLUMNS, selection, selectionArgs,
null, null, CachedHashtags.NAME, null); null, null, CachedHashtags.NAME, null);
if (Utils.isDebugBuild() && cursor == null) throw new NullPointerException();
return cursor;
} }
} }
public void setAccountId(long accountId) {
mAccountId = accountId;
}
@Override @Override
public Cursor swapCursor(final Cursor cursor) { public Cursor swapCursor(final Cursor cursor) {
if (cursor != null) { if (cursor != null) {

View File

@ -24,6 +24,7 @@ import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.text.InputFilter; import android.text.InputFilter;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -46,19 +47,20 @@ public class AddUserListMemberDialogFragment extends BaseSupportDialogFragment i
@Override @Override
public void onClick(final DialogInterface dialog, final int which) { public void onClick(final DialogInterface dialog, final int which) {
final Bundle args = getArguments(); final Bundle args = getArguments();
if (args == null || !args.containsKey(EXTRA_ACCOUNT_ID) || !args.containsKey(EXTRA_LIST_ID)) return; if (args == null || !args.containsKey(EXTRA_ACCOUNT_ID) || !args.containsKey(EXTRA_LIST_ID) || !args.containsKey(EXTRA_USERS))
return;
switch (which) { switch (which) {
case DialogInterface.BUTTON_POSITIVE: { case DialogInterface.BUTTON_POSITIVE: {
final String mText = ParseUtils.parseString(mEditText.getText()); final String mText = ParseUtils.parseString(mEditText.getText());
final AsyncTwitterWrapper twitter = getTwitterWrapper(); final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (mText == null || mText.length() <= 0 || twitter == null) return; if (mText == null || mText.length() <= 0 || twitter == null) return;
// twitter.addUserListMembersAsync(args.getLong(EXTRA_ACCOUNT_ID), twitter.addUserListMembersAsync(args.getLong(EXTRA_ACCOUNT_ID), args.getLong(EXTRA_LIST_ID));
// args.getInt(EXTRA_LIST_ID), mText);
break; break;
} }
} }
} }
@NonNull
@Override @Override
public Dialog onCreateDialog(final Bundle savedInstanceState) { public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity()); final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
@ -70,6 +72,8 @@ public class AddUserListMemberDialogFragment extends BaseSupportDialogFragment i
mEditText.setText(savedInstanceState.getCharSequence(EXTRA_TEXT)); mEditText.setText(savedInstanceState.getCharSequence(EXTRA_TEXT));
} }
mUserAutoCompleteAdapter = new UserHashtagAutoCompleteAdapter(wrapped); mUserAutoCompleteAdapter = new UserHashtagAutoCompleteAdapter(wrapped);
final Bundle args = getArguments();
mUserAutoCompleteAdapter.setAccountId(args.getLong(EXTRA_ACCOUNT_ID));
mEditText.setAdapter(mUserAutoCompleteAdapter); mEditText.setAdapter(mUserAutoCompleteAdapter);
mEditText.setThreshold(1); mEditText.setThreshold(1);
mEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(20)}); mEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(20)});

View File

@ -98,6 +98,7 @@ import org.mariotaku.twidere.util.TwidereValidator;
import org.mariotaku.twidere.util.UserColorNameUtils; import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.message.TaskStateChangedEvent; import org.mariotaku.twidere.util.message.TaskStateChangedEvent;
import org.mariotaku.twidere.view.StatusComposeEditText;
import org.mariotaku.twidere.view.StatusTextCountView; import org.mariotaku.twidere.view.StatusTextCountView;
import org.mariotaku.twidere.view.iface.IColorLabelView; import org.mariotaku.twidere.view.iface.IColorLabelView;
@ -110,7 +111,7 @@ import java.util.Locale;
import static org.mariotaku.twidere.util.Utils.buildDirectMessageConversationUri; import static org.mariotaku.twidere.util.Utils.buildDirectMessageConversationUri;
import static org.mariotaku.twidere.util.Utils.showOkMessage; import static org.mariotaku.twidere.util.Utils.showOkMessage;
public class DirectMessagesConversationFragment extends BaseSupportFragment implements public class MessagesConversationFragment extends BaseSupportFragment implements
LoaderCallbacks<Cursor>, TextWatcher, OnClickListener, OnItemSelectedListener, LoaderCallbacks<Cursor>, TextWatcher, OnClickListener, OnItemSelectedListener,
OnEditorActionListener, MenuButtonClickListener, PopupMenu.OnMenuItemClickListener { OnEditorActionListener, MenuButtonClickListener, PopupMenu.OnMenuItemClickListener {
@ -126,7 +127,7 @@ public class DirectMessagesConversationFragment extends BaseSupportFragment impl
private RecyclerView mMessagesListView; private RecyclerView mMessagesListView;
private ListView mUsersSearchList; private ListView mUsersSearchList;
private EditText mEditText; private StatusComposeEditText mEditText;
private StatusTextCountView mTextCountView; private StatusTextCountView mTextCountView;
private View mSendButton; private View mSendButton;
private ImageView mAddImageButton; private ImageView mAddImageButton;
@ -238,6 +239,7 @@ public class DirectMessagesConversationFragment extends BaseSupportFragment impl
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) { public void onTextChanged(CharSequence s, int start, int before, int count) {
final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem(); final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem();
mEditText.setAccountId(account.account_id);
searchUsers(account.account_id, ParseUtils.parseString(s), true); searchUsers(account.account_id, ParseUtils.parseString(s), true);
} }
@ -611,7 +613,7 @@ public class DirectMessagesConversationFragment extends BaseSupportFragment impl
final View inputSendContainer = view.findViewById(R.id.input_send_container); final View inputSendContainer = view.findViewById(R.id.input_send_container);
mConversationContainer = view.findViewById(R.id.conversation_container); mConversationContainer = view.findViewById(R.id.conversation_container);
mRecipientSelectorContainer = view.findViewById(R.id.recipient_selector_container); mRecipientSelectorContainer = view.findViewById(R.id.recipient_selector_container);
mEditText = (EditText) inputSendContainer.findViewById(R.id.edit_text); mEditText = (StatusComposeEditText) inputSendContainer.findViewById(R.id.edit_text);
mTextCountView = (StatusTextCountView) inputSendContainer.findViewById(R.id.text_count); mTextCountView = (StatusTextCountView) inputSendContainer.findViewById(R.id.text_count);
mSendButton = inputSendContainer.findViewById(R.id.send); mSendButton = inputSendContainer.findViewById(R.id.send);
mAddImageButton = (ImageView) inputSendContainer.findViewById(R.id.add_image); mAddImageButton = (ImageView) inputSendContainer.findViewById(R.id.add_image);

View File

@ -49,20 +49,27 @@ import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.LayoutParams; import android.support.v7.widget.RecyclerView.LayoutParams;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.Html; import android.text.Html;
import android.text.SpannableString;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.webkit.URLUtil;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Space; import android.widget.Space;
import android.widget.TextView; import android.widget.TextView;
import org.mariotaku.twidere.R; import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IThemedActivity;
import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity; import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter.StatusAdapterListener; import org.mariotaku.twidere.adapter.AbsStatusesAdapter.StatusAdapterListener;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration; import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
@ -81,6 +88,7 @@ import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.text.method.StatusContentMovementMethod; import org.mariotaku.twidere.text.method.StatusContentMovementMethod;
import org.mariotaku.twidere.util.AsyncTaskUtils; import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ClipboardUtils;
import org.mariotaku.twidere.util.CompareUtils; import org.mariotaku.twidere.util.CompareUtils;
import org.mariotaku.twidere.util.ImageLoadingHandler; import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.LinkCreator; import org.mariotaku.twidere.util.LinkCreator;
@ -123,9 +131,8 @@ import static org.mariotaku.twidere.util.Utils.showErrorMessage;
/** /**
* Created by mariotaku on 14/12/5. * Created by mariotaku on 14/12/5.
*/ */
public class StatusFragment extends BaseSupportFragment public class StatusFragment extends BaseSupportFragment implements LoaderCallbacks<SingleResponse<ParcelableStatus>>,
implements LoaderCallbacks<SingleResponse<ParcelableStatus>>, OnMediaClickListener, OnMediaClickListener, StatusAdapterListener {
StatusAdapterListener {
private static final int LOADER_ID_DETAIL_STATUS = 1; private static final int LOADER_ID_DETAIL_STATUS = 1;
private static final int LOADER_ID_STATUS_REPLIES = 2; private static final int LOADER_ID_STATUS_REPLIES = 2;
@ -858,6 +865,10 @@ public class StatusFragment extends BaseSupportFragment
updateItemDecoration(); updateItemDecoration();
} }
private int getStatusPosition() {
return getConversationCount();
}
public boolean setStatus(ParcelableStatus status) { public boolean setStatus(ParcelableStatus status) {
final ParcelableStatus old = mStatus; final ParcelableStatus old = mStatus;
mStatus = status; mStatus = status;
@ -1084,14 +1095,10 @@ public class StatusFragment extends BaseSupportFragment
textView.setText(Html.fromHtml(status.text_html)); textView.setText(Html.fromHtml(status.text_html));
final StatusLinkClickHandler linkClickHandler = new StatusLinkClickHandler(context, null); final StatusLinkClickHandler linkClickHandler = new StatusLinkClickHandler(context, null);
linkClickHandler.setStatus(status); linkClickHandler.setStatus(status);
final TwidereLinkify linkify = new TwidereLinkify(linkClickHandler); final TwidereLinkify linkify = new TwidereLinkify(linkClickHandler, VALUE_LINK_HIGHLIGHT_OPTION_CODE_BOTH, false);
linkify.applyAllLinks(textView, status.account_id, status.is_possibly_sensitive); linkify.applyAllLinks(textView, status.account_id, status.is_possibly_sensitive);
ThemeUtils.applyParagraphSpacing(textView, 1.1f); ThemeUtils.applyParagraphSpacing(textView, 1.1f);
textView.setMovementMethod(StatusContentMovementMethod.getInstance());
// textView.setCustomSelectionActionModeCallback(this);
final String timeString = formatToLongTimeString(context, status.timestamp); final String timeString = formatToLongTimeString(context, status.timestamp);
final String sourceHtml = status.source; final String sourceHtml = status.source;
if (!isEmpty(timeString) && !isEmpty(sourceHtml)) { if (!isEmpty(timeString) && !isEmpty(sourceHtml)) {
@ -1181,7 +1188,8 @@ public class StatusFragment extends BaseSupportFragment
private void initViews() { private void initViews() {
// menuBar.setOnMenuItemClickListener(this); // menuBar.setOnMenuItemClickListener(this);
menuBar.setOnMenuItemClickListener(this); menuBar.setOnMenuItemClickListener(this);
final FragmentActivity activity = adapter.getFragment().getActivity(); final StatusFragment fragment = adapter.getFragment();
final FragmentActivity activity = fragment.getActivity();
final MenuInflater inflater = activity.getMenuInflater(); final MenuInflater inflater = activity.getMenuInflater();
inflater.inflate(R.menu.menu_status, menuBar.getMenu()); inflater.inflate(R.menu.menu_status, menuBar.getMenu());
ThemeUtils.wrapMenuIcon(menuBar, MENU_GROUP_STATUS_SHARE); ThemeUtils.wrapMenuIcon(menuBar, MENU_GROUP_STATUS_SHARE);
@ -1197,6 +1205,52 @@ public class StatusFragment extends BaseSupportFragment
screenNameView.setTextSize(defaultTextSize * 0.85f); screenNameView.setTextSize(defaultTextSize * 0.85f);
locationView.setTextSize(defaultTextSize * 0.85f); locationView.setTextSize(defaultTextSize * 0.85f);
timeSourceView.setTextSize(defaultTextSize * 0.85f); timeSourceView.setTextSize(defaultTextSize * 0.85f);
textView.setMovementMethod(StatusContentMovementMethod.getInstance());
textView.setCustomSelectionActionModeCallback(new Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
final FragmentActivity activity = fragment.getActivity();
if (activity instanceof IThemedActivity) {
final int themeRes = ((IThemedActivity) activity).getCurrentThemeResourceId();
final int accentColor = ((IThemedActivity) activity).getCurrentThemeColor();
ThemeUtils.applySupportActionModeBackground(mode, fragment.getActivity(), themeRes, accentColor, true);
}
mode.getMenuInflater().inflate(R.menu.action_status_text_selection, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
final int start = textView.getSelectionStart(), end = textView.getSelectionEnd();
final SpannableString string = SpannableString.valueOf(textView.getText());
final URLSpan[] spans = string.getSpans(start, end, URLSpan.class);
final boolean avail = spans.length == 1 && URLUtil.isValidUrl(spans[0].getURL());
Utils.setMenuItemAvailability(menu, android.R.id.copyUrl, avail);
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case android.R.id.copyUrl: {
final int start = textView.getSelectionStart(), end = textView.getSelectionEnd();
final SpannableString string = SpannableString.valueOf(textView.getText());
final URLSpan[] spans = string.getSpans(start, end, URLSpan.class);
if (spans.length != 1) return true;
ClipboardUtils.setText(activity, spans[0].getURL());
mode.finish();
return true;
}
}
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
});
} }

View File

@ -738,7 +738,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
getUserInfo(accountId, userId, screenName, false); getUserInfo(accountId, userId, screenName, false);
final float actionBarElevation = ThemeUtils.getActionBarElevation(activity); final float actionBarElevation = ThemeUtils.getSupportActionBarElevation(activity);
ViewCompat.setElevation(mPagerIndicator, actionBarElevation); ViewCompat.setElevation(mPagerIndicator, actionBarElevation);
setupBaseActionBar(); setupBaseActionBar();

View File

@ -458,7 +458,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
} }
case VIRTUAL_TABLE_ID_CACHED_USERS_WITH_RELATIONSHIP: { case VIRTUAL_TABLE_ID_CACHED_USERS_WITH_RELATIONSHIP: {
final long accountId = ParseUtils.parseLong(uri.getLastPathSegment(), -1); final long accountId = ParseUtils.parseLong(uri.getLastPathSegment(), -1);
final SQLSelectQuery query = CachedUsersQueryBuilder.buildWithRelationship(projection, final SQLSelectQuery query = CachedUsersQueryBuilder.withRelationship(projection,
selection, sortOrder, accountId); selection, sortOrder, accountId);
final Cursor c = mDatabaseWrapper.rawQuery(query.getSQL(), selectionArgs); final Cursor c = mDatabaseWrapper.rawQuery(query.getSQL(), selectionArgs);
setNotificationUri(c, CachedUsers.CONTENT_URI); setNotificationUri(c, CachedUsers.CONTENT_URI);
@ -466,7 +466,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
} }
case VIRTUAL_TABLE_ID_CACHED_USERS_WITH_SCORE: { case VIRTUAL_TABLE_ID_CACHED_USERS_WITH_SCORE: {
final long accountId = ParseUtils.parseLong(uri.getLastPathSegment(), -1); final long accountId = ParseUtils.parseLong(uri.getLastPathSegment(), -1);
final SQLSelectQuery query = CachedUsersQueryBuilder.buildWithScore(projection, final SQLSelectQuery query = CachedUsersQueryBuilder.withScore(projection,
selection, sortOrder, accountId); selection, sortOrder, accountId);
final Cursor c = mDatabaseWrapper.rawQuery(query.getSQL(), selectionArgs); final Cursor c = mDatabaseWrapper.rawQuery(query.getSQL(), selectionArgs);
setNotificationUri(c, CachedUsers.CONTENT_URI); setNotificationUri(c, CachedUsers.CONTENT_URI);

View File

@ -19,20 +19,16 @@
package org.mariotaku.twidere.util; package org.mariotaku.twidere.util;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.text.ClipboardManager;
@SuppressWarnings("deprecation")
public final class ClipboardUtils { public final class ClipboardUtils {
public static CharSequence getText(final Context context) {
if (context == null) return null;
return ((ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE)).getText();
}
public static boolean setText(final Context context, final CharSequence text) { public static boolean setText(final Context context, final CharSequence text) {
if (context == null) return false; if (context == null) return false;
((ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE)).setText(text != null ? text : ""); final ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClip(ClipData.newPlainText(text, text));
return true; return true;
} }
} }

View File

@ -19,7 +19,7 @@
package org.mariotaku.twidere.util; package org.mariotaku.twidere.util;
import android.annotation.TargetApi; import android.annotation.SuppressLint;
import android.app.ActionBar; import android.app.ActionBar;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@ -33,10 +33,13 @@ import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewCompat;
import android.support.v7.internal.app.WindowDecorActionBar;
import android.support.v7.internal.app.WindowDecorActionBar.ActionModeImpl;
import android.support.v7.internal.view.SupportActionModeWrapper;
import android.support.v7.internal.view.SupportActionModeWrapperTrojan;
import android.support.v7.internal.view.menu.ActionMenuItemView; import android.support.v7.internal.view.menu.ActionMenuItemView;
import android.support.v7.widget.ActionMenuView; import android.support.v7.widget.ActionMenuView;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@ -44,6 +47,7 @@ import android.text.Spanned;
import android.text.TextPaint; import android.text.TextPaint;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.Menu; import android.view.Menu;
@ -67,6 +71,7 @@ import org.mariotaku.twidere.view.TabPagerIndicator;
import org.mariotaku.twidere.view.iface.IThemedView; import org.mariotaku.twidere.view.iface.IThemedView;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
public class ThemeUtils implements Constants { public class ThemeUtils implements Constants {
@ -128,6 +133,35 @@ public class ThemeUtils implements Constants {
} }
} }
public static void applySupportActionModeBackground(ActionMode mode, FragmentActivity activity,
int themeRes, int accentColor, boolean outlineEnabled) {
// Very dirty implementation
if (!(mode instanceof SupportActionModeWrapper) || !(activity instanceof IThemedActivity))
return;
final android.support.v7.view.ActionMode modeCompat =
SupportActionModeWrapperTrojan.getWrappedObject((SupportActionModeWrapper) mode);
if (!(modeCompat instanceof ActionModeImpl)) return;
try {
WindowDecorActionBar actionBar = null;
final Field[] fields = ActionModeImpl.class.getDeclaredFields();
for (Field field : fields) {
if (WindowDecorActionBar.class.isAssignableFrom(field.getType())) {
field.setAccessible(true);
actionBar = (WindowDecorActionBar) field.get(modeCompat);
break;
}
}
if (actionBar == null) return;
final Field contextViewField = WindowDecorActionBar.class.getDeclaredField("mContextView");
contextViewField.setAccessible(true);
final View view = (View) contextViewField.get(actionBar);
if (view == null) return;
ViewAccessor.setBackground(view, getActionBarBackground(activity, themeRes, accentColor, outlineEnabled));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void initPagerIndicatorAsActionBarTab(FragmentActivity activity, TabPagerIndicator indicator) { public static void initPagerIndicatorAsActionBarTab(FragmentActivity activity, TabPagerIndicator indicator) {
final float supportActionBarElevation = getSupportActionBarElevation(activity); final float supportActionBarElevation = getSupportActionBarElevation(activity);
ViewCompat.setElevation(indicator, supportActionBarElevation); ViewCompat.setElevation(indicator, supportActionBarElevation);
@ -376,9 +410,11 @@ public class ThemeUtils implements Constants {
} }
} }
@TargetApi(VERSION_CODES.LOLLIPOP)
public static float getActionBarElevation(final Context context) { public static float getActionBarElevation(final Context context) {
final TypedArray a = context.obtainStyledAttributes(null, new int[]{android.R.attr.elevation}, android.R.attr.actionBarStyle, 0); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return 0;
@SuppressLint("InlinedApi")
final TypedArray a = context.obtainStyledAttributes(null, new int[]{android.R.attr.elevation},
android.R.attr.actionBarStyle, 0);
try { try {
return a.getDimension(0, 0); return a.getDimension(0, 0);
} finally { } finally {

View File

@ -100,6 +100,7 @@ public final class TwidereLinkify implements Constants {
private final OnLinkClickListener mOnLinkClickListener; private final OnLinkClickListener mOnLinkClickListener;
private final Extractor mExtractor = new Extractor(); private final Extractor mExtractor = new Extractor();
private final boolean mAddMovementMethod;
private int mHighlightOption; private int mHighlightOption;
public TwidereLinkify(final OnLinkClickListener listener) { public TwidereLinkify(final OnLinkClickListener listener) {
@ -107,7 +108,12 @@ public final class TwidereLinkify implements Constants {
} }
public TwidereLinkify(final OnLinkClickListener listener, final int highlightOption) { public TwidereLinkify(final OnLinkClickListener listener, final int highlightOption) {
this(listener, highlightOption, true);
}
public TwidereLinkify(final OnLinkClickListener listener, final int highlightOption, boolean addMovementMethod) {
mOnLinkClickListener = listener; mOnLinkClickListener = listener;
mAddMovementMethod = addMovementMethod;
setHighlightOption(highlightOption); setHighlightOption(highlightOption);
} }

View File

@ -44,15 +44,15 @@ public class TwidereQueryBuilder {
public static final class CachedUsersQueryBuilder { public static final class CachedUsersQueryBuilder {
public static SQLSelectQuery buildWithRelationship(final String[] projection, public static SQLSelectQuery withRelationship(final String[] projection,
final String selection, final String selection,
final String sortOrder, final String sortOrder,
final long accountId) { final long accountId) {
return buildWithRelationship(Utils.getColumnsFromProjection(projection), selection, return withRelationship(Utils.getColumnsFromProjection(projection), selection,
sortOrder, accountId); sortOrder, accountId);
} }
public static SQLSelectQuery buildWithRelationship(final Selectable select, public static SQLSelectQuery withRelationship(final Selectable select,
final String selection, final String selection,
final String sortOrder, final String sortOrder,
final long accountId) { final long accountId) {
@ -78,7 +78,7 @@ public class TwidereQueryBuilder {
return qb.build(); return qb.build();
} }
public static SQLSelectQuery buildWithScore(final String[] projection, public static SQLSelectQuery withScore(final String[] projection,
final String selection, final String selection,
final String sortOrder, final String sortOrder,
final long accountId) { final long accountId) {
@ -99,7 +99,7 @@ public class TwidereQueryBuilder {
CachedRelationships.MUTING)); CachedRelationships.MUTING));
columns[columns.length - 1] = new Column(expr, "score"); columns[columns.length - 1] = new Column(expr, "score");
qb.select(select); qb.select(select);
qb.from(buildWithRelationship(new Columns(columns), null, null, accountId)); qb.from(withRelationship(new Columns(columns), null, null, accountId));
if (selection != null) { if (selection != null) {
qb.where(new Expression(selection)); qb.where(new Expression(selection));
} }

View File

@ -142,7 +142,7 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback; import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback;
import org.mariotaku.twidere.fragment.support.AddStatusFilterDialogFragment; import org.mariotaku.twidere.fragment.support.AddStatusFilterDialogFragment;
import org.mariotaku.twidere.fragment.support.DestroyStatusDialogFragment; import org.mariotaku.twidere.fragment.support.DestroyStatusDialogFragment;
import org.mariotaku.twidere.fragment.support.DirectMessagesConversationFragment; import org.mariotaku.twidere.fragment.support.MessagesConversationFragment;
import org.mariotaku.twidere.fragment.support.IncomingFriendshipsFragment; import org.mariotaku.twidere.fragment.support.IncomingFriendshipsFragment;
import org.mariotaku.twidere.fragment.support.MutesUsersListFragment; import org.mariotaku.twidere.fragment.support.MutesUsersListFragment;
import org.mariotaku.twidere.fragment.support.SavedSearchesListFragment; import org.mariotaku.twidere.fragment.support.SavedSearchesListFragment;
@ -884,7 +884,7 @@ public final class Utils implements Constants, TwitterConstants {
break; break;
} }
case LINK_ID_DIRECT_MESSAGES_CONVERSATION: { case LINK_ID_DIRECT_MESSAGES_CONVERSATION: {
fragment = new DirectMessagesConversationFragment(); fragment = new MessagesConversationFragment();
final String paramRecipientId = uri.getQueryParameter(QUERY_PARAM_RECIPIENT_ID); final String paramRecipientId = uri.getQueryParameter(QUERY_PARAM_RECIPIENT_ID);
final String paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME); final String paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME);
final long conversationId = ParseUtils.parseLong(paramRecipientId); final long conversationId = ParseUtils.parseLong(paramRecipientId);

View File

@ -34,6 +34,7 @@ import org.mariotaku.twidere.view.themed.ThemedMultiAutoCompleteTextView;
public class StatusComposeEditText extends ThemedMultiAutoCompleteTextView implements IThemedView { public class StatusComposeEditText extends ThemedMultiAutoCompleteTextView implements IThemedView {
private UserHashtagAutoCompleteAdapter mAdapter; private UserHashtagAutoCompleteAdapter mAdapter;
private long mAccountId;
public StatusComposeEditText(final Context context) { public StatusComposeEditText(final Context context) {
this(context, null); this(context, null);
@ -64,10 +65,11 @@ public class StatusComposeEditText extends ThemedMultiAutoCompleteTextView imple
@Override @Override
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
if (!isInEditMode() && (mAdapter == null || mAdapter.isCursorClosed())) { if (!isInEditMode() && mAdapter == null) {
mAdapter = new UserHashtagAutoCompleteAdapter(this); mAdapter = new UserHashtagAutoCompleteAdapter(this);
} }
setAdapter(mAdapter); setAdapter(mAdapter);
updateAccountId();
} }
@Override @Override
@ -77,7 +79,16 @@ public class StatusComposeEditText extends ThemedMultiAutoCompleteTextView imple
mAdapter.closeCursor(); mAdapter.closeCursor();
mAdapter = null; mAdapter = null;
} }
// setAdapter(null); }
public void setAccountId(long accountId) {
mAccountId = accountId;
updateAccountId();
}
private void updateAccountId() {
if (mAdapter == null) return;
mAdapter.setAccountId(mAccountId);
} }
@Override @Override