improved quote feature

This commit is contained in:
Mariotaku Lee 2015-05-12 23:47:52 +08:00
parent 21a4b1046f
commit 912dc2cb39
11 changed files with 189 additions and 64 deletions

View File

@ -1453,12 +1453,13 @@ public class ComposeActivity extends ThemedFragmentActivity implements LocationL
@Override
protected Boolean doInBackground(final Object... params) {
InputStream is = null;
OutputStream os = null;
try {
final ContentResolver resolver = activity.getContentResolver();
final InputStream is = resolver.openInputStream(src);
final OutputStream os = resolver.openOutputStream(dst);
is = resolver.openInputStream(src);
os = resolver.openOutputStream(dst);
Utils.copyStream(is, os);
os.close();
if (ContentResolver.SCHEME_FILE.equals(src.getScheme()) && delete_src) {
final File file = new File(src.getPath());
if (!file.delete()) {
@ -1468,6 +1469,9 @@ public class ComposeActivity extends ThemedFragmentActivity implements LocationL
} catch (final IOException e) {
Log.w(LOGTAG, e);
return false;
} finally {
Utils.closeSilently(os);
Utils.closeSilently(is);
}
return true;
}

View File

@ -76,6 +76,7 @@ public abstract class AbsContentRecyclerViewFragment<A extends IContentCardAdapt
// Data fields
private Rect mSystemWindowsInsets = new Rect();
private DividerItemDecoration mItemDecoration;
@Override
public boolean canScroll(float dy) {
@ -218,7 +219,8 @@ public abstract class AbsContentRecyclerViewFragment<A extends IContentCardAdapt
}
});
if (compact) {
mRecyclerView.addItemDecoration(new DividerItemDecoration(context, mLayoutManager.getOrientation()));
mItemDecoration = new DividerItemDecoration(context, mLayoutManager.getOrientation());
mRecyclerView.addItemDecoration(mItemDecoration);
}
mRecyclerView.setAdapter((RecyclerView.Adapter) mAdapter);
@ -268,6 +270,9 @@ public abstract class AbsContentRecyclerViewFragment<A extends IContentCardAdapt
}
public void setLoadMoreIndicatorVisible(boolean visible) {
if (mItemDecoration != null) {
mItemDecoration.setDecorationEndOffset(visible ? 1 : 0);
}
mAdapter.setLoadMoreIndicatorVisible(visible);
}

View File

@ -25,15 +25,24 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.support.v7.widget.PopupMenu;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.rengwuxian.materialedittext.MaterialEditText;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MenuUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder.DummyStatusHolderAdapter;
@ -44,6 +53,9 @@ public class RetweetQuoteDialogFragment extends BaseSupportDialogFragment implem
DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "retweet_quote";
private MaterialEditText mEditComment;
private PopupMenu mPopupMenu;
private View mCommentMenu;
@Override
public void onClick(final DialogInterface dialog, final int which) {
@ -53,7 +65,26 @@ public class RetweetQuoteDialogFragment extends BaseSupportDialogFragment implem
case DialogInterface.BUTTON_POSITIVE: {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return;
if (isMyRetweet(status)) {
if (mEditComment.length() > 0) {
final Menu menu = mPopupMenu.getMenu();
final MenuItem quoteOriginalStatus = menu.findItem(R.id.quote_original_status);
final MenuItem linkToQuotedStatus = menu.findItem(R.id.link_to_quoted_status);
final Uri statusLink;
final long inReplyToStatusId;
if (!status.is_quote) {
inReplyToStatusId = status.id;
statusLink = LinkCreator.getTwitterStatusLink(status.quoted_by_user_screen_name, status.id);
} else if (quoteOriginalStatus.isChecked()) {
inReplyToStatusId = status.quote_id;
statusLink = LinkCreator.getTwitterStatusLink(status.user_screen_name, status.quote_id);
} else {
inReplyToStatusId = status.id;
statusLink = LinkCreator.getTwitterStatusLink(status.quoted_by_user_screen_name, status.id);
}
final String commentText = mEditComment.getText() + " " + statusLink;
twitter.updateStatusAsync(new long[]{status.account_id}, commentText, null, null,
linkToQuotedStatus.isChecked() ? inReplyToStatusId : -1, status.is_possibly_sensitive);
} else if (isMyRetweet(status)) {
twitter.cancelRetweetAsync(status.account_id, status.id, status.my_retweet_id);
} else {
twitter.retweetStatusAsync(status.account_id, status.id);
@ -82,6 +113,8 @@ public class RetweetQuoteDialogFragment extends BaseSupportDialogFragment implem
final StatusViewHolder holder = new StatusViewHolder(new DummyStatusHolderAdapter(context), view.findViewById(R.id.item_content));
final ParcelableStatus status = getStatus();
assert status != null;
builder.setView(view);
builder.setTitle(R.string.retweet_quote_confirm_title);
builder.setPositiveButton(isMyRetweet(status) ? R.string.cancel_retweet : R.string.retweet, this);
@ -93,6 +126,32 @@ public class RetweetQuoteDialogFragment extends BaseSupportDialogFragment implem
view.findViewById(R.id.item_menu).setVisibility(View.GONE);
view.findViewById(R.id.action_buttons).setVisibility(View.GONE);
view.findViewById(R.id.item_content).setFocusable(false);
mEditComment = (MaterialEditText) view.findViewById(R.id.edit_comment);
mCommentMenu = view.findViewById(R.id.comment_menu);
mPopupMenu = new PopupMenu(context, mCommentMenu, Gravity.NO_GRAVITY,
R.attr.actionOverflowMenuStyle, 0);
mCommentMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPopupMenu.show();
}
});
mCommentMenu.setOnTouchListener(mPopupMenu.getDragToOpenListener());
mPopupMenu.inflate(R.menu.menu_dialog_comment);
final Menu menu = mPopupMenu.getMenu();
MenuUtils.setMenuItemAvailability(menu, R.id.quote_original_status,
status.retweet_id > 0 || status.quote_id > 0);
mPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.isCheckable()) {
item.setChecked(!item.isChecked());
return true;
}
return false;
}
});
return builder.create();
}

