Rearrange observers for DirectItemsAdapter so that it is never initialised without a thread
This commit is contained in:
parent
2b2f390f59
commit
482cbdab97
@ -58,6 +58,7 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
private final ProfileModel currentUser;
|
||||
private DirectThread thread;
|
||||
private final AsyncListDiffer<DirectItemOrHeader> differ;
|
||||
private List<DirectItem> items;
|
||||
|
||||
private static final DiffUtil.ItemCallback<DirectItemOrHeader> diffCallback = new DiffUtil.ItemCallback<DirectItemOrHeader>() {
|
||||
@Override
|
||||
@ -97,8 +98,10 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
}
|
||||
};
|
||||
|
||||
public DirectItemsAdapter(@NonNull final ProfileModel currentUser) {
|
||||
public DirectItemsAdapter(@NonNull final ProfileModel currentUser,
|
||||
@NonNull final DirectThread thread) {
|
||||
this.currentUser = currentUser;
|
||||
this.thread = thread;
|
||||
differ = new AsyncListDiffer<>(new AdapterListUpdateCallback(this),
|
||||
new AsyncDifferConfig.Builder<>(diffCallback).build());
|
||||
// this.onClickListener = onClickListener;
|
||||
@ -118,9 +121,10 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
return getItemViewHolder(layoutInflater, baseBinding, directItemType);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private DirectItemViewHolder getItemViewHolder(final LayoutInflater layoutInflater,
|
||||
final LayoutDmBaseBinding baseBinding,
|
||||
final DirectItemType directItemType) {
|
||||
@NonNull final DirectItemType directItemType) {
|
||||
switch (directItemType) {
|
||||
case TEXT: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
@ -232,6 +236,7 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
public void setThread(final DirectThread thread) {
|
||||
if (thread == null) return;
|
||||
this.thread = thread;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void submitList(@Nullable final List<DirectItem> list) {
|
||||
@ -240,6 +245,7 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
return;
|
||||
}
|
||||
differ.submitList(sectionAndSort(list));
|
||||
this.items = list;
|
||||
}
|
||||
|
||||
public void submitList(@Nullable final List<DirectItem> list, @Nullable final Runnable commitCallback) {
|
||||
@ -248,6 +254,7 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
return;
|
||||
}
|
||||
differ.submitList(sectionAndSort(list), commitCallback);
|
||||
this.items = list;
|
||||
}
|
||||
|
||||
private List<DirectItemOrHeader> sectionAndSort(final List<DirectItem> list) {
|
||||
@ -289,6 +296,10 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
return differ.getCurrentList();
|
||||
}
|
||||
|
||||
public List<DirectItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull final RecyclerView.ViewHolder holder) {
|
||||
if (holder instanceof DirectItemViewHolder) {
|
||||
@ -303,6 +314,10 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
}
|
||||
}
|
||||
|
||||
public DirectThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
public static class DirectItemOrHeader {
|
||||
Date date;
|
||||
DirectItem item;
|
||||
|
@ -49,7 +49,7 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public DirectItemViewHolder(@NonNull final LayoutDmBaseBinding binding,
|
||||
@NonNull final ProfileModel currentUser,
|
||||
final DirectThread thread,
|
||||
@NonNull final DirectThread thread,
|
||||
@NonNull final View.OnClickListener onClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
|
@ -14,6 +14,7 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@ -30,6 +31,8 @@ import androidx.appcompat.app.ActionBar;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MediatorLiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.lifecycle.ViewModelStoreOwner;
|
||||
@ -313,10 +316,8 @@ public class DirectMessageThreadFragment extends Fragment {
|
||||
super.onResume();
|
||||
fragmentActivity.getWindow().setSoftInputMode(SOFT_INPUT_ADJUST_NOTHING | SOFT_INPUT_STATE_HIDDEN);
|
||||
if (wasKbShowing) {
|
||||
appExecutors.mainThread().execute(() -> {
|
||||
binding.input.requestFocus();
|
||||
binding.input.post(this::showKeyboard);
|
||||
});
|
||||
binding.input.requestFocus();
|
||||
binding.input.post(this::showKeyboard);
|
||||
wasKbShowing = false;
|
||||
}
|
||||
setObservers();
|
||||
@ -332,12 +333,6 @@ public class DirectMessageThreadFragment extends Fragment {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
if (prevTitleRunnable != null) {
|
||||
appExecutors.mainThread().cancel(prevTitleRunnable);
|
||||
@ -363,13 +358,14 @@ public class DirectMessageThreadFragment extends Fragment {
|
||||
if (context == null) return;
|
||||
if (getArguments() == null) return;
|
||||
actionBar = fragmentActivity.getSupportActionBar();
|
||||
setObservers();
|
||||
final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(getArguments());
|
||||
viewModel.getThreadTitle().postValue(fragmentArgs.getTitle());
|
||||
final String threadId = fragmentArgs.getThreadId();
|
||||
viewModel.setThreadId(threadId);
|
||||
setupList();
|
||||
root.post(this::setupInput);
|
||||
root.post(this::getInitialData);
|
||||
setObservers();
|
||||
}
|
||||
|
||||
private void getInitialData() {
|
||||
@ -386,9 +382,6 @@ public class DirectMessageThreadFragment extends Fragment {
|
||||
// setTitle(UPDATING_TITLE);
|
||||
final DirectThread thread = first.get();
|
||||
viewModel.setThread(thread);
|
||||
if (itemsAdapter != null) {
|
||||
itemsAdapter.setThread(thread);
|
||||
}
|
||||
return;
|
||||
}
|
||||
viewModel.fetchChats();
|
||||
@ -554,29 +547,12 @@ public class DirectMessageThreadFragment extends Fragment {
|
||||
}
|
||||
setTitle(viewModel.getThreadTitle().getValue());
|
||||
});
|
||||
viewModel.getThread().observe(getViewLifecycleOwner(), thread -> {
|
||||
if (thread != null && itemsAdapter != null) itemsAdapter.setThread(thread);
|
||||
});
|
||||
appStateViewModel.getCurrentUser().observe(getViewLifecycleOwner(), currentUser -> {
|
||||
viewModel.setCurrentUser(currentUser);
|
||||
setupItemsAdapter(currentUser);
|
||||
viewModel.getItems().observe(
|
||||
getViewLifecycleOwner(),
|
||||
list -> itemsAdapter.submitList(list, () -> {
|
||||
itemOrHeaders = itemsAdapter.getList();
|
||||
binding.chats.post(() -> {
|
||||
final RecyclerView.LayoutManager layoutManager = binding.chats.getLayoutManager();
|
||||
if (layoutManager instanceof LinearLayoutManager) {
|
||||
final int position = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
|
||||
if (position < 0) return;
|
||||
if (position == itemsAdapter.getItemCount() - 1) {
|
||||
viewModel.fetchChats();
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
final ItemsAdapterDataMerger itemsAdapterDataMerger = new ItemsAdapterDataMerger(appStateViewModel.getCurrentUser(), viewModel.getThread());
|
||||
itemsAdapterDataMerger.observe(getViewLifecycleOwner(), userThreadPair -> {
|
||||
viewModel.setCurrentUser(userThreadPair.first);
|
||||
setupItemsAdapter(userThreadPair.first, userThreadPair.second);
|
||||
});
|
||||
viewModel.getItems().observe(getViewLifecycleOwner(), this::submitItemsToAdapter);
|
||||
final NavController navController = NavHostFragment.findNavController(this);
|
||||
final NavBackStackEntry backStackEntry = navController.getCurrentBackStackEntry();
|
||||
if (backStackEntry != null) {
|
||||
@ -585,15 +561,47 @@ public class DirectMessageThreadFragment extends Fragment {
|
||||
if (!(result instanceof Uri)) return;
|
||||
final Uri uri = (Uri) result;
|
||||
viewModel.sendUri(uri);
|
||||
// clear result
|
||||
resultLiveData.postValue(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setupItemsAdapter(final ProfileModel currentUser) {
|
||||
if (itemsAdapter != null) return;
|
||||
itemsAdapter = new DirectItemsAdapter(currentUser);
|
||||
private void submitItemsToAdapter(final List<DirectItem> items) {
|
||||
if (itemsAdapter == null) return;
|
||||
itemsAdapter.submitList(items, () -> {
|
||||
itemOrHeaders = itemsAdapter.getList();
|
||||
binding.chats.post(() -> {
|
||||
final RecyclerView.LayoutManager layoutManager = binding.chats.getLayoutManager();
|
||||
if (layoutManager instanceof LinearLayoutManager) {
|
||||
final int position = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
|
||||
if (position < 0) return;
|
||||
if (position == itemsAdapter.getItemCount() - 1) {
|
||||
viewModel.fetchChats();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void setupItemsAdapter(final ProfileModel currentUser, final DirectThread thread) {
|
||||
if (itemsAdapter != null) {
|
||||
if (itemsAdapter.getThread() == thread) return;
|
||||
itemsAdapter.setThread(thread);
|
||||
return;
|
||||
}
|
||||
itemsAdapter = new DirectItemsAdapter(currentUser, thread);
|
||||
itemsAdapter.setHasStableIds(true);
|
||||
itemsAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY);
|
||||
binding.chats.setAdapter(itemsAdapter);
|
||||
registerDataObserver();
|
||||
final List<DirectItem> items = viewModel.getItems().getValue();
|
||||
if (items != null && itemsAdapter.getItems() != items) {
|
||||
submitItemsToAdapter(items);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDataObserver() {
|
||||
itemsAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
|
||||
@Override
|
||||
@ -607,7 +615,6 @@ public class DirectMessageThreadFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
});
|
||||
root.post(this::getInitialData);
|
||||
}
|
||||
|
||||
private void setupInput() {
|
||||
@ -1097,4 +1104,26 @@ public class DirectMessageThreadFragment extends Fragment {
|
||||
});
|
||||
animatorSet.start();
|
||||
}
|
||||
|
||||
public static class ItemsAdapterDataMerger extends MediatorLiveData<Pair<ProfileModel, DirectThread>> {
|
||||
private ProfileModel user;
|
||||
private DirectThread thread;
|
||||
|
||||
public ItemsAdapterDataMerger(final LiveData<ProfileModel> userLiveData,
|
||||
final LiveData<DirectThread> threadLiveData) {
|
||||
addSource(userLiveData, user -> {
|
||||
this.user = user;
|
||||
combine();
|
||||
});
|
||||
addSource(threadLiveData, thread -> {
|
||||
this.thread = thread;
|
||||
combine();
|
||||
});
|
||||
}
|
||||
|
||||
private void combine() {
|
||||
if (user == null || thread == null) return;
|
||||
setValue(new Pair<>(user, thread));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user