1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-07 23:38:40 +01:00

implementing group

This commit is contained in:
Mariotaku Lee 2016-03-09 16:36:07 +08:00
parent 877e5296a6
commit cb675ec7bc
19 changed files with 798 additions and 396 deletions

View File

@ -2,22 +2,19 @@ package org.mariotaku.twidere.model;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
import org.mariotaku.twidere.api.twitter.util.TwitterDateConverter;
import java.util.Date;
/**
* Created by mariotaku on 16/3/9.
*/
@ParcelablePlease
@JsonObject
public class ParcelableGroup implements Parcelable {
public class ParcelableGroup implements Parcelable, Comparable<ParcelableGroup> {
@ParcelableThisPlease
@JsonField(name = "account_key")
@ -45,6 +42,10 @@ public class ParcelableGroup implements Parcelable {
@JsonField(name = "location")
public String location;
@ParcelableThisPlease
@JsonField(name = "position")
public long position;
@ParcelableThisPlease
@JsonField(name = "created")
public long created;
@ -123,4 +124,9 @@ public class ParcelableGroup implements Parcelable {
return new ParcelableGroup[size];
}
};
@Override
public int compareTo(@NonNull ParcelableGroup another) {
return (int) (this.position - another.position);
}
}

View File

@ -82,10 +82,7 @@ public class ParcelableUserList implements Parcelable, Comparable<ParcelableUser
@Override
public int compareTo(@NonNull final ParcelableUserList another) {
final long diff = position - another.position;
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
return (int) diff;
return (int) (position - another.position);
}
@Override

View File

@ -1,9 +1,24 @@
package org.mariotaku.twidere.fragment.support;
import android.support.v4.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.loader.support.UserGroupsLoader;
import org.mariotaku.twidere.model.ParcelableGroup;
import org.mariotaku.twidere.model.UserKey;
import java.util.List;
/**
* Created by mariotaku on 16/3/9.
*/
public class UserGroupsFragment extends Fragment {
public class UserGroupsFragment extends ParcelableGroupsFragment {
@Override
protected Loader<List<ParcelableGroup>> onCreateUserListsLoader(Context context, Bundle args, boolean fromUser) {
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final long userId = args.getLong(EXTRA_USER_ID, -1);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
return new UserGroupsLoader(context, accountKey, userId, screenName, getData());
}
}

View File

@ -429,6 +429,10 @@ public class LinkHandlerActivity extends BaseAppCompatActivity implements System
setTitle(R.string.user_lists);
break;
}
case LINK_ID_USER_GROUPS: {
setTitle(R.string.groups);
break;
}
case LINK_ID_USER_LIST_TIMELINE: {
setTitle(R.string.list_timeline);
break;

View File

@ -1,156 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder;
import org.mariotaku.twidere.view.holder.UserViewHolder;
public abstract class AbsUsersAdapter<D> extends LoadMoreSupportAdapter<ViewHolder> implements Constants,
IUsersAdapter<D> {
public static final int ITEM_VIEW_TYPE_USER = 2;
private final LayoutInflater mInflater;
private final int mCardBackgroundColor;
private final int mProfileImageStyle;
private final int mTextSize;
private final boolean mDisplayProfileImage;
private final boolean mShowAbsoluteTime;
private UserAdapterListener mUserAdapterListener;
private RequestClickListener mRequestClickListener;
public AbsUsersAdapter(final Context context) {
super(context);
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context, ThemeUtils.getThemeBackgroundOption(context), ThemeUtils.getUserThemeBackgroundAlpha(context));
mInflater = LayoutInflater.from(context);
mTextSize = mPreferences.getInt(KEY_TEXT_SIZE, context.getResources().getInteger(R.integer.default_text_size));
mProfileImageStyle = Utils.getProfileImageStyle(mPreferences.getString(KEY_PROFILE_IMAGE_STYLE, null));
mDisplayProfileImage = mPreferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE);
mShowAbsoluteTime = mPreferences.getBoolean(KEY_SHOW_ABSOLUTE_TIME);
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;
}
@Override
public float getTextSize() {
return mTextSize;
}
@Override
public boolean isProfileImageEnabled() {
return mDisplayProfileImage;
}
public abstract D getData();
public boolean isUser(int position) {
return position < getUserCount();
}
@Override
public boolean isShowAbsoluteTime() {
return mShowAbsoluteTime;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ITEM_VIEW_TYPE_USER: {
final View view;
view = mInflater.inflate(R.layout.card_item_user_compact, parent, false);
final View itemContent = view.findViewById(R.id.item_content);
itemContent.setBackgroundColor(mCardBackgroundColor);
final UserViewHolder holder = new UserViewHolder(this, view);
holder.setOnClickListeners();
holder.setupViewOptions();
return holder;
}
case ITEM_VIEW_TYPE_LOAD_INDICATOR: {
final View view = mInflater.inflate(R.layout.card_item_load_indicator, parent, false);
return new LoadIndicatorViewHolder(view);
}
}
throw new IllegalStateException("Unknown view type " + viewType);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case ITEM_VIEW_TYPE_USER: {
bindUser(((UserViewHolder) holder), position);
break;
}
}
}
@Override
public int getItemViewType(int position) {
if ((getLoadMoreIndicatorPosition() & IndicatorPosition.START) != 0 && position == 0) {
return ITEM_VIEW_TYPE_LOAD_INDICATOR;
}
if (position == getUserCount()) {
return ITEM_VIEW_TYPE_LOAD_INDICATOR;
}
return ITEM_VIEW_TYPE_USER;
}
@Nullable
@Override
public UserAdapterListener getUserAdapterListener() {
return mUserAdapterListener;
}
public void setUserAdapterListener(UserAdapterListener userAdapterListener) {
mUserAdapterListener = userAdapterListener;
}
@Override
public RequestClickListener getRequestClickListener() {
return mRequestClickListener;
}
public void setRequestClickListener(RequestClickListener requestClickListener) {
mRequestClickListener = requestClickListener;
}
@Override
public boolean shouldShowAccountsColor() {
return false;
}
protected abstract void bindUser(UserViewHolder holder, int position);
}

