improved compose account selection button appearance

implemented retweet in tweet list
This commit is contained in:
Mariotaku Lee 2014-12-10 20:15:09 +08:00
parent 10ac7ccf52
commit 30c302fa52
49 changed files with 1110 additions and 961 deletions

View File

@ -5,7 +5,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0-rc4'
classpath 'com.android.tools.build:gradle:1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

@ -1 +1 @@
Subproject commit 19b5078fc96f7a9d54b51d95648bbee545d650d5
Subproject commit bed0ede61d99c45746f84a87930d271f195e35a0

@ -1 +1 @@
Subproject commit 3835fb07d65585a09a6895747e313eed13304bce
Subproject commit f988e0bdf132fdd4f6430d9de9acde64c6770730

@ -1 +1 @@
Subproject commit befa4a83f6fb54ac210668815e8d7bb2c930935a
Subproject commit c2abc8708204fd2437cd069f173ac8a74f601266

@ -1 +1 @@
Subproject commit 028b9da420d0a3e7368bc1c09ff0400996d386ec
Subproject commit d58d3151e8410524d8d223a7b78c62f3a1a5a69d

@ -1 +1 @@
Subproject commit 7e5c5d298168dea83e9b6a45684fa6416712fa2e
Subproject commit 45c34152104f49e8cad50ebc86233de131ce3000

@ -1 +1 @@
Subproject commit 397e9d058eeff6e4a040677219815c3c1ede4ddc
Subproject commit ef54ac9c260a982279fa963bca948e8b8d0ecf01

View File

