package org.mian.gitnex.fragments; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.gitnex.tea4j.v2.models.NotificationThread; import org.mian.gitnex.R; import org.mian.gitnex.activities.IssueDetailActivity; import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.adapters.NotificationsAdapter; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.FragmentNotificationsBinding; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.SimpleCallback; import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.contexts.IssueContext; import org.mian.gitnex.helpers.contexts.RepositoryContext; /** * @author opyale * @author M M Arif */ public class NotificationsFragment extends Fragment implements NotificationsAdapter.OnNotificationClickedListener, NotificationsAdapter.OnMoreClickedListener { private final List notificationThreads = new ArrayList<>(); private FragmentNotificationsBinding viewBinding; private NotificationsAdapter notificationsAdapter; private Activity activity; private Context context; private Menu menu; private int pageCurrentIndex = 1; private int pageResultLimit; private String currentFilterMode = "unread"; public static String emptyErrorResponse; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Nullable @Override public View onCreateView( @NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { viewBinding = FragmentNotificationsBinding.inflate(inflater, container, false); setHasOptionsMenu(true); activity = requireActivity(); context = getContext(); pageResultLimit = Constants.getCurrentResultLimit(context); notificationsAdapter = new NotificationsAdapter(context, notificationThreads, this, this); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context); viewBinding.notifications.setHasFixedSize(true); viewBinding.notifications.setLayoutManager(linearLayoutManager); viewBinding.notifications.setAdapter(notificationsAdapter); viewBinding.notifications.addOnScrollListener( new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { if (!recyclerView.canScrollVertically(1) && dy != 0) { pageCurrentIndex++; loadNotifications(true); } if (currentFilterMode.equalsIgnoreCase("unread")) { if (dy > 0 && viewBinding.markAllAsRead.isShown()) { viewBinding.markAllAsRead.setVisibility(View.GONE); } else if (dy < 0) { viewBinding.markAllAsRead.setVisibility(View.VISIBLE); } } } @Override public void onScrollStateChanged( @NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } }); viewBinding.markAllAsRead.setOnClickListener( v1 -> RetrofitClient.getApiInterface(context) .notifyReadList( null, "false", Arrays.asList("unread", "pinned"), "read") .enqueue( (SimpleCallback>) (call, voidResponse) -> { if (voidResponse.isPresent() && voidResponse.get().isSuccessful()) { SnackBar.success( context, requireActivity() .findViewById( android.R.id .content), getString( R.string .markedNotificationsAsRead)); pageCurrentIndex = 1; loadNotifications(false); } else { if (!emptyErrorResponse.isEmpty()) { if (emptyErrorResponse.contains( "205")) { SnackBar.success( context, requireActivity() .findViewById( android.R.id .content), getString( R.string .markedNotificationsAsRead)); pageCurrentIndex = 1; loadNotifications(false); } } else { activity.runOnUiThread( () -> SnackBar.error( context, requireActivity() .findViewById( android .R .id .content), getString( R.string .genericError))); } } })); viewBinding.pullToRefresh.setOnRefreshListener( () -> { viewBinding.pullToRefresh.setRefreshing(false); pageCurrentIndex = 1; loadNotifications(false); }); loadNotifications(true); return viewBinding.getRoot(); } private void loadNotifications(boolean append) { viewBinding.noDataNotifications.setVisibility(View.GONE); viewBinding.progressBar.setVisibility(View.VISIBLE); String[] filter = currentFilterMode.equals("read") ? new String[] {"pinned", "read"} : new String[] {"pinned", "unread"}; RetrofitClient.getApiInterface(context) .notifyGetList( false, Arrays.asList(filter), null, null, null, pageCurrentIndex, pageResultLimit) .enqueue( (SimpleCallback>) (call1, listResponse) -> { if (listResponse.isPresent() && listResponse.get().isSuccessful() && listResponse.get().body() != null) { if (!append) { notificationThreads.clear(); } if (listResponse.get().body() != null) { notificationThreads.addAll( Objects.requireNonNull( listResponse.get().body())); } else { notificationsAdapter.setMoreDataAvailable(false); } if (!append || Objects.requireNonNull(listResponse.get().body()) .size() > 0) { notificationsAdapter.notifyDataChanged(); } } AppUtil.setMultiVisibility(View.GONE, viewBinding.progressBar); if (notificationThreads.isEmpty()) { viewBinding.noDataNotifications.setVisibility(View.VISIBLE); } else { viewBinding.noDataNotifications.setVisibility(View.GONE); } if (currentFilterMode.equalsIgnoreCase("unread")) { if (notificationThreads.isEmpty()) { viewBinding.markAllAsRead.setVisibility(View.GONE); } else { viewBinding.markAllAsRead.setVisibility(View.VISIBLE); } } }); } private void changeFilterMode() { int filterIcon = currentFilterMode.equalsIgnoreCase("read") ? R.drawable.ic_filter_closed : R.drawable.ic_filter; menu.getItem(0).setIcon(filterIcon); if (currentFilterMode.equalsIgnoreCase("read")) { viewBinding.markAllAsRead.setVisibility(View.GONE); } else { viewBinding.markAllAsRead.setVisibility(View.VISIBLE); } } @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { this.menu = menu; inflater.inflate(R.menu.filter_menu_notifications, menu); changeFilterMode(); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { if (item.getItemId() == R.id.filterNotifications) { BottomSheetNotificationsFilterFragment bottomSheetNotificationsFilterFragment = new BottomSheetNotificationsFilterFragment(); bottomSheetNotificationsFilterFragment.show( getChildFragmentManager(), "notificationsFilterBottomSheet"); bottomSheetNotificationsFilterFragment.setOnClickListener( (text) -> { currentFilterMode = text; changeFilterMode(); pageCurrentIndex = 1; loadNotifications(false); }); return true; } return super.onOptionsItemSelected(item); } @Override public void onNotificationClicked(NotificationThread notificationThread) { if (notificationThread.isUnread() && !notificationThread.isPinned()) { RetrofitClient.getApiInterface(context) .notifyReadThread(String.valueOf(notificationThread.getId()), "read") .enqueue( (SimpleCallback) (call, voidResponse) -> { // reload without any checks, because Gitea returns a 205 // and Java expects this to be empty // but Gitea send a response -> results in a call of // onFailure and no response is present // if(voidResponse.isPresent() && // voidResponse.get().isSuccessful()) { pageCurrentIndex = 1; loadNotifications(false); // } }); } if (StringUtils.containsAny( notificationThread.getSubject().getType().toLowerCase(), "pull", "issue")) { RepositoryContext repo = new RepositoryContext( notificationThread.getRepository().getOwner().getLogin(), notificationThread.getRepository().getName(), context); // we can't use the repository object here directly because // the permissions are missing String issueUrl = notificationThread.getSubject().getUrl(); repo.saveToDB(context); Intent intent = new IssueContext( repo, Integer.parseInt( issueUrl.substring(issueUrl.lastIndexOf("/") + 1)), notificationThread.getSubject().getType()) .getIntent(context, IssueDetailActivity.class); intent.putExtra("openedFromLink", "true"); startActivity(intent); } else if (notificationThread.getSubject().getType().equalsIgnoreCase("repository")) { startActivity( new RepositoryContext(notificationThread.getRepository(), context) .getIntent(context, RepoDetailActivity.class)); } } @Override public void onMoreClicked(NotificationThread notificationThread) { BottomSheetNotificationsFragment bottomSheetNotificationsFragment = new BottomSheetNotificationsFragment(); bottomSheetNotificationsFragment.onAttach( context, notificationThread, () -> { pageCurrentIndex = 1; loadNotifications(false); }); bottomSheetNotificationsFragment.show( getChildFragmentManager(), "notificationsBottomSheet"); } }