Search now actually searches, yay
This commit is contained in:
@@ -17,7 +17,6 @@ import org.joinmastodon.android.api.requests.search.GetSearchResults;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Emoji;
|
||||
import org.joinmastodon.android.model.EmojiCategory;
|
||||
import org.joinmastodon.android.model.Hashtag;
|
||||
import org.joinmastodon.android.model.SearchResults;
|
||||
import org.joinmastodon.android.ui.drawables.ComposeAutocompleteBackgroundDrawable;
|
||||
@@ -27,13 +26,10 @@ import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.api.APIRequest;
|
||||
@@ -165,7 +161,7 @@ public class ComposeAutocompleteViewController{
|
||||
.filter(e->e.visibleInPicker && e.shortcode.startsWith(_text))
|
||||
.map(WrappedEmoji::new)
|
||||
.collect(Collectors.toList());
|
||||
updateList(oldList, emojis, emojisAdapter, (e1, e2)->e1.emoji.shortcode.equals(e2.emoji.shortcode));
|
||||
UiUtils.updateList(oldList, emojis, list, emojisAdapter, (e1, e2)->e1.emoji.shortcode.equals(e2.emoji.shortcode));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,39 +177,15 @@ public class ComposeAutocompleteViewController{
|
||||
return contentView;
|
||||
}
|
||||
|
||||
private <T> void updateList(List<T> oldList, List<T> newList, RecyclerView.Adapter<?> adapter, BiPredicate<T, T> areItemsSame){
|
||||
DiffUtil.calculateDiff(new DiffUtil.Callback(){
|
||||
@Override
|
||||
public int getOldListSize(){
|
||||
return oldList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewListSize(){
|
||||
return newList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition){
|
||||
return areItemsSame.test(oldList.get(oldItemPosition), newList.get(newItemPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition){
|
||||
return true;
|
||||
}
|
||||
}).dispatchUpdatesTo(adapter);
|
||||
}
|
||||
|
||||
private void doSearchUsers(){
|
||||
currentRequest=new GetSearchResults(lastText, GetSearchResults.Type.ACCOUNTS)
|
||||
currentRequest=new GetSearchResults(lastText, GetSearchResults.Type.ACCOUNTS, false)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(SearchResults result){
|
||||
currentRequest=null;
|
||||
List<WrappedAccount> oldList=users;
|
||||
users=result.accounts.stream().map(WrappedAccount::new).collect(Collectors.toList());
|
||||
updateList(oldList, users, usersAdapter, (a1, a2)->a1.account.id.equals(a2.account.id));
|
||||
UiUtils.updateList(oldList, users, list, usersAdapter, (a1, a2)->a1.account.id.equals(a2.account.id));
|
||||
if(listIsHidden){
|
||||
listIsHidden=false;
|
||||
V.setVisibilityAnimated(list, View.VISIBLE);
|
||||
@@ -230,14 +202,14 @@ public class ComposeAutocompleteViewController{
|
||||
}
|
||||
|
||||
private void doSearchHashtags(){
|
||||
currentRequest=new GetSearchResults(lastText, GetSearchResults.Type.HASHTAGS)
|
||||
currentRequest=new GetSearchResults(lastText, GetSearchResults.Type.HASHTAGS, false)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(SearchResults result){
|
||||
currentRequest=null;
|
||||
List<Hashtag> oldList=hashtags;
|
||||
hashtags=result.hashtags;
|
||||
updateList(oldList, hashtags, hashtagsAdapter, (t1, t2)->t1.name.equals(t2.name));
|
||||
UiUtils.updateList(oldList, hashtags, list, hashtagsAdapter, (t1, t2)->t1.name.equals(t2.name));
|
||||
if(listIsHidden){
|
||||
listIsHidden=false;
|
||||
V.setVisibilityAnimated(list, View.VISIBLE);
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.ui.OutlineProviders;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class AccountStatusDisplayItem extends StatusDisplayItem{
|
||||
public final Account account;
|
||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||
private CharSequence parsedName;
|
||||
public ImageLoaderRequest avaRequest;
|
||||
|
||||
public AccountStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Account account){
|
||||
super(parentID, parentFragment);
|
||||
this.account=account;
|
||||
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
|
||||
emojiHelper.setText(parsedName);
|
||||
if(!TextUtils.isEmpty(account.avatar))
|
||||
avaRequest=new UrlImageLoaderRequest(account.avatar, V.dp(50), V.dp(50));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType(){
|
||||
return Type.ACCOUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageCount(){
|
||||
return 1+emojiHelper.getImageCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLoaderRequest getImageRequest(int index){
|
||||
if(index==0)
|
||||
return avaRequest;
|
||||
return emojiHelper.getImageRequest(index-1);
|
||||
}
|
||||
|
||||
public static class Holder extends StatusDisplayItem.Holder<AccountStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||
private final TextView name, username;
|
||||
private final ImageView photo;
|
||||
|
||||
public Holder(Context context, ViewGroup parent){
|
||||
super(context, R.layout.display_item_account, parent);
|
||||
name=findViewById(R.id.name);
|
||||
username=findViewById(R.id.username);
|
||||
photo=findViewById(R.id.photo);
|
||||
|
||||
photo.setOutlineProvider(OutlineProviders.roundedRect(12));
|
||||
photo.setClipToOutline(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(AccountStatusDisplayItem item){
|
||||
name.setText(item.parsedName);
|
||||
username.setText("@"+item.account.acct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(int index, Drawable image){
|
||||
if(image instanceof Animatable && !((Animatable) image).isRunning())
|
||||
((Animatable) image).start();
|
||||
if(index==0){
|
||||
photo.setImageDrawable(image);
|
||||
}else{
|
||||
item.emojiHelper.setImageDrawable(index-1, image);
|
||||
name.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearImage(int index){
|
||||
setImage(index, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.model.Hashtag;
|
||||
import org.joinmastodon.android.ui.views.HashtagChartView;
|
||||
|
||||
public class HashtagStatusDisplayItem extends StatusDisplayItem{
|
||||
public final Hashtag tag;
|
||||
|
||||
public HashtagStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Hashtag tag){
|
||||
super(parentID, parentFragment);
|
||||
this.tag=tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType(){
|
||||
return Type.HASHTAG;
|
||||
}
|
||||
|
||||
public static class Holder extends StatusDisplayItem.Holder<HashtagStatusDisplayItem>{
|
||||
private final TextView title, subtitle;
|
||||
private final HashtagChartView chart;
|
||||
|
||||
public Holder(Context context, ViewGroup parent){
|
||||
super(context, R.layout.item_trending_hashtag, parent);
|
||||
title=findViewById(R.id.title);
|
||||
subtitle=findViewById(R.id.subtitle);
|
||||
chart=findViewById(R.id.chart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(HashtagStatusDisplayItem _item){
|
||||
Hashtag item=_item.tag;
|
||||
title.setText('#'+item.name);
|
||||
int numPeople=item.history.get(0).accounts;
|
||||
if(item.history.size()>1)
|
||||
numPeople+=item.history.get(1).accounts;
|
||||
subtitle.setText(_item.parentFragment.getResources().getQuantityString(R.plurals.x_people_talking, numPeople, numPeople));
|
||||
chart.setData(item.history);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ public abstract class StatusDisplayItem{
|
||||
public final String parentID;
|
||||
public final BaseStatusListFragment parentFragment;
|
||||
public boolean inset;
|
||||
public int index;
|
||||
|
||||
public StatusDisplayItem(String parentID, BaseStatusListFragment parentFragment){
|
||||
this.parentID=parentID;
|
||||
@@ -60,6 +61,8 @@ public abstract class StatusDisplayItem{
|
||||
case CARD -> new LinkCardStatusDisplayItem.Holder(activity, parent);
|
||||
case FOOTER -> new FooterStatusDisplayItem.Holder(activity, parent);
|
||||
case ACCOUNT_CARD -> new AccountCardStatusDisplayItem.Holder(activity, parent);
|
||||
case ACCOUNT -> new AccountStatusDisplayItem.Holder(activity, parent);
|
||||
case HASHTAG -> new HashtagStatusDisplayItem.Holder(activity, parent);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -110,8 +113,11 @@ public abstract class StatusDisplayItem{
|
||||
if(addFooter){
|
||||
items.add(new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID));
|
||||
}
|
||||
for(StatusDisplayItem item:items)
|
||||
int i=1;
|
||||
for(StatusDisplayItem item:items){
|
||||
item.inset=inset;
|
||||
item.index=i++;
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -135,6 +141,8 @@ public abstract class StatusDisplayItem{
|
||||
CARD,
|
||||
FOOTER,
|
||||
ACCOUNT_CARD,
|
||||
ACCOUNT,
|
||||
HASHTAG
|
||||
}
|
||||
|
||||
public static abstract class Holder<T extends StatusDisplayItem> extends BindableViewHolder<T> implements UsableRecyclerView.Clickable{
|
||||
|
||||
@@ -34,7 +34,7 @@ public class CustomEmojiHelper{
|
||||
}
|
||||
|
||||
public ImageLoaderRequest getImageRequest(int image){
|
||||
return requests.get(image);
|
||||
return image<requests.size() ? requests.get(image) : null; // TODO fix this in the image loader
|
||||
}
|
||||
|
||||
public void setImageDrawable(int image, Drawable drawable){
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.joinmastodon.android.ui.utils;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
||||
|
||||
public class HideableSingleViewRecyclerAdapter extends SingleViewRecyclerAdapter{
|
||||
private boolean visible=true;
|
||||
|
||||
public HideableSingleViewRecyclerAdapter(View view){
|
||||
super(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(){
|
||||
return visible ? 1 : 0;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible){
|
||||
if(visible==this.visible)
|
||||
return;
|
||||
this.visible=visible;
|
||||
if(visible)
|
||||
notifyItemInserted(0);
|
||||
else
|
||||
notifyItemRemoved(0);
|
||||
}
|
||||
|
||||
public boolean isVisible(){
|
||||
return visible;
|
||||
}
|
||||
}
|
||||
@@ -39,12 +39,15 @@ import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.browser.customtabs.CustomTabsIntent;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
@@ -311,4 +314,39 @@ public class UiUtils{
|
||||
.exec(accountID);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void updateList(List<T> oldList, List<T> newList, RecyclerView list, RecyclerView.Adapter<?> adapter, BiPredicate<T, T> areItemsSame){
|
||||
// Save topmost item position and offset because for some reason RecyclerView would scroll the list to weird places when you insert items at the top
|
||||
int topItem, topItemOffset;
|
||||
if(list.getChildCount()==0){
|
||||
topItem=topItemOffset=0;
|
||||
}else{
|
||||
View child=list.getChildAt(0);
|
||||
topItem=list.getChildAdapterPosition(child);
|
||||
topItemOffset=child.getTop();
|
||||
}
|
||||
DiffUtil.calculateDiff(new DiffUtil.Callback(){
|
||||
@Override
|
||||
public int getOldListSize(){
|
||||
return oldList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewListSize(){
|
||||
return newList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition){
|
||||
return areItemsSame.test(oldList.get(oldItemPosition), newList.get(newItemPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition){
|
||||
return true;
|
||||
}
|
||||
}).dispatchUpdatesTo(adapter);
|
||||
list.scrollToPosition(topItem);
|
||||
list.scrollBy(0, topItemOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class HashtagChartView extends View{
|
||||
}
|
||||
|
||||
public void setData(List<History> data){
|
||||
int max=0;
|
||||
int max=1; // avoid dividing by zero
|
||||
for(History h:data){
|
||||
max=Math.max(h.accounts, max);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user