View File

@ -0,0 +1,85 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter;
import android.content.Context;
import org.mariotaku.twidere.model.ParcelableGroup;
import org.mariotaku.twidere.view.holder.GroupViewHolder;
import java.util.List;
public class ParcelableGroupsAdapter extends AbsGroupsAdapter<List<ParcelableGroup>> {
private List<ParcelableGroup> mData;
public ParcelableGroupsAdapter(Context context) {
super(context);
}
@Override
public List<ParcelableGroup> getData() {
return mData;
}
@Override
public void setData(List<ParcelableGroup> data) {
mData = data;
notifyDataSetChanged();
}
@Override
protected void bindGroup(GroupViewHolder holder, int position) {
holder.displayGroup(getGroup(position));
}
@Override
public int getItemCount() {
final int position = getLoadMoreIndicatorPosition();
int count = getGroupsCount();
if ((position & IndicatorPosition.START) != 0) {
count++;
}
if ((position & IndicatorPosition.END) != 0) {
count++;
}
return count;
}
@Override
public ParcelableGroup getGroup(int position) {
if (position == getGroupsCount()) return null;
return mData.get(position);
}
@Override
public long getGroupId(int position) {
if (position == getGroupsCount()) return -1;
return mData.get(position).id;
}
@Override
public int getGroupsCount() {
if (mData == null) return 0;
return mData.size();
}
}

View File