@ -216,7 +216,7 @@ public class HomeActivity extends BaseSupportActivity implements OnClickListener
@Override
public void onClick(final View v) {
switch (v.getId()) {
case R.id.actions_button: {
case R.id.action_buttons: {
triggerActionsClick();
break;
}
@ -247,7 +247,7 @@ public class HomeActivity extends BaseSupportActivity implements OnClickListener
mSlidingMenu = (HomeSlidingMenu) findViewById(R.id.home_menu);
mViewPager = (ExtendedViewPager) findViewById(R.id.main_pager);
mEmptyTabHint = findViewById(R.id.empty_tab_hint);
mActionsButton = findViewById(R.id.actions_button);
mActionsButton = findViewById(R.id.action_buttons);
mTabsContainer = findViewById(R.id.tabs_container);
mTabIndicator = (TabPagerIndicator) findViewById(R.id.main_tabs);
mActionBarOverlay = findViewById(R.id.actionbar_overlay);
@ -297,7 +297,7 @@ public class HomeActivity extends BaseSupportActivity implements OnClickListener
@Override
public boolean onLongClick(final View v) {
switch (v.getId()) {
case R.id.actions_button: {
case R.id.action_buttons: {
showMenuItemToast(v, v.getContentDescription(), true);
return true;
}

View File

@ -59,7 +59,9 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
switch (viewType) {
case ITEM_VIEW_TYPE_STATUS: {
final View view = mInflater.inflate(mCardLayoutResource, parent, false);
return new StatusViewHolder(this, view);
final StatusViewHolder holder = new StatusViewHolder(this, view);
holder.setupViews();
return holder;
}
case ITEM_VIEW_TYPE_GAP: {
final View view = mInflater.inflate(R.layout.card_item_gap, parent, false);

View File

@ -39,8 +39,11 @@ public class AccountsSpinnerAdapter extends ArrayAdapter<ParcelableAccount> {
private final boolean mDisplayProfileImage;
public AccountsSpinnerAdapter(final Context context) {
super(context, R.layout.list_item_two_line_small);
setDropDownViewResource(R.layout.list_item_two_line_small);
this(context, R.layout.list_item_user);
}
public AccountsSpinnerAdapter(final Context context, int itemViewResource) {
super(context, itemViewResource);
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
mDisplayProfileImage = context.getSharedPreferences(DirectMessagesConversationFragment.SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE).getBoolean(DirectMessagesConversationFragment.KEY_DISPLAY_PROFILE_IMAGE, true);
@ -69,18 +72,28 @@ public class AccountsSpinnerAdapter extends ArrayAdapter<ParcelableAccount> {
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
final TextView text2 = (TextView) view.findViewById(android.R.id.text2);
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
text2.setVisibility(item.is_dummy ? View.GONE : View.VISIBLE);
icon.setVisibility(item.is_dummy ? View.GONE : View.VISIBLE);
if (text2 != null) {
text2.setVisibility(item.is_dummy ? View.GONE : View.VISIBLE);
}
if (icon != null) {
icon.setVisibility(item.is_dummy ? View.GONE : View.VISIBLE);
}
if (!item.is_dummy) {
text1.setText(item.name);
text2.setText(String.format("@%s", item.screen_name));
if (mDisplayProfileImage) {
mImageLoader.displayProfileImage(icon, item.profile_image_url);
} else {
mImageLoader.cancelDisplayTask(icon);
icon.setImageResource(R.drawable.ic_profile_image_default);
if (text1 != null) {
text1.setText(item.name);
}
} else {
if (text2 != null) {
text2.setText(String.format("@%s", item.screen_name));
}
if (icon != null) {
if (mDisplayProfileImage) {
mImageLoader.displayProfileImage(icon, item.profile_image_url);
} else {
mImageLoader.cancelDisplayTask(icon);
icon.setImageResource(R.drawable.ic_profile_image_default);
}
}
} else if (text1 != null) {
text1.setText(R.string.none);
}
}

View File

@ -1,376 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v4.util.Pair;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView.ScaleType;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.support.UserFragment;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.iface.ICardItemView.OnOverflowIconClickListener;
import java.util.Locale;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.findStatusInDatabases;
import static org.mariotaku.twidere.util.Utils.getCardHighlightOptionInt;
import static org.mariotaku.twidere.util.Utils.isFiltered;
import static org.mariotaku.twidere.util.Utils.openImage;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
public class CursorStatusesListAdapter extends BaseCursorAdapter implements IStatusesListAdapter<Cursor>, OnClickListener,
OnOverflowIconClickListener {
public static final String[] CURSOR_COLS = Statuses.COLUMNS;
private final Context mContext;
private final ImageLoaderWrapper mImageLoader;
private final MultiSelectManager mMultiSelectManager;
private final SQLiteDatabase mDatabase;
private final ImageLoadingHandler mImageLoadingHandler;
private MenuButtonClickListener mListener;
private boolean mDisplayImagePreview, mGapDisallowed, mMentionsHighlightDisabled, mFavoritesHighlightDisabled,
mDisplaySensitiveContents, mIndicateMyStatusDisabled, mIsLastItemFiltered, mFiltersEnabled,
mAnimationEnabled;
private boolean mFilterIgnoreUser, mFilterIgnoreSource, mFilterIgnoreTextHtml, mFilterIgnoreTextPlain,
mFilterRetweetedById;
private int mMaxAnimationPosition, mCardHighlightOption;
private ParcelableStatus.CursorIndices mIndices;
private ScaleType mImagePreviewScaleType;
public CursorStatusesListAdapter(final Context context) {
this(context, Utils.isCompactCards(context));
}
public CursorStatusesListAdapter(final Context context, final boolean compactCards) {
super(context, getItemResource(compactCards), null, new String[0], new int[0], 0);
mContext = context;
final TwidereApplication application = TwidereApplication.getInstance(context);
mMultiSelectManager = application.getMultiSelectManager();
mImageLoader = application.getImageLoaderWrapper();
mDatabase = application.getSQLiteDatabase();
mImageLoadingHandler = new ImageLoadingHandler();
configBaseCardAdapter(context, this);
setMaxAnimationPosition(-1);
}
@Override
public void bindView(final View view, final Context context, final Cursor cursor) {
final StatusViewHolder holder = (StatusViewHolder) view.getTag();
holder.displayStatus(cursor, mIndices);
}
@Override
public int findPositionByStatusId(final long status_id) {
final Cursor c = getCursor();
if (c == null || c.isClosed()) return -1;
for (int i = 0, count = c.getCount(); i < count; i++) {
if (c.moveToPosition(i) && c.getLong(mIndices.status_id) == status_id) return i;
}
return -1;
}
@Override
public long getAccountId(final int position) {
final Cursor c = getCursor();
if (c == null || c.isClosed() || !c.moveToPosition(position)) return -1;
return c.getLong(mIndices.account_id);
}
@Override
public int getStatusCount() {
return super.getCount();
}
@Override
public void onItemActionClick(ViewHolder holder, int id, int position) {
}
@Override
public void onItemMenuClick(ViewHolder holder, int position) {
}
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
}
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
}
@Override
public int getCount() {
final int count = super.getCount();
return mFiltersEnabled && mIsLastItemFiltered && count > 0 ? count - 1 : count;
}
@Override
public ParcelableStatus getLastStatus() {
final Cursor c = getCursor();
if (c == null || c.isClosed() || !c.moveToLast()) return null;
final long account_id = c.getLong(mIndices.account_id);
final long status_id = c.getLong(mIndices.status_id);
return findStatusInDatabases(mContext, account_id, status_id);
}
@Override
public long getLastStatusId() {
final Cursor c = getCursor();
try {
if (c == null || c.isClosed() || !c.moveToLast()) return -1;
return c.getLong(mIndices.status_id);
} catch (final IllegalStateException e) {
return -1;
}
}
@Override
public Context getContext() {
return mContext;
}
@Override
public ImageLoadingHandler getImageLoadingHandler() {
return mImageLoadingHandler;
}
@Override
public ParcelableStatus getStatus(final int position) {
final Cursor c = getCursor();
if (c == null || c.isClosed() || !c.moveToPosition(position)) return null;
return new ParcelableStatus(c, mIndices);
}
@Override
public long getStatusId(final int position) {
final Cursor c = getCursor();
if (c == null || c.isClosed() || !c.moveToPosition(position)) return -1;
return c.getLong(mIndices.status_id);
}
@Override
public boolean isGapItem(int position) {
return false;
}
@Override
public boolean isLastItemFiltered() {
return mFiltersEnabled && mIsLastItemFiltered;
}
@Override
public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
final View view = super.newView(context, cursor, parent);
final Object tag = view.getTag();
if (!(tag instanceof StatusViewHolder)) {
final StatusViewHolder holder = new StatusViewHolder(this, view);
view.setTag(holder);
}
return view;
}
@Override
public void onClick(final View view) {
if (mMultiSelectManager.isActive()) return;
final Object tag = view.getTag();
final int position = tag instanceof Integer ? (Integer) tag : -1;
if (position == -1) return;
switch (view.getId()) {
case R.id.image_preview: {
final ParcelableStatus status = getStatus(position);
if (status == null || status.first_media == null) return;
openImage(mContext, status.account_id, status.first_media, status.is_possibly_sensitive);
break;
}
case R.id.my_profile_image:
case R.id.profile_image: {
final ParcelableStatus status = getStatus(position);
if (status == null) return;
final Activity activity = (Activity) getContext();
final Bundle options = Utils.makeSceneTransitionOption(activity,
new Pair<>(view, UserFragment.TRANSITION_NAME_PROFILE_IMAGE));
openUserProfile(mContext, status.account_id, status.user_id,
status.user_screen_name, options);
break;
}
}
}
@Override
public void onOverflowIconClick(final View view) {
if (mMultiSelectManager.isActive()) return;
final Object tag = view.getTag();
if (tag instanceof StatusViewHolder) {
final StatusViewHolder holder = (StatusViewHolder) tag;
final int position = holder.getPosition();
if (position == -1 || mListener == null) return;
mListener.onMenuButtonClick(view, position, getItemId(position));
}
}
@Override
public void setAnimationEnabled(final boolean anim) {
mAnimationEnabled = anim;
}
@Override
public void setCardHighlightOption(final String option) {
mCardHighlightOption = getCardHighlightOptionInt(option);
}
@Override
public void setData(final Cursor data) {
swapCursor(data);
}
@Override
public void setDisplayImagePreview(final boolean display) {
mDisplayImagePreview = display;
}
@Override
public void setDisplaySensitiveContents(final boolean display) {
mDisplaySensitiveContents = display;
}
@Override
public void setFavoritesHightlightDisabled(final boolean disable) {
mFavoritesHighlightDisabled = disable;
}
@Override
public void setFiltersEnabled(final boolean enabled) {
if (mFiltersEnabled == enabled) return;
mFiltersEnabled = enabled;
rebuildFilterInfo(getCursor(), mIndices);
}
@Override
public void setGapDisallowed(final boolean disallowed) {
mGapDisallowed = disallowed;
}
@Override
public void setHighlightKeyword(final String... keywords) {
// TODO Auto-generated method stub
}
@Override
public void setIgnoredFilterFields(final boolean user, final boolean textPlain, final boolean textHtml,
final boolean source, final boolean retweetedById) {
mFilterIgnoreTextPlain = textPlain;
mFilterIgnoreTextHtml = textHtml;
mFilterIgnoreUser = user;
mFilterIgnoreSource = source;
mFilterRetweetedById = retweetedById;
rebuildFilterInfo(getCursor(), mIndices);
}
@Override
public void setImagePreviewScaleType(final String scaleTypeString) {
final ScaleType scaleType = ScaleType.valueOf(scaleTypeString.toUpperCase(Locale.US));
mImagePreviewScaleType = scaleType;
}
@Override
public void setIndicateMyStatusDisabled(final boolean disable) {
mIndicateMyStatusDisabled = disable;
}
@Override
public void setMaxAnimationPosition(final int position) {
mMaxAnimationPosition = position;
}
@Override
public void setMentionsHightlightDisabled(final boolean disable) {
mMentionsHighlightDisabled = disable;
}
@Override
public void setMenuButtonClickListener(final MenuButtonClickListener listener) {
mListener = listener;
}
@Override
public Cursor swapCursor(final Cursor cursor) {
mIndices = cursor != null ? new ParcelableStatus.CursorIndices(cursor) : null;
rebuildFilterInfo(cursor, mIndices);
return super.swapCursor(cursor);
}
private void rebuildFilterInfo(final Cursor c, final ParcelableStatus.CursorIndices i) {
if (i != null && c != null && moveCursorToLast(c)) {
final long userId = mFilterIgnoreUser ? -1 : c.getLong(mIndices.user_id);
final String textPlain = mFilterIgnoreTextPlain ? null : c.getString(mIndices.text_plain);
final String textHtml = mFilterIgnoreTextHtml ? null : c.getString(mIndices.text_html);
final String source = mFilterIgnoreSource ? null : c.getString(mIndices.source);
final long retweetedById = mFilterRetweetedById ? -1 : c.getLong(mIndices.retweeted_by_user_id);
mIsLastItemFiltered = isFiltered(mDatabase, userId, textPlain, textHtml, source, retweetedById);
} else {
mIsLastItemFiltered = false;
}
}
private static int getItemResource(final boolean compactCards) {
return compactCards ? R.layout.card_item_status_compat : R.layout.card_item_status;
}
private static boolean moveCursorToLast(final Cursor c) {
if (c == null || c.isClosed()) return false;
try {
return c.moveToNext();
} catch (final Exception e) {
return false;
}
}
@Override
public void onGapClick(ViewHolder holder, int position) {
}
}

View File

@ -43,7 +43,7 @@ public class SimpleParcelableUsersAdapter extends BaseArrayAdapter<ParcelableUse
private final Context mContext;
public SimpleParcelableUsersAdapter(final Context context) {
super(context, R.layout.list_item_two_line);
super(context, R.layout.list_item_user);
mContext = context;
final TwidereApplication app = TwidereApplication.getInstance(context);
mImageLoader = app.getImageLoaderWrapper();

View File

@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.State;
import android.view.View;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
@ -55,7 +56,7 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
public void onDraw(Canvas c, RecyclerView parent, State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
@ -98,7 +99,7 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {

View File

@ -188,15 +188,31 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
@Override
public void onStatusActionClick(StatusViewHolder holder, int id, int position) {
final ParcelableStatus status = mAdapter.getStatus(position);
if (status == null) return;
switch (id) {
case R.id.reply_count: {
final Context context = getActivity();
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_REPLY);
intent.setPackage(context.getPackageName());
intent.putExtra(IntentConstants.EXTRA_STATUS, mAdapter.getStatus(position));
intent.putExtra(IntentConstants.EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
case R.id.retweet_count: {
RetweetQuoteDialogFragment.show(getFragmentManager(), status);
break;
}
case R.id.favorite_count: {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return;
if (status.is_favorite) {
twitter.destroyFavoriteAsync(status.account_id, status.id);
} else {
twitter.createFavoriteAsync(status.account_id, status.id);
}
break;
}
}
}

View File

@ -305,7 +305,7 @@ abstract class BaseStatusesListFragment<Data> extends BasePullToRefreshListFragm
cancelRetweet(twitter, status);
} else {
final long id_to_retweet = status.retweet_id > 0 ? status.retweet_id : status.id;
twitter.retweetStatus(status.account_id, id_to_retweet);
twitter.retweetStatusAsync(status.account_id, id_to_retweet);
}
break;
}

View File

@ -24,6 +24,7 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import org.mariotaku.twidere.R;
@ -33,51 +34,52 @@ import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
public class DestroyFriendshipDialogFragment extends BaseSupportDialogFragment implements
DialogInterface.OnClickListener {
DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "destroy_friendship";
public static final String FRAGMENT_TAG = "destroy_friendship";
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (user == null || twitter == null) return;
twitter.destroyFriendshipAsync(user.account_id, user.id);
break;
default:
break;
}
}
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (user == null || twitter == null) return;
twitter.destroyFriendshipAsync(user.account_id, user.id);
break;
default:
break;
}
}
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final ParcelableUser user = getUser();
if (user != null) {
final String display_name = Utils.getDisplayName(getActivity(), user.id, user.name, user.screen_name);
builder.setTitle(getString(R.string.unfollow_user, display_name));
builder.setMessage(getString(R.string.unfollow_user_confirm_message, display_name));
}
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final ParcelableUser user = getUser();
if (user != null) {
final String display_name = Utils.getDisplayName(getActivity(), user.id, user.name, user.screen_name);
builder.setTitle(getString(R.string.unfollow_user, display_name));
builder.setMessage(getString(R.string.unfollow_user_confirm_message, display_name));
}
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private ParcelableUser getUser() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USER)) return null;
return args.getParcelable(EXTRA_USER);
}
private ParcelableUser getUser() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USER)) return null;
return args.getParcelable(EXTRA_USER);
}
public static DestroyFriendshipDialogFragment show(final FragmentManager fm, final ParcelableUser user) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER, user);
final DestroyFriendshipDialogFragment f = new DestroyFriendshipDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
public static DestroyFriendshipDialogFragment show(final FragmentManager fm, final ParcelableUser user) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER, user);
final DestroyFriendshipDialogFragment f = new DestroyFriendshipDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
}

