Improve follow recommendations screen (AND-101)
This commit is contained in:
@@ -38,6 +38,7 @@ public abstract class BaseAccountListFragment extends MastodonRecyclerFragment<A
|
||||
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
||||
protected String accountID;
|
||||
protected ArrayList<APIRequest<?>> relationshipsRequests=new ArrayList<>();
|
||||
protected int itemLayoutRes=R.layout.item_account_list;
|
||||
|
||||
public BaseAccountListFragment(){
|
||||
super(40);
|
||||
@@ -151,7 +152,7 @@ public abstract class BaseAccountListFragment extends MastodonRecyclerFragment<A
|
||||
@NonNull
|
||||
@Override
|
||||
public AccountViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
AccountViewHolder holder=new AccountViewHolder(BaseAccountListFragment.this, parent, relationships);
|
||||
AccountViewHolder holder=new AccountViewHolder(BaseAccountListFragment.this, parent, relationships, itemLayoutRes);
|
||||
onConfigureViewHolder(holder);
|
||||
return holder;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.app.ProgressDialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetFollowSuggestions;
|
||||
@@ -12,35 +13,38 @@ import org.joinmastodon.android.fragments.account_list.BaseAccountListFragment;
|
||||
import org.joinmastodon.android.model.FollowSuggestion;
|
||||
import org.joinmastodon.android.model.Relationship;
|
||||
import org.joinmastodon.android.model.viewmodel.AccountViewModel;
|
||||
import org.joinmastodon.android.ui.OutlineProviders;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
|
||||
import org.joinmastodon.android.utils.ElevationOnScrollListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class OnboardingFollowSuggestionsFragment extends BaseAccountListFragment{
|
||||
private String accountID;
|
||||
private View buttonBar;
|
||||
private ElevationOnScrollListener onScrollListener;
|
||||
private int numRunningFollowRequests=0;
|
||||
|
||||
public OnboardingFollowSuggestionsFragment(){
|
||||
super(R.layout.fragment_onboarding_follow_suggestions, 40);
|
||||
itemLayoutRes=R.layout.item_account_list_onboarding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
setTitle(R.string.popular_on_mastodon);
|
||||
setTitle(R.string.onboarding_recommendations_title);
|
||||
accountID=getArguments().getString("account");
|
||||
loadData();
|
||||
}
|
||||
@@ -49,7 +53,6 @@ public class OnboardingFollowSuggestionsFragment extends BaseAccountListFragment
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
buttonBar=view.findViewById(R.id.button_bar);
|
||||
list.addOnScrollListener(onScrollListener=new ElevationOnScrollListener((FragmentRootLinearLayout) view, buttonBar, getToolbar()));
|
||||
|
||||
view.findViewById(R.id.btn_next).setOnClickListener(UiUtils.rateLimitedClickListener(this::onFollowAllClick));
|
||||
view.findViewById(R.id.btn_skip).setOnClickListener(UiUtils.rateLimitedClickListener(v->proceed()));
|
||||
@@ -58,9 +61,7 @@ public class OnboardingFollowSuggestionsFragment extends BaseAccountListFragment
|
||||
@Override
|
||||
protected void onUpdateToolbar(){
|
||||
super.onUpdateToolbar();
|
||||
if(onScrollListener!=null){
|
||||
onScrollListener.setViews(buttonBar, getToolbar());
|
||||
}
|
||||
getToolbar().setContentInsetsRelative(V.dp(56), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +70,7 @@ public class OnboardingFollowSuggestionsFragment extends BaseAccountListFragment
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<FollowSuggestion> result){
|
||||
onDataLoaded(result.stream().map(fs->new AccountViewModel(fs.account, accountID)).collect(Collectors.toList()), false);
|
||||
onDataLoaded(result.stream().map(fs->new AccountViewModel(fs.account, accountID).stripLinksFromBio()).collect(Collectors.toList()), false);
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
@@ -80,6 +81,19 @@ public class OnboardingFollowSuggestionsFragment extends BaseAccountListFragment
|
||||
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView.Adapter<?> getAdapter(){
|
||||
TextView introText=new TextView(getActivity());
|
||||
introText.setTextAppearance(R.style.m3_body_large);
|
||||
introText.setTextColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnSurface));
|
||||
introText.setPaddingRelative(V.dp(56), 0, V.dp(24), V.dp(8));
|
||||
introText.setText(R.string.onboarding_recommendations_intro);
|
||||
MergeRecyclerAdapter mergeAdapter=new MergeRecyclerAdapter();
|
||||
mergeAdapter.addAdapter(new SingleViewRecyclerAdapter(introText));
|
||||
mergeAdapter.addAdapter(super.getAdapter());
|
||||
return mergeAdapter;
|
||||
}
|
||||
|
||||
private void onFollowAllClick(View v){
|
||||
if(!loaded || relationships.isEmpty())
|
||||
return;
|
||||
@@ -155,5 +169,6 @@ public class OnboardingFollowSuggestionsFragment extends BaseAccountListFragment
|
||||
protected void onConfigureViewHolder(AccountViewHolder holder){
|
||||
super.onConfigureViewHolder(holder);
|
||||
holder.setStyle(AccountViewHolder.AccessoryType.BUTTON, true);
|
||||
holder.avatar.setOutlineProvider(OutlineProviders.roundedRect(8));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.joinmastodon.android.model.viewmodel;
|
||||
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
@@ -7,6 +8,7 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.AccountField;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.ui.text.LinkSpan;
|
||||
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -43,4 +45,13 @@ public class AccountViewModel{
|
||||
}
|
||||
this.verifiedLink=verifiedLink;
|
||||
}
|
||||
|
||||
public AccountViewModel stripLinksFromBio(){
|
||||
if(parsedBio instanceof Spannable spannable){
|
||||
for(LinkSpan span:spannable.getSpans(0, spannable.length(), LinkSpan.class)){
|
||||
spannable.removeSpan(span);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
@@ -53,7 +54,7 @@ import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class AccountViewHolder extends BindableViewHolder<AccountViewModel> implements ImageLoaderViewHolder, UsableRecyclerView.Clickable, UsableRecyclerView.LongClickable{
|
||||
private final TextView name, username, followers, verifiedLink, bio;
|
||||
private final ImageView avatar;
|
||||
public final ImageView avatar;
|
||||
private final ProgressBarButton button;
|
||||
private final PopupMenu contextMenu;
|
||||
private final View menuAnchor;
|
||||
@@ -75,7 +76,11 @@ public class AccountViewHolder extends BindableViewHolder<AccountViewModel> impl
|
||||
private boolean checked;
|
||||
|
||||
public AccountViewHolder(Fragment fragment, ViewGroup list, HashMap<String, Relationship> relationships){
|
||||
super(fragment.getActivity(), R.layout.item_account_list, list);
|
||||
this(fragment, list, relationships, R.layout.item_account_list);
|
||||
}
|
||||
|
||||
public AccountViewHolder(Fragment fragment, ViewGroup list, HashMap<String, Relationship> relationships, @LayoutRes int layout){
|
||||
super(fragment.getActivity(), layout, list);
|
||||
this.fragment=fragment;
|
||||
this.accountID=Objects.requireNonNull(fragment.getArguments().getString("account"));
|
||||
this.relationships=relationships;
|
||||
@@ -111,24 +116,28 @@ public class AccountViewHolder extends BindableViewHolder<AccountViewModel> impl
|
||||
public void onBind(AccountViewModel item){
|
||||
name.setText(item.parsedName);
|
||||
username.setText("@"+item.account.acct);
|
||||
String followersStr=fragment.getResources().getQuantityString(R.plurals.x_followers, item.account.followersCount>1000 ? 999 : (int)item.account.followersCount);
|
||||
String followersNum=UiUtils.abbreviateNumber(item.account.followersCount);
|
||||
int index=followersStr.indexOf("%,d");
|
||||
followersStr=followersStr.replace("%,d", followersNum);
|
||||
SpannableStringBuilder followersFormatted=new SpannableStringBuilder(followersStr);
|
||||
if(index!=-1){
|
||||
followersFormatted.setSpan(mediumSpan, index, index+followersNum.length(), 0);
|
||||
if(followers!=null){
|
||||
String followersStr=fragment.getResources().getQuantityString(R.plurals.x_followers, item.account.followersCount>1000 ? 999 : (int)item.account.followersCount);
|
||||
String followersNum=UiUtils.abbreviateNumber(item.account.followersCount);
|
||||
int index=followersStr.indexOf("%,d");
|
||||
followersStr=followersStr.replace("%,d", followersNum);
|
||||
SpannableStringBuilder followersFormatted=new SpannableStringBuilder(followersStr);
|
||||
if(index!=-1){
|
||||
followersFormatted.setSpan(mediumSpan, index, index+followersNum.length(), 0);
|
||||
}
|
||||
followers.setText(followersFormatted);
|
||||
}
|
||||
if(verifiedLink!=null){
|
||||
boolean hasVerifiedLink=item.verifiedLink!=null;
|
||||
if(!hasVerifiedLink)
|
||||
verifiedLink.setText(R.string.no_verified_link);
|
||||
else
|
||||
verifiedLink.setText(item.verifiedLink);
|
||||
verifiedLink.setCompoundDrawablesRelativeWithIntrinsicBounds(hasVerifiedLink ? R.drawable.ic_check_small_16px : R.drawable.ic_help_16px, 0, 0, 0);
|
||||
int tintColor=UiUtils.getThemeColor(fragment.getActivity(), hasVerifiedLink ? R.attr.colorM3Primary : R.attr.colorM3Secondary);
|
||||
verifiedLink.setTextColor(tintColor);
|
||||
verifiedLink.setCompoundDrawableTintList(ColorStateList.valueOf(tintColor));
|
||||
}
|
||||
followers.setText(followersFormatted);
|
||||
boolean hasVerifiedLink=item.verifiedLink!=null;
|
||||
if(!hasVerifiedLink)
|
||||
verifiedLink.setText(R.string.no_verified_link);
|
||||
else
|
||||
verifiedLink.setText(item.verifiedLink);
|
||||
verifiedLink.setCompoundDrawablesRelativeWithIntrinsicBounds(hasVerifiedLink ? R.drawable.ic_check_small_16px : R.drawable.ic_help_16px, 0, 0, 0);
|
||||
int tintColor=UiUtils.getThemeColor(fragment.getActivity(), hasVerifiedLink ? R.attr.colorM3Primary : R.attr.colorM3Secondary);
|
||||
verifiedLink.setTextColor(tintColor);
|
||||
verifiedLink.setCompoundDrawableTintList(ColorStateList.valueOf(tintColor));
|
||||
bindRelationship();
|
||||
if(showBio){
|
||||
bio.setText(item.parsedBio);
|
||||
@@ -338,7 +347,7 @@ public class AccountViewHolder extends BindableViewHolder<AccountViewModel> impl
|
||||
Menu menu=contextMenu.getMenu();
|
||||
Account account=item.account;
|
||||
|
||||
menu.findItem(R.id.share).setTitle(fragment.getString(R.string.share_user, account.getDisplayUsername()));
|
||||
menu.findItem(R.id.share).setTitle(R.string.share_user);
|
||||
menu.findItem(R.id.mute).setTitle(fragment.getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername()));
|
||||
menu.findItem(R.id.block).setTitle(fragment.getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getDisplayUsername()));
|
||||
menu.findItem(R.id.report).setTitle(fragment.getString(R.string.report_user, account.getDisplayUsername()));
|
||||
|
||||
Reference in New Issue
Block a user