@ -20,24 +20,51 @@
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder;
import org.mariotaku.twidere.view.holder.UserViewHolder;
import java.util.List;
public class ParcelableUsersAdapter extends AbsUsersAdapter<List<ParcelableUser>> {
public class ParcelableUsersAdapter extends LoadMoreSupportAdapter<RecyclerView.ViewHolder>
implements Constants, IUsersAdapter<List<ParcelableUser>> {
public static final int ITEM_VIEW_TYPE_USER = 2;
private final LayoutInflater mInflater;
private final int mCardBackgroundColor;
private final int mProfileImageStyle;
private final int mTextSize;
private final boolean mDisplayProfileImage;
private final boolean mShowAbsoluteTime;
private List<ParcelableUser> mData;
private UserAdapterListener mUserAdapterListener;
private RequestClickListener mRequestClickListener;
public ParcelableUsersAdapter(Context context) {
super(context);
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context,
ThemeUtils.getThemeBackgroundOption(context),
ThemeUtils.getUserThemeBackgroundAlpha(context));
mInflater = LayoutInflater.from(context);
mTextSize = mPreferences.getInt(KEY_TEXT_SIZE, context.getResources().getInteger(R.integer.default_text_size));
mProfileImageStyle = Utils.getProfileImageStyle(mPreferences.getString(KEY_PROFILE_IMAGE_STYLE, null));
mDisplayProfileImage = mPreferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE);
mShowAbsoluteTime = mPreferences.getBoolean(KEY_SHOW_ABSOLUTE_TIME);
}
@Override
public List<ParcelableUser> getData() {
return mData;
}
@ -49,7 +76,6 @@ public class ParcelableUsersAdapter extends AbsUsersAdapter<List<ParcelableUser>
notifyDataSetChanged();
}
@Override
protected void bindUser(UserViewHolder holder, int position) {
holder.displayUser(getUser(position));
}
@ -114,4 +140,89 @@ public class ParcelableUsersAdapter extends AbsUsersAdapter<List<ParcelableUser>
return RecyclerView.NO_POSITION;
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;
}
@Override
public float getTextSize() {
return mTextSize;
}
@Override
public boolean isProfileImageEnabled() {
return mDisplayProfileImage;
}
@Override
public boolean isShowAbsoluteTime() {
return mShowAbsoluteTime;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ITEM_VIEW_TYPE_USER: {
final View view;
view = mInflater.inflate(R.layout.card_item_user_compact, parent, false);
final View itemContent = view.findViewById(R.id.item_content);
itemContent.setBackgroundColor(mCardBackgroundColor);
final UserViewHolder holder = new UserViewHolder(this, view);
holder.setOnClickListeners();
holder.setupViewOptions();
return holder;
}
case ITEM_VIEW_TYPE_LOAD_INDICATOR: {
final View view = mInflater.inflate(R.layout.card_item_load_indicator, parent, false);
return new LoadIndicatorViewHolder(view);
}
}
throw new IllegalStateException("Unknown view type " + viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case ITEM_VIEW_TYPE_USER: {
bindUser(((UserViewHolder) holder), position);
break;
}
}
}
@Override
public int getItemViewType(int position) {
if ((getLoadMoreIndicatorPosition() & IndicatorPosition.START) != 0 && position == 0) {
return ITEM_VIEW_TYPE_LOAD_INDICATOR;
}
if (position == getUserCount()) {
return ITEM_VIEW_TYPE_LOAD_INDICATOR;
}
return ITEM_VIEW_TYPE_USER;
}
@Nullable
@Override
public UserAdapterListener getUserAdapterListener() {
return mUserAdapterListener;
}
public void setUserAdapterListener(UserAdapterListener userAdapterListener) {
mUserAdapterListener = userAdapterListener;
}
@Override
public RequestClickListener getRequestClickListener() {
return mRequestClickListener;
}
public void setRequestClickListener(RequestClickListener requestClickListener) {
mRequestClickListener = requestClickListener;
}
@Override
public boolean shouldShowAccountsColor() {
return false;
}
}

View File

@ -1,157 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import org.mariotaku.twidere.adapter.AbsUsersAdapter;
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter.UserAdapterListener;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.util.UserKeyUtils;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.RecyclerViewNavigationHelper;
import org.mariotaku.twidere.view.holder.UserViewHolder;
abstract class AbsUsersFragment<Data> extends AbsContentListRecyclerViewFragment<AbsUsersAdapter<Data>>
implements LoaderCallbacks<Data>, UserAdapterListener, KeyboardShortcutCallback {
private RecyclerViewNavigationHelper mNavigationHelper;
public final Data getData() {
return getAdapter().getData();
}
@Override
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
return mNavigationHelper.handleKeyboardShortcutSingle(handler, keyCode, event, metaState);
}
@Override
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event, int metaState) {
return mNavigationHelper.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState);
}
@Override
public boolean isKeyboardShortcutHandled(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
return mNavigationHelper.isKeyboardShortcutHandled(handler, keyCode, event, metaState);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final AbsUsersAdapter<Data> adapter = getAdapter();
final RecyclerView recyclerView = getRecyclerView();
final LinearLayoutManager layoutManager = getLayoutManager();
adapter.setUserAdapterListener(this);
mNavigationHelper = new RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter,
this);
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().initLoader(0, loaderArgs, this);
}
@Override
public final Loader<Data> onCreateLoader(int id, Bundle args) {
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
args.remove(EXTRA_FROM_USER);
return onCreateUsersLoader(getActivity(), args, fromUser);
}
@Override
public void onLoadFinished(Loader<Data> loader, Data data) {
final AbsUsersAdapter<Data> adapter = getAdapter();
adapter.setData(data);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
adapter.setLoadMoreSupportedPosition(hasMoreData(data) ? IndicatorPosition.END : IndicatorPosition.NONE);
setRefreshEnabled(true);
}
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
showContent();
}
@Override
public void onLoaderReset(Loader<Data> loader) {
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
}
@Override
public void onUserClick(UserViewHolder holder, int position) {
final ParcelableUser user = getAdapter().getUser(position);
final FragmentActivity activity = getActivity();
if (UserKeyUtils.isSameHost(user.account_key, user.key)) {
IntentUtils.openUserProfile(activity, user.account_key, user.key.getId(),
user.screen_name, null, true, getUserReferral());
} else if (user.extras != null && user.extras.statusnet_profile_url != null) {
final Uri uri = Uri.parse(user.extras.statusnet_profile_url);
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
} else {
final Uri uri = LinkCreator.getTwitterUserLink(user.screen_name);
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
}
@UserFragment.Referral
protected String getUserReferral() {
return null;
}
@Override
public boolean onUserLongClick(UserViewHolder holder, int position) {
return true;
}
protected abstract boolean hasMoreData(Data data);
protected abstract Loader<Data> onCreateUsersLoader(final Context context,
@NonNull final Bundle args,
final boolean fromUser);
@Override
protected void setupRecyclerView(Context context, boolean compact) {
super.setupRecyclerView(context, true);
}
}

