BarInsta/app/src/main/java/awais/instagrabber/fragments/comments/CommentsViewerFragment.java

259 lines
11 KiB
Java

package awais.instagrabber.fragments.comments;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.snackbar.Snackbar;
import java.util.Collections;
import java.util.List;
import awais.instagrabber.R;
import awais.instagrabber.adapters.CommentsAdapter;
import awais.instagrabber.customviews.helpers.RecyclerLazyLoader;
import awais.instagrabber.databinding.FragmentCommentsBinding;
import awais.instagrabber.fragments.settings.PreferenceKeys;
import awais.instagrabber.models.Comment;
import awais.instagrabber.models.Resource;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
import awais.instagrabber.viewmodels.AppStateViewModel;
import awais.instagrabber.viewmodels.CommentsViewerViewModel;
public final class CommentsViewerFragment extends BottomSheetDialogFragment {
private static final String TAG = CommentsViewerFragment.class.getSimpleName();
private CommentsViewerViewModel viewModel;
private CommentsAdapter commentsAdapter;
private FragmentCommentsBinding binding;
private ConstraintLayout root;
private boolean shouldRefresh = true;
private AppStateViewModel appStateViewModel;
private boolean showingReplies;
@Override
public void onStart() {
super.onStart();
final Dialog dialog = getDialog();
if (dialog == null) return;
final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog;
final View bottomSheetInternal = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
if (bottomSheetInternal == null) return;
bottomSheetInternal.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
bottomSheetInternal.requestLayout();
final BottomSheetBehavior<View> behavior = BottomSheetBehavior.from(bottomSheetInternal);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
behavior.setSkipCollapsed(true);
}
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final FragmentActivity activity = getActivity();
if (activity == null) return;
viewModel = new ViewModelProvider(this).get(CommentsViewerViewModel.class);
appStateViewModel = new ViewModelProvider(activity).get(AppStateViewModel.class);
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
return new BottomSheetDialog(requireContext(), getTheme()) {
@Override
public void onBackPressed() {
if (showingReplies) {
getChildFragmentManager().popBackStack();
showingReplies = false;
return;
}
super.onBackPressed();
}
};
}
@NonNull
@Override
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
if (root != null) {
shouldRefresh = false;
return root;
}
binding = FragmentCommentsBinding.inflate(getLayoutInflater());
binding.swipeRefreshLayout.setEnabled(false);
binding.swipeRefreshLayout.setNestedScrollingEnabled(false);
root = binding.getRoot();
appStateViewModel.getCurrentUserLiveData().observe(getViewLifecycleOwner(), userResource -> {
if (userResource == null || userResource.status == Resource.Status.LOADING) return;
viewModel.setCurrentUser(userResource.data);
if (userResource.data == null) {
viewModel.fetchComments();
return;
}
viewModel.getCurrentUserId().observe(getViewLifecycleOwner(), new Observer<Long>() {
@Override
public void onChanged(final Long i) {
if (i != 0L) {
viewModel.fetchComments();
viewModel.getCurrentUserId().removeObserver(this);
}
}
});
});
if (getArguments() == null) return root;
final CommentsViewerFragmentArgs args = CommentsViewerFragmentArgs.fromBundle(getArguments());
viewModel.setPostDetails(args.getShortCode(), args.getPostId(), args.getPostUserId());
return root;
}
@Override
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
if (!shouldRefresh) return;
shouldRefresh = false;
init();
}
private void init() {
setupToolbar();
setupList();
setupObservers();
}
private void setupObservers() {
viewModel.getCurrentUserId().observe(getViewLifecycleOwner(), currentUserId -> {
long userId = 0;
if (currentUserId != null) {
userId = currentUserId;
}
setupAdapter(userId);
if (userId == 0) return;
Helper.setupCommentInput(binding.commentField, binding.commentText, false, text -> {
final LiveData<Resource<Object>> resourceLiveData = viewModel.comment(text, false);
resourceLiveData.observe(getViewLifecycleOwner(), new Observer<Resource<Object>>() {
@Override
public void onChanged(final Resource<Object> objectResource) {
if (objectResource == null) return;
final Context context = getContext();
if (context == null) return;
Helper.handleCommentResource(
context,
objectResource.status,
objectResource.message,
resourceLiveData,
this,
binding.commentField,
binding.commentText,
binding.comments);
}
});
return null;
});
});
viewModel.getRootList().observe(getViewLifecycleOwner(), listResource -> {
if (listResource == null) return;
switch (listResource.status) {
case SUCCESS:
binding.swipeRefreshLayout.setRefreshing(false);
if (commentsAdapter != null) {
commentsAdapter.submitList(listResource.data);
}
break;
case ERROR:
binding.swipeRefreshLayout.setRefreshing(false);
if (!TextUtils.isEmpty(listResource.message)) {
Snackbar.make(binding.getRoot(), listResource.message, Snackbar.LENGTH_LONG).show();
}
break;
case LOADING:
binding.swipeRefreshLayout.setRefreshing(true);
break;
}
});
viewModel.getRootCommentsCount().observe(getViewLifecycleOwner(), count -> {
if (count == null || count == 0) {
binding.toolbar.setTitle(R.string.title_comments);
return;
}
final String titleComments = getString(R.string.title_comments);
final String countString = String.valueOf(count);
final SpannableString titleWithCount = new SpannableString(String.format("%s %s", titleComments, countString));
titleWithCount.setSpan(new RelativeSizeSpan(0.8f),
titleWithCount.length() - countString.length(),
titleWithCount.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
binding.toolbar.setTitle(titleWithCount);
});
}
private void setupToolbar() {
binding.toolbar.setTitle(R.string.title_comments);
}
private void setupAdapter(final long currentUserId) {
final Context context = getContext();
if (context == null) return;
commentsAdapter = new CommentsAdapter(currentUserId, false, Helper.getCommentCallback(
context,
getViewLifecycleOwner(),
getNavController(),
viewModel,
(comment, focusInput) -> {
if (comment == null) return null;
final boolean disableTransition = Utils.settingsHelper.getBoolean(PreferenceKeys.PREF_DISABLE_SCREEN_TRANSITIONS);
final RepliesFragment repliesFragment = RepliesFragment.newInstance(comment, focusInput != null && focusInput);
final FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
if (!disableTransition) {
transaction.setCustomAnimations(R.anim.slide_left, R.anim.slide_right, 0, R.anim.slide_right);
}
transaction.add(R.id.replies_container_view, repliesFragment)
.addToBackStack(RepliesFragment.TAG)
.commit();
showingReplies = true;
return null;
}));
final Resource<List<Comment>> listResource = viewModel.getRootList().getValue();
binding.comments.setAdapter(commentsAdapter);
commentsAdapter.submitList(listResource != null ? listResource.data : Collections.emptyList());
}
private void setupList() {
final Context context = getContext();
if (context == null) return;
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
final RecyclerLazyLoader lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> viewModel.fetchComments());
Helper.setupList(context, binding.comments, layoutManager, lazyLoader);
}
@Nullable
private NavController getNavController() {
NavController navController = null;
try {
navController = NavHostFragment.findNavController(this);
} catch (IllegalStateException e) {
Log.e(TAG, "navigateToProfile", e);
}
return navController;
}
}