View File

@ -1350,8 +1350,8 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final AppCompatActivity activity = (AppCompatActivity) getActivity();
final IThemedActivity themed = (IThemedActivity) activity;
final int themeRes = themed.getCurrentThemeResourceId();
final int actionBarColor = ThemeUtils.getActionBarColor(activity, color,
themed.getCurrentThemeResourceId(), themed.getThemeBackgroundOption());
final String backgroundOption = themed.getThemeBackgroundOption();
final int actionBarColor = ThemeUtils.getActionBarColor(activity, color, themeRes, backgroundOption);
if (mTintedStatusContent != null) {
mTintedStatusContent.setColor(actionBarColor, themed.getCurrentThemeBackgroundAlpha());
}
@ -1363,7 +1363,8 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mProfileBannerView.setBackgroundColor(color);
mLocationView.setLinkTextColor(color);
mURLView.setLinkTextColor(color);
ViewSupport.setBackground(mPagerIndicator, ThemeUtils.getActionBarStackedBackground(activity, themeRes, color, true));
ViewSupport.setBackground(mPagerIndicator, ThemeUtils.getActionBarStackedBackground(activity,
themeRes, color, backgroundOption, true));
final HeaderDrawerLayout drawer = mHeaderDrawerLayout;
if (drawer != null) {

View File

@ -83,12 +83,12 @@ public class ColorPickerPreference extends DialogPreference implements DialogInt
@Override
protected void onPrepareDialogBuilder(Builder builder) {
mController = ColorPickerDialog.Controller.applyToDialogBuilder(builder);
mController.setAlphaEnabled(mAlphaSliderEnabled);
final Resources res = builder.getContext().getResources();
for (int presetColor : PRESET_COLORS) {
mController.addColor(res.getColor(presetColor));
}
mController.setInitialColor(getValue());
mController.setAlphaEnabled(mAlphaSliderEnabled);
builder.setPositiveButton(res.getString(android.R.string.ok), this);
builder.setNegativeButton(res.getString(android.R.string.cancel), this);
}

View File

@ -65,7 +65,6 @@ import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IThemedActivity;
import org.mariotaku.twidere.activity.support.HomeActivity;
import org.mariotaku.twidere.graphic.ActionBarColorDrawable;
import org.mariotaku.twidere.graphic.ActionIconDrawable;
import org.mariotaku.twidere.text.ParagraphSpacingSpan;
@ -101,7 +100,7 @@ public class ThemeUtils implements Constants {
if (actionBar == null || context == null) return;
actionBar.setBackgroundDrawable(getActionBarBackground(context, themeRes, accentColor, backgroundOption, outlineEnabled));
actionBar.setSplitBackgroundDrawable(getActionBarSplitBackground(context, themeRes));
actionBar.setStackedBackgroundDrawable(getActionBarStackedBackground(context, themeRes, accentColor, outlineEnabled));
actionBar.setStackedBackgroundDrawable(getActionBarStackedBackground(context, themeRes, accentColor, backgroundOption, outlineEnabled));
}
@ -110,7 +109,7 @@ public class ThemeUtils implements Constants {
if (actionBar == null || context == null) return;
actionBar.setPrimaryBackground(getActionBarBackground(context, themeRes, accentColor, backgroundOption, outlineEnabled));
actionBar.setSplitBackground(getActionBarSplitBackground(context, themeRes));
actionBar.setStackedBackground(getActionBarStackedBackground(context, themeRes, accentColor, outlineEnabled));
actionBar.setStackedBackground(getActionBarStackedBackground(context, themeRes, accentColor, backgroundOption, outlineEnabled));
}
public static void applyColorFilterToMenuIcon(final Menu menu, final int color, final int popupColor,
@ -261,14 +260,9 @@ public class ThemeUtils implements Constants {
@NonNull
public static Drawable getActionBarStackedBackground(final Context context, final int themeRes,
final int accentColor, boolean outlineEnabled) {
final int actionBarColor;
if (isDarkTheme(themeRes)) {
actionBarColor = context.getResources().getColor(R.color.background_color_action_bar_dark);
} else {
actionBarColor = accentColor;
}
return ActionBarColorDrawable.create(actionBarColor, outlineEnabled);
final int accentColor, String backgroundOption,
boolean outlineEnabled) {
return getActionBarBackground(context, themeRes, accentColor, backgroundOption, outlineEnabled);
}
public static int getCardBackgroundColor(final Context context, String backgroundOption, int themeAlpha) {
@ -717,6 +711,7 @@ public class ThemeUtils implements Constants {
if (!(activity instanceof IThemedActivity)) return;
final int themeRes = ((IThemedActivity) activity).getCurrentThemeResourceId();
final int themeColor = ((IThemedActivity) activity).getCurrentThemeColor();
final String backgroundOption = ((IThemedActivity) activity).getCurrentThemeBackgroundOption();
final int colorDark, colorLight;
final int[] textColors = new int[2];
getTextColorPrimaryAndInverse(activity, textColors);
@ -729,7 +724,7 @@ public class ThemeUtils implements Constants {
}
final int contrastColor = TwidereColorUtils.getContrastYIQ(themeColor, ACCENT_COLOR_THRESHOLD,
colorDark, colorLight);
ViewSupport.setBackground(indicator, getActionBarStackedBackground(activity, themeRes, themeColor, true));
ViewSupport.setBackground(indicator, getActionBarStackedBackground(activity, themeRes, themeColor, backgroundOption, true));
if (isDarkTheme(themeRes)) {
final int foregroundColor = getThemeForegroundColor(activity);
indicator.setIconColor(foregroundColor);

View File

@ -140,8 +140,15 @@ import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity;
import org.mariotaku.twidere.activity.support.MediaViewerActivity;
import org.mariotaku.twidere.adapter.iface.IBaseAdapter;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter;
import org.mariotaku.twidere.api.twitter.model.Status;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterConstants;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.auth.OAuthSupport;
import org.mariotaku.twidere.api.twitter.model.DirectMessage;
import org.mariotaku.twidere.api.twitter.model.RateLimitStatus;
import org.mariotaku.twidere.api.twitter.model.Relationship;
import org.mariotaku.twidere.api.twitter.model.Status;
import org.mariotaku.twidere.api.twitter.model.UserMentionEntity;
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback;
import org.mariotaku.twidere.fragment.support.AccountsManagerFragment;
import org.mariotaku.twidere.fragment.support.AddStatusFilterDialogFragment;
@ -249,13 +256,6 @@ import javax.net.ssl.SSLException;
import edu.tsinghua.spice.SpiceService;
import edu.ucdavis.earlybird.UCDService;
import org.mariotaku.twidere.api.twitter.model.DirectMessage;
import org.mariotaku.twidere.api.twitter.model.RateLimitStatus;
import org.mariotaku.twidere.api.twitter.model.Relationship;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterConstants;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.UserMentionEntity;
import static android.text.TextUtils.isEmpty;
import static android.text.format.DateUtils.getRelativeTimeSpanString;
@ -1023,9 +1023,13 @@ public final class Utils implements Constants, TwitterConstants {
break;
}
case LINK_ID_SEARCH: {
final String param_query = uri.getQueryParameter(QUERY_PARAM_QUERY);
if (isEmpty(param_query)) return null;
args.putString(EXTRA_QUERY, param_query);
final String paramQuery = uri.getQueryParameter(QUERY_PARAM_QUERY);
if (!args.containsKey(EXTRA_QUERY) && !isEmpty(paramQuery)) {
args.putString(EXTRA_QUERY, paramQuery);
}
if (!args.containsKey(EXTRA_QUERY)) {
return null;
}
fragment = new SearchFragment();
break;
}
@ -2746,15 +2750,28 @@ public final class Utils implements Constants, TwitterConstants {
activity.startActivity(intent);
}
public static void openSearch(final Context context, final long account_id, final String query) {
public static void openSearch(final Context context, final long accountId, final String query) {
openSearch(context, accountId, query, null);
}
public static void openSearch(final Context context, final long accountId, final String query, String type) {
if (context == null) return;
final Intent intent = new Intent(Intent.ACTION_VIEW);
// Some devices cannot process query parameter with hashes well, so add this intent extra
intent.putExtra(EXTRA_QUERY, query);
intent.putExtra(EXTRA_ACCOUNT_ID, accountId);
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_SEARCH);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(accountId));
builder.appendQueryParameter(QUERY_PARAM_QUERY, query);
final Uri uri = builder.build();
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if (!TextUtils.isEmpty(type)) {
builder.appendQueryParameter(QUERY_PARAM_TYPE, type);
intent.putExtra(EXTRA_TYPE, type);
}
intent.setData(builder.build());
context.startActivity(intent);
}
@ -2833,17 +2850,7 @@ public final class Utils implements Constants, TwitterConstants {
}
public static void openTweetSearch(final Context context, final long accountId, final String query) {
if (context == null) return;
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_SEARCH);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(accountId));
builder.appendQueryParameter(QUERY_PARAM_TYPE, QUERY_PARAM_VALUE_TWEETS);
if (query != null) {
builder.appendQueryParameter(QUERY_PARAM_QUERY, query);
}
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
context.startActivity(intent);
openSearch(context, accountId, query, QUERY_PARAM_VALUE_TWEETS);
}
public static void openUserBlocks(final Activity activity, final long account_id) {

View File

@ -163,6 +163,7 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
additionalHeaders.add(Pair.create("Accept", "image/webp, */*"));
}
final String method = GET.METHOD;
final String requestUri;
if (auth != null && auth.hasAuthorization()) {
final Endpoint endpoint;
if (auth instanceof OAuthAuthorization) {
@ -179,9 +180,8 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
final RequestInfo info = new RequestInfo(method, uri.getPath(), queries, null,
additionalHeaders, null, null, null, null);
additionalHeaders.add(Pair.create("Authorization", auth.getHeader(endpoint, info)));
}
final String requestUri;
if (mThumbor != null) {
requestUri = modifiedUri.toString();
} else if (mThumbor != null) {
requestUri = mThumbor.buildImage(modifiedUri.toString()).filter(ThumborUrlBuilder.quality(85)).toUrl();
} else {
requestUri = modifiedUri.toString();

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
@ -18,29 +17,52 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<ScrollView
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/status_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/element_spacing_normal"
android:layout_height="match_parent"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_large"
android:paddingRight="@dimen/element_spacing_large">
android:paddingRight="@dimen/element_spacing_large"
android:paddingTop="@dimen/element_spacing_normal">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
<LinearLayout
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="wrap_content"
android:inputType="text"/>
android:orientation="horizontal">
<include layout="@layout/card_item_status_common"/>
<org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText
android:id="@+id/edit_comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:focusable="true"
android:hint="@string/comment_hint"
android:inputType="text"
android:visibility="visible"
app:met_maxCharacters="140">
<requestFocus />
</org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/comment_menu"
style="?cardActionButtonStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_weight="0"
android:color="?android:textColorTertiary"
android:focusable="false"
android:src="@drawable/ic_action_more_vertical" />
</LinearLayout>
<include layout="@layout/card_item_status_common" />
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/link_to_quoted_status"
android:checkable="true"
android:checked="true"
android:title="@string/link_to_quoted_status" />
<item
android:id="@+id/quote_original_status"
android:checkable="true"
android:title="@string/quote_original_status" />
</menu>

View File

@ -406,6 +406,7 @@
<string name="search_name_deleted">Search \"<xliff:g id="name">%s</xliff:g>\" deleted.</string>
<string name="import_from">Import from…</string>
<string name="link_to_quoted_status">Link to quoted tweet</string>
<string name="quote_original_status">Quote original tweet</string>
<string name="followed_user">Followed <xliff:g id="user">%s</xliff:g>.</string>
<string name="sent_follow_request_to_user">Sent follow request to <xliff:g id="user">%s</xliff:g>.</string>
<string name="unfollowed_user">Unfollowed <xliff:g id="user">%s</xliff:g>.</string>
@ -746,4 +747,5 @@
<string name="delete_conversation_confirm_message">Delete all messages of this conversation?</string>
<string name="name_first_summary_on">Display name first</string>
<string name="name_first_summary_off">Display @screenname first</string>
<string name="comment_hint">Comment...</string>
</resources>