View File

@ -19,12 +19,13 @@
package org.mariotaku.twidere.fragment.support;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
@ -45,8 +46,8 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.ListView;
@ -60,26 +61,25 @@ import com.squareup.otto.Subscribe;
import org.mariotaku.menucomponent.widget.PopupMenu;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.ImagePickerActivity;
import org.mariotaku.twidere.activity.support.UserListSelectorActivity;
import org.mariotaku.twidere.adapter.AccountsSpinnerAdapter;
import org.mariotaku.twidere.adapter.DirectMessagesConversationAdapter;
import org.mariotaku.twidere.adapter.SimpleParcelableUsersAdapter;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter.MenuButtonClickListener;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.loader.support.UserSearchLoader;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.provider.TweetStore;
import org.mariotaku.twidere.provider.TweetStore.CachedUsers;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages.Conversation;
import org.mariotaku.twidere.task.TwidereAsyncTask;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ClipboardUtils;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereValidator;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.accessor.ViewAccessor;
import org.mariotaku.twidere.util.message.TaskStateChangedEvent;
import org.mariotaku.twidere.view.StatusTextCountView;
import org.mariotaku.twidere.view.iface.IColorLabelView;
@ -90,27 +90,29 @@ import java.util.Locale;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.util.Utils.buildDirectMessageConversationUri;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.getActivatedAccountIds;
import static org.mariotaku.twidere.util.Utils.getNewestMessageIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getOldestMessageIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.showOkMessage;
public class DirectMessagesConversationFragment extends BasePullToRefreshListFragment implements
public class DirectMessagesConversationFragment extends BaseSupportFragment implements
LoaderCallbacks<Cursor>, OnMenuItemClickListener, TextWatcher, OnClickListener,
OnItemSelectedListener, OnEditorActionListener, MenuButtonClickListener {
private static final int LOADER_ID_SEARCH_USERS = 1;
private TwidereValidator mValidator;
private AsyncTwitterWrapper mTwitterWrapper;
private SharedPreferences mPreferences;
private ListView mListView;
private ListView mMessagesListView, mUsersSearchList;
private EditText mEditText;
private StatusTextCountView mTextCountView;
private View mSendButton;
private ImageView mAddImageButton;
private View mConversationContainer, mRecipientSelectorContainer, mRecipientSelector;
private View mConversationContainer, mRecipientSelectorContainer;
private Spinner mAccountSpinner;
private ImageView mSenderProfileImageView, mRecipientProfileImageView;
private EditText mUserQuery;
private View mUsersSearchProgress;
private View mQueryButton;
private PopupMenu mPopupMenu;
@ -123,13 +125,37 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
private Locale mLocale;
private DirectMessagesConversationAdapter mAdapter;
private SimpleParcelableUsersAdapter mUsersSearchAdapter;
private ParcelableAccount mSender;
private ParcelableUser mRecipient;
private ImageLoaderWrapper mImageLoader;
private IColorLabelView mProfileImageContainer;
private LoaderCallbacks<List<ParcelableUser>> mSearchLoadersCallback = new LoaderCallbacks<List<ParcelableUser>>() {
@Override
public Loader<List<ParcelableUser>> onCreateLoader(int id, Bundle args) {
mUsersSearchList.setVisibility(View.GONE);
mUsersSearchProgress.setVisibility(View.VISIBLE);
final long accountId = args.getLong(EXTRA_ACCOUNT_ID);
final String query = args.getString(EXTRA_QUERY);
return new UserSearchLoader(getActivity(), accountId, query, 0, null);
}
@Override
public void onLoadFinished(Loader<List<ParcelableUser>> loader, List<ParcelableUser> data) {
mUsersSearchList.setVisibility(View.VISIBLE);
mUsersSearchProgress.setVisibility(View.GONE);
mUsersSearchAdapter.setData(data, true);
}
@Override
public void onLoaderReset(Loader<List<ParcelableUser>> loader) {
}
};
@Subscribe
public void notifyTaskStateChanged(TaskStateChangedEvent event) {
@ -150,35 +176,50 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
final FragmentActivity activity = getActivity();
final ActionBar actionBar = activity.getActionBar();
if (actionBar != null) {
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
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);
mQueryButton = actionBarView.findViewById(R.id.query_button);
final List<ParcelableAccount> accounts = ParcelableAccount.getAccountsList(activity, false);
final AccountsSpinnerAdapter adapter = new AccountsSpinnerAdapter(actionBar.getThemedContext(), R.layout.spinner_item_account_icon);
adapter.setDropDownViewResource(R.layout.list_item_user);
adapter.addAll(accounts);
mAccountSpinner.setAdapter(adapter);
mAccountSpinner.setOnItemSelectedListener(this);
mQueryButton.setOnClickListener(this);
}
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mImageLoader = TwidereApplication.getInstance(getActivity()).getImageLoaderWrapper();
mTwitterWrapper = getTwitterWrapper();
mValidator = new TwidereValidator(getActivity());
mLocale = getResources().getConfiguration().locale;
mAdapter = new DirectMessagesConversationAdapter(getActivity());
setListAdapter(mAdapter);
mMessagesListView.setAdapter(mAdapter);
mAdapter.setMenuButtonClickListener(this);
mListView = getListView();
mListView.setDivider(null);
mListView.setSelector(android.R.color.transparent);
mListView.setFastScrollEnabled(mPreferences.getBoolean(KEY_FAST_SCROLL_THUMB, false));
mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
mListView.setStackFromBottom(true);
setListShownNoAnimation(false);
mMessagesListView.setDivider(null);
mMessagesListView.setSelector(android.R.color.transparent);
mMessagesListView.setFastScrollEnabled(mPreferences.getBoolean(KEY_FAST_SCROLL_THUMB, false));
mMessagesListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
mMessagesListView.setStackFromBottom(true);
mUsersSearchAdapter = new SimpleParcelableUsersAdapter(activity);
mUsersSearchList.setAdapter(mUsersSearchAdapter);
if (mPreferences.getBoolean(KEY_QUICK_SEND, false)) {
mEditText.setOnEditorActionListener(this);
}
mEditText.addTextChangedListener(this);
final List<ParcelableAccount> accounts = ParcelableAccount.getAccountsList(getActivity(), false);
mAccountSpinner.setAdapter(new AccountsSpinnerAdapter(getActivity(), accounts));
mAccountSpinner.setOnItemSelectedListener(this);
mSendButton.setOnClickListener(this);
mAddImageButton.setOnClickListener(this);
mSendButton.setEnabled(false);
mRecipientSelector.setOnClickListener(this);
if (savedInstanceState != null) {
final long accountId = savedInstanceState.getLong(EXTRA_ACCOUNT_ID, -1);
final long recipientId = savedInstanceState.getLong(EXTRA_RECIPIENT_ID, -1);
@ -194,6 +235,9 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
final boolean isValid = mAccountId > 0 && mRecipientId > 0;
mConversationContainer.setVisibility(isValid ? View.VISIBLE : View.GONE);
mRecipientSelectorContainer.setVisibility(isValid ? View.GONE : View.VISIBLE);
mUsersSearchList.setVisibility(View.GONE);
mUsersSearchProgress.setVisibility(View.GONE);
}
@Override
@ -235,6 +279,7 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
|| mSenderProfileImageView == null) {
return;
}
mProfileImageContainer.setVisibility(mRecipient != null ? View.VISIBLE : View.GONE);
if (mSender != null && mRecipient != null) {
mImageLoader.displayProfileImage(mSenderProfileImageView, mSender.profile_image_url);
mImageLoader.displayProfileImage(mRecipientProfileImageView, mRecipient.profile_image_url);
@ -262,14 +307,14 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
sendDirectMessage();
break;
}
case R.id.recipient_selector: {
if (mAccountId <= 0) return;
final Intent intent = new Intent(INTENT_ACTION_SELECT_USER);
intent.setClass(getActivity(), UserListSelectorActivity.class);
intent.putExtra(EXTRA_ACCOUNT_ID, mAccountId);
startActivityForResult(intent, REQUEST_SELECT_USER);
break;
}
// case R.id.recipient_selector: {
// if (mAccountId <= 0) return;
// final Intent intent = new Intent(INTENT_ACTION_SELECT_USER);
// intent.setClass(getActivity(), UserListSelectorActivity.class);
// intent.putExtra(EXTRA_ACCOUNT_ID, mAccountId);
// startActivityForResult(intent, REQUEST_SELECT_USER);
// break;
// }
case R.id.add_image: {
final Intent intent = new Intent(getActivity(), ImagePickerActivity.class);
startActivityForResult(intent, REQUEST_PICK_IMAGE);
@ -282,6 +327,26 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
recipient.screen_name, null);
break;
}
case R.id.query_button: {
final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem();
searchUsers(account.account_id, ParseUtils.parseString(mUserQuery.getText()));
break;
}
}
}
private boolean mSearchUsersLoaderInitialized;
private void searchUsers(long accountId, String query) {
final Bundle args = new Bundle();
args.putLong(EXTRA_ACCOUNT_ID, accountId);
args.putString(EXTRA_QUERY, query);
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);
}
}
@ -301,18 +366,16 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_messages_conversation, null);
final FrameLayout listContainer = (FrameLayout) view.findViewById(R.id.list_container);
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
listContainer.addView(super.onCreateView(inflater, container, savedInstanceState), lp);
final ViewGroup inputSendContainer = (ViewGroup) view.findViewById(R.id.input_send_container);
final FragmentActivity activity = getActivity();
final int themeRes = ThemeUtils.getThemeResource(activity);
ViewAccessor.setBackground(inputSendContainer, ThemeUtils.getActionBarSplitBackground(activity, themeRes));
final Context actionBarContext = ThemeUtils.getActionBarContext(activity);
View.inflate(actionBarContext, R.layout.fragment_messages_conversation_input_send, inputSendContainer);
return view;
return inflater.inflate(R.layout.fragment_messages_conversation, container, false);
}
@Override
protected void fitSystemWindows(Rect insets) {
super.fitSystemWindows(insets);
final View view = getView();
if (view != null) {
view.setPadding(insets.left, insets.top, insets.right, insets.bottom);
}
}
@Override
@ -344,7 +407,6 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
@Override
public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) {
mAdapter.swapCursor(cursor);
setListShown(true);
}
@Override
@ -381,33 +443,33 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
}
@Override
public void onRefreshFromEnd() {
new TwidereAsyncTask<Void, Void, long[][]>() {
@Override
protected long[][] doInBackground(final Void... 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 onRefreshFromStart() {
loadMoreMessages();
}
// @Override
// public void onRefreshFromEnd() {
// new TwidereAsyncTask<Void, Void, long[][]>() {
//
// @Override
// protected long[][] doInBackground(final Void... 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 onRefreshFromStart() {
// loadMoreMessages();
// }
@Override
public void onResume() {
@ -462,24 +524,25 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
@Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mUsersSearchProgress = view.findViewById(R.id.users_search_progress);
mUsersSearchList = (ListView) view.findViewById(R.id.users_search_list);
mMessagesListView = (ListView) view.findViewById(android.R.id.list);
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);
mRecipientSelector = view.findViewById(R.id.recipient_selector);
mAccountSpinner = (Spinner) view.findViewById(R.id.account_selector);
mEditText = (EditText) 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);
mRecipientSelector = view.findViewById(R.id.recipient_selector);
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;
}
// @Override
// public boolean scrollToStart() {
// if (mAdapter == null || mAdapter.isEmpty()) return false;
// setSelection(mAdapter.getCount() - 1);
// return true;
// }
public void showConversation(final long accountId, final long recipientId) {
mAccountId = accountId;
@ -497,47 +560,56 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
mLoaderInitialized = true;
lm.initLoader(0, args, this);
}
updateActionBar();
updateProfileImage();
}
@Override
protected void onReachedTop() {
if (!mLoadMoreAutomatically) return;
loadMoreMessages();
private void updateActionBar() {
final FragmentActivity activity = getActivity();
final ActionBar actionBar = activity.getActionBar();
if (actionBar == null) return;
actionBar.setDisplayOptions(mRecipient != null ? ActionBar.DISPLAY_SHOW_TITLE : ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
}
protected void updateRefreshState() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null || !getUserVisibleHint()) return;
final boolean refreshing = twitter.isReceivedDirectMessagesRefreshing()
|| twitter.isSentDirectMessagesRefreshing();
setProgressBarIndeterminateVisibility(refreshing);
setRefreshing(refreshing);
// @Override
// protected void onReachedTop() {
// if (!mLoadMoreAutomatically) return;
// loadMoreMessages();
// }
private void updateRefreshState() {
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
// if (twitter == null || !getUserVisibleHint()) return;
// final boolean refreshing = twitter.isReceivedDirectMessagesRefreshing()
// || twitter.isSentDirectMessagesRefreshing();
// setProgressBarIndeterminateVisibility(refreshing);
// setRefreshing(refreshing);
}
private void loadMoreMessages() {
if (isRefreshing()) return;
new TwidereAsyncTask<Void, Void, long[][]>() {
@Override
protected long[][] doInBackground(final Void... params) {
final long[][] result = new long[3][];
result[0] = getActivatedAccountIds(getActivity());
result[1] = getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
result[2] = getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Outbox.CONTENT_URI);
return result;
}
@Override
protected void onPostExecute(final long[][] result) {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return;
twitter.getReceivedDirectMessagesAsync(result[0], result[1], null);
twitter.getSentDirectMessagesAsync(result[0], result[2], null);
}
}.executeTask();
}
// private void loadMoreMessages() {
// if (isRefreshing()) return;
// new TwidereAsyncTask<Void, Void, long[][]>() {
//
// @Override
// protected long[][] doInBackground(final Void... params) {
// final long[][] result = new long[3][];
// result[0] = getActivatedAccountIds(getActivity());
// result[1] = getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
// result[2] = getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Outbox.CONTENT_URI);
// return result;
// }
//
// @Override
// protected void onPostExecute(final long[][] result) {
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
// if (twitter == null) return;
// twitter.getReceivedDirectMessagesAsync(result[0], result[1], null);
// twitter.getSentDirectMessagesAsync(result[0], result[2], null);
// }
//
// }.executeTask();
// }
private void sendDirectMessage() {
final Editable text = mEditText.getText();
@ -568,12 +640,7 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
}
private void updateAddImageButton() {
final int color = ThemeUtils.getThemeColor(getActivity());
if (mImageUri != null) {
mAddImageButton.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
} else {
mAddImageButton.clearColorFilter();
}
mAddImageButton.setActivated(mImageUri != null);
}
private void updateTextCount() {
@ -582,4 +649,83 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
mTextCountView.setTextCount(count);
}
private static class UsersSearchAdapter extends BaseAdapter {
private final LayoutInflater mInflater;
private Object mUsers;
private int mScreenNameIdx;
private long mAccountId;
public UsersSearchAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
public void setUsers(List<ParcelableUser> users) {
mUsers = users;
notifyDataSetChanged();
}
public void setUsers(Cursor users) {
mUsers = users;
notifyDataSetChanged();
}
@Override
public int getCount() {
if (mUsers instanceof Cursor) {
final Cursor c = (Cursor) mUsers;
mScreenNameIdx = c.getColumnIndex(CachedUsers.SCREEN_NAME);
return c.getCount();
} else if (mUsers instanceof List) {
return ((List) mUsers).size();
}
return 0;
}
public void setAccountId(long accountId) {
mAccountId = accountId;
}
@Override
public ParcelableUser getItem(int position) {
if (mUsers instanceof Cursor) {
final Cursor c = (Cursor) mUsers;
return new ParcelableUser(c, mAccountId);
} else if (mUsers instanceof List) {
return (ParcelableUser) ((List) mUsers).get(position);
}
throw new IllegalStateException();
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view;
if (convertView != null) {
view = convertView;
} else {
view = mInflater.inflate(R.layout.list_item_user, parent, false);
}
if (mUsers instanceof Cursor) {
final Cursor c = (Cursor) mUsers;
c.moveToPosition(position);
bindUser(view, c);
} else if (mUsers instanceof List) {
bindUser(view, getItem(position));
}
return view;
}
private void bindUser(View view, ParcelableUser user) {
}
private void bindUser(View view, Cursor cursor) {
}
}
}