View File

@ -25,7 +25,6 @@ import android.support.annotation.NonNull;
import com.squareup.otto.Subscribe;
import org.mariotaku.twidere.adapter.AbsUsersAdapter;
import org.mariotaku.twidere.adapter.ParcelableUsersAdapter;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.loader.support.IDsUsersLoader;
@ -70,7 +69,7 @@ public class IncomingFriendshipsFragment extends CursorSupportUsersListFragment
@Override
public void onAcceptClicked(UserViewHolder holder, int position) {
final AbsUsersAdapter<List<ParcelableUser>> adapter = getAdapter();
final ParcelableUsersAdapter adapter = getAdapter();
final ParcelableUser user = adapter.getUser(position);
if (user == null) return;
mTwitterWrapper.acceptFriendshipAsync(user.account_key, user.key);
@ -78,7 +77,7 @@ public class IncomingFriendshipsFragment extends CursorSupportUsersListFragment
@Override
public void onDenyClicked(UserViewHolder holder, int position) {
final AbsUsersAdapter<List<ParcelableUser>> adapter = getAdapter();
final ParcelableUsersAdapter adapter = getAdapter();
final ParcelableUser user = adapter.getUser(position);
if (user == null) return;
mTwitterWrapper.denyFriendshipAsync(user.account_key, user.key);

View File

@ -23,35 +23,93 @@ import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import org.mariotaku.twidere.adapter.AbsGroupsAdapter;
import org.mariotaku.twidere.adapter.AbsUserListsAdapter;
import org.mariotaku.twidere.adapter.ParcelableGroupsAdapter;
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.loader.support.iface.ICursorSupportLoader;
import org.mariotaku.twidere.model.ParcelableGroup;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.RecyclerViewNavigationHelper;
import org.mariotaku.twidere.view.holder.GroupViewHolder;
import org.mariotaku.twidere.view.holder.UserListViewHolder;
abstract class AbsGroupsFragment<Data> extends AbsContentListRecyclerViewFragment<AbsGroupsAdapter<Data>>
implements LoaderCallbacks<Data>, AbsGroupsAdapter.GroupAdapterListener, KeyboardShortcutCallback {
import java.util.List;
public abstract class ParcelableGroupsFragment extends AbsContentListRecyclerViewFragment<AbsGroupsAdapter<List<ParcelableGroup>>>
implements LoaderManager.LoaderCallbacks<List<ParcelableGroup>>, AbsGroupsAdapter.GroupAdapterListener,
KeyboardShortcutsHandler.KeyboardShortcutCallback {
private RecyclerViewNavigationHelper mNavigationHelper;
private long mNextCursor;
private long mPrevCursor;
public final Data getData() {
@Override
public boolean isRefreshing() {
if (getContext() == null || isDetached()) return false;
final LoaderManager lm = getLoaderManager();
return lm.hasRunningLoaders();
}
@NonNull
@Override
protected final ParcelableGroupsAdapter onCreateAdapter(Context context, boolean compact) {
return new ParcelableGroupsAdapter(context);
}
@Override
protected void setupRecyclerView(Context context, boolean compact) {
super.setupRecyclerView(context, true);
}
@Nullable
protected UserKey getAccountKey() {
final Bundle args = getArguments();
return args.getParcelable(EXTRA_ACCOUNT_KEY);
}
protected boolean hasMoreData(List<ParcelableGroup> data) {
return data == null || !data.isEmpty();
}
@Override
public void onLoadFinished(Loader<List<ParcelableGroup>> loader, List<ParcelableGroup> data) {
final AbsGroupsAdapter<List<ParcelableGroup>> adapter = getAdapter();
adapter.setData(data);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
adapter.setLoadMoreSupportedPosition(hasMoreData(data) ? IndicatorPosition.END : IndicatorPosition.NONE);
setRefreshEnabled(true);
}
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
setRefreshEnabled(true);
setRefreshing(false);
setLoadMoreIndicatorPosition(IndicatorPosition.NONE);
}
@Override
public void onLoadMoreContents(@IndicatorPosition int position) {
// Only supports load from end, skip START flag
if ((position & IndicatorPosition.START) != 0) return;
super.onLoadMoreContents(position);
if (position == 0) return;
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
loaderArgs.putLong(EXTRA_NEXT_CURSOR, getNextCursor());
getLoaderManager().restartLoader(0, loaderArgs, this);
}
protected void removeUsers(long... ids) {
//TODO remove from adapter
}
public final List<ParcelableGroup> getData() {
return getAdapter().getData();
}
@ -73,7 +131,7 @@ abstract class AbsGroupsFragment<Data> extends AbsContentListRecyclerViewFragmen
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final AbsGroupsAdapter<Data> adapter = getAdapter();
final AbsGroupsAdapter<List<ParcelableGroup>> adapter = getAdapter();
final RecyclerView recyclerView = getRecyclerView();
final LinearLayoutManager layoutManager = getLayoutManager();
adapter.setListener(this);
@ -86,32 +144,14 @@ abstract class AbsGroupsFragment<Data> extends AbsContentListRecyclerViewFragmen
}
@Override
public final Loader<Data> onCreateLoader(int id, Bundle args) {
public final Loader<List<ParcelableGroup>> onCreateLoader(int id, Bundle args) {
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
args.remove(EXTRA_FROM_USER);
return onCreateUserListsLoader(getActivity(), args, fromUser);
}
@Override
public void onLoadFinished(Loader<Data> loader, Data data) {
final AbsGroupsAdapter<Data> adapter = getAdapter();
adapter.setData(data);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
adapter.setLoadMoreSupportedPosition(hasMoreData(data) ? IndicatorPosition.END : IndicatorPosition.NONE);
setRefreshEnabled(true);
}
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
if (loader instanceof ICursorSupportLoader) {
mNextCursor = ((ICursorSupportLoader) loader).getNextCursor();
mPrevCursor = ((ICursorSupportLoader) loader).getNextCursor();
}
showContent();
}
@Override
public void onLoaderReset(Loader<Data> loader) {
public void onLoaderReset(Loader<List<ParcelableGroup>> loader) {
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
@ -135,14 +175,5 @@ abstract class AbsGroupsFragment<Data> extends AbsContentListRecyclerViewFragmen
return mNextCursor;
}
protected ParcelableUserList getSelectedUserList() {
//TODO return selected
return null;
}
protected abstract boolean hasMoreData(Data data);
protected abstract Loader<Data> onCreateUserListsLoader(Context context, Bundle args, boolean fromUser);
protected abstract Loader<List<ParcelableGroup>> onCreateUserListsLoader(Context context, Bundle args, boolean fromUser);
}

View File

@ -20,17 +20,37 @@
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import org.mariotaku.twidere.adapter.ParcelableUsersAdapter;
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.util.UserKeyUtils;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.RecyclerViewNavigationHelper;
import org.mariotaku.twidere.view.holder.UserViewHolder;
import java.util.List;
public abstract class ParcelableUsersFragment extends AbsUsersFragment<List<ParcelableUser>> {
public abstract class ParcelableUsersFragment extends AbsContentListRecyclerViewFragment<ParcelableUsersAdapter>
implements LoaderManager.LoaderCallbacks<List<ParcelableUser>>, IUsersAdapter.UserAdapterListener,
KeyboardShortcutsHandler.KeyboardShortcutCallback {
private RecyclerViewNavigationHelper mNavigationHelper;
@Override
public boolean isRefreshing() {
@ -48,17 +68,24 @@ public abstract class ParcelableUsersFragment extends AbsUsersFragment<List<Parc
@NonNull
@Override
public ParcelableUsersAdapter getAdapter() {
return (ParcelableUsersAdapter) super.getAdapter();
return super.getAdapter();
}
@Override
protected boolean hasMoreData(List<ParcelableUser> data) {
return data == null || !data.isEmpty();
}
@Override
public void onLoadFinished(Loader<List<ParcelableUser>> loader, List<ParcelableUser> data) {
super.onLoadFinished(loader, data);
final ParcelableUsersAdapter adapter = getAdapter();
adapter.setData(data);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
adapter.setLoadMoreSupportedPosition(hasMoreData(data) ? IndicatorPosition.END : IndicatorPosition.NONE);
setRefreshEnabled(true);
}
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
showContent();
setRefreshEnabled(true);
setRefreshing(false);
setLoadMoreIndicatorPosition(IndicatorPosition.NONE);
@ -68,4 +95,88 @@ public abstract class ParcelableUsersFragment extends AbsUsersFragment<List<Parc
//TODO remove from adapter
}
public final List<ParcelableUser> getData() {
return getAdapter().getData();
}
@Override
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
return mNavigationHelper.handleKeyboardShortcutSingle(handler, keyCode, event, metaState);
}
@Override
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event, int metaState) {
return mNavigationHelper.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState);
}
@Override
public boolean isKeyboardShortcutHandled(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
return mNavigationHelper.isKeyboardShortcutHandled(handler, keyCode, event, metaState);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ParcelableUsersAdapter adapter = getAdapter();
final RecyclerView recyclerView = getRecyclerView();
final LinearLayoutManager layoutManager = getLayoutManager();
adapter.setUserAdapterListener(this);
mNavigationHelper = new RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter,
this);
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().initLoader(0, loaderArgs, this);
}
@Override
public final Loader<List<ParcelableUser>> onCreateLoader(int id, Bundle args) {
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
args.remove(EXTRA_FROM_USER);
return onCreateUsersLoader(getActivity(), args, fromUser);
}
@Override
public void onLoaderReset(Loader<List<ParcelableUser>> loader) {
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
}
@Override
public void onUserClick(UserViewHolder holder, int position) {
final ParcelableUser user = getAdapter().getUser(position);
final FragmentActivity activity = getActivity();
if (UserKeyUtils.isSameHost(user.account_key, user.key)) {
IntentUtils.openUserProfile(activity, user.account_key, user.key.getId(),
user.screen_name, null, true, getUserReferral());
} else if (user.extras != null && user.extras.statusnet_profile_url != null) {
final Uri uri = Uri.parse(user.extras.statusnet_profile_url);
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
} else {
final Uri uri = LinkCreator.getTwitterUserLink(user.screen_name);
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
}
@UserFragment.Referral
protected String getUserReferral() {
return null;
}
@Override
public boolean onUserLongClick(UserViewHolder holder, int position) {
return true;
}
protected abstract Loader<List<ParcelableUser>> onCreateUsersLoader(final Context context,
@NonNull final Bundle args,
final boolean fromUser);
@Override
protected void setupRecyclerView(Context context, boolean compact) {
super.setupRecyclerView(context, true);
}
}

View File

@ -807,6 +807,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mProfileImageView.setOnClickListener(this);
mProfileBannerView.setOnClickListener(this);
mListedContainer.setOnClickListener(this);
mGroupsContainer.setOnClickListener(this);
mFollowersContainer.setOnClickListener(this);
mFriendsContainer.setOnClickListener(this);
mHeaderErrorIcon.setOnClickListener(this);

View File

@ -0,0 +1,117 @@
/*
* 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.loader.support;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import android.util.Log;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.api.statusnet.model.Group;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.CursorSupport;
import org.mariotaku.twidere.api.twitter.model.PageableResponseList;
import org.mariotaku.twidere.loader.support.iface.ICursorSupportLoader;
import org.mariotaku.twidere.model.ParcelableGroup;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableGroupUtils;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import org.mariotaku.twidere.util.collection.NoDuplicatesArrayList;
import java.util.Collections;
import java.util.List;
public abstract class BaseGroupsLoader extends AsyncTaskLoader<List<ParcelableGroup>>
implements TwidereConstants, ICursorSupportLoader {
protected final NoDuplicatesArrayList<ParcelableGroup> mData = new NoDuplicatesArrayList<>();
protected final UserKey mAccountId;
private final long mCursor;
private long mNextCursor, mPrevCursor;
public BaseGroupsLoader(final Context context, final UserKey accountKey, final long cursor,
final List<ParcelableGroup> data) {
super(context);
if (data != null) {
mData.addAll(data);
}
mCursor = cursor;
mAccountId = accountKey;
}
@Override
public long getCursor() {
return mCursor;
}
@Override
public long getNextCursor() {
return mNextCursor;
}
@Override
public long getPrevCursor() {
return mPrevCursor;
}
public abstract List<Group> getGroups(final Twitter twitter) throws TwitterException;
@Override
public List<ParcelableGroup> loadInBackground() {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(getContext(), mAccountId, true);
List<Group> listLoaded = null;
try {
listLoaded = getGroups(twitter);
} catch (final TwitterException e) {
Log.w(LOGTAG, e);
}
if (listLoaded != null) {
final int listSize = listLoaded.size();
if (listLoaded instanceof PageableResponseList) {
mNextCursor = ((CursorSupport) listLoaded).getNextCursor();
mPrevCursor = ((CursorSupport) listLoaded).getPreviousCursor();
final int dataSize = mData.size();
for (int i = 0; i < listSize; i++) {
final Group group = listLoaded.get(i);
mData.add(ParcelableGroupUtils.from(group, mAccountId, dataSize + i, isMember(group)));
}
} else {
for (int i = 0; i < listSize; i++) {
final Group list = listLoaded.get(i);
mData.add(ParcelableGroupUtils.from(listLoaded.get(i), mAccountId, i, isMember(list)));
}
}
}
Collections.sort(mData);
return mData;
}
@Override
public void onStartLoading() {
forceLoad();
}
protected boolean isMember(final Group list) {
return list.isMember();
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.loader.support;
import android.content.Context;
import org.mariotaku.twidere.api.statusnet.model.Group;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
import org.mariotaku.twidere.api.twitter.model.UserList;
import org.mariotaku.twidere.model.ParcelableGroup;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.model.UserKey;
import java.util.List;
public class UserGroupsLoader extends BaseGroupsLoader {
private final long mUserId;
private final String mScreenName;
public UserGroupsLoader(final Context context, final UserKey accountKey, final long userId,
final String screenName, final List<ParcelableGroup> data) {
super(context, accountKey, 0, data);
mUserId = userId;
mScreenName = screenName;
}
@Override
public ResponseList<Group> getGroups(final Twitter twitter) throws TwitterException {
if (twitter == null) return null;
if (mUserId > 0)
return twitter.getGroups(mUserId);
else if (mScreenName != null) return twitter.getGroups(mScreenName);
return null;
}
@Override
protected boolean isMember(final Group list) {
return true;
}
}

View File

@ -0,0 +1,42 @@
package org.mariotaku.twidere.model.util;
import org.mariotaku.twidere.api.statusnet.model.Group;
import org.mariotaku.twidere.model.ParcelableGroup;
import org.mariotaku.twidere.model.UserKey;
import java.util.Date;
/**
* Created by mariotaku on 16/3/9.
*/
public class ParcelableGroupUtils {
public static ParcelableGroup from(Group group, UserKey accountKey, int position, boolean member) {
ParcelableGroup obj = new ParcelableGroup();
obj.account_key = accountKey;
obj.member = member;
obj.position = position;
obj.id = group.getId();
obj.nickname = group.getNickname();
obj.homepage = group.getHomepage();
obj.fullname = group.getFullname();
obj.url = group.getUrl();
obj.description = group.getDescription();
obj.location = group.getLocation();
obj.created = getTime(group.getCreated());
obj.modified = getTime(group.getModified());
obj.admin_count = group.getAdminCount();
obj.member_count = group.getMemberCount();
obj.original_logo = group.getOriginalLogo();
obj.homepage_logo = group.getHomepageLogo();
obj.stream_logo = group.getStreamLogo();
obj.mini_logo = group.getMiniLogo();
obj.blocked = group.isBlocked();
obj.id = group.getId();
return obj;
}
private static long getTime(Date date) {
if (date == null) return -1;
return date.getTime();
}
}

View File

@ -68,8 +68,11 @@ public class UserKeyUtils {
}
public static boolean isSameHost(UserKey accountKey, UserKey userKey) {
final String a = accountKey.getHost(), b = userKey.getHost();
return isSameHost(accountKey.getHost(), userKey.getHost());
}
public static boolean isSameHost(String a, String b) {
if (TextUtils.isEmpty(a) || TextUtils.isEmpty(b)) return true;
return a.equals(b);
return TextUtils.equals(a, b);
}
}

