implement adding/removing users from lists

This commit is contained in:
sk
2022-11-12 16:14:45 +01:00
parent 1e0ae6e570
commit 625134605b
9 changed files with 182 additions and 8 deletions

View File

@@ -0,0 +1,17 @@
package org.joinmastodon.android.api.requests.lists;
import org.joinmastodon.android.api.MastodonAPIRequest;
import java.util.List;
public class AddAccountsToList extends MastodonAPIRequest<Object> {
public AddAccountsToList(String listId, List<String> accountIds){
super(HttpMethod.POST, "/lists/"+listId+"/accounts", Object.class);
Request req = new Request();
req.accountIds = accountIds;
setRequestBody(req);
}
public static class Request{
public List<String> accountIds;
}
}

View File

@@ -11,4 +11,7 @@ public class GetLists extends MastodonAPIRequest<List<ListTimeline>>{
public GetLists() {
super(HttpMethod.GET, "/lists", new TypeToken<>(){});
}
public GetLists(String accountID) {
super(HttpMethod.GET, "/accounts/"+accountID+"/lists", new TypeToken<>(){});
}
}

View File

@@ -0,0 +1,17 @@
package org.joinmastodon.android.api.requests.lists;
import org.joinmastodon.android.api.MastodonAPIRequest;
import java.util.List;
public class RemoveAccountsFromList extends MastodonAPIRequest<Object> {
public RemoveAccountsFromList(String listId, List<String> accountIds){
super(HttpMethod.DELETE, "/lists/"+listId+"/accounts", Object.class);
Request req = new Request();
req.accountIds = accountIds;
setRequestBody(req);
}
public static class Request{
public List<String> accountIds;
}
}

View File