View File

@ -0,0 +1,110 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import static org.mariotaku.twidere.util.Utils.isMyRetweet;
public class RetweetQuoteDialogFragment extends BaseSupportDialogFragment implements
DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "retweet_quote";
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableStatus status = getStatus();
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (status == null || twitter == null) return;
if (isMyRetweet(status)) {
twitter.destroyStatusAsync(status.account_id, status.retweet_id);
} else {
twitter.retweetStatusAsync(status.account_id, status.id);
}
break;
default:
break;
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final Context context = builder.getContext();
final ImageLoaderWrapper loader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
final ImageLoadingHandler handler = new ImageLoadingHandler(R.id.media_preview_progress);
final LayoutInflater inflater = LayoutInflater.from(context);
@SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.dialog_scrollable_status, null);
final StatusViewHolder holder = new StatusViewHolder(view.findViewById(R.id.item_content));
final ParcelableStatus status = getStatus();
builder.setView(view);
builder.setTitle(R.string.retweet_quote_confirm_title);
builder.setPositiveButton(isMyRetweet(status) ? R.string.cancel_retweet : R.string.retweet, this);
builder.setNeutralButton(R.string.quote, this);
builder.setNegativeButton(android.R.string.cancel, null);
holder.displayStatus(context, loader, handler, getStatus());
view.findViewById(R.id.item_menu).setVisibility(View.GONE);
view.findViewById(R.id.action_buttons).setVisibility(View.GONE);
view.findViewById(R.id.reply_retweet_status).setVisibility(View.GONE);
return builder.create();
}
private ParcelableStatus getStatus() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_STATUS)) return null;
return args.getParcelable(EXTRA_STATUS);
}
public static RetweetQuoteDialogFragment show(final FragmentManager fm, final ParcelableStatus status) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_STATUS, status);
final RetweetQuoteDialogFragment f = new RetweetQuoteDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
}

View File

