This commit is contained in:
Grishka 2024-02-24 03:48:06 +03:00
parent 6bcf259de9
commit d0e33c8a12
2 changed files with 125 additions and 55 deletions

View File

@ -1,12 +1,17 @@
package org.joinmastodon.android.fragments; package org.joinmastodon.android.fragments;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.ActionMode; import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets; import android.view.WindowInsets;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
@ -19,7 +24,7 @@ import org.joinmastodon.android.api.requests.lists.GetListAccounts;
import org.joinmastodon.android.api.requests.lists.RemoveAccountsFromList; import org.joinmastodon.android.api.requests.lists.RemoveAccountsFromList;
import org.joinmastodon.android.events.AccountAddedToListEvent; import org.joinmastodon.android.events.AccountAddedToListEvent;
import org.joinmastodon.android.events.AccountRemovedFromListEvent; import org.joinmastodon.android.events.AccountRemovedFromListEvent;
import org.joinmastodon.android.fragments.account_list.AddListMembersFragment; import org.joinmastodon.android.fragments.account_list.AddNewListMembersFragment;
import org.joinmastodon.android.fragments.account_list.PaginatedAccountListFragment; import org.joinmastodon.android.fragments.account_list.PaginatedAccountListFragment;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.FollowList; import org.joinmastodon.android.model.FollowList;
@ -33,24 +38,31 @@ import org.parceler.Parcels;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.fragments.OnBackPressedListener;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.FragmentRootLinearLayout;
public class ListMembersFragment extends PaginatedAccountListFragment{ public class ListMembersFragment extends PaginatedAccountListFragment implements AddNewListMembersFragment.Listener, OnBackPressedListener{
private static final int ADD_MEMBER_RESULT=600;
private ImageButton fab; private ImageButton fab;
private FollowList followList; private FollowList followList;
private boolean inSelectionMode; private boolean inSelectionMode;
private Set<String> selectedAccounts=new HashSet<>(); private Set<String> selectedAccounts=new HashSet<>();
private ActionMode actionMode; private ActionMode actionMode;
private MenuItem deleteItem; private MenuItem deleteItem;
private FrameLayout searchFragmentContainer;
private FrameLayout fragmentContentWrap;
private AddNewListMembersFragment searchFragment;
private FragmentRootLinearLayout rootView;
private WindowInsets lastInsets;
private HashSet<String> accountIDsInList=new HashSet<>();
private boolean dismissingSearchFragment;
public ListMembersFragment(){ public ListMembersFragment(){
setListLayoutId(R.layout.recycler_fragment_with_fab); setListLayoutId(R.layout.recycler_fragment_with_fab);
@ -76,6 +88,26 @@ public class ListMembersFragment extends PaginatedAccountListFragment{
return new GetListAccounts(followList.id, maxID, count); return new GetListAccounts(followList.id, maxID, count);
} }
@Override
protected void onDataLoaded(List<AccountViewModel> d, boolean more){
if(refreshing)
accountIDsInList.clear();
for(AccountViewModel a:d){
accountIDsInList.add(a.account.id);
}
super.onDataLoaded(d, more);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view=super.onCreateView(inflater, container, savedInstanceState);
FrameLayout wrapper=new FrameLayout(getActivity());
wrapper.addView(view);
rootView=(FragmentRootLinearLayout) view;
fragmentContentWrap=wrapper;
return wrapper;
}
@Override @Override
protected void onConfigureViewHolder(AccountViewHolder holder){ protected void onConfigureViewHolder(AccountViewHolder holder){
super.onConfigureViewHolder(holder); super.onConfigureViewHolder(holder);
@ -132,16 +164,19 @@ public class ListMembersFragment extends PaginatedAccountListFragment{
@Override @Override
public void onApplyWindowInsets(WindowInsets insets){ public void onApplyWindowInsets(WindowInsets insets){
super.onApplyWindowInsets(insets); lastInsets=insets;
if(searchFragment!=null)
searchFragment.onApplyWindowInsets(insets);
UiUtils.applyBottomInsetToFAB(fab, insets); UiUtils.applyBottomInsetToFAB(fab, insets);
} if(Build.VERSION.SDK_INT>=29 && insets.getTappableElementInsets().bottom==0){
list.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
@Override emptyView.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
public void onFragmentResult(int reqCode, boolean success, Bundle result){ progress.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
if(reqCode==ADD_MEMBER_RESULT && success){ insets=insets.inset(0, 0, 0, insets.getSystemWindowInsetBottom());
Account acc=Objects.requireNonNull(Parcels.unwrap(result.getParcelable("selectedAccount"))); }else{
addAccounts(List.of(acc)); list.setPadding(0, 0, 0, 0);
} }
rootView.onApplyWindowInsets(insets);
} }
@Subscribe @Subscribe
@ -160,9 +195,25 @@ public class ListMembersFragment extends PaginatedAccountListFragment{
} }
private void onFabClick(){ private void onFabClick(){
searchFragmentContainer=new FrameLayout(getActivity());
searchFragmentContainer.setId(R.id.search_fragment);
fragmentContentWrap.addView(searchFragmentContainer);
Bundle args=new Bundle(); Bundle args=new Bundle();
args.putString("account", accountID); args.putString("account", accountID);
Nav.goForResult(getActivity(), AddListMembersFragment.class, args, ADD_MEMBER_RESULT, this); args.putParcelable("list", Parcels.wrap(followList));
args.putBoolean("_can_go_back", true);
searchFragment=new AddNewListMembersFragment(this);
searchFragment.setArguments(args);
getChildFragmentManager().beginTransaction().add(R.id.search_fragment, searchFragment).commit();
getChildFragmentManager().executePendingTransactions();
if(lastInsets!=null)
searchFragment.onApplyWindowInsets(lastInsets);
searchFragmentContainer.setTranslationX(V.dp(100));
searchFragmentContainer.setAlpha(0f);
searchFragmentContainer.animate().translationX(0).alpha(1).setDuration(300).withLayer().setInterpolator(CubicBezierInterpolator.DEFAULT).withEndAction(()->{
rootView.setVisibility(View.GONE);
}).start();
} }
private void onItemClick(AccountViewHolder holder){ private void onItemClick(AccountViewHolder holder){
@ -198,7 +249,7 @@ public class ListMembersFragment extends PaginatedAccountListFragment{
if(id==R.id.remove_from_list){ if(id==R.id.remove_from_list){
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.confirm_remove_list_member) .setTitle(R.string.confirm_remove_list_member)
.setPositiveButton(R.string.remove, (dlg, which)->removeAccounts(Set.of(holder.getItem().account.id))) .setPositiveButton(R.string.remove, (dlg, which)->removeAccounts(Set.of(holder.getItem().account.id), null))
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show(); .show();
} }
@ -229,7 +280,7 @@ public class ListMembersFragment extends PaginatedAccountListFragment{
public boolean onActionItemClicked(ActionMode mode, MenuItem item){ public boolean onActionItemClicked(ActionMode mode, MenuItem item){
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.confirm_remove_list_members) .setTitle(R.string.confirm_remove_list_members)
.setPositiveButton(R.string.remove, (dlg, which)->removeAccounts(new HashSet<>(selectedAccounts))) .setPositiveButton(R.string.remove, (dlg, which)->removeAccounts(new HashSet<>(selectedAccounts), null))
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show(); .show();
return true; return true;
@ -251,13 +302,16 @@ public class ListMembersFragment extends PaginatedAccountListFragment{
actionMode.setTitle(getResources().getQuantityString(R.plurals.x_items_selected, selectedAccounts.size(), selectedAccounts.size())); actionMode.setTitle(getResources().getQuantityString(R.plurals.x_items_selected, selectedAccounts.size(), selectedAccounts.size()));
} }
private void removeAccounts(Set<String> ids){ private void removeAccounts(Set<String> ids, Runnable onDone){
new RemoveAccountsFromList(followList.id, ids) new RemoveAccountsFromList(followList.id, ids)
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override
public void onSuccess(Void result){ public void onSuccess(Void result){
if(onDone!=null)
onDone.run();
if(inSelectionMode) if(inSelectionMode)
actionMode.finish(); actionMode.finish();
accountIDsInList.removeAll(ids);
removeAccountRows(ids); removeAccountRows(ids);
} }
@ -270,12 +324,15 @@ public class ListMembersFragment extends PaginatedAccountListFragment{
.exec(accountID); .exec(accountID);
} }
private void addAccounts(Collection<Account> accounts){ private void addAccounts(Collection<Account> accounts, Runnable onDone){
new AddAccountsToList(followList.id, accounts.stream().map(a->a.id).collect(Collectors.toSet())) new AddAccountsToList(followList.id, accounts.stream().map(a->a.id).collect(Collectors.toSet()))
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override
public void onSuccess(Void result){ public void onSuccess(Void result){
if(onDone!=null)
onDone.run();
for(Account acc:accounts){ for(Account acc:accounts){
accountIDsInList.add(acc.id);
data.add(new AccountViewModel(acc, accountID)); data.add(new AccountViewModel(acc, accountID));
} }
list.getAdapter().notifyItemRangeInserted(data.size()-accounts.size(), accounts.size()); list.getAdapter().notifyItemRangeInserted(data.size()-accounts.size(), accounts.size());
@ -298,4 +355,54 @@ public class ListMembersFragment extends PaginatedAccountListFragment{
} }
} }
} }
@Override
public boolean isAccountInList(AccountViewModel account){
return accountIDsInList.contains(account.account.id);
}
@Override
public void addAccountToList(AccountViewModel account, Runnable onDone){
addAccounts(Set.of(account.account), onDone);
}
@Override
public void removeAccountAccountFromList(AccountViewModel account, Runnable onDone){
removeAccounts(Set.of(account.account.id), onDone);
}
@Override
public boolean onBackPressed(){
if(searchFragment!=null){
dismissSearchFragment();
return true;
}
return false;
}
private void dismissSearchFragment(){
if(searchFragment==null || dismissingSearchFragment)
return;
dismissingSearchFragment=true;
rootView.setVisibility(View.VISIBLE);
searchFragmentContainer.animate().translationX(V.dp(100)).alpha(0).setDuration(200).withLayer().setInterpolator(CubicBezierInterpolator.DEFAULT).withEndAction(()->{
getChildFragmentManager().beginTransaction().remove(searchFragment).commit();
getChildFragmentManager().executePendingTransactions();
fragmentContentWrap.removeView(searchFragmentContainer);
searchFragmentContainer=null;
searchFragment=null;
dismissingSearchFragment=false;
}).start();
getActivity().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(contentView.getWindowToken(), 0);
}
@Override
protected void setStatusBarColor(int color){
rootView.setStatusBarColor(color);
}
@Override
protected void setNavigationBarColor(int color){
rootView.setNavigationBarColor(color);
}
} }

View File

@ -1,37 +0,0 @@
package org.joinmastodon.android.fragments.account_list;
import android.os.Bundle;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.SearchAccounts;
import org.joinmastodon.android.model.Account;
import java.util.List;
import me.grishka.appkit.api.SimpleCallback;
public class AddListMembersFragment extends AccountSearchFragment{
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
dataLoaded();
}
@Override
protected void doLoadData(int offset, int count){
refreshing=true;
currentRequest=new SearchAccounts(currentQuery, 0, 0, false, true)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Account> result){
AddListMembersFragment.this.onSuccess(result);
}
})
.exec(accountID);
}
@Override
protected String getSearchViewPlaceholder(){
return getString(R.string.search_among_people_you_follow);
}
}