View File

@ -29,9 +29,10 @@ import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IGroupsAdapter;
import org.mariotaku.twidere.model.ParcelableGroup;
import org.mariotaku.twidere.model.util.UserKeyUtils;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.UserColorNameManager;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.NameView;
import org.mariotaku.twidere.view.iface.IColorLabelView;
import java.util.Locale;
@ -45,11 +46,11 @@ public class GroupViewHolder extends ViewHolder implements View.OnClickListener,
private final IColorLabelView itemContent;
private final ImageView profileImageView;
private final TextView nameView;
private final TextView createdByView;
private final NameView nameView;
private final TextView externalIndicator;
private final TextView descriptionView;
private final TextView membersCountView;
private final TextView subscribersCountView;
private final TextView adminsCountView;
private IGroupsAdapter.GroupAdapterListener groupClickListener;
@ -58,22 +59,26 @@ public class GroupViewHolder extends ViewHolder implements View.OnClickListener,
itemContent = (IColorLabelView) itemView.findViewById(R.id.item_content);
this.adapter = adapter;
profileImageView = (ImageView) itemView.findViewById(R.id.profile_image);
nameView = (TextView) itemView.findViewById(R.id.name);
createdByView = (TextView) itemView.findViewById(R.id.created_by);
nameView = (NameView) itemView.findViewById(R.id.name);
externalIndicator = (TextView) itemView.findViewById(R.id.external_indicator);
descriptionView = (TextView) itemView.findViewById(R.id.description);
membersCountView = (TextView) itemView.findViewById(R.id.members_count);
subscribersCountView = (TextView) itemView.findViewById(R.id.subscribers_count);
adminsCountView = (TextView) itemView.findViewById(R.id.admins_count);
}
public void displayGroup(ParcelableGroup group) {
final Context context = adapter.getContext();
final MediaLoaderWrapper loader = adapter.getMediaLoader();
final UserColorNameManager manager = adapter.getUserColorNameManager();
nameView.setText(group.fullname);
final boolean nameFirst = adapter.isNameFirst();
nameView.setName(group.fullname);
nameView.setScreenName("!" + group.nickname);
final String groupHost = UserKeyUtils.getUserHost(group.url);
if (UserKeyUtils.isSameHost(group.account_key.getHost(), groupHost)) {
externalIndicator.setVisibility(View.GONE);
} else {
externalIndicator.setVisibility(View.VISIBLE);
externalIndicator.setText(context.getString(R.string.external_user_host_format,
groupHost));
}
if (adapter.isProfileImageEnabled()) {
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, group.homepage_logo);
@ -84,7 +89,7 @@ public class GroupViewHolder extends ViewHolder implements View.OnClickListener,
descriptionView.setVisibility(TextUtils.isEmpty(group.description) ? View.GONE : View.VISIBLE);
descriptionView.setText(group.description);
membersCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), group.member_count));
subscribersCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), group.admin_count));
adminsCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), group.admin_count));
}
public void setOnClickListeners() {
@ -124,8 +129,12 @@ public class GroupViewHolder extends ViewHolder implements View.OnClickListener,
}
public void setTextSize(final float textSize) {
nameView.setTextSize(textSize);
createdByView.setTextSize(textSize * 0.75f);
descriptionView.setTextSize(textSize);
externalIndicator.setTextSize(textSize);
nameView.setPrimaryTextSize(textSize);
nameView.setSecondaryTextSize(textSize * 0.75f);
membersCountView.setTextSize(textSize);
adminsCountView.setTextSize(textSize);
}
}

