fedilab-Android-App/app/src/main/java/app/fedilab/android/mastodon/activities/MastodonListActivity.java

496 lines
29 KiB
Java

package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* 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.
*
* Fedilab 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 Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.BuildConfig;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityListBinding;
import app.fedilab.android.databinding.PopupAddListBinding;
import app.fedilab.android.databinding.PopupManageAccountsListBinding;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.MastodonList;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.client.entities.app.Pinned;
import app.fedilab.android.mastodon.client.entities.app.PinnedTimeline;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.ui.drawer.AccountListAdapter;
import app.fedilab.android.mastodon.ui.drawer.MastodonListAdapter;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.ReorderVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.TimelinesVM;
import es.dmoral.toasty.Toasty;
public class MastodonListActivity extends BaseBarActivity implements MastodonListAdapter.ActionOnList {
AccountListAdapter accountsInListAdapter;
private ActivityListBinding binding;
private boolean canGoBack;
private TimelinesVM timelinesVM;
private MastodonList mastodonList;
private ArrayList<MastodonList> mastodonListList;
private MastodonListAdapter mastodonListAdapter;
private AccountsVM accountsVM;
private List<Account> accountsInList;
private boolean flagLoading;
private String max_id;
private FragmentMastodonTimeline fragmentMastodonTimeline;
private boolean orderASC;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityListBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
canGoBack = false;
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
flagLoading = false;
orderASC = true;
max_id = null;
accountsVM = new ViewModelProvider(MastodonListActivity.this).get(AccountsVM.class);
timelinesVM = new ViewModelProvider(MastodonListActivity.this).get(TimelinesVM.class);
timelinesVM.getLists(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
.observe(MastodonListActivity.this, mastodonLists -> {
ReorderVM reorderVM = new ViewModelProvider(MastodonListActivity.this).get(ReorderVM.class);
reorderVM.getPinned().observe(MastodonListActivity.this, pinned -> {
if (mastodonLists != null && mastodonLists.size() > 0) {
mastodonListList = new ArrayList<>(mastodonLists);
if (pinned != null) {
if (pinned.pinnedTimelines != null && pinned.pinnedTimelines.size() > 0) {
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.type == Timeline.TimeLineEnum.LIST) {
for (MastodonList mastodonList : mastodonLists) {
if (mastodonList.id.equalsIgnoreCase(pinnedTimeline.mastodonList.id)) {
mastodonList.position = pinnedTimeline.position;
}
}
}
}
}
}
sortAsc(mastodonListList);
mastodonListAdapter = new MastodonListAdapter(mastodonListList);
mastodonListAdapter.actionOnList = this;
binding.notContent.setVisibility(View.GONE);
binding.recyclerView.setAdapter(mastodonListAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(MastodonListActivity.this));
} else {
binding.notContent.setVisibility(View.VISIBLE);
}
});
});
getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (canGoBack) {
canGoBack = false;
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.recyclerView, () -> {
if (fragmentMastodonTimeline != null) {
fragmentMastodonTimeline.onDestroyView();
}
});
setTitle(R.string.action_lists);
invalidateOptionsMenu();
} else {
finish();
}
}
});
}
private void sortAsc(List<MastodonList> mastodonLists) {
Collections.sort(mastodonLists, (obj1, obj2) -> obj1.title.compareToIgnoreCase(obj2.title));
orderASC = true;
invalidateOptionsMenu();
}
private void sortDesc(List<MastodonList> mastodonLists) {
Collections.sort(mastodonLists, (obj1, obj2) -> obj2.title.compareToIgnoreCase(obj1.title));
orderASC = false;
invalidateOptionsMenu();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getOnBackPressedDispatcher().onBackPressed();
return true;
} else if (item.getItemId() == R.id.action_user_mute_home) {
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(MastodonListActivity.this);
dialogBuilder.setTitle(R.string.put_all_accounts_in_home_muted);
dialogBuilder.setPositiveButton(R.string.mute_them_all, (dialog, id) -> {
timelinesVM.getAccountsInList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id, null, null, 0)
.observe(MastodonListActivity.this, accounts -> {
if (accounts != null && accounts.size() > 0) {
accountsVM.muteAccountsHome(Helper.getCurrentAccount(MastodonListActivity.this), accounts);
}
});
dialog.dismiss();
});
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
dialogBuilder.show();
} else if (item.getItemId() == R.id.action_manage_users) {
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(MastodonListActivity.this);
PopupManageAccountsListBinding popupManageAccountsListBinding = PopupManageAccountsListBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupManageAccountsListBinding.getRoot());
popupManageAccountsListBinding.loader.setVisibility(View.VISIBLE);
popupManageAccountsListBinding.searchAccount.setOnTouchListener((v, event) -> {
final int DRAWABLE_RIGHT = 2;
if (event.getAction() == MotionEvent.ACTION_UP) {
if (popupManageAccountsListBinding.searchAccount.length() > 0 && event.getRawX() >= (popupManageAccountsListBinding.searchAccount.getRight() - popupManageAccountsListBinding.searchAccount.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
popupManageAccountsListBinding.searchAccount.setText("");
}
}
return false;
});
timelinesVM.getAccountsInList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id, null, null, 10)
.observe(MastodonListActivity.this, accounts -> {
popupManageAccountsListBinding.loader.setVisibility(View.GONE);
accountsInList = accounts;
if (accountsInList == null) {
accountsInList = new ArrayList<>();
}
if (accountsInList.size() > 0) {
max_id = accountsInList.get(accountsInList.size() - 1).id;
popupManageAccountsListBinding.noContent.setVisibility(View.GONE);
popupManageAccountsListBinding.lvAccountsCurrent.setVisibility(View.VISIBLE);
} else {
popupManageAccountsListBinding.noContent.setVisibility(View.VISIBLE);
popupManageAccountsListBinding.lvAccountsCurrent.setVisibility(View.GONE);
}
accountsInListAdapter = new AccountListAdapter(mastodonList, accountsInList, null);
popupManageAccountsListBinding.lvAccountsCurrent.setAdapter(accountsInListAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MastodonListActivity.this);
popupManageAccountsListBinding.lvAccountsCurrent.setLayoutManager(linearLayoutManager);
popupManageAccountsListBinding.lvAccountsCurrent.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
int firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
if (dy > 0) {
int visibleItemCount = linearLayoutManager.getChildCount();
int totalItemCount = linearLayoutManager.getItemCount();
if (firstVisibleItem + visibleItemCount == totalItemCount) {
if (!flagLoading) {
flagLoading = true;
timelinesVM.getAccountsInList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id, max_id, null, 10)
.observe(MastodonListActivity.this, accounts -> {
if (accounts != null && accounts.size() > 0) {
int position = accountsInList.size();
max_id = accountsInList.get(accounts.size() - 1).id;
accountsInList.addAll(accounts);
accountsInListAdapter.notifyItemRangeChanged(position, accounts.size());
}
});
}
}
}
}
});
});
popupManageAccountsListBinding.searchAccount.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (count > 0) {
popupManageAccountsListBinding.searchAccount.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_baseline_close_24, 0);
} else {
popupManageAccountsListBinding.searchAccount.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_baseline_search_24, 0);
}
}
@Override
public void afterTextChanged(Editable s) {
if (s != null && s.length() > 0) {
accountsVM.searchAccounts(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, s.toString(), 20, true, true)
.observe(MastodonListActivity.this, accounts -> {
popupManageAccountsListBinding.lvAccountsSearch.setVisibility(View.VISIBLE);
popupManageAccountsListBinding.lvAccountsCurrent.setVisibility(View.GONE);
AccountListAdapter accountListAdapter = new AccountListAdapter(mastodonList, accountsInList, accounts);
popupManageAccountsListBinding.lvAccountsSearch.setAdapter(accountListAdapter);
popupManageAccountsListBinding.lvAccountsSearch.setLayoutManager(new LinearLayoutManager(MastodonListActivity.this));
});
} else {
popupManageAccountsListBinding.lvAccountsSearch.setVisibility(View.GONE);
popupManageAccountsListBinding.lvAccountsCurrent.setVisibility(View.VISIBLE);
}
}
});
dialogBuilder.setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss());
dialogBuilder.create().show();
} else if (item.getItemId() == R.id.action_delete && mastodonList != null) {
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(MastodonListActivity.this);
alt_bld.setTitle(R.string.action_lists_delete);
alt_bld.setMessage(R.string.action_lists_confirm_delete);
alt_bld.setPositiveButton(R.string.delete, (dialog, id) -> {
timelinesVM.deleteList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id);
int position = 0;
for (MastodonList mastodonListTmp : mastodonListList) {
if (mastodonListTmp.id.equalsIgnoreCase(mastodonList.id)) {
break;
}
position++;
}
mastodonListList.remove(position);
mastodonListAdapter.notifyItemRemoved(position);
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.recyclerView, () -> {
canGoBack = false;
if (fragmentMastodonTimeline != null) {
fragmentMastodonTimeline.onDestroyView();
}
invalidateOptionsMenu();
setTitle(R.string.action_lists);
});
if (mastodonListList.size() == 0) {
binding.notContent.setVisibility(View.VISIBLE);
} else {
binding.notContent.setVisibility(View.GONE);
}
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
args.putSerializable(Helper.RECEIVE_MASTODON_LIST, mastodonListList);
new CachedBundle(MastodonListActivity.this).insertBundle(args, Helper.getCurrentAccount(MastodonListActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
intentBD.setPackage(BuildConfig.APPLICATION_ID);
sendBroadcast(intentBD);
});
});
alt_bld.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
AlertDialog alert = alt_bld.create();
alert.show();
} else if (item.getItemId() == R.id.action_add_list) {
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(MastodonListActivity.this);
PopupAddListBinding popupAddListBinding = PopupAddListBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupAddListBinding.getRoot());
popupAddListBinding.addList.setFilters(new InputFilter[]{new InputFilter.LengthFilter(255)});
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
if (popupAddListBinding.addList.getText() != null && popupAddListBinding.addList.getText().toString().trim().length() > 0) {
timelinesVM.createList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, popupAddListBinding.addList.getText().toString().trim(), null)
.observe(MastodonListActivity.this, newMastodonList -> {
if (mastodonListList == null) {
mastodonListList = new ArrayList<>();
}
if (newMastodonList != null) {
mastodonListList.add(0, newMastodonList);
if (mastodonListAdapter == null) {
mastodonListAdapter = new MastodonListAdapter(mastodonListList);
mastodonListAdapter.actionOnList = MastodonListActivity.this;
binding.notContent.setVisibility(View.GONE);
binding.recyclerView.setAdapter(mastodonListAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(MastodonListActivity.this));
}
mastodonListAdapter.notifyItemInserted(0);
} else {
Toasty.error(MastodonListActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
}
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
args.putSerializable(Helper.RECEIVE_MASTODON_LIST, mastodonListList);
new CachedBundle(MastodonListActivity.this).insertBundle(args, Helper.getCurrentAccount(MastodonListActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
intentBD.setPackage(BuildConfig.APPLICATION_ID);
sendBroadcast(intentBD);
});
});
dialog.dismiss();
} else {
popupAddListBinding.addList.setError(getString(R.string.not_valid_list_name));
}
});
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
dialogBuilder.create().show();
} else if (item.getItemId() == R.id.action_edit) {
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(MastodonListActivity.this);
PopupAddListBinding popupAddListBinding = PopupAddListBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupAddListBinding.getRoot());
popupAddListBinding.addList.setFilters(new InputFilter[]{new InputFilter.LengthFilter(255)});
popupAddListBinding.addList.setText(mastodonList.title);
popupAddListBinding.addList.setSelection(Objects.requireNonNull(popupAddListBinding.addList.getText()).length());
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
if (popupAddListBinding.addList.getText() != null && popupAddListBinding.addList.getText().toString().trim().length() > 0) {
timelinesVM.updateList(
BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id,
popupAddListBinding.addList.getText().toString().trim(), null)
.observe(MastodonListActivity.this, newMastodonList -> {
if (mastodonListList != null && newMastodonList != null) {
int position = 0;
for (MastodonList mastodonList : mastodonListList) {
if (newMastodonList.id.equalsIgnoreCase(mastodonList.id)) {
ReorderVM reorderVM = new ViewModelProvider(MastodonListActivity.this).get(ReorderVM.class);
int finalPosition = position;
reorderVM.getAllPinned().observe(MastodonListActivity.this, pinned -> {
if (pinned != null) {
if (pinned.pinnedTimelines != null) {
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.mastodonList != null) {
if (pinnedTimeline.mastodonList.id.equalsIgnoreCase(newMastodonList.id)) {
if (!newMastodonList.title.equalsIgnoreCase(pinnedTimeline.mastodonList.title)) {
pinnedTimeline.mastodonList.title = newMastodonList.title;
setTitle(newMastodonList.title);
mastodonListList.get(finalPosition).title = newMastodonList.title;
mastodonListAdapter.notifyItemChanged(finalPosition);
new Thread(() -> {
try {
new Pinned(MastodonListActivity.this).updatePinned(pinned);
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(MastodonListActivity.this).insertBundle(args, Helper.getCurrentAccount(MastodonListActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
intentBD.setPackage(BuildConfig.APPLICATION_ID);
sendBroadcast(intentBD);
});
} catch (
DBException e) {
e.printStackTrace();
}
}).start();
}
break;
}
}
}
}
}
});
}
position++;
}
} else {
Toasty.error(MastodonListActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
}
});
dialog.dismiss();
} else {
popupAddListBinding.addList.setError(getString(R.string.not_valid_list_name));
}
});
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
dialogBuilder.create().show();
} else if (item.getItemId() == R.id.action_order) {
if (mastodonListList != null && mastodonListList.size() > 0 && mastodonListAdapter != null) {
if (orderASC) {
sortDesc(mastodonListList);
} else {
sortAsc(mastodonListList);
}
invalidateOptionsMenu();
mastodonListAdapter.notifyItemRangeChanged(0, mastodonListList.size());
}
}
return super.onOptionsItemSelected(item);
}
@Override
public void click(MastodonList mastodonList) {
this.mastodonList = mastodonList;
canGoBack = true;
ThemeHelper.slideViewsToLeft(binding.recyclerView, binding.fragmentContainer, () -> {
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_LIST_ID, mastodonList.id);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.LIST);
setTitle(mastodonList.title);
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
invalidateOptionsMenu();
});
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
if (!canGoBack) {
getMenuInflater().inflate(R.menu.menu_main_list, menu);
MenuItem order = menu.findItem(R.id.action_order);
if (order != null) {
if (orderASC) {
order.setIcon(R.drawable.ic_baseline_filter_asc_24);
} else {
order.setIcon(R.drawable.ic_baseline_filter_desc_24);
}
}
} else {
getMenuInflater().inflate(R.menu.menu_list, menu);
}
return true;
}
}