mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-26 16:47:30 +00:00
Add pending inbox
This commit is contained in:
parent
6aee7ea863
commit
5e3aed38b9
@ -1,11 +1,15 @@
|
|||||||
package awais.instagrabber.fragments.directmessages;
|
package awais.instagrabber.fragments.directmessages;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
@ -17,11 +21,13 @@ import androidx.lifecycle.Observer;
|
|||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.lifecycle.ViewModelStoreOwner;
|
import androidx.lifecycle.ViewModelStoreOwner;
|
||||||
import androidx.navigation.NavController;
|
import androidx.navigation.NavController;
|
||||||
|
import androidx.navigation.NavDirections;
|
||||||
import androidx.navigation.fragment.NavHostFragment;
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
|
|
||||||
import com.google.android.material.badge.BadgeDrawable;
|
import com.google.android.material.badge.BadgeDrawable;
|
||||||
|
import com.google.android.material.badge.BadgeUtils;
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -41,7 +47,6 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
|||||||
private CoordinatorLayout root;
|
private CoordinatorLayout root;
|
||||||
private RecyclerLazyLoaderAtEdge lazyLoader;
|
private RecyclerLazyLoaderAtEdge lazyLoader;
|
||||||
private DirectInboxViewModel viewModel;
|
private DirectInboxViewModel viewModel;
|
||||||
// private boolean refreshInbox = false;
|
|
||||||
private boolean shouldRefresh = true;
|
private boolean shouldRefresh = true;
|
||||||
private FragmentDirectMessagesInboxBinding binding;
|
private FragmentDirectMessagesInboxBinding binding;
|
||||||
private DMRefreshBroadcastReceiver receiver;
|
private DMRefreshBroadcastReceiver receiver;
|
||||||
@ -50,6 +55,9 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
|||||||
private boolean scrollToTop = false;
|
private boolean scrollToTop = false;
|
||||||
private boolean navigating;
|
private boolean navigating;
|
||||||
private Observer<List<DirectThread>> threadsObserver;
|
private Observer<List<DirectThread>> threadsObserver;
|
||||||
|
private MenuItem pendingRequestsMenuItem;
|
||||||
|
private BadgeDrawable pendingRequestTotalBadgeDrawable;
|
||||||
|
private boolean isPendingRequestTotalBadgeAttached;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
@ -60,6 +68,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
|||||||
final ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
final ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
||||||
viewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectInboxViewModel.class);
|
viewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectInboxViewModel.class);
|
||||||
}
|
}
|
||||||
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -99,7 +108,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
observeViewModel();
|
setupObservers();
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
receiver = new DMRefreshBroadcastReceiver(() -> {
|
receiver = new DMRefreshBroadcastReceiver(() -> {
|
||||||
@ -109,10 +118,36 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
|||||||
context.registerReceiver(receiver, new IntentFilter(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM));
|
context.registerReceiver(receiver, new IntentFilter(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnsafeExperimentalUsageError")
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
unregisterReceiver();
|
unregisterReceiver();
|
||||||
|
isPendingRequestTotalBadgeAttached = false;
|
||||||
|
if (pendingRequestTotalBadgeDrawable != null) {
|
||||||
|
BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId());
|
||||||
|
pendingRequestTotalBadgeDrawable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
pendingRequestsMenuItem = menu.add(Menu.NONE, R.id.pending_requests, Menu.NONE, "Pending requests");
|
||||||
|
pendingRequestsMenuItem.setIcon(R.drawable.ic_account_clock_24)
|
||||||
|
.setVisible(false)
|
||||||
|
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||||
|
attachPendingRequestsBadge(viewModel.getPendingRequestsTotal().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
||||||
|
if (item.getItemId() == R.id.pending_requests) {
|
||||||
|
final NavDirections directions = DirectMessageInboxFragmentDirections.actionInboxToPendingInbox();
|
||||||
|
NavHostFragment.findNavController(this).navigate(directions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unregisterReceiver() {
|
private void unregisterReceiver() {
|
||||||
@ -136,7 +171,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
|||||||
viewModel.onDestroy();
|
viewModel.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void observeViewModel() {
|
private void setupObservers() {
|
||||||
threadsObserver = list -> {
|
threadsObserver = list -> {
|
||||||
if (inboxAdapter == null) return;
|
if (inboxAdapter == null) return;
|
||||||
inboxAdapter.submitList(list, () -> {
|
inboxAdapter.submitList(list, () -> {
|
||||||
@ -148,6 +183,31 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
|||||||
viewModel.getThreads().observe(fragmentActivity, threadsObserver);
|
viewModel.getThreads().observe(fragmentActivity, threadsObserver);
|
||||||
viewModel.getFetchingInbox().observe(getViewLifecycleOwner(), fetching -> binding.swipeRefreshLayout.setRefreshing(fetching));
|
viewModel.getFetchingInbox().observe(getViewLifecycleOwner(), fetching -> binding.swipeRefreshLayout.setRefreshing(fetching));
|
||||||
viewModel.getUnseenCount().observe(getViewLifecycleOwner(), this::setBottomNavBarBadge);
|
viewModel.getUnseenCount().observe(getViewLifecycleOwner(), this::setBottomNavBarBadge);
|
||||||
|
viewModel.getPendingRequestsTotal().observe(getViewLifecycleOwner(), this::attachPendingRequestsBadge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnsafeExperimentalUsageError")
|
||||||
|
private void attachPendingRequestsBadge(@Nullable final Integer count) {
|
||||||
|
if (pendingRequestsMenuItem == null) return;
|
||||||
|
if (pendingRequestTotalBadgeDrawable == null) {
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
pendingRequestTotalBadgeDrawable = BadgeDrawable.create(context);
|
||||||
|
}
|
||||||
|
if (count == null || count == 0) {
|
||||||
|
BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId());
|
||||||
|
isPendingRequestTotalBadgeAttached = false;
|
||||||
|
pendingRequestTotalBadgeDrawable.setNumber(0);
|
||||||
|
pendingRequestsMenuItem.setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pendingRequestsMenuItem.setVisible(true);
|
||||||
|
if (pendingRequestTotalBadgeDrawable.getNumber() == count) return;
|
||||||
|
pendingRequestTotalBadgeDrawable.setNumber(count);
|
||||||
|
if (!isPendingRequestTotalBadgeAttached) {
|
||||||
|
BadgeUtils.attachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId());
|
||||||
|
isPendingRequestTotalBadgeAttached = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeViewModelObservers() {
|
private void removeViewModelObservers() {
|
||||||
@ -161,7 +221,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
|||||||
private void init() {
|
private void init() {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
observeViewModel();
|
setupObservers();
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener(this);
|
binding.swipeRefreshLayout.setOnRefreshListener(this);
|
||||||
binding.inboxList.setHasFixedSize(true);
|
binding.inboxList.setHasFixedSize(true);
|
||||||
binding.inboxList.setItemViewCacheSize(20);
|
binding.inboxList.setItemViewCacheSize(20);
|
||||||
|
@ -56,6 +56,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
|||||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse;
|
import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse;
|
||||||
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
|
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
|
||||||
import awais.instagrabber.viewmodels.DirectInboxViewModel;
|
import awais.instagrabber.viewmodels.DirectInboxViewModel;
|
||||||
|
import awais.instagrabber.viewmodels.DirectPendingInboxViewModel;
|
||||||
import awais.instagrabber.viewmodels.DirectSettingsViewModel;
|
import awais.instagrabber.viewmodels.DirectSettingsViewModel;
|
||||||
|
|
||||||
public class DirectMessageSettingsFragment extends Fragment implements ConfirmDialogFragmentCallback {
|
public class DirectMessageSettingsFragment extends Fragment implements ConfirmDialogFragmentCallback {
|
||||||
@ -70,22 +71,28 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
|||||||
private boolean isPendingRequestsSetupDone = false;
|
private boolean isPendingRequestsSetupDone = false;
|
||||||
private DirectPendingUsersAdapter pendingUsersAdapter;
|
private DirectPendingUsersAdapter pendingUsersAdapter;
|
||||||
private Set<User> approvalRequiredUsers;
|
private Set<User> approvalRequiredUsers;
|
||||||
// private List<Option<String>> options;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
final Bundle arguments = getArguments();
|
||||||
|
if (arguments == null) return;
|
||||||
final NavController navController = NavHostFragment.findNavController(this);
|
final NavController navController = NavHostFragment.findNavController(this);
|
||||||
final ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
final ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
||||||
final DirectInboxViewModel inboxViewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectInboxViewModel.class);
|
final DirectMessageSettingsFragmentArgs args = DirectMessageSettingsFragmentArgs.fromBundle(arguments);
|
||||||
final List<DirectThread> threads = inboxViewModel.getThreads().getValue();
|
final boolean pending = args.getPending();
|
||||||
final Bundle arguments = getArguments();
|
final List<DirectThread> threads;
|
||||||
if (arguments == null) {
|
final User viewer;
|
||||||
navController.navigateUp();
|
if (pending) {
|
||||||
return;
|
final DirectPendingInboxViewModel inboxViewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectPendingInboxViewModel.class);
|
||||||
|
threads = inboxViewModel.getThreads().getValue();
|
||||||
|
viewer = inboxViewModel.getViewer();
|
||||||
|
} else {
|
||||||
|
final DirectInboxViewModel inboxViewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectInboxViewModel.class);
|
||||||
|
threads = inboxViewModel.getThreads().getValue();
|
||||||
|
viewer = inboxViewModel.getViewer();
|
||||||
}
|
}
|
||||||
final DirectMessageSettingsFragmentArgs fragmentArgs = DirectMessageSettingsFragmentArgs.fromBundle(arguments);
|
final String threadId = args.getThreadId();
|
||||||
final String threadId = fragmentArgs.getThreadId();
|
|
||||||
final Optional<DirectThread> first = threads != null ? threads.stream()
|
final Optional<DirectThread> first = threads != null ? threads.stream()
|
||||||
.filter(thread -> thread.getThreadId().equals(threadId))
|
.filter(thread -> thread.getThreadId().equals(threadId))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@ -95,7 +102,7 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
viewModel = new ViewModelProvider(this).get(DirectSettingsViewModel.class);
|
viewModel = new ViewModelProvider(this).get(DirectSettingsViewModel.class);
|
||||||
viewModel.setViewer(inboxViewModel.getViewer());
|
viewModel.setViewer(viewer);
|
||||||
viewModel.setThread(first.get());
|
viewModel.setThread(first.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,37 +112,14 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
|||||||
final ViewGroup container,
|
final ViewGroup container,
|
||||||
final Bundle savedInstanceState) {
|
final Bundle savedInstanceState) {
|
||||||
binding = FragmentDirectMessagesSettingsBinding.inflate(inflater, container, false);
|
binding = FragmentDirectMessagesSettingsBinding.inflate(inflater, container, false);
|
||||||
// final String threadId = DirectMessageSettingsFragmentArgs.fromBundle(getArguments()).getThreadId();
|
|
||||||
// threadTitle = DirectMessageSettingsFragmentArgs.fromBundle(getArguments()).getTitle();
|
|
||||||
// binding.swipeRefreshLayout.setEnabled(false);
|
|
||||||
|
|
||||||
// final ActionBar actionBar = fragmentActivity.getSupportActionBar();
|
|
||||||
// if (actionBar != null) {
|
|
||||||
// actionBar.setTitle(threadTitle);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// titleSend.setOnClickListener(v -> new ChangeSettings(titleText.getText().toString()).execute("update_title"));
|
|
||||||
|
|
||||||
// binding.titleText.addTextChangedListener(new TextWatcherAdapter() {
|
|
||||||
// @Override
|
|
||||||
// public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
// binding.titleSend.setVisibility(s.toString().equals(threadTitle) ? View.GONE : View.VISIBLE);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// final AppCompatButton btnLeave = binding.btnLeave;
|
|
||||||
// btnLeave.setOnClickListener(v -> new AlertDialog.Builder(context)
|
|
||||||
// .setTitle(R.string.dms_action_leave_question)
|
|
||||||
// .setPositiveButton(R.string.yes, (x, y) -> new ChangeSettings(titleText.getText().toString()).execute("leave"))
|
|
||||||
// .setNegativeButton(R.string.no, null)
|
|
||||||
// .show());
|
|
||||||
|
|
||||||
// currentlyRunning = new DirectMessageInboxThreadFetcher(threadId, null, null, fetchListener).execute();
|
// currentlyRunning = new DirectMessageInboxThreadFetcher(threadId, null, null, fetchListener).execute();
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
|
||||||
|
final Bundle arguments = getArguments();
|
||||||
|
if (arguments == null) return;
|
||||||
init();
|
init();
|
||||||
setupObservers();
|
setupObservers();
|
||||||
}
|
}
|
||||||
@ -169,6 +153,7 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
|||||||
usersAdapter.setAdminUserIds(adminUserIds);
|
usersAdapter.setAdminUserIds(adminUserIds);
|
||||||
});
|
});
|
||||||
viewModel.getMuted().observe(getViewLifecycleOwner(), muted -> binding.muteMessages.setChecked(muted));
|
viewModel.getMuted().observe(getViewLifecycleOwner(), muted -> binding.muteMessages.setChecked(muted));
|
||||||
|
viewModel.isPending().observe(getViewLifecycleOwner(), pending -> binding.muteMessages.setVisibility(pending ? View.GONE : View.VISIBLE));
|
||||||
if (viewModel.isViewerAdmin()) {
|
if (viewModel.isViewerAdmin()) {
|
||||||
viewModel.getApprovalRequiredToJoin().observe(getViewLifecycleOwner(), required -> binding.approvalRequired.setChecked(required));
|
viewModel.getApprovalRequiredToJoin().observe(getViewLifecycleOwner(), required -> binding.approvalRequired.setChecked(required));
|
||||||
viewModel.getPendingRequests().observe(getViewLifecycleOwner(), this::setPendingRequests);
|
viewModel.getPendingRequests().observe(getViewLifecycleOwner(), this::setPendingRequests);
|
||||||
|
@ -105,6 +105,7 @@ import awais.instagrabber.utils.TextUtils;
|
|||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.viewmodels.AppStateViewModel;
|
import awais.instagrabber.viewmodels.AppStateViewModel;
|
||||||
import awais.instagrabber.viewmodels.DirectInboxViewModel;
|
import awais.instagrabber.viewmodels.DirectInboxViewModel;
|
||||||
|
import awais.instagrabber.viewmodels.DirectPendingInboxViewModel;
|
||||||
import awais.instagrabber.viewmodels.DirectThreadViewModel;
|
import awais.instagrabber.viewmodels.DirectThreadViewModel;
|
||||||
|
|
||||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
||||||
@ -347,9 +348,11 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
|||||||
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
||||||
final int itemId = item.getItemId();
|
final int itemId = item.getItemId();
|
||||||
if (itemId == R.id.info) {
|
if (itemId == R.id.info) {
|
||||||
final NavDirections action = DirectMessageThreadFragmentDirections
|
final DirectMessageThreadFragmentDirections.ActionThreadToSettings directions = DirectMessageThreadFragmentDirections
|
||||||
.actionDMThreadFragmentToDMSettingsFragment(viewModel.getThreadId(), null);
|
.actionThreadToSettings(viewModel.getThreadId(), null);
|
||||||
NavHostFragment.findNavController(this).navigate(action);
|
final Boolean pending = viewModel.isPending().getValue();
|
||||||
|
directions.setPending(pending == null ? false : pending);
|
||||||
|
NavHostFragment.findNavController(this).navigate(directions);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (itemId == R.id.mark_as_seen) {
|
if (itemId == R.id.mark_as_seen) {
|
||||||
@ -470,10 +473,20 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void getInitialData() {
|
private void getInitialData() {
|
||||||
|
final Bundle arguments = getArguments();
|
||||||
|
if (arguments == null) return;
|
||||||
|
final DirectMessageThreadFragmentArgs args = DirectMessageThreadFragmentArgs.fromBundle(arguments);
|
||||||
|
final boolean pending = args.getPending();
|
||||||
final NavController navController = NavHostFragment.findNavController(this);
|
final NavController navController = NavHostFragment.findNavController(this);
|
||||||
final ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
final ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
||||||
final DirectInboxViewModel threadListViewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectInboxViewModel.class);
|
final List<DirectThread> threads;
|
||||||
final List<DirectThread> threads = threadListViewModel.getThreads().getValue();
|
if (!pending) {
|
||||||
|
final DirectInboxViewModel threadListViewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectInboxViewModel.class);
|
||||||
|
threads = threadListViewModel.getThreads().getValue();
|
||||||
|
} else {
|
||||||
|
final DirectPendingInboxViewModel threadListViewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectPendingInboxViewModel.class);
|
||||||
|
threads = threadListViewModel.getThreads().getValue();
|
||||||
|
}
|
||||||
final Optional<DirectThread> first = threads != null
|
final Optional<DirectThread> first = threads != null
|
||||||
? threads.stream()
|
? threads.stream()
|
||||||
.filter(thread -> thread.getThreadId().equals(viewModel.getThreadId()))
|
.filter(thread -> thread.getThreadId().equals(viewModel.getThreadId()))
|
||||||
@ -529,19 +542,26 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setObservers() {
|
private void setObservers() {
|
||||||
|
viewModel.isPending().observe(getViewLifecycleOwner(), isPending -> {
|
||||||
|
if (isPending == null) {
|
||||||
|
hideInput();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isPending) {
|
||||||
|
showPendingOptions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hidePendingOptions();
|
||||||
|
final Integer inputMode = viewModel.getInputMode().getValue();
|
||||||
|
if (inputMode != null && inputMode == 1) return;
|
||||||
|
showInput();
|
||||||
|
});
|
||||||
viewModel.getInputMode().observe(getViewLifecycleOwner(), inputMode -> {
|
viewModel.getInputMode().observe(getViewLifecycleOwner(), inputMode -> {
|
||||||
|
final Boolean isPending = viewModel.isPending().getValue();
|
||||||
|
if (isPending != null && isPending) return;
|
||||||
if (inputMode == null || inputMode == 0) return;
|
if (inputMode == null || inputMode == 0) return;
|
||||||
if (inputMode == 1) {
|
if (inputMode == 1) {
|
||||||
binding.emojiToggle.setVisibility(View.GONE);
|
hideInput();
|
||||||
binding.camera.setVisibility(View.GONE);
|
|
||||||
binding.gallery.setVisibility(View.GONE);
|
|
||||||
binding.input.setVisibility(View.GONE);
|
|
||||||
binding.inputBg.setVisibility(View.GONE);
|
|
||||||
binding.recordView.setVisibility(View.GONE);
|
|
||||||
binding.send.setVisibility(View.GONE);
|
|
||||||
if (itemTouchHelper != null) {
|
|
||||||
itemTouchHelper.attachToRecyclerView(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
viewModel.getThreadTitle().observe(getViewLifecycleOwner(), this::setTitle);
|
viewModel.getThreadTitle().observe(getViewLifecycleOwner(), this::setTitle);
|
||||||
@ -614,6 +634,81 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
|||||||
prevLength = length;
|
prevLength = length;
|
||||||
});
|
});
|
||||||
viewModel.getPendingRequestsCount().observe(getViewLifecycleOwner(), this::attachPendingRequestsBadge);
|
viewModel.getPendingRequestsCount().observe(getViewLifecycleOwner(), this::attachPendingRequestsBadge);
|
||||||
|
viewModel.getUsers().observe(getViewLifecycleOwner(), users -> {
|
||||||
|
if (users == null || users.isEmpty()) return;
|
||||||
|
final User user = users.get(0);
|
||||||
|
binding.acceptPendingRequestQuestion.setText(getString(R.string.accept_request_from_user, user.getUsername(), user.getFullName()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hidePendingOptions() {
|
||||||
|
binding.acceptPendingRequestQuestion.setVisibility(View.GONE);
|
||||||
|
binding.decline.setVisibility(View.GONE);
|
||||||
|
binding.accept.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPendingOptions() {
|
||||||
|
binding.acceptPendingRequestQuestion.setVisibility(View.VISIBLE);
|
||||||
|
binding.decline.setVisibility(View.VISIBLE);
|
||||||
|
binding.accept.setVisibility(View.VISIBLE);
|
||||||
|
binding.accept.setOnClickListener(v -> {
|
||||||
|
final LiveData<Resource<Object>> resourceLiveData = viewModel.acceptRequest();
|
||||||
|
handlePendingChangeResource(resourceLiveData, false);
|
||||||
|
});
|
||||||
|
binding.decline.setOnClickListener(v -> {
|
||||||
|
final LiveData<Resource<Object>> resourceLiveData = viewModel.declineRequest();
|
||||||
|
handlePendingChangeResource(resourceLiveData, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePendingChangeResource(final LiveData<Resource<Object>> resourceLiveData, final boolean isDecline) {
|
||||||
|
resourceLiveData.observe(getViewLifecycleOwner(), resource -> {
|
||||||
|
if (resource == null) return;
|
||||||
|
final Resource.Status status = resource.status;
|
||||||
|
switch (status) {
|
||||||
|
case SUCCESS:
|
||||||
|
resourceLiveData.removeObservers(getViewLifecycleOwner());
|
||||||
|
if (isDecline) {
|
||||||
|
final NavController navController = NavHostFragment.findNavController(this);
|
||||||
|
navController.navigateUp();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOADING:
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
if (resource.message != null) {
|
||||||
|
Snackbar.make(binding.getRoot(), resource.message, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
resourceLiveData.removeObservers(getViewLifecycleOwner());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideInput() {
|
||||||
|
binding.emojiToggle.setVisibility(View.GONE);
|
||||||
|
binding.camera.setVisibility(View.GONE);
|
||||||
|
binding.gallery.setVisibility(View.GONE);
|
||||||
|
binding.input.setVisibility(View.GONE);
|
||||||
|
binding.inputBg.setVisibility(View.GONE);
|
||||||
|
binding.recordView.setVisibility(View.GONE);
|
||||||
|
binding.send.setVisibility(View.GONE);
|
||||||
|
if (itemTouchHelper != null) {
|
||||||
|
itemTouchHelper.attachToRecyclerView(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showInput() {
|
||||||
|
binding.emojiToggle.setVisibility(View.VISIBLE);
|
||||||
|
binding.camera.setVisibility(View.VISIBLE);
|
||||||
|
binding.gallery.setVisibility(View.VISIBLE);
|
||||||
|
binding.input.setVisibility(View.VISIBLE);
|
||||||
|
binding.inputBg.setVisibility(View.VISIBLE);
|
||||||
|
binding.recordView.setVisibility(View.VISIBLE);
|
||||||
|
binding.send.setVisibility(View.VISIBLE);
|
||||||
|
if (itemTouchHelper != null) {
|
||||||
|
itemTouchHelper.attachToRecyclerView(binding.chats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("UnsafeExperimentalUsageError")
|
@SuppressLint("UnsafeExperimentalUsageError")
|
||||||
|
@ -0,0 +1,152 @@
|
|||||||
|
package awais.instagrabber.fragments.directmessages;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.lifecycle.Observer;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
import androidx.lifecycle.ViewModelStoreOwner;
|
||||||
|
import androidx.navigation.NavController;
|
||||||
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.activities.MainActivity;
|
||||||
|
import awais.instagrabber.adapters.DirectMessageInboxAdapter;
|
||||||
|
import awais.instagrabber.customviews.helpers.RecyclerLazyLoaderAtEdge;
|
||||||
|
import awais.instagrabber.databinding.FragmentDirectPendingInboxBinding;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||||
|
import awais.instagrabber.viewmodels.DirectPendingInboxViewModel;
|
||||||
|
|
||||||
|
public class DirectPendingInboxFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
||||||
|
private static final String TAG = DirectPendingInboxFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
private CoordinatorLayout root;
|
||||||
|
private RecyclerLazyLoaderAtEdge lazyLoader;
|
||||||
|
private DirectPendingInboxViewModel viewModel;
|
||||||
|
private boolean shouldRefresh = true;
|
||||||
|
private FragmentDirectPendingInboxBinding binding;
|
||||||
|
private DirectMessageInboxAdapter inboxAdapter;
|
||||||
|
private MainActivity fragmentActivity;
|
||||||
|
private boolean scrollToTop = false;
|
||||||
|
private boolean navigating;
|
||||||
|
private Observer<List<DirectThread>> threadsObserver;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
fragmentActivity = (MainActivity) getActivity();
|
||||||
|
if (fragmentActivity != null) {
|
||||||
|
final NavController navController = NavHostFragment.findNavController(this);
|
||||||
|
final ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
||||||
|
viewModel = new ViewModelProvider(viewModelStoreOwner).get(DirectPendingInboxViewModel.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||||
|
final ViewGroup container,
|
||||||
|
final Bundle savedInstanceState) {
|
||||||
|
if (root != null) {
|
||||||
|
shouldRefresh = false;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
binding = FragmentDirectPendingInboxBinding.inflate(inflater, container, false);
|
||||||
|
root = binding.getRoot();
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
|
||||||
|
if (!shouldRefresh) return;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRefresh() {
|
||||||
|
lazyLoader.resetState();
|
||||||
|
scrollToTop = true;
|
||||||
|
if (viewModel != null) {
|
||||||
|
viewModel.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
setupObservers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(@NonNull final Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
removeViewModelObservers();
|
||||||
|
viewModel.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupObservers() {
|
||||||
|
threadsObserver = list -> {
|
||||||
|
if (inboxAdapter == null) return;
|
||||||
|
inboxAdapter.submitList(list, () -> {
|
||||||
|
if (!scrollToTop) return;
|
||||||
|
binding.pendingInboxList.smoothScrollToPosition(0);
|
||||||
|
scrollToTop = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
viewModel.getThreads().observe(fragmentActivity, threadsObserver);
|
||||||
|
viewModel.getFetchingInbox().observe(getViewLifecycleOwner(), fetching -> binding.swipeRefreshLayout.setRefreshing(fetching));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeViewModelObservers() {
|
||||||
|
if (viewModel == null) return;
|
||||||
|
if (threadsObserver != null) {
|
||||||
|
viewModel.getThreads().removeObserver(threadsObserver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
setupObservers();
|
||||||
|
binding.swipeRefreshLayout.setOnRefreshListener(this);
|
||||||
|
binding.pendingInboxList.setHasFixedSize(true);
|
||||||
|
binding.pendingInboxList.setItemViewCacheSize(20);
|
||||||
|
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
||||||
|
binding.pendingInboxList.setLayoutManager(layoutManager);
|
||||||
|
inboxAdapter = new DirectMessageInboxAdapter(thread -> {
|
||||||
|
if (navigating) return;
|
||||||
|
navigating = true;
|
||||||
|
if (isAdded()) {
|
||||||
|
final DirectPendingInboxFragmentDirections.ActionPendingInboxToThread directions = DirectPendingInboxFragmentDirections
|
||||||
|
.actionPendingInboxToThread(thread.getThreadId(), thread.getThreadTitle());
|
||||||
|
directions.setPending(true);
|
||||||
|
NavHostFragment.findNavController(this).navigate(directions);
|
||||||
|
}
|
||||||
|
navigating = false;
|
||||||
|
});
|
||||||
|
inboxAdapter.setHasStableIds(true);
|
||||||
|
binding.pendingInboxList.setAdapter(inboxAdapter);
|
||||||
|
lazyLoader = new RecyclerLazyLoaderAtEdge(layoutManager, page -> {
|
||||||
|
if (viewModel == null) return;
|
||||||
|
viewModel.fetchInbox();
|
||||||
|
});
|
||||||
|
binding.pendingInboxList.addOnScrollListener(lazyLoader);
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,9 @@ public interface DirectMessagesRepository {
|
|||||||
@GET("/api/v1/direct_v2/inbox/")
|
@GET("/api/v1/direct_v2/inbox/")
|
||||||
Call<DirectInboxResponse> fetchInbox(@QueryMap Map<String, Object> queryMap);
|
Call<DirectInboxResponse> fetchInbox(@QueryMap Map<String, Object> queryMap);
|
||||||
|
|
||||||
|
@GET("/api/v1/direct_v2/pending_inbox/")
|
||||||
|
Call<DirectInboxResponse> fetchPendingInbox(@QueryMap Map<String, Object> queryMap);
|
||||||
|
|
||||||
@GET("/api/v1/direct_v2/threads/{threadId}/")
|
@GET("/api/v1/direct_v2/threads/{threadId}/")
|
||||||
Call<DirectThreadFeedResponse> fetchThread(@Path("threadId") String threadId,
|
Call<DirectThreadFeedResponse> fetchThread(@Path("threadId") String threadId,
|
||||||
@QueryMap Map<String, Object> queryMap);
|
@QueryMap Map<String, Object> queryMap);
|
||||||
@ -132,4 +135,14 @@ public interface DirectMessagesRepository {
|
|||||||
@POST("/api/v1/direct_v2/threads/{threadId}/remove_all_users/")
|
@POST("/api/v1/direct_v2/threads/{threadId}/remove_all_users/")
|
||||||
Call<DirectThreadDetailsChangeResponse> end(@Path("threadId") String threadId,
|
Call<DirectThreadDetailsChangeResponse> end(@Path("threadId") String threadId,
|
||||||
@FieldMap final Map<String, String> form);
|
@FieldMap final Map<String, String> form);
|
||||||
|
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("/api/v1/direct_v2/threads/{threadId}/approve/")
|
||||||
|
Call<String> approveRequest(@Path("threadId") String threadId,
|
||||||
|
@FieldMap final Map<String, String> form);
|
||||||
|
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("/api/v1/direct_v2/threads/{threadId}/decline/")
|
||||||
|
Call<String> declineRequest(@Path("threadId") String threadId,
|
||||||
|
@FieldMap final Map<String, String> form);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ public class DirectInboxResponse {
|
|||||||
private final long seqId;
|
private final long seqId;
|
||||||
private final long snapshotAtMs;
|
private final long snapshotAtMs;
|
||||||
private final int pendingRequestsTotal;
|
private final int pendingRequestsTotal;
|
||||||
|
private final boolean hasPendingTopRequests;
|
||||||
private final User mostRecentInviter;
|
private final User mostRecentInviter;
|
||||||
private final String status;
|
private final String status;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ public class DirectInboxResponse {
|
|||||||
final long seqId,
|
final long seqId,
|
||||||
final long snapshotAtMs,
|
final long snapshotAtMs,
|
||||||
final int pendingRequestsTotal,
|
final int pendingRequestsTotal,
|
||||||
|
final boolean hasPendingTopRequests,
|
||||||
final User mostRecentInviter,
|
final User mostRecentInviter,
|
||||||
final String status) {
|
final String status) {
|
||||||
this.viewer = viewer;
|
this.viewer = viewer;
|
||||||
@ -23,6 +25,7 @@ public class DirectInboxResponse {
|
|||||||
this.seqId = seqId;
|
this.seqId = seqId;
|
||||||
this.snapshotAtMs = snapshotAtMs;
|
this.snapshotAtMs = snapshotAtMs;
|
||||||
this.pendingRequestsTotal = pendingRequestsTotal;
|
this.pendingRequestsTotal = pendingRequestsTotal;
|
||||||
|
this.hasPendingTopRequests = hasPendingTopRequests;
|
||||||
this.mostRecentInviter = mostRecentInviter;
|
this.mostRecentInviter = mostRecentInviter;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
@ -47,6 +50,10 @@ public class DirectInboxResponse {
|
|||||||
return pendingRequestsTotal;
|
return pendingRequestsTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasPendingTopRequests() {
|
||||||
|
return hasPendingTopRequests;
|
||||||
|
}
|
||||||
|
|
||||||
public User getMostRecentInviter() {
|
public User getMostRecentInviter() {
|
||||||
return mostRecentInviter;
|
return mostRecentInviter;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ public class DirectThread implements Serializable {
|
|||||||
private final boolean isPin;
|
private final boolean isPin;
|
||||||
private final boolean named;
|
private final boolean named;
|
||||||
private final boolean canonical;
|
private final boolean canonical;
|
||||||
private final boolean pending;
|
private boolean pending;
|
||||||
private final boolean archived;
|
private final boolean archived;
|
||||||
private final boolean valuedRequest;
|
private final boolean valuedRequest;
|
||||||
private final String threadType;
|
private final String threadType;
|
||||||
@ -43,6 +43,7 @@ public class DirectThread implements Serializable {
|
|||||||
private final DirectThreadDirectStory directStory;
|
private final DirectThreadDirectStory directStory;
|
||||||
private boolean approvalRequiredForNewMembers;
|
private boolean approvalRequiredForNewMembers;
|
||||||
private int inputMode;
|
private int inputMode;
|
||||||
|
private final List<ThreadContext> threadContextItems;
|
||||||
|
|
||||||
public DirectThread(final String threadId,
|
public DirectThread(final String threadId,
|
||||||
final String threadV2Id,
|
final String threadV2Id,
|
||||||
@ -76,7 +77,8 @@ public class DirectThread implements Serializable {
|
|||||||
final DirectItem lastPermanentItem,
|
final DirectItem lastPermanentItem,
|
||||||
final DirectThreadDirectStory directStory,
|
final DirectThreadDirectStory directStory,
|
||||||
final boolean approvalRequiredForNewMembers,
|
final boolean approvalRequiredForNewMembers,
|
||||||
final int inputMode) {
|
final int inputMode,
|
||||||
|
final List<ThreadContext> threadContextItems) {
|
||||||
this.threadId = threadId;
|
this.threadId = threadId;
|
||||||
this.threadV2Id = threadV2Id;
|
this.threadV2Id = threadV2Id;
|
||||||
this.users = users;
|
this.users = users;
|
||||||
@ -110,6 +112,7 @@ public class DirectThread implements Serializable {
|
|||||||
this.directStory = directStory;
|
this.directStory = directStory;
|
||||||
this.approvalRequiredForNewMembers = approvalRequiredForNewMembers;
|
this.approvalRequiredForNewMembers = approvalRequiredForNewMembers;
|
||||||
this.inputMode = inputMode;
|
this.inputMode = inputMode;
|
||||||
|
this.threadContextItems = threadContextItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getThreadId() {
|
public String getThreadId() {
|
||||||
@ -164,6 +167,10 @@ public class DirectThread implements Serializable {
|
|||||||
return pending;
|
return pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPending(final boolean pending) {
|
||||||
|
this.pending = pending;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isArchived() {
|
public boolean isArchived() {
|
||||||
return archived;
|
return archived;
|
||||||
}
|
}
|
||||||
@ -260,6 +267,10 @@ public class DirectThread implements Serializable {
|
|||||||
this.inputMode = inputMode;
|
this.inputMode = inputMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ThreadContext> getThreadContextItems() {
|
||||||
|
return threadContextItems;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public DirectItem getFirstDirectItem() {
|
public DirectItem getFirstDirectItem() {
|
||||||
DirectItem firstItem = null;
|
DirectItem firstItem = null;
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package awais.instagrabber.repositories.responses.directmessages;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class ThreadContext implements Serializable {
|
||||||
|
private final int type;
|
||||||
|
private final String text;
|
||||||
|
|
||||||
|
public ThreadContext(final int type, final String text) {
|
||||||
|
this.type = type;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@ import awais.instagrabber.repositories.responses.VideoVersion;
|
|||||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemVoiceMedia;
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemVoiceMedia;
|
||||||
|
|
||||||
public class DirectItemFactory {
|
public final class DirectItemFactory {
|
||||||
|
|
||||||
public static DirectItem createText(final long userId,
|
public static DirectItem createText(final long userId,
|
||||||
final String clientContext,
|
final String clientContext,
|
||||||
|
@ -3,6 +3,7 @@ package awais.instagrabber.viewmodels;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.ViewModel;
|
import androidx.lifecycle.ViewModel;
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ public class DirectInboxViewModel extends ViewModel {
|
|||||||
private final MutableLiveData<List<DirectThread>> threads = new MutableLiveData<>();
|
private final MutableLiveData<List<DirectThread>> threads = new MutableLiveData<>();
|
||||||
private final MutableLiveData<Boolean> fetchingUnseenCount = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> fetchingUnseenCount = new MutableLiveData<>(false);
|
||||||
private final MutableLiveData<Integer> unseenCount = new MutableLiveData<>(0);
|
private final MutableLiveData<Integer> unseenCount = new MutableLiveData<>(0);
|
||||||
|
private final MutableLiveData<Integer> pendingRequestsTotal = new MutableLiveData<>(0);
|
||||||
|
|
||||||
private Call<DirectInboxResponse> inboxRequest;
|
private Call<DirectInboxResponse> inboxRequest;
|
||||||
private Call<DirectBadgeCount> unseenCountRequest;
|
private Call<DirectBadgeCount> unseenCountRequest;
|
||||||
@ -54,12 +56,12 @@ public class DirectInboxViewModel extends ViewModel {
|
|||||||
fetchUnseenCount();
|
fetchUnseenCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MutableLiveData<List<DirectThread>> getThreads() {
|
public LiveData<List<DirectThread>> getThreads() {
|
||||||
return threads;
|
return threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setThreads(final List<DirectThread> threads) {
|
public void setThreads(final List<DirectThread> threads) {
|
||||||
getThreads().postValue(threads);
|
this.threads.postValue(threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addThreads(final Collection<DirectThread> threads) {
|
public void addThreads(final Collection<DirectThread> threads) {
|
||||||
@ -70,14 +72,18 @@ public class DirectInboxViewModel extends ViewModel {
|
|||||||
this.threads.postValue(list);
|
this.threads.postValue(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MutableLiveData<Integer> getUnseenCount() {
|
public LiveData<Integer> getUnseenCount() {
|
||||||
return unseenCount;
|
return unseenCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MutableLiveData<Boolean> getFetchingInbox() {
|
public LiveData<Boolean> getFetchingInbox() {
|
||||||
return fetchingInbox;
|
return fetchingInbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<Integer> getPendingRequestsTotal() {
|
||||||
|
return pendingRequestsTotal;
|
||||||
|
}
|
||||||
|
|
||||||
public User getViewer() {
|
public User getViewer() {
|
||||||
return viewer;
|
return viewer;
|
||||||
}
|
}
|
||||||
@ -126,6 +132,7 @@ public class DirectInboxViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
cursor = inbox.getOldestCursor();
|
cursor = inbox.getOldestCursor();
|
||||||
hasOlder = inbox.hasOlder();
|
hasOlder = inbox.hasOlder();
|
||||||
|
pendingRequestsTotal.postValue(response.getPendingRequestsTotal());
|
||||||
// unseenCount.postValue(inbox.getUnseenCount());
|
// unseenCount.postValue(inbox.getUnseenCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,141 @@
|
|||||||
|
package awais.instagrabber.viewmodels;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
import androidx.lifecycle.ViewModel;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectBadgeCount;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectInbox;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectInboxResponse;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||||
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
import awais.instagrabber.webservices.DirectMessagesService;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
|
public class DirectPendingInboxViewModel extends ViewModel {
|
||||||
|
private static final String TAG = DirectPendingInboxViewModel.class.getSimpleName();
|
||||||
|
|
||||||
|
private final DirectMessagesService service;
|
||||||
|
private final MutableLiveData<Boolean> fetchingInbox = new MutableLiveData<>(false);
|
||||||
|
private final MutableLiveData<List<DirectThread>> threads = new MutableLiveData<>();
|
||||||
|
|
||||||
|
private Call<DirectInboxResponse> inboxRequest;
|
||||||
|
private Call<DirectBadgeCount> unseenCountRequest;
|
||||||
|
private long seqId;
|
||||||
|
private String cursor;
|
||||||
|
private boolean hasOlder = true;
|
||||||
|
private User viewer;
|
||||||
|
|
||||||
|
public DirectPendingInboxViewModel() {
|
||||||
|
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
|
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||||
|
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
|
||||||
|
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||||
|
if (TextUtils.isEmpty(csrfToken) || userId <= 0 || TextUtils.isEmpty(deviceUuid)) {
|
||||||
|
throw new IllegalArgumentException("User is not logged in!");
|
||||||
|
}
|
||||||
|
service = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid);
|
||||||
|
fetchInbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<List<DirectThread>> getThreads() {
|
||||||
|
return threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThreads(final List<DirectThread> threads) {
|
||||||
|
this.threads.postValue(threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addThreads(final Collection<DirectThread> threads) {
|
||||||
|
if (threads == null) return;
|
||||||
|
List<DirectThread> list = getThreads().getValue();
|
||||||
|
list = list == null ? new LinkedList<>() : new LinkedList<>(list);
|
||||||
|
list.addAll(threads);
|
||||||
|
this.threads.postValue(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Boolean> getFetchingInbox() {
|
||||||
|
return fetchingInbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getViewer() {
|
||||||
|
return viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fetchInbox() {
|
||||||
|
if ((fetchingInbox.getValue() != null && fetchingInbox.getValue()) || !hasOlder) return;
|
||||||
|
stopCurrentInboxRequest();
|
||||||
|
fetchingInbox.postValue(true);
|
||||||
|
inboxRequest = service.fetchPendingInbox(cursor, seqId);
|
||||||
|
inboxRequest.enqueue(new Callback<DirectInboxResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull final Call<DirectInboxResponse> call, @NonNull final Response<DirectInboxResponse> response) {
|
||||||
|
parseInboxResponse(response.body());
|
||||||
|
fetchingInbox.postValue(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Call<DirectInboxResponse> call, @NonNull final Throwable t) {
|
||||||
|
Log.e(TAG, "Failed fetching pending inbox", t);
|
||||||
|
fetchingInbox.postValue(false);
|
||||||
|
hasOlder = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseInboxResponse(final DirectInboxResponse response) {
|
||||||
|
if (response == null) {
|
||||||
|
hasOlder = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!response.getStatus().equals("ok")) {
|
||||||
|
Log.e(TAG, "DM pending inbox fetch response: status not ok");
|
||||||
|
hasOlder = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seqId = response.getSeqId();
|
||||||
|
if (viewer == null) {
|
||||||
|
viewer = response.getViewer();
|
||||||
|
}
|
||||||
|
final DirectInbox inbox = response.getInbox();
|
||||||
|
final List<DirectThread> threads = inbox.getThreads();
|
||||||
|
if (!TextUtils.isEmpty(cursor)) {
|
||||||
|
addThreads(threads);
|
||||||
|
} else {
|
||||||
|
setThreads(threads);
|
||||||
|
}
|
||||||
|
cursor = inbox.getOldestCursor();
|
||||||
|
hasOlder = inbox.hasOlder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopCurrentInboxRequest() {
|
||||||
|
if (inboxRequest == null || inboxRequest.isCanceled() || inboxRequest.isExecuted()) return;
|
||||||
|
inboxRequest.cancel();
|
||||||
|
inboxRequest = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
cursor = null;
|
||||||
|
seqId = 0;
|
||||||
|
hasOlder = true;
|
||||||
|
fetchInbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDestroy() {
|
||||||
|
stopCurrentInboxRequest();
|
||||||
|
}
|
||||||
|
}
|
@ -67,6 +67,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
|||||||
private final MutableLiveData<Boolean> approvalRequiredToJoin = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> approvalRequiredToJoin = new MutableLiveData<>(false);
|
||||||
private final MutableLiveData<DirectThreadParticipantRequestsResponse> pendingRequests = new MutableLiveData<>(null);
|
private final MutableLiveData<DirectThreadParticipantRequestsResponse> pendingRequests = new MutableLiveData<>(null);
|
||||||
private final MutableLiveData<Integer> inputMode = new MutableLiveData<>(null);
|
private final MutableLiveData<Integer> inputMode = new MutableLiveData<>(null);
|
||||||
|
private final MutableLiveData<Boolean> isPending = new MutableLiveData<>(false);
|
||||||
private final DirectMessagesService directMessagesService;
|
private final DirectMessagesService directMessagesService;
|
||||||
private final long userId;
|
private final long userId;
|
||||||
private final Resources resources;
|
private final Resources resources;
|
||||||
@ -115,6 +116,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
|||||||
muted.postValue(thread.isMuted());
|
muted.postValue(thread.isMuted());
|
||||||
mentionsMuted.postValue(thread.isMentionsMuted());
|
mentionsMuted.postValue(thread.isMentionsMuted());
|
||||||
approvalRequiredToJoin.postValue(thread.isApprovalRequiredForNewMembers());
|
approvalRequiredToJoin.postValue(thread.isApprovalRequiredForNewMembers());
|
||||||
|
isPending.postValue(thread.isPending());
|
||||||
if (thread.getInputMode() != 1 && thread.isGroup() && viewerIsAdmin) {
|
if (thread.getInputMode() != 1 && thread.isGroup() && viewerIsAdmin) {
|
||||||
fetchPendingRequests();
|
fetchPendingRequests();
|
||||||
}
|
}
|
||||||
@ -163,6 +165,10 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
|||||||
return pendingRequests;
|
return pendingRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<Boolean> isPending() {
|
||||||
|
return isPending;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isViewerAdmin() {
|
public boolean isViewerAdmin() {
|
||||||
return viewerIsAdmin;
|
return viewerIsAdmin;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
private final MutableLiveData<DirectItem> replyToItem = new MutableLiveData<>();
|
private final MutableLiveData<DirectItem> replyToItem = new MutableLiveData<>();
|
||||||
private final MutableLiveData<Integer> pendingRequestsCount = new MutableLiveData<>(null);
|
private final MutableLiveData<Integer> pendingRequestsCount = new MutableLiveData<>(null);
|
||||||
private final MutableLiveData<Integer> inputMode = new MutableLiveData<>(0);
|
private final MutableLiveData<Integer> inputMode = new MutableLiveData<>(0);
|
||||||
|
private final MutableLiveData<Boolean> isPending = new MutableLiveData<>(null);
|
||||||
|
|
||||||
private final DirectMessagesService service;
|
private final DirectMessagesService service;
|
||||||
private final ContentResolver contentResolver;
|
private final ContentResolver contentResolver;
|
||||||
@ -340,6 +341,10 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
return inputMode;
|
return inputMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<Boolean> isPending() {
|
||||||
|
return isPending;
|
||||||
|
}
|
||||||
|
|
||||||
public void fetchChats() {
|
public void fetchChats() {
|
||||||
final Boolean isFetching = fetching.getValue();
|
final Boolean isFetching = fetching.getValue();
|
||||||
if ((isFetching != null && isFetching) || !hasOlder) return;
|
if ((isFetching != null && isFetching) || !hasOlder) return;
|
||||||
@ -404,6 +409,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
users.postValue(thread.getUsers());
|
users.postValue(thread.getUsers());
|
||||||
leftUsers.postValue(thread.getLeftUsers());
|
leftUsers.postValue(thread.getLeftUsers());
|
||||||
fetching.postValue(false);
|
fetching.postValue(false);
|
||||||
|
isPending.postValue(thread.isPending());
|
||||||
final List<Long> adminUserIds = thread.getAdminUserIds();
|
final List<Long> adminUserIds = thread.getAdminUserIds();
|
||||||
viewerIsAdmin = adminUserIds.contains(viewerId);
|
viewerIsAdmin = adminUserIds.contains(viewerId);
|
||||||
if (thread.getInputMode() != 1 && thread.isGroup() && viewerIsAdmin) {
|
if (thread.getInputMode() != 1 && thread.isGroup() && viewerIsAdmin) {
|
||||||
@ -1105,4 +1111,75 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<Resource<Object>> acceptRequest() {
|
||||||
|
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||||
|
final Call<String> request = service.approveRequest(threadId);
|
||||||
|
request.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull final Call<String> call,
|
||||||
|
@NonNull final Response<String> response) {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
try {
|
||||||
|
final String string = response.errorBody() != null ? response.errorBody().string() : "";
|
||||||
|
final String msg = String.format(Locale.US,
|
||||||
|
"onResponse: url: %s, responseCode: %d, errorBody: %s",
|
||||||
|
call.request().url().toString(),
|
||||||
|
response.code(),
|
||||||
|
string);
|
||||||
|
Log.e(TAG, msg);
|
||||||
|
data.postValue(Resource.error(msg, null));
|
||||||
|
return;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "onResponse: ", e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isPending.postValue(false);
|
||||||
|
data.postValue(Resource.success(new Object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||||
|
Log.e(TAG, "onFailure: ", t);
|
||||||
|
data.postValue(Resource.error(t.getMessage(), null));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Resource<Object>> declineRequest() {
|
||||||
|
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||||
|
final Call<String> request = service.declineRequest(threadId);
|
||||||
|
request.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull final Call<String> call,
|
||||||
|
@NonNull final Response<String> response) {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
try {
|
||||||
|
final String string = response.errorBody() != null ? response.errorBody().string() : "";
|
||||||
|
final String msg = String.format(Locale.US,
|
||||||
|
"onResponse: url: %s, responseCode: %d, errorBody: %s",
|
||||||
|
call.request().url().toString(),
|
||||||
|
response.code(),
|
||||||
|
string);
|
||||||
|
Log.e(TAG, msg);
|
||||||
|
data.postValue(Resource.error(msg, null));
|
||||||
|
return;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "onResponse: ", e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.postValue(Resource.success(new Object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||||
|
Log.e(TAG, "onFailure: ", t);
|
||||||
|
data.postValue(Resource.error(t.getMessage(), null));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,4 +409,36 @@ public class DirectMessagesService extends BaseService {
|
|||||||
);
|
);
|
||||||
return repository.end(threadId, form);
|
return repository.end(threadId, form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Call<DirectInboxResponse> fetchPendingInbox(final String cursor, final long seqId) {
|
||||||
|
final ImmutableMap.Builder<String, Object> queryMapBuilder = ImmutableMap.<String, Object>builder()
|
||||||
|
.put("visual_message_return_type", "unseen")
|
||||||
|
.put("thread_message_limit", 10)
|
||||||
|
.put("persistentBadging", true)
|
||||||
|
.put("limit", 10);
|
||||||
|
if (!TextUtils.isEmpty(cursor)) {
|
||||||
|
queryMapBuilder.put("cursor", cursor);
|
||||||
|
queryMapBuilder.put("direction", "older");
|
||||||
|
}
|
||||||
|
if (seqId != 0) {
|
||||||
|
queryMapBuilder.put("seq_id", seqId);
|
||||||
|
}
|
||||||
|
return repository.fetchPendingInbox(queryMapBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Call<String> approveRequest(@NonNull final String threadId) {
|
||||||
|
final ImmutableMap<String, String> form = ImmutableMap.of(
|
||||||
|
"_csrftoken", csrfToken,
|
||||||
|
"_uuid", deviceUuid
|
||||||
|
);
|
||||||
|
return repository.approveRequest(threadId, form);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Call<String> declineRequest(@NonNull final String threadId) {
|
||||||
|
final ImmutableMap<String, String> form = ImmutableMap.of(
|
||||||
|
"_csrftoken", csrfToken,
|
||||||
|
"_uuid", deviceUuid
|
||||||
|
);
|
||||||
|
return repository.declineRequest(threadId, form);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
11
app/src/main/res/drawable/ic_account_clock_24.xml
Normal file
11
app/src/main/res/drawable/ic_account_clock_24.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#000"
|
||||||
|
android:pathData="M10.63,14.1C12.23,10.58 16.38,9.03 19.9,10.63C23.42,12.23 24.97,16.38 23.37,19.9C22.24,22.4 19.75,24 17,24C14.3,24 11.83,22.44 10.67,20H1V18C1.06,16.86 1.84,15.93 3.34,15.18C4.84,14.43 6.72,14.04 9,14C9.57,14 10.11,14.05 10.63,14.1V14.1M9,4C10.12,4.03 11.06,4.42 11.81,5.17C12.56,5.92 12.93,6.86 12.93,8C12.93,9.14 12.56,10.08 11.81,10.83C11.06,11.58 10.12,11.95 9,11.95C7.88,11.95 6.94,11.58 6.19,10.83C5.44,10.08 5.07,9.14 5.07,8C5.07,6.86 5.44,5.92 6.19,5.17C6.94,4.42 7.88,4.03 9,4M17,22A5,5 0 0,0 22,17A5,5 0 0,0 17,12A5,5 0 0,0 12,17A5,5 0 0,0 17,22M16,14H17.5V16.82L19.94,18.23L19.19,19.53L16,17.69V14Z" />
|
||||||
|
</vector>
|
@ -11,12 +11,18 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layout_constraintBottom_toTopOf="@id/reply_info"
|
app:layout_constraintBottom_toTopOf="@id/chats_barrier"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:listitem="@layout/layout_dm_base" />
|
tools:listitem="@layout/layout_dm_base" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Barrier
|
||||||
|
android:id="@+id/chats_barrier"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:barrierDirection="bottom" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/reply_bg"
|
android:id="@+id/reply_bg"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -44,7 +50,7 @@
|
|||||||
app:layout_constraintBottom_toTopOf="@id/reply_preview_text"
|
app:layout_constraintBottom_toTopOf="@id/reply_preview_text"
|
||||||
app:layout_constraintEnd_toStartOf="@id/reply_preview_image"
|
app:layout_constraintEnd_toStartOf="@id/reply_preview_image"
|
||||||
app:layout_constraintStart_toStartOf="@id/input_bg"
|
app:layout_constraintStart_toStartOf="@id/input_bg"
|
||||||
app:layout_constraintTop_toBottomOf="@id/chats"
|
app:layout_constraintTop_toBottomOf="@id/chats_barrier"
|
||||||
tools:text="Replying to yourself"
|
tools:text="Replying to yourself"
|
||||||
tools:visibility="gone" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
@ -110,6 +116,7 @@
|
|||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="4dp"
|
||||||
android:background="@drawable/bg_input"
|
android:background="@drawable/bg_input"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/input"
|
app:layout_constraintBottom_toBottomOf="@id/input"
|
||||||
app:layout_constraintEnd_toStartOf="@id/send"
|
app:layout_constraintEnd_toStartOf="@id/send"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@ -124,6 +131,7 @@
|
|||||||
android:layout_marginEnd="2dp"
|
android:layout_marginEnd="2dp"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
|
android:visibility="gone"
|
||||||
app:icon="@drawable/ic_face_24"
|
app:icon="@drawable/ic_face_24"
|
||||||
app:iconGravity="textStart"
|
app:iconGravity="textStart"
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
@ -148,6 +156,7 @@
|
|||||||
android:paddingBottom="12dp"
|
android:paddingBottom="12dp"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textColorHint="@color/grey_500"
|
android:textColorHint="@color/grey_500"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/camera"
|
app:layout_constraintEnd_toStartOf="@id/camera"
|
||||||
app:layout_constraintStart_toEndOf="@id/emoji_toggle"
|
app:layout_constraintStart_toEndOf="@id/emoji_toggle"
|
||||||
@ -163,12 +172,13 @@
|
|||||||
android:paddingStart="4dp"
|
android:paddingStart="4dp"
|
||||||
android:paddingEnd="4dp"
|
android:paddingEnd="4dp"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/input_bg"
|
app:layout_constraintBottom_toBottomOf="@id/input_bg"
|
||||||
app:layout_constraintEnd_toStartOf="@id/gallery"
|
app:layout_constraintEnd_toStartOf="@id/gallery"
|
||||||
app:layout_constraintStart_toEndOf="@id/input"
|
app:layout_constraintStart_toEndOf="@id/input"
|
||||||
app:layout_constraintTop_toTopOf="@id/input"
|
app:layout_constraintTop_toTopOf="@id/input"
|
||||||
app:srcCompat="@drawable/ic_camera_24"
|
app:srcCompat="@drawable/ic_camera_24"
|
||||||
tools:visibility="visible" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageButton
|
||||||
android:id="@+id/gallery"
|
android:id="@+id/gallery"
|
||||||
@ -181,22 +191,23 @@
|
|||||||
android:paddingEnd="4dp"
|
android:paddingEnd="4dp"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/ic_image_24"
|
android:src="@drawable/ic_image_24"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/input_bg"
|
app:layout_constraintBottom_toBottomOf="@id/input_bg"
|
||||||
app:layout_constraintEnd_toStartOf="@id/send"
|
app:layout_constraintEnd_toStartOf="@id/send"
|
||||||
app:layout_constraintStart_toEndOf="@id/camera"
|
app:layout_constraintStart_toEndOf="@id/camera"
|
||||||
app:layout_constraintTop_toTopOf="@id/input"
|
app:layout_constraintTop_toTopOf="@id/input"
|
||||||
tools:visibility="visible" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<awais.instagrabber.customviews.RecordView
|
<awais.instagrabber.customviews.RecordView
|
||||||
android:id="@+id/record_view"
|
android:id="@+id/record_view"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:visibility="visible"
|
android:visibility="gone"
|
||||||
app:counter_time_color="@color/white"
|
app:counter_time_color="@color/white"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/input_bg"
|
app:layout_constraintBottom_toBottomOf="@id/input_bg"
|
||||||
app:layout_constraintEnd_toEndOf="@id/input_bg"
|
app:layout_constraintEnd_toEndOf="@id/input_bg"
|
||||||
app:layout_constraintStart_toStartOf="@id/input"
|
app:layout_constraintStart_toStartOf="@id/input"
|
||||||
app:layout_constraintTop_toBottomOf="@id/chats"
|
app:layout_constraintTop_toBottomOf="@id/chats_barrier"
|
||||||
app:slide_to_cancel_arrow="@drawable/recv_ic_arrow"
|
app:slide_to_cancel_arrow="@drawable/recv_ic_arrow"
|
||||||
app:slide_to_cancel_arrow_color="@color/white"
|
app:slide_to_cancel_arrow_color="@color/white"
|
||||||
app:slide_to_cancel_bounds="0dp"
|
app:slide_to_cancel_bounds="0dp"
|
||||||
@ -210,6 +221,7 @@
|
|||||||
style="@style/Widget.MaterialComponents.Button.Icon.NoInsets"
|
style="@style/Widget.MaterialComponents.Button.Icon.NoInsets"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
android:visibility="gone"
|
||||||
app:backgroundTint="@color/blue_900"
|
app:backgroundTint="@color/blue_900"
|
||||||
app:elevation="4dp"
|
app:elevation="4dp"
|
||||||
app:icon="@drawable/avd_mic_to_send_anim"
|
app:icon="@drawable/avd_mic_to_send_anim"
|
||||||
@ -226,17 +238,55 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="250dp"
|
android:layout_height="250dp"
|
||||||
android:translationY="250dp"
|
android:translationY="250dp"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<View
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/long_click_backdrop"
|
android:id="@+id/accept_pending_request_question"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:clickable="true"
|
android:paddingTop="16dp"
|
||||||
android:elevation="5dp"
|
android:paddingBottom="8dp"
|
||||||
android:focusable="true"
|
android:text="@string/accept_request_from_user"
|
||||||
android:focusableInTouchMode="true"
|
android:textAlignment="center"
|
||||||
android:visibility="gone" />
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/decline"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/chats_barrier"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/decline"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:text="@string/decline"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
android:textColor="@color/red_500"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/accept"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accept_pending_request_question"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/accept"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:text="@string/accept"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/decline"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accept_pending_request_question"
|
||||||
|
tools:visibility="visible" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
23
app/src/main/res/layout/fragment_direct_pending_inbox.xml
Normal file
23
app/src/main/res/layout/fragment_direct_pending_inbox.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/swipeRefreshLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/pending_inbox_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingBottom="?attr/actionBarSize"
|
||||||
|
tools:listitem="@layout/layout_dm_inbox_item" />
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -80,25 +80,7 @@
|
|||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_global_user_search"
|
android:id="@+id/action_global_user_search"
|
||||||
app:destination="@id/user_search_nav_graph">
|
app:destination="@id/user_search_nav_graph" />
|
||||||
<!--<argument-->
|
|
||||||
<!-- android:name="multiple"-->
|
|
||||||
<!-- app:argType="boolean" />-->
|
|
||||||
|
|
||||||
<!--<argument-->
|
|
||||||
<!-- android:name="title"-->
|
|
||||||
<!-- app:argType="string"-->
|
|
||||||
<!-- app:nullable="true" />-->
|
|
||||||
|
|
||||||
<!--<argument-->
|
|
||||||
<!-- android:name="action_label"-->
|
|
||||||
<!-- app:argType="string"-->
|
|
||||||
<!-- app:nullable="true" />-->
|
|
||||||
|
|
||||||
<!--<argument-->
|
|
||||||
<!-- android:name="hideUserIds"-->
|
|
||||||
<!-- app:argType="long[]" />-->
|
|
||||||
</action>
|
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/directMessagesInboxFragment"
|
android:id="@+id/directMessagesInboxFragment"
|
||||||
@ -108,6 +90,9 @@
|
|||||||
<action
|
<action
|
||||||
android:id="@+id/action_inbox_to_thread"
|
android:id="@+id/action_inbox_to_thread"
|
||||||
app:destination="@id/directMessagesThreadFragment" />
|
app:destination="@id/directMessagesThreadFragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_inbox_to_pending_inbox"
|
||||||
|
app:destination="@id/directPendingInboxFragment" />
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/directMessagesThreadFragment"
|
android:id="@+id/directMessagesThreadFragment"
|
||||||
@ -119,8 +104,12 @@
|
|||||||
<argument
|
<argument
|
||||||
android:name="title"
|
android:name="title"
|
||||||
app:argType="string" />
|
app:argType="string" />
|
||||||
|
<argument
|
||||||
|
android:name="pending"
|
||||||
|
android:defaultValue="false"
|
||||||
|
app:argType="boolean" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_dMThreadFragment_to_dMSettingsFragment"
|
android:id="@+id/action_thread_to_settings"
|
||||||
app:destination="@id/directMessagesSettingsFragment" />
|
app:destination="@id/directMessagesSettingsFragment" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_thread_to_image_edit"
|
android:id="@+id/action_thread_to_image_edit"
|
||||||
@ -144,6 +133,11 @@
|
|||||||
app:argType="string"
|
app:argType="string"
|
||||||
app:nullable="true" />
|
app:nullable="true" />
|
||||||
|
|
||||||
|
<argument
|
||||||
|
android:name="pending"
|
||||||
|
android:defaultValue="false"
|
||||||
|
app:argType="boolean" />
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_settings_to_inbox"
|
android:id="@+id/action_settings_to_inbox"
|
||||||
app:destination="@id/directMessagesInboxFragment"
|
app:destination="@id/directMessagesInboxFragment"
|
||||||
@ -170,4 +164,13 @@
|
|||||||
android:name="options"
|
android:name="options"
|
||||||
app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
|
app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/directPendingInboxFragment"
|
||||||
|
android:name="awais.instagrabber.fragments.directmessages.DirectPendingInboxFragment"
|
||||||
|
android:label="@string/pending_requests"
|
||||||
|
tools:layout="@layout/fragment_direct_pending_inbox">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_pending_inbox_to_thread"
|
||||||
|
app:destination="@id/directMessagesThreadFragment" />
|
||||||
|
</fragment>
|
||||||
</navigation>
|
</navigation>
|
@ -3,4 +3,5 @@
|
|||||||
<item name="reply" type="id" />
|
<item name="reply" type="id" />
|
||||||
<item name="unsend" type="id" />
|
<item name="unsend" type="id" />
|
||||||
<item name="forward" type="id" />
|
<item name="forward" type="id" />
|
||||||
|
<item name="pending_requests" type="id" />
|
||||||
</resources>
|
</resources>
|
@ -418,4 +418,8 @@
|
|||||||
<string name="dms_action_end">End chat</string>
|
<string name="dms_action_end">End chat</string>
|
||||||
<string name="dms_action_end_question">End chat?</string>
|
<string name="dms_action_end_question">End chat?</string>
|
||||||
<string name="dms_action_end_description">All members will be removed from the group. They will still be able to view the chat history.</string>
|
<string name="dms_action_end_description">All members will be removed from the group. They will still be able to view the chat history.</string>
|
||||||
|
<string name="pending_requests">Pending Requests</string>
|
||||||
|
<string name="accept_request_from_user">Accept request from %1s (%2s)?</string>
|
||||||
|
<string name="decline">Decline</string>
|
||||||
|
<string name="accept">Accept</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user