View File

@ -0,0 +1,123 @@
<?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.ColorLabelRelativeLayout
android:id="@+id/item_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:padding="@dimen/element_spacing_normal"
app:ignorePadding="true"
tools:context=".adapter.ParcelableUsersAdapter">
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:contentDescription="@string/profile_image"
android:scaleType="fitCenter"
tools:src="@mipmap/ic_launcher"/>
<org.mariotaku.twidere.view.NameView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_alignWithParentIfMissing="true"
android:layout_toEndOf="@id/profile_image"
android:layout_toRightOf="@id/profile_image"
android:gravity="center_vertical"
app:nv_primaryTextColor="?android:textColorPrimary"
app:nv_primaryTextStyle="bold"
app:nv_secondaryTextColor="?android:textColorSecondary"
app:nv_twoLine="false"/>
<org.mariotaku.twidere.view.ActionIconThemedTextView
android:id="@+id/external_indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/name"
android:layout_alignStart="@+id/name"
android:layout_below="@+id/name"
android:paddingTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:textStyle="italic"
tools:text="External group at gnu.io"/>
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/name"
android:layout_alignStart="@+id/name"
android:layout_below="@+id/external_indicator"
android:paddingTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
tools:text="@string/sample_status_text"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/name"
android:layout_alignStart="@+id/name"
android:layout_below="@+id/description"
android:orientation="horizontal"
android:paddingTop="@dimen/element_spacing_small">
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/members_count"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableLeft="@drawable/ic_indicator_followers"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_indicator_followers"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="255"/>
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/admins_count"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableLeft="@drawable/ic_indicator_followers"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_indicator_followers"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="255"/>
</LinearLayout>
</org.mariotaku.twidere.view.ColorLabelRelativeLayout>

View File

@ -757,4 +757,5 @@
<string name="uploader_version_incompatible">Incompatible media uploader</string>
<string name="groups">Groups</string>
<string name="external_user_host_format">External user at <xliff:g id="host">%s</xliff:g></string>
<string name="external_group_host_format">External group at <xliff:g id="host">%s</xliff:g></string>
</resources>