@ -123,12 +123,21 @@ public class StatusFragment extends BaseSupportFragment
private static final int LOADER_ID_DETAIL_STATUS = 1;
private static final int LOADER_ID_STATUS_REPLIES = 2;
private static final int STATE_LOADED = 1;
private static final int STATE_LOADING = 2;
private static final int STATE_ERROR = 3;
private RecyclerView mRecyclerView;
private StatusAdapter mStatusAdapter;
private boolean mRepliesLoaderInitialized;
private LoadConversationTask mLoadConversationTask;
private LinearLayoutManager mLayoutManager;
private View mStatusContent;
private View mProgressContainer;
private View mErrorContainer;
private LoaderCallbacks<List<ParcelableStatus>> mRepliesLoaderCallback = new LoaderCallbacks<List<ParcelableStatus>>() {
@Override
public Loader<List<ParcelableStatus>> onCreateLoader(int id, Bundle args) {
@ -153,7 +162,6 @@ public class StatusFragment extends BaseSupportFragment
}
};
private LinearLayoutManager mLayoutManager;
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
@ -214,12 +222,14 @@ public class StatusFragment extends BaseSupportFragment
mStatusAdapter = new StatusAdapter(this, compact);
mRecyclerView.setAdapter(mStatusAdapter);
setState(STATE_LOADING);
getLoaderManager().initLoader(LOADER_ID_DETAIL_STATUS, getArguments(), this);
}
@Override
public void onMediaClick(View view, ParcelableMedia media) {
public void onMediaClick(View view, ParcelableMedia media, long accountId) {
Utils.openImageDirectly(getActivity(), accountId, media.url);
}
@Override
@ -240,15 +250,26 @@ public class StatusFragment extends BaseSupportFragment
final int position = mStatusAdapter.findPositionById(itemId);
mLayoutManager.scrollToPositionWithOffset(position, top);
}
setState(STATE_LOADED);
} else {
//TODO show errors
setState(STATE_ERROR);
}
}
private void setState(int state) {
mStatusContent.setVisibility(state == STATE_LOADED ? View.VISIBLE : View.GONE);
mProgressContainer.setVisibility(state == STATE_LOADING ? View.VISIBLE : View.GONE);
mErrorContainer.setVisibility(state == STATE_ERROR ? View.VISIBLE : View.GONE);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mStatusContent = view.findViewById(R.id.status_content);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
mProgressContainer = view.findViewById(R.id.progress_container);
mErrorContainer = view.findViewById(R.id.error_retry_container);
}
@Override
@ -318,12 +339,13 @@ public class StatusFragment extends BaseSupportFragment
private static final int VIEW_TYPE_SPACE = 4;
private final Context mContext;
private final StatusFragment mFragment;
private final LayoutInflater mInflater;
private final ImageLoaderWrapper mImageLoader;
private final boolean mNameFirst, mNicknameOnly;
private final int mCardLayoutResource;
private final StatusFragment mFragment;
private final int mTextSize;
private ParcelableStatus mStatus;
@ -332,6 +354,7 @@ public class StatusFragment extends BaseSupportFragment
public StatusAdapter(StatusFragment fragment, boolean compact) {
final Context context = fragment.getActivity();
final Resources res = context.getResources();
final SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE);
mFragment = fragment;
@ -340,6 +363,7 @@ public class StatusFragment extends BaseSupportFragment
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
mNameFirst = preferences.getBoolean(KEY_NAME_FIRST, true);
mNicknameOnly = preferences.getBoolean(KEY_NICKNAME_ONLY, true);
mTextSize = preferences.getInt(KEY_TEXT_SIZE, res.getInteger(R.integer.default_text_size));
if (compact) {
mCardLayoutResource = R.layout.card_item_status_compat;
} else {
@ -390,6 +414,10 @@ public class StatusFragment extends BaseSupportFragment
return getConversationCount() + 1 + getRepliesCount() + 1;
}
public int getTextSize() {
return mTextSize;
}
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
openStatus(mFragment.getActivity(), getStatus(position), null);
@ -603,11 +631,10 @@ public class StatusFragment extends BaseSupportFragment
}
}
private static class DetailStatusViewHolder extends ViewHolder implements OnClickListener, OnMediaClickListener, OnMenuItemClickListener {
private static class DetailStatusViewHolder extends ViewHolder implements OnClickListener, OnMenuItemClickListener {
private final StatusAdapter adapter;
private final View cardContent, progressContainer;
private final CardView cardView;
private final TwidereMenuBar menuBar;
@ -631,8 +658,6 @@ public class StatusFragment extends BaseSupportFragment
super(itemView);
this.adapter = adapter;
cardView = (CardView) itemView.findViewById(R.id.card);
cardContent = itemView.findViewById(R.id.card_content);
progressContainer = itemView.findViewById(R.id.progress_container);
menuBar = (TwidereMenuBar) itemView.findViewById(R.id.menu_bar);
nameView = (TextView) itemView.findViewById(R.id.name);
screenNameView = (TextView) itemView.findViewById(R.id.screen_name);
@ -702,7 +727,7 @@ public class StatusFragment extends BaseSupportFragment
} else {
final long id_to_retweet = status.is_retweet && status.retweet_id > 0 ? status.retweet_id
: status.id;
twitter.retweetStatus(status.account_id, id_to_retweet);
twitter.retweetStatusAsync(status.account_id, id_to_retweet);
}
break;
}
@ -789,7 +814,6 @@ public class StatusFragment extends BaseSupportFragment
public void showStatus(ParcelableStatus status) {
if (status == null) return;
progressContainer.setVisibility(View.GONE);
final Context context = adapter.getContext();
final Resources resources = context.getResources();
final ImageLoaderWrapper loader = adapter.getImageLoader();
@ -857,7 +881,7 @@ public class StatusFragment extends BaseSupportFragment
mediaPreviewGrid.removeAllViews();
final int maxColumns = resources.getInteger(R.integer.grid_column_image_preview);
MediaPreviewUtils.addToLinearLayout(mediaPreviewGrid, loader, status.media,
maxColumns, this);
status.account_id, maxColumns, adapter.getFragment());
} else {
mediaPreviewContainer.setVisibility(View.VISIBLE);
mediaPreviewLoad.setVisibility(View.VISIBLE);
@ -868,17 +892,17 @@ public class StatusFragment extends BaseSupportFragment
menuBar.show();
}
@Override
public void onMediaClick(View view, ParcelableMedia media) {
adapter.mFragment.onMediaClick(view, media);
}
private void initViews() {
menuBar.setOnMenuItemClickListener(this);
menuBar.inflate(R.menu.menu_status);
mediaPreviewLoad.setOnClickListener(this);
profileContainer.setOnClickListener(this);
final int defaultTextSize = adapter.getTextSize();
nameView.setTextSize(defaultTextSize * 1.25f);
textView.setTextSize(defaultTextSize * 1.25f);
screenNameView.setTextSize(defaultTextSize * 0.85f);
timeSourceView.setTextSize(defaultTextSize * 0.85f);
}

View File

@ -645,7 +645,7 @@ public class StatusFragmentOld extends ParcelableStatusesListFragment implements
}
@Override
public void onMediaClick(final View view, final ParcelableMedia media) {
public void onMediaClick(final View view, final ParcelableMedia media, long accountId) {
final ParcelableStatus status = mStatus;
if (status == null) return;
// UCD
@ -756,7 +756,7 @@ public class StatusFragmentOld extends ParcelableStatusesListFragment implements
} else {
final long id_to_retweet = status.is_retweet && status.retweet_id > 0 ? status.retweet_id
: status.id;
mTwitterWrapper.retweetStatus(status.account_id, id_to_retweet);
mTwitterWrapper.retweetStatusAsync(status.account_id, id_to_retweet);
}
break;
}
@ -905,13 +905,15 @@ public class StatusFragmentOld extends ParcelableStatusesListFragment implements
}
private void loadPreviewImages() {
if (mStatus == null) return;
final ParcelableStatus status = mStatus;
if (status == null) return;
mLoadImagesIndicator.setVisibility(View.GONE);
mImagePreviewGrid.setVisibility(View.VISIBLE);
mImagePreviewGrid.removeAllViews();
if (mStatus.media != null) {
final int maxColumns = getResources().getInteger(R.integer.grid_column_image_preview);
MediaPreviewUtils.addToLinearLayout(mImagePreviewGrid, mImageLoader, mStatus.media, maxColumns, this);
MediaPreviewUtils.addToLinearLayout(mImagePreviewGrid, mImageLoader, status.media,
status.account_id, maxColumns, this);
}
}

View File