@@ -1,29 +1,48 @@
package org.joinmastodon.android.fragments;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.requests.lists.AddAccountsToList;
import org.joinmastodon.android.api.requests.lists.GetLists;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.api.requests.lists.RemoveAccountsFromList;
import org.joinmastodon.android.model.ListTimeline;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.fragments.BaseRecyclerFragment;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class ListTimelinesFragment extends BaseRecyclerFragment<ListTimeline> implements ScrollableToTop {
private String accountId;
private String profileAccountId;
private String profileDisplayUsername;
private HashMap<String, Boolean> userInListBefore = new HashMap<>();
private HashMap<String, Boolean> userInList = new HashMap<>();
private int inProgress = 0;
public ListTimelinesFragment() {
super(10);
@@ -32,16 +51,101 @@ public class ListTimelinesFragment extends BaseRecyclerFragment<ListTimeline> im
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accountId=getArguments().getString("account");
Bundle args=getArguments();
accountId=args.getString("account");
if(args.containsKey("profileAccount")){
profileAccountId=args.getString("profileAccount");
profileDisplayUsername=args.getString("profileDisplayUsername");
setTitle(getString(R.string.lists_with_user, profileDisplayUsername));
setHasOptionsMenu(true);
}
}
@Override
protected void onShown(){
super.onShown();
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
loadData();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Button saveButton=new Button(getActivity());
saveButton.setText(R.string.save);
saveButton.setOnClickListener(this::onSaveClick);
LinearLayout wrap=new LinearLayout(getActivity());
wrap.setOrientation(LinearLayout.HORIZONTAL);
wrap.addView(saveButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
wrap.setPadding(V.dp(16), V.dp(4), V.dp(16), V.dp(8));
wrap.setClipToPadding(false);
MenuItem item=menu.add(R.string.save);
item.setActionView(wrap);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}
private void onSaveClick(View view) {
List<String> addUserToLists = new ArrayList<>();
List<String> removeUserFromLists = new ArrayList<>();
for (Map.Entry<String, Boolean> entry : userInList.entrySet()) {
Boolean changedValue = entry.getValue();
String id = entry.getKey();
if (changedValue != null && !changedValue.equals(userInListBefore.get(id))) {
(changedValue ? addUserToLists : removeUserFromLists).add(id);
}
}
List<String> accountIdList = Collections.singletonList(profileAccountId);
for (String listId : addUserToLists) {
inProgress++;
new AddAccountsToList(listId, accountIdList).setCallback(new SimpleCallback<>(this) {
@Override
public void onSuccess(Object o) { onRequestComplete(); }
@Override
public void onError(ErrorResponse error) { super.onError(error); onSuccess(null); }
}).exec(accountId);
}
for (String listId : removeUserFromLists) {
inProgress++;
new RemoveAccountsFromList(listId, accountIdList).setCallback(new SimpleCallback<>(this) {
@Override
public void onSuccess(Object o) { onRequestComplete(); }
@Override
public void onError(ErrorResponse error) { super.onError(error); onSuccess(null); }
}).exec(accountId);
}
}
private void onRequestComplete() {
if (--inProgress == 0) reload();
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetLists()
userInListBefore.clear();
userInList.clear();
currentRequest=(profileAccountId != null ? new GetLists(profileAccountId) : new GetLists())
.setCallback(new SimpleCallback<>(this) {
@Override
public void onSuccess(List<ListTimeline> result) {
onDataLoaded(result, false);
public void onSuccess(List<ListTimeline> lists) {
for (ListTimeline l : lists) userInListBefore.put(l.id, true);
userInList.putAll(userInListBefore);
onDataLoaded(lists, false);
if (profileAccountId == null) return;
currentRequest=new GetLists().setCallback(new SimpleCallback<>(ListTimelinesFragment.this) {
@Override
public void onSuccess(List<ListTimeline> allLists) {
List<ListTimeline> newLists = new ArrayList<>();
for (ListTimeline l : allLists) {
if (lists.stream().noneMatch(e -> e.id.equals(l.id))) newLists.add(l);
if (!userInListBefore.containsKey(l.id)) {
userInListBefore.put(l.id, false);
}
}
userInList.putAll(userInListBefore);
onDataLoaded(newLists, false);
}
}).exec(accountId);
}
})
.exec(accountId);
@@ -77,15 +181,30 @@ public class ListTimelinesFragment extends BaseRecyclerFragment<ListTimeline> im
private class ListViewHolder extends BindableViewHolder<ListTimeline> implements UsableRecyclerView.Clickable{
private final TextView title;
private final CheckBox listToggle;
public ListViewHolder(){
super(getActivity(), R.layout.item_list_timeline, list);
title=findViewById(R.id.title);
listToggle=findViewById(R.id.list_toggle);
}
@Override
public void onBind(ListTimeline item) {
title.setText(item.title);
if (profileAccountId != null) {
Boolean checked = userInList.get(item.id);
listToggle.setChecked(userInList.containsKey(item.id) && checked != null && checked);
listToggle.setOnClickListener(this::onClickToggle);
} else {
listToggle.setVisibility(View.GONE);
}
}
private void onClickToggle(View view) {
if (view instanceof CheckBox cb) {
userInList.put(item.id, cb.isChecked());
}
}
@Override

View File

@@ -521,10 +521,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
return;
inflater.inflate(R.menu.profile, menu);
menu.findItem(R.id.share).setTitle(getString(R.string.share_user, account.getDisplayUsername()));
menu.findItem(R.id.manage_user_lists).setTitle(getString(R.string.lists_with_user, account.getDisplayUsername()));
if(isOwnProfile){
for(int i=0;i<menu.size();i++){
MenuItem item=menu.getItem(i);
item.setVisible(item.getItemId()==R.id.share);
item.setVisible(item.getItemId()==R.id.share || item.getItemId()==R.id.manage_user_lists);
}
return;
}
@@ -580,6 +581,12 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
})
.wrapProgress(getActivity(), R.string.loading, false)
.exec(accountID);
}else if(id==R.id.manage_user_lists){
final Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("profileAccount", profileAccountID);
args.putString("profileDisplayUsername", account.getDisplayUsername());
Nav.go(getActivity(), ListTimelinesFragment.class, args);
}
return true;
}