@ -357,7 +357,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mProgressContainer.setVisibility(View.GONE);
mUser = user;
final int userColor = getUserColor(getActivity(), user.id, true);
mProfileImageView.setBorderColor(userColor != 0 ? userColor : Color.WHITE);
mProfileImageView.setBorderColor(userColor);
mProfileNameContainer.drawEnd(getAccountColor(getActivity(), user.account_id));
final String nick = getUserNickname(getActivity(), user.id, true);
mNameView
@ -374,7 +374,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mDescriptionContainer.setVisibility(userIsMe || !isEmpty(user.description_html) ? View.VISIBLE : View.GONE);
mDescriptionView.setText(user.description_html != null ? Html.fromHtml(user.description_html) : null);
final TwidereLinkify linkify = new TwidereLinkify(this);
linkify.setLinkTextColor(ThemeUtils.getUserLinkTextColor(getActivity()));
linkify.setLinkTextColor(user.link_color);
linkify.applyAllLinks(mDescriptionView, user.account_id, false);
mDescriptionView.setMovementMethod(null);
mLocationContainer.setVisibility(userIsMe || !isEmpty(user.location) ? View.VISIBLE : View.GONE);
@ -382,6 +382,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mURLContainer.setVisibility(userIsMe || !isEmpty(user.url) || !isEmpty(user.url_expanded) ? View.VISIBLE
: View.GONE);
mURLView.setText(isEmpty(user.url_expanded) ? user.url : user.url_expanded);
mURLView.setLinkTextColor(user.link_color);
mURLView.setMovementMethod(null);
final String createdAt = formatToLongTimeString(getActivity(), user.created_at);
final float daysSinceCreated = (System.currentTimeMillis() - user.created_at) / 1000 / 60 / 60 / 24;
@ -700,6 +701,15 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
break;
}
case R.id.follow: {
if (user.id == user.account_id) {
final Bundle extras = new Bundle();
extras.putLong(EXTRA_ACCOUNT_ID, user.account_id);
final Intent intent = new Intent(INTENT_ACTION_EDIT_USER_PROFILE);
intent.setClass(getActivity(), UserProfileEditorActivity.class);
intent.putExtras(extras);
startActivity(intent);
break;
}
final Relationship relationship = mRelationship;
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (relationship == null || twitter == null) return;
@ -988,15 +998,6 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
startActivityForResult(intent, REQUEST_SELECT_ACCOUNT);
break;
}
case MENU_EDIT: {
final Bundle extras = new Bundle();
extras.putLong(EXTRA_ACCOUNT_ID, user.account_id);
final Intent intent = new Intent(INTENT_ACTION_EDIT_USER_PROFILE);
intent.setClass(getActivity(), UserProfileEditorActivity.class);
intent.putExtras(extras);
startActivity(intent);
return true;
}
case MENU_FOLLOW: {
if (relationship == null) return false;
final boolean isFollowing = relationship.isSourceFollowingTarget();
@ -1067,7 +1068,6 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final Relationship relationship = mRelationship;
if (twitter == null || user == null) return;
final boolean isMyself = user.account_id == user.id;
setMenuItemAvailability(menu, MENU_EDIT, isMyself);
final MenuItem mentionItem = menu.findItem(MENU_MENTION);
if (mentionItem != null) {
mentionItem.setTitle(getString(R.string.mention_user_name, getDisplayName(getActivity(), user)));

View File

@ -136,8 +136,8 @@ public class CardPreviewPreference extends Preference implements Constants, OnSh
@Override
protected View onCreateView(final ViewGroup parent) {
if (mPreferences != null && mPreferences.getBoolean(KEY_COMPACT_CARDS, false))
return mInflater.inflate(R.layout.card_item_status_compact_deprecated, parent, false);
return mInflater.inflate(R.layout.card_item_status_deprecated, parent, false);
return mInflater.inflate(R.layout.list_item_status_compact_deprecated, parent, false);
return mInflater.inflate(R.layout.list_item_status_deprecated, parent, false);
}
}

View File

@ -104,7 +104,7 @@ public class ThemePreviewPreference extends Preference implements Constants, OnS
if (statusContentView != null) {
ViewAccessor.setBackground(statusContentView, ThemeUtils.getWindowBackground(context));
final View profileView = statusContentView.findViewById(R.id.profile);
final View profileView = statusContentView.findViewById(R.id.profile_container);
final ImageView profileImageView = (ImageView) statusContentView.findViewById(R.id.profile_image);
final TextView nameView = (TextView) statusContentView.findViewById(R.id.name);
final TextView screenNameView = (TextView) statusContentView.findViewById(R.id.screen_name);

View File

@ -366,7 +366,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int retweetStatus(final long accountId, final long status_id) {
public int retweetStatusAsync(final long accountId, final long status_id) {
final RetweetStatusTask task = new RetweetStatusTask(accountId, status_id);
return mAsyncTaskManager.add(task, true);
}

View File

@ -194,8 +194,8 @@ public class MediaPreviewUtils {
private static final String URL_PHOTOZOU_PHOTO_INFO = "https://api.photozou.jp/rest/photo_info.json";
public static void addToLinearLayout(final LinearLayout container, final ImageLoaderWrapper loader,
final List<ParcelableMedia> mediaList, final int maxColumnCount,
final OnMediaClickListener mediaClickListener) {
final List<ParcelableMedia> mediaList, final long accountId,
final int maxColumnCount, final OnMediaClickListener mediaClickListener) {
if (container.getOrientation() != LinearLayout.VERTICAL)
throw new IllegalArgumentException();
final Context context = container.getContext();
@ -207,7 +207,7 @@ public class MediaPreviewUtils {
final int bestColumnCount = imageCountSqrt % 1 == 0 ? (int) imageCountSqrt : maxColumnCount;
final int firstColumn = imageCount % bestColumnCount, fullRowCount = imageCount / bestColumnCount;
final int rowCount = fullRowCount + (firstColumn > 0 ? 1 : 0);
final View.OnClickListener clickListener = new ImageGridClickListener(mediaClickListener);
final View.OnClickListener clickListener = new ImageGridClickListener(mediaClickListener, accountId);
container.setMotionEventSplittingEnabled(false);
for (int currentRow = 0; currentRow < rowCount; currentRow++) {
final LinearLayout rowContainer = new LinearLayout(context);
@ -233,9 +233,10 @@ public class MediaPreviewUtils {
}
public static void addToLinearLayout(final LinearLayout container, final ImageLoaderWrapper loader,
final ParcelableMedia[] mediaArray, final int maxColumnCount,
final OnMediaClickListener listener) {
addToLinearLayout(container, loader, Arrays.asList(mediaArray), maxColumnCount, listener);
final ParcelableMedia[] mediaArray, final long accountId,
final int maxColumnCount, final OnMediaClickListener listener) {
addToLinearLayout(container, loader, Arrays.asList(mediaArray), accountId, maxColumnCount,
listener);
}
public static ParcelableMedia getAllAvailableImage(final String link, final boolean fullImage) {
@ -461,20 +462,22 @@ public class MediaPreviewUtils {
}
public interface OnMediaClickListener {
void onMediaClick(View view, ParcelableMedia media);
void onMediaClick(View view, ParcelableMedia media, long accountId);
}
private static class ImageGridClickListener implements View.OnClickListener {
private final OnMediaClickListener mListener;
private final long mAccountId;
ImageGridClickListener(final OnMediaClickListener listener) {
ImageGridClickListener(final OnMediaClickListener listener, final long accountId) {
mListener = listener;
mAccountId = accountId;
}
@Override
public void onClick(final View v) {
if (mListener == null) return;
mListener.onMediaClick(v, (ParcelableMedia) v.getTag());
mListener.onMediaClick(v, (ParcelableMedia) v.getTag(), mAccountId);
}
}

View File

@ -93,7 +93,7 @@ public class OnLinkClickHandler implements OnLinkClickListener, Constants {
}
protected void openLink(final String link) {
if (context == null || manager.isActive()) return;
if (context == null || (manager != null && manager.isActive())) return;
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {

View File

@ -36,8 +36,7 @@ import org.mariotaku.twidere.R;
*/
public class ActionIconTextView extends TextView {
private int mColor;
private int mActivatedColor;
private int mColor, mDisabledColor, mActivatedColor;
public ActionIconTextView(Context context) {
this(context, null);
@ -49,19 +48,18 @@ public class ActionIconTextView extends TextView {
public ActionIconTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
final TypedArray defaultValues = context.obtainStyledAttributes(
new int[]{android.R.attr.colorActivatedHighlight});
final int defaultActivatedColor = defaultValues.getColor(0, 0);
defaultValues.recycle();
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IconActionButton);
mColor = a.getColor(R.styleable.IconActionButton_iabColor, 0);
mActivatedColor = a.getColor(R.styleable.IconActionButton_iabActivatedColor, defaultActivatedColor);
mDisabledColor = a.getColor(R.styleable.IconActionButton_iabDisabledColor, 0);
mActivatedColor = a.getColor(R.styleable.IconActionButton_iabActivatedColor, 0);
a.recycle();
updateColorFilter();
}
public int getActivatedColor() {
return mActivatedColor;
if (mActivatedColor != 0) return mActivatedColor;
final ColorStateList colors = getLinkTextColors();
if (colors != null) return colors.getDefaultColor();
return getCurrentTextColor();
}
public int getColor() {
@ -71,32 +69,46 @@ public class ActionIconTextView extends TextView {
return getCurrentTextColor();
}
public int getDisabledColor() {
if (mDisabledColor != 0) return mDisabledColor;
final ColorStateList colors = getTextColors();
if (colors != null) return colors.getColorForState(new int[0], colors.getDefaultColor());
return getCurrentTextColor();
}
@Override
public void setActivated(boolean activated) {
super.setActivated(activated);
updateColorFilter();
}
@Override
public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {
super.setCompoundDrawables(left, top, right, bottom);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end, Drawable bottom) {
super.setCompoundDrawablesRelative(start, top, end, bottom);
updateColorFilter();
}
@Override
public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {
super.setCompoundDrawables(left, top, right, bottom);
updateColorFilter();
}
private void updateColorFilter() {
protected void drawableStateChanged() {
super.drawableStateChanged();
for (Drawable d : getCompoundDrawables()) {
if (d != null) {
d.mutate();
d.setColorFilter(isActivated() ? getActivatedColor() : getColor(), Mode.SRC_ATOP);
final int color;
if (isActivated()) {
color = getActivatedColor();
} else if (isEnabled()) {
color = getColor();
} else {
color = getDisabledColor();
}
d.setColorFilter(color, Mode.SRC_ATOP);
}
}
}
}

View File

@ -49,9 +49,6 @@ public class ComposeSelectAccountButton extends ViewGroup {
private final AccountIconsAdapter mAccountIconsAdapter;
private final Helper mColorLabelHelper;
private OnClickListener mOnClickListener;
private OnLongClickListener mOnLongClickListener;
public ComposeSelectAccountButton(Context context) {
this(context, null);
}
@ -213,7 +210,11 @@ public class ComposeSelectAccountButton extends ViewGroup {
final int idx = findChildIndex(child);
if (firstVisibleItem < 1 && idx == 0) {
// when firstVisibleItem is 0 or -1, assume view with idx == 0 is first view
layoutParams.leftMargin = 0;
if (itemCount == 1) {
layoutParams.leftMargin = (contentWidth - contentHeight) / 2 - child.getPaddingLeft() - child.getPaddingRight();
} else {
layoutParams.leftMargin = 0;
}
} else {
layoutParams.leftMargin = -Math.min((contentHeight * itemCount - contentWidth)
/ (itemCount - 1) + child.getPaddingLeft() + child.getPaddingRight(), contentHeight);
@ -223,7 +224,15 @@ public class ComposeSelectAccountButton extends ViewGroup {
@Override
public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) {
final int height = MeasureSpec.getSize(heightSpec), width = Math.round(height * 1.5f);
final int height = MeasureSpec.getSize(heightSpec), width;
if (getItemCount() > 1) {
width = Math.round(height * 1.5f);
} else if (getChildCount() > 0) {
final View firstChild = getChildAt(0);
width = height + firstChild.getPaddingLeft() + firstChild.getPaddingRight();
} else {
width = height;
}
mWidth = width;
mHeight = height;
super.onMeasure(recycler, state, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightSpec);

View File

@ -15,6 +15,7 @@ import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatus.CursorIndices;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.UserColorNicknameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.CircularImageView;
@ -42,11 +43,14 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
private final View mediaPreviewContainer;
private final TextView replyCountView, retweetCountView, favoriteCountView;
public StatusViewHolder(View itemView) {
this(null, itemView);
}
public StatusViewHolder(IStatusesAdapter<?> adapter, View itemView) {
super(itemView);
this.adapter = adapter;
itemView.findViewById(R.id.item_content).setOnClickListener(this);
itemView.findViewById(R.id.menu).setOnClickListener(this);
profileImageView = (CircularImageView) itemView.findViewById(R.id.profile_image);
profileTypeView = (ImageView) itemView.findViewById(R.id.profile_type);
textView = (TextView) itemView.findViewById(R.id.text);
@ -64,6 +68,11 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
favoriteCountView = (TextView) itemView.findViewById(R.id.favorite_count);
//TODO
// profileImageView.setSelectorColor(ThemeUtils.getUserHighlightColor(itemView.getContext()));
}
public void setupViews() {
itemView.findViewById(R.id.item_content).setOnClickListener(this);
itemView.findViewById(R.id.item_menu).setOnClickListener(this);
itemView.setOnClickListener(this);
profileImageView.setOnClickListener(this);
@ -73,9 +82,13 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
favoriteCountView.setOnClickListener(this);
}
public void displayStatus(ParcelableStatus status) {
final ImageLoaderWrapper loader = adapter.getImageLoader();
final Context context = adapter.getContext();
public void displayStatus(final ParcelableStatus status) {
displayStatus(adapter.getContext(), adapter.getImageLoader(),
adapter.getImageLoadingHandler(), status);
}
public void displayStatus(final Context context, final ImageLoaderWrapper loader,
final ImageLoadingHandler handler, final ParcelableStatus status) {
final ParcelableMedia[] media = status.media;
if (status.retweet_id > 0) {
@ -121,13 +134,9 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
if (media != null && media.length > 0) {
final ParcelableMedia firstMedia = media[0];
if (status.text_plain.codePointCount(0, status.text_plain.length()) == firstMedia.end) {
textView.setText(status.text_unescaped.substring(0, firstMedia.start));
} else {
textView.setText(status.text_unescaped);
}
textView.setText(status.text_unescaped);
loader.displayPreviewImageWithCredentials(mediaPreviewView, firstMedia.media_url,
status.account_id, adapter.getImageLoadingHandler());
status.account_id, handler);
mediaPreviewContainer.setVisibility(View.VISIBLE);
} else {
loader.cancelDisplayTask(mediaPreviewView);
@ -228,14 +237,9 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
loader.displayProfileImage(profileImageView, user_profile_image_url);
if (media != null && media.length > 0) {
final String text_plain = cursor.getString(indices.text_plain);
final String text_unescaped = cursor.getString(indices.text_unescaped);
final String textUnescaped = cursor.getString(indices.text_unescaped);
final ParcelableMedia firstMedia = media[0];
if (text_plain.codePointCount(0, text_plain.length()) == firstMedia.end) {
textView.setText(text_unescaped.substring(0, firstMedia.start));
} else {
textView.setText(text_unescaped);
}
textView.setText(textUnescaped);
loader.displayPreviewImageWithCredentials(mediaPreviewView, firstMedia.media_url,
account_id, adapter.getImageLoadingHandler());
mediaPreviewContainer.setVisibility(View.VISIBLE);
@ -288,7 +292,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
adapter.onStatusClick(this, position);
break;
}
case R.id.menu: {
case R.id.item_menu: {
adapter.onItemMenuClick(this, position);
break;
}
@ -296,7 +300,9 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
adapter.onUserProfileClick(this, position);
break;
}
case R.id.reply_count: {
case R.id.reply_count:
case R.id.retweet_count:
case R.id.favorite_count: {
adapter.onItemActionClick(this, v.getId(), position);
break;
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<org.mariotaku.twidere.view.HomeActionButton
android:id="@+id/actions_button"
android:id="@+id/action_buttons"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/float_action_button_size"
android:layout_height="@dimen/float_action_button_size"

View File

@ -0,0 +1,63 @@
<?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="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:layout_height="?android:actionBarSize">
<Spinner
android:id="@+id/account_spinner"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0"
tools:listitem="@layout/spinner_item_account_icon"/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="@dimen/element_spacing_small">
<EditText
android:id="@+id/user_query"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:gravity="bottom"
android:inputType="textPersonName"/>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/query_button"
style="?cardActionButtonStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_gravity="right"
android:padding="@dimen/element_spacing_normal"
android:scaleType="centerInside"
android:src="@drawable/ic_action_search"/>
</FrameLayout>
</LinearLayout>

View File

@ -13,220 +13,6 @@
app:cardCornerRadius="2dp"
app:cardElevation="2dp">
<RelativeLayout
android:id="@+id/item_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:orientation="vertical">
<org.mariotaku.twidere.view.CircularImageView
android:id="@+id/retweet_profile_image"
android:layout_width="@dimen/element_size_small"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:scaleType="centerCrop"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/reply_retweet_status"
android:layout_width="match_parent"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_minus_normal"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:layout_toRightOf="@id/retweet_profile_image"
android:ellipsize="end"
android:gravity="center_vertical"
android:minHeight="@dimen/element_size_small"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="10sp"/>
<RelativeLayout
android:id="@+id/profile_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/retweet_profile_image"
android:layout_below="@id/reply_retweet_status"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_mlarge">
<org.mariotaku.twidere.view.CircularImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_status_profile_image"
android:layout_height="@dimen/icon_size_status_profile_image"
android:layout_centerVertical="true"
android:layout_margin="@dimen/element_spacing_small"
android:contentDescription="@string/profile_image"
android:scaleType="centerCrop"/>
<ImageView
android:id="@+id/profile_type"
android:layout_width="@dimen/icon_size_profile_type"
android:layout_height="@dimen/icon_size_profile_type"
android:layout_alignBottom="@id/profile_image"
android:layout_alignRight="@id/profile_image"
android:scaleType="fitCenter"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_toLeftOf="@+id/menu"
android:layout_toRightOf="@id/profile_image"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/element_spacing_xsmall"
android:layout_marginTop="@dimen/element_spacing_small"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
<TextView
android:id="@+id/screen_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_small"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="10sp"/>
</LinearLayout>
<org.mariotaku.twidere.view.ShortTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingTop="@dimen/element_spacing_xsmall"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textSize="10sp"/>
</LinearLayout>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/menu"
style="?cardActionButtonStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_action_more_vertical"/>
</RelativeLayout>
<org.mariotaku.twidere.view.ImagePreviewContainer
android:id="@+id/media_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/profile_container"
android:layout_marginTop="@dimen/element_spacing_normal"
android:foreground="?android:selectableItemBackground">
<ImageView
android:id="@+id/media_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/media"
android:scaleType="centerCrop"/>
<ProgressBar
android:id="@+id/media_preview_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/element_spacing_large"/>
</org.mariotaku.twidere.view.ImagePreviewContainer>
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/media_preview_container"
android:layout_marginBottom="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@+id/text"
android:overScrollMode="never"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/reply_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_reply"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:iabActivatedColor="@color/highlight_reply"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/retweet_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_retweet"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:iabActivatedColor="@color/highlight_retweet"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/favorite_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_star"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:iabActivatedColor="@color/highlight_favorite"/>
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
<include layout="@layout/card_item_status_common"/>
</android.support.v7.widget.CardView>

View File

@ -0,0 +1,242 @@
<?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/>.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/item_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:orientation="vertical">
<org.mariotaku.twidere.view.CircularImageView
android:id="@+id/retweet_profile_image"
android:layout_width="@dimen/element_size_small"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:scaleType="centerCrop"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/reply_retweet_status"
android:layout_width="match_parent"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_minus_normal"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:layout_toRightOf="@id/retweet_profile_image"
android:ellipsize="end"
android:gravity="center_vertical"
android:minHeight="@dimen/element_size_small"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="10sp"/>
<RelativeLayout
android:id="@+id/profile_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/retweet_profile_image"
android:layout_below="@id/reply_retweet_status"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_mlarge">
<org.mariotaku.twidere.view.CircularImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_status_profile_image"
android:layout_height="@dimen/icon_size_status_profile_image"
android:layout_centerVertical="true"
android:layout_margin="@dimen/element_spacing_small"
android:contentDescription="@string/profile_image"
android:scaleType="centerCrop"/>
<ImageView
android:id="@+id/profile_type"
android:layout_width="@dimen/icon_size_profile_type"
android:layout_height="@dimen/icon_size_profile_type"
android:layout_alignBottom="@id/profile_image"
android:layout_alignRight="@id/profile_image"
android:scaleType="fitCenter"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_toLeftOf="@+id/item_menu"
android:layout_toRightOf="@id/profile_image"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/element_spacing_xsmall"
android:layout_marginTop="@dimen/element_spacing_small"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
<TextView
android:id="@+id/screen_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_small"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="10sp"/>
</LinearLayout>
<org.mariotaku.twidere.view.ShortTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingTop="@dimen/element_spacing_xsmall"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textSize="10sp"/>
</LinearLayout>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/item_menu"
style="?cardActionButtonStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_action_more_vertical"/>
</RelativeLayout>
<org.mariotaku.twidere.view.ImagePreviewContainer
android:id="@+id/media_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/profile_container"
android:layout_marginTop="@dimen/element_spacing_normal"
android:foreground="?android:selectableItemBackground">
<ImageView
android:id="@+id/media_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/media"
android:scaleType="centerCrop"/>
<ProgressBar
android:id="@+id/media_preview_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/element_spacing_large"/>
</org.mariotaku.twidere.view.ImagePreviewContainer>
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/media_preview_container"
android:layout_marginBottom="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
<HorizontalScrollView
android:id="@+id/action_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@+id/text"
android:overScrollMode="never"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/reply_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_reply"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:iabActivatedColor="@color/highlight_reply"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/retweet_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_retweet"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:iabActivatedColor="@color/highlight_retweet"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/favorite_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_star"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:iabActivatedColor="@color/highlight_favorite"/>
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
</merge>

View File

@ -199,11 +199,11 @@
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/menu"
android:layout_toLeftOf="@+id/item_menu"
android:layout_toRightOf="@+id/actions_scroller"/>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/menu"
android:id="@+id/item_menu"
style="?cardActionButtonStyle"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/card_item_status_deprecated"/>
<include layout="@layout/card_item_status_common"/>
</ScrollView>

View File

@ -1,65 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.DirectMessagesConversationFragment">
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.DirectMessagesConversationFragment">
<RelativeLayout
android:id="@+id/conversation_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<LinearLayout
android:id="@+id/conversation_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<FrameLayout
android:id="@+id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/input_send_container"/>
<FrameLayout
android:id="@+id/list_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<FrameLayout
android:id="@+id/input_send_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/recipient_selector_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="visible">
</FrameLayout>
<LinearLayout
android:layout_width="300dp"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<FrameLayout
android:id="@+id/input_send_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0">
<Spinner
android:id="@+id/account_selector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:listPreferredItemHeightSmall"
android:padding="@dimen/element_spacing_normal"
tools:listitem="@layout/list_item_two_line_small"/>
<include layout="@layout/fragment_messages_conversation_input_send"/>
</FrameLayout>
</LinearLayout>
<TextView
android:id="@+id/recipient_selector"
style="?android:dropDownSpinnerStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:gravity="center_vertical"
android:minHeight="?android:listPreferredItemHeightSmall"
android:padding="@dimen/element_spacing_normal"
android:text="@string/select_user"
android:textAppearance="?android:textAppearanceMedium"/>
</LinearLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/recipient_selector_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
tools:visibility="gone">
<ListView
android:id="@+id/users_search_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarStyle="outsideInset"
android:padding="@dimen/element_spacing_normal"/>
<ProgressBar
android:id="@+id/users_search_progress"
style="?android:progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"/>
</FrameLayout>
</FrameLayout>

View File

@ -25,25 +25,29 @@
android:descendantFocusability="beforeDescendants"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<requestFocus/>
</android.support.v7.widget.RecyclerView>
<RelativeLayout
android:id="@+id/status_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:visibility="gone">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<requestFocus/>
</android.support.v7.widget.RecyclerView>
<org.mariotaku.twidere.view.themed.ThemedMultiAutoCompleteTextView
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="wrap_content"/>
</RelativeLayout>
<include layout="@layout/layout_content_fragment_common"/>
</FrameLayout>

View File

@ -296,6 +296,5 @@
</LinearLayout>
<include layout="@layout/layout_content_fragment_common"/>
</android.support.v7.widget.CardView>
</FrameLayout>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<org.mariotaku.twidere.view.HomeActionButtonCompat
android:id="@+id/actions_button"
android:id="@+id/action_buttons"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -0,0 +1,59 @@
<?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.CircularImageView
android:id="@android:id/icon"
android:layout_width="@dimen/icon_size_list_item_small"
android:layout_height="@dimen/icon_size_list_item_small"
android:contentDescription="@string/icon"
android:scaleType="centerCrop"/>
<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>

View File

@ -0,0 +1,38 @@
<?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/>.
-->
<org.mariotaku.twidere.view.SquareFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="match_parent"
tools:layout_height="?android:actionBarSize"
android:padding="@dimen/element_spacing_small">
<org.mariotaku.twidere.view.CircularImageView
android:id="@android:id/icon"
android:layout_width="@dimen/icon_size_list_item_small"
android:layout_height="@dimen/icon_size_list_item_small"
android:layout_gravity="center"
android:contentDescription="@string/profile_image"
android:scaleType="centerCrop"
tools:src="@drawable/ic_profile_image_default"/>
</org.mariotaku.twidere.view.SquareFrameLayout>

View File

@ -4,6 +4,6 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/card_item_status_deprecated"/>
<include layout="@layout/list_item_status_deprecated"/>
</LinearLayout>

View File

@ -1,12 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@id/edit"
android:icon="@drawable/ic_action_edit"
android:showAsAction="always"
android:title="@string/edit_profile"
android:visible="false"/>
<item
android:id="@id/mention"
android:icon="@drawable/ic_action_at"

View File

@ -6,6 +6,7 @@
<attr name="profileImageStyle" format="reference"/>
<attr name="profileImageStyleLarge" format="reference"/>
<attr name="menuIconColor" format="color"/>
<attr name="menuIconColorDisabled" format="color"/>
<attr name="menuIconColorActionBar" format="color"/>
<attr name="messageBubbleColor" format="color"/>
<attr name="cardItemBackground" format="reference"/>
@ -75,6 +76,7 @@
<declare-styleable name="IconActionButton">
<attr name="iabColor" format="color"/>
<attr name="iabActivatedColor" format="color"/>
<attr name="iabDisabledColor" format="color"/>
</declare-styleable>
<declare-styleable name="CircularImageView">
<attr name="civBorder" format="boolean"/>

View File

@ -687,5 +687,6 @@
<string name="profile_text_color">Text color</string>
<string name="profile_background_color">Background color</string>
<string name="profile_link_color_main_color">Link color (main color)</string>
<string name="retweet_quote_confirm_title">Retweet to your followers?</string>
</resources>

View File

@ -109,15 +109,6 @@
<style name="TextAppearance.TabPageIndicator" parent="android:TextAppearance.Small"/>
<style name="SwipeBackLayout">
<item name="edgeSize">16dip</item>
<item name="shadowLeft">@drawable/shadow_left</item>
<item name="shadowRight">@drawable/shadow_right</item>
<item name="shadowBottom">@drawable/shadow_bottom</item>
<item name="scalePercent">@fraction/swipeback_scale_exit</item>
<item name="scrimAlpha">0.75</item>
</style>
<style name="Widget.CardItemView" parent="Widget.Base">
<item name="cardBackground">?cardItemBackground</item>
<item name="cardBackgroundAlpha">50%p</item>

View File

@ -104,6 +104,7 @@
<!-- Twidere specific styles -->
<item name="menuIconColor">@color/action_icon_dark</item>
<item name="menuIconColorDisabled">@color/action_icon_dark_disabled</item>
<item name="menuIconColorActionBar">@color/action_icon_light</item>
<item name="messageBubbleColor">@color/message_bubble_color_light</item>
</style>