mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-12-22 21:16:57 +00:00
Centralised syncing of inbox.
This commit is contained in:
parent
ea7236dcc1
commit
a7a595f8d4
@ -39,8 +39,8 @@ android {
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
// minifyEnabled true
|
||||
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
||||
release {
|
||||
@ -62,7 +62,7 @@ dependencies {
|
||||
def nav_version = '2.3.2'
|
||||
def exoplayer_version = '2.12.0'
|
||||
|
||||
implementation 'com.google.android.material:material:1.3.0-beta01'
|
||||
implementation 'com.google.android.material:material:1.3.0-rc01'
|
||||
|
||||
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
|
||||
implementation "com.google.android.exoplayer:exoplayer-dash:$exoplayer_version"
|
||||
|
@ -38,6 +38,7 @@ import androidx.emoji.text.FontRequestEmojiCompatConfig;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavDestination;
|
||||
@ -75,6 +76,7 @@ import awais.instagrabber.utils.IntentUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.emoji.EmojiParser;
|
||||
import awais.instagrabber.viewmodels.AppStateViewModel;
|
||||
|
||||
import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
@ -102,6 +104,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
private int firstFragmentGraphIndex;
|
||||
private boolean isActivityCheckerServiceBound = false;
|
||||
private boolean isBackStackEmpty = false;
|
||||
private boolean isLoggedIn;
|
||||
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
@ -131,6 +134,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
CookieUtils.setupCookies(cookie);
|
||||
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) != 0;
|
||||
setContentView(binding.getRoot());
|
||||
final Toolbar toolbar = binding.toolbar;
|
||||
setSupportActionBar(toolbar);
|
||||
@ -142,6 +146,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
final boolean checkUpdates = settingsHelper.getBoolean(Constants.CHECK_UPDATES);
|
||||
if (checkUpdates) FlavorTown.updateCheck(this);
|
||||
FlavorTown.changelogCheck(this);
|
||||
new ViewModelProvider(this).get(AppStateViewModel.class); // Just initiate the App state here
|
||||
final Intent intent = getIntent();
|
||||
handleIntent(intent);
|
||||
if (!TextUtils.isEmpty(cookie) && settingsHelper.getBoolean(Constants.CHECK_ACTIVITY)) {
|
||||
@ -387,8 +392,6 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
|
||||
private void setupBottomNavigationBar(final boolean setDefaultFromSettings) {
|
||||
int main_nav_ids = R.array.main_nav_ids;
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) != 0;
|
||||
if (!isLoggedIn) {
|
||||
main_nav_ids = R.array.logged_out_main_nav_ids;
|
||||
final int selectedItemId = binding.bottomNavView.getSelectedItemId();
|
||||
|
@ -258,7 +258,7 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||
public void setThread(final DirectThread thread) {
|
||||
if (thread == null) return;
|
||||
this.thread = thread;
|
||||
notifyDataSetChanged();
|
||||
// notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void submitList(@Nullable final List<DirectItem> list) {
|
||||
|
@ -36,7 +36,9 @@ public final class DirectMessageInboxAdapter extends ListAdapter<DirectThread, D
|
||||
final DirectItem oldItemFirst = oldThread.getFirstDirectItem();
|
||||
final DirectItem newItemFirst = newThread.getFirstDirectItem();
|
||||
if (oldItemFirst == null || newItemFirst == null) return false;
|
||||
return oldItemFirst.getItemId().equals(newItemFirst.getItemId());
|
||||
final boolean idsEqual = oldItemFirst.getItemId().equals(newItemFirst.getItemId());
|
||||
if (!idsEqual) return false;
|
||||
return oldItemFirst.getTimestamp() == newItemFirst.getTimestamp();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -349,9 +349,19 @@ public final class DirectInboxItemViewHolder extends RecyclerView.ViewHolder {
|
||||
}
|
||||
|
||||
private void setReadState(@NonNull final DirectThread thread) {
|
||||
final DirectItem item = thread.getItems().get(0);
|
||||
final Map<Long, DirectThreadLastSeenAt> lastSeenAtMap = thread.getLastSeenAt();
|
||||
final boolean read = ResponseBodyUtils.isRead(item, lastSeenAtMap, Collections.singletonList(thread.getViewerId()), thread.getDirectStory());
|
||||
final boolean read;
|
||||
if (thread.getDirectStory() != null) {
|
||||
read = false;
|
||||
} else {
|
||||
final DirectItem item = thread.getFirstDirectItem();
|
||||
if (item.getUserId() == thread.getViewerId()) {
|
||||
// if last item was sent by user, then it is read (even though we have auto read unchecked?)
|
||||
read = true;
|
||||
} else {
|
||||
final Map<Long, DirectThreadLastSeenAt> lastSeenAtMap = thread.getLastSeenAt();
|
||||
read = ResponseBodyUtils.isRead(item, lastSeenAtMap, Collections.singletonList(thread.getViewerId()));
|
||||
}
|
||||
}
|
||||
binding.unread.setVisibility(read ? View.GONE : View.VISIBLE);
|
||||
binding.threadTitle.setTypeface(binding.threadTitle.getTypeface(), read ? Typeface.NORMAL : Typeface.BOLD);
|
||||
binding.subtitle.setTypeface(binding.subtitle.getTypeface(), read ? Typeface.NORMAL : Typeface.BOLD);
|
||||
|
@ -196,7 +196,10 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder imple
|
||||
if (item.isPending()) {
|
||||
binding.deliveryStatus.setImageResource(R.drawable.ic_check_24);
|
||||
} else {
|
||||
final boolean read = ResponseBodyUtils.isRead(item, thread.getLastSeenAt(), userIds, null);
|
||||
final boolean read = ResponseBodyUtils.isRead(item,
|
||||
thread.getLastSeenAt(),
|
||||
userIds
|
||||
);
|
||||
binding.deliveryStatus.setImageResource(R.drawable.ic_check_all_24);
|
||||
ImageViewCompat.setImageTintList(
|
||||
binding.deliveryStatus,
|
||||
@ -358,7 +361,7 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder imple
|
||||
final DirectItemReactions reactions = item.getReactions();
|
||||
final List<DirectItemEmojiReaction> emojis = reactions != null ? reactions.getEmojis() : null;
|
||||
if (emojis == null || emojis.isEmpty()) {
|
||||
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall);
|
||||
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, 0);
|
||||
binding.reactionsWrapper.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
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.snackbar.Snackbar;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -172,6 +173,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
||||
}
|
||||
|
||||
private void setupObservers() {
|
||||
removeViewModelObservers();
|
||||
threadsObserver = list -> {
|
||||
if (inboxAdapter == null) return;
|
||||
inboxAdapter.submitList(list, () -> {
|
||||
@ -181,8 +183,28 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
||||
});
|
||||
};
|
||||
viewModel.getThreads().observe(fragmentActivity, threadsObserver);
|
||||
viewModel.getFetchingInbox().observe(getViewLifecycleOwner(), fetching -> binding.swipeRefreshLayout.setRefreshing(fetching));
|
||||
viewModel.getUnseenCount().observe(getViewLifecycleOwner(), this::setBottomNavBarBadge);
|
||||
viewModel.getInbox().observe(getViewLifecycleOwner(), inboxResource -> {
|
||||
if (inboxResource == null) return;
|
||||
switch (inboxResource.status) {
|
||||
case SUCCESS:
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
break;
|
||||
case ERROR:
|
||||
if (inboxResource.message != null) {
|
||||
Snackbar.make(binding.getRoot(), inboxResource.message, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
break;
|
||||
case LOADING:
|
||||
binding.swipeRefreshLayout.setRefreshing(true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
viewModel.getUnseenCount().observe(getViewLifecycleOwner(), unseenCountResource -> {
|
||||
if (unseenCountResource == null) return;
|
||||
final Integer unseenCount = unseenCountResource.data;
|
||||
setBottomNavBarBadge(unseenCount == null ? 0 : unseenCount);
|
||||
});
|
||||
viewModel.getPendingRequestsTotal().observe(getViewLifecycleOwner(), this::attachPendingRequestsBadge);
|
||||
}
|
||||
|
||||
@ -230,11 +252,10 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
||||
inboxAdapter = new DirectMessageInboxAdapter(thread -> {
|
||||
if (navigating) return;
|
||||
navigating = true;
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString("threadId", thread.getThreadId());
|
||||
bundle.putString("title", thread.getThreadTitle());
|
||||
if (isAdded()) {
|
||||
NavHostFragment.findNavController(this).navigate(R.id.action_inbox_to_thread, bundle);
|
||||
final DirectMessageInboxFragmentDirections.ActionInboxToThread directions = DirectMessageInboxFragmentDirections
|
||||
.actionInboxToThread(thread.getThreadId(), thread.getThreadTitle());
|
||||
NavHostFragment.findNavController(this).navigate(directions);
|
||||
}
|
||||
navigating = false;
|
||||
});
|
||||
|
@ -11,13 +11,11 @@ import android.widget.CompoundButton;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.lifecycle.ViewModelStoreOwner;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavDestination;
|
||||
@ -31,13 +29,13 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.ProfileNavGraphDirections;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.UserSearchNavGraphDirections;
|
||||
import awais.instagrabber.activities.MainActivity;
|
||||
import awais.instagrabber.adapters.DirectPendingUsersAdapter;
|
||||
import awais.instagrabber.adapters.DirectPendingUsersAdapter.PendingUser;
|
||||
import awais.instagrabber.adapters.DirectPendingUsersAdapter.PendingUserCallback;
|
||||
@ -52,12 +50,11 @@ import awais.instagrabber.fragments.UserSearchFragment;
|
||||
import awais.instagrabber.fragments.UserSearchFragmentDirections;
|
||||
import awais.instagrabber.models.Resource;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse;
|
||||
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
|
||||
import awais.instagrabber.viewmodels.DirectInboxViewModel;
|
||||
import awais.instagrabber.viewmodels.DirectPendingInboxViewModel;
|
||||
import awais.instagrabber.viewmodels.AppStateViewModel;
|
||||
import awais.instagrabber.viewmodels.DirectSettingsViewModel;
|
||||
import awais.instagrabber.viewmodels.factories.DirectSettingsViewModelFactory;
|
||||
|
||||
public class DirectMessageSettingsFragment extends Fragment implements ConfirmDialogFragmentCallback {
|
||||
private static final String TAG = DirectMessageSettingsFragment.class.getSimpleName();
|
||||
@ -77,33 +74,14 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
super.onCreate(savedInstanceState);
|
||||
final Bundle arguments = getArguments();
|
||||
if (arguments == null) return;
|
||||
final NavController navController = NavHostFragment.findNavController(this);
|
||||
final ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
||||
final DirectMessageSettingsFragmentArgs args = DirectMessageSettingsFragmentArgs.fromBundle(arguments);
|
||||
final boolean pending = args.getPending();
|
||||
final List<DirectThread> threads;
|
||||
final User viewer;
|
||||
if (pending) {
|
||||
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 String threadId = args.getThreadId();
|
||||
final Optional<DirectThread> first = threads != null ? threads.stream()
|
||||
.filter(thread -> thread.getThreadId().equals(threadId))
|
||||
.findFirst()
|
||||
: Optional.empty();
|
||||
if (!first.isPresent()) {
|
||||
navController.navigateUp();
|
||||
return;
|
||||
}
|
||||
viewModel = new ViewModelProvider(this).get(DirectSettingsViewModel.class);
|
||||
viewModel.setViewer(viewer);
|
||||
viewModel.setThread(first.get());
|
||||
final MainActivity fragmentActivity = (MainActivity) requireActivity();
|
||||
final AppStateViewModel appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class);
|
||||
viewModel = new ViewModelProvider(this, new DirectSettingsViewModelFactory(fragmentActivity.getApplication(),
|
||||
args.getThreadId(),
|
||||
args.getPending(),
|
||||
appStateViewModel.getCurrentUser()))
|
||||
.get(DirectSettingsViewModel.class);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -143,21 +121,23 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
binding.muteMessages.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
viewModel.getUsers().observe(getViewLifecycleOwner(), users -> {
|
||||
// Need to observe, so that getValue is correct
|
||||
viewModel.getUsers().observe(getViewLifecycleOwner(), users -> {});
|
||||
viewModel.getLeftUsers().observe(getViewLifecycleOwner(), users -> {});
|
||||
viewModel.getUsersAndLeftUsers().observe(getViewLifecycleOwner(), usersPair -> {
|
||||
if (usersAdapter == null) return;
|
||||
usersAdapter.submitUsers(users.first, users.second);
|
||||
usersAdapter.submitUsers(usersPair.first, usersPair.second);
|
||||
});
|
||||
viewModel.getTitle().observe(getViewLifecycleOwner(), title -> binding.titleEdit.setText(title));
|
||||
viewModel.getAdminUserIds().observe(getViewLifecycleOwner(), adminUserIds -> {
|
||||
if (usersAdapter == null) return;
|
||||
usersAdapter.setAdminUserIds(adminUserIds);
|
||||
});
|
||||
viewModel.getMuted().observe(getViewLifecycleOwner(), muted -> binding.muteMessages.setChecked(muted));
|
||||
viewModel.isMuted().observe(getViewLifecycleOwner(), muted -> binding.muteMessages.setChecked(muted));
|
||||
viewModel.isPending().observe(getViewLifecycleOwner(), pending -> binding.muteMessages.setVisibility(pending ? View.GONE : View.VISIBLE));
|
||||
if (viewModel.isViewerAdmin()) {
|
||||
viewModel.getApprovalRequiredToJoin().observe(getViewLifecycleOwner(), required -> binding.approvalRequired.setChecked(required));
|
||||
viewModel.getPendingRequests().observe(getViewLifecycleOwner(), this::setPendingRequests);
|
||||
}
|
||||
viewModel.isViewerAdmin().observe(getViewLifecycleOwner(), this::setApprovalRelatedUI);
|
||||
viewModel.getApprovalRequiredToJoin().observe(getViewLifecycleOwner(), required -> binding.approvalRequired.setChecked(required));
|
||||
viewModel.getPendingRequests().observe(getViewLifecycleOwner(), this::setPendingRequests);
|
||||
final NavController navController = NavHostFragment.findNavController(this);
|
||||
final NavBackStackEntry backStackEntry = navController.getCurrentBackStackEntry();
|
||||
if (backStackEntry != null) {
|
||||
@ -192,7 +172,11 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
|
||||
private void addMembers(final Set<User> users) {
|
||||
final Boolean approvalRequired = viewModel.getApprovalRequiredToJoin().getValue();
|
||||
if (!viewModel.isViewerAdmin() && approvalRequired != null && approvalRequired) {
|
||||
Boolean isViewerAdmin = viewModel.isViewerAdmin().getValue();
|
||||
if (isViewerAdmin == null) {
|
||||
isViewerAdmin = false;
|
||||
}
|
||||
if (!isViewerAdmin && approvalRequired != null && approvalRequired) {
|
||||
approvalRequiredUsers = users;
|
||||
final ConfirmDialogFragment confirmDialogFragment = ConfirmDialogFragment.newInstance(
|
||||
APPROVAL_REQUIRED_REQUEST_CODE,
|
||||
@ -226,13 +210,15 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
}
|
||||
|
||||
private void setupSettings() {
|
||||
binding.groupSettings.setVisibility(viewModel.isGroup() ? View.VISIBLE : View.GONE);
|
||||
Boolean isGroup = viewModel.isGroup().getValue();
|
||||
if (isGroup == null) isGroup = false;
|
||||
binding.groupSettings.setVisibility(isGroup ? View.VISIBLE : View.GONE);
|
||||
binding.muteMessagesLabel.setOnClickListener(v -> binding.muteMessages.toggle());
|
||||
binding.muteMessages.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
final LiveData<Resource<Object>> resourceLiveData = isChecked ? viewModel.mute() : viewModel.unmute();
|
||||
handleSwitchChangeResource(resourceLiveData, buttonView);
|
||||
});
|
||||
if (!viewModel.isGroup()) return;
|
||||
if (!isGroup) return;
|
||||
binding.titleEdit.addTextChangedListener(new TextWatcherAdapter() {
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
@ -256,14 +242,13 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
final NavDestination currentDestination = navController.getCurrentDestination();
|
||||
if (currentDestination == null) return;
|
||||
if (currentDestination.getId() != R.id.directMessagesSettingsFragment) return;
|
||||
final Pair<List<User>, List<User>> users = viewModel.getUsers().getValue();
|
||||
final List<User> users = viewModel.getUsers().getValue();
|
||||
final long[] currentUserIds;
|
||||
if (users != null && users.first != null) {
|
||||
final List<User> currentMembers = users.first;
|
||||
currentUserIds = currentMembers.stream()
|
||||
.mapToLong(User::getPk)
|
||||
.sorted()
|
||||
.toArray();
|
||||
if (users != null) {
|
||||
currentUserIds = users.stream()
|
||||
.mapToLong(User::getPk)
|
||||
.sorted()
|
||||
.toArray();
|
||||
} else {
|
||||
currentUserIds = new long[0];
|
||||
}
|
||||
@ -281,7 +266,6 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
final LiveData<Resource<Object>> resourceLiveData = isChecked ? viewModel.muteMentions() : viewModel.unmuteMentions();
|
||||
handleSwitchChangeResource(resourceLiveData, buttonView);
|
||||
});
|
||||
setApprovalRelatedUI();
|
||||
binding.leave.setOnClickListener(v -> {
|
||||
final ConfirmDialogFragment confirmDialogFragment = ConfirmDialogFragment.newInstance(
|
||||
LEAVE_THREAD_REQUEST_CODE,
|
||||
@ -293,7 +277,9 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
);
|
||||
confirmDialogFragment.show(getChildFragmentManager(), "leave_thread_confirmation_dialog");
|
||||
});
|
||||
if (viewModel.isViewerAdmin()) {
|
||||
Boolean isViewerAdmin = viewModel.isViewerAdmin().getValue();
|
||||
if (isViewerAdmin == null) isViewerAdmin = false;
|
||||
if (isViewerAdmin) {
|
||||
binding.end.setVisibility(View.VISIBLE);
|
||||
binding.end.setOnClickListener(v -> {
|
||||
final ConfirmDialogFragment confirmDialogFragment = ConfirmDialogFragment.newInstance(
|
||||
@ -311,8 +297,8 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
}
|
||||
}
|
||||
|
||||
private void setApprovalRelatedUI() {
|
||||
if (!viewModel.isViewerAdmin()) {
|
||||
private void setApprovalRelatedUI(final boolean isViewerAdmin) {
|
||||
if (!isViewerAdmin) {
|
||||
binding.pendingMembersGroup.setVisibility(View.GONE);
|
||||
binding.approvalRequired.setVisibility(View.GONE);
|
||||
binding.approvalRequiredLabel.setVisibility(View.GONE);
|
||||
@ -352,7 +338,7 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
final Context context = getContext();
|
||||
if (context == null) return;
|
||||
binding.users.setLayoutManager(new LinearLayoutManager(context));
|
||||
final User inviter = viewModel.getThread().getInviter();
|
||||
final User inviter = viewModel.getInviter().getValue();
|
||||
usersAdapter = new DirectUsersAdapter(
|
||||
inviter != null ? inviter.getPk() : -1,
|
||||
(position, user, selected) -> {
|
||||
|
@ -37,7 +37,6 @@ import androidx.lifecycle.MediatorLiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.lifecycle.ViewModelStoreOwner;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavDirections;
|
||||
@ -58,7 +57,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import awais.instagrabber.ProfileNavGraphDirections;
|
||||
@ -104,9 +102,8 @@ import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.viewmodels.AppStateViewModel;
|
||||
import awais.instagrabber.viewmodels.DirectInboxViewModel;
|
||||
import awais.instagrabber.viewmodels.DirectPendingInboxViewModel;
|
||||
import awais.instagrabber.viewmodels.DirectThreadViewModel;
|
||||
import awais.instagrabber.viewmodels.factories.DirectThreadViewModelFactory;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
|
||||
@ -235,7 +232,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
@Override
|
||||
public void onReaction(final DirectItem item, final Emoji emoji) {
|
||||
if (item == null) return;
|
||||
final LiveData<Resource<DirectItem>> resourceLiveData = viewModel.sendReaction(item, emoji);
|
||||
final LiveData<Resource<Object>> resourceLiveData = viewModel.sendReaction(item, emoji);
|
||||
if (resourceLiveData != null) {
|
||||
resourceLiveData.observe(getViewLifecycleOwner(), directItemResource -> handleSentMessage(resourceLiveData));
|
||||
}
|
||||
@ -295,13 +292,29 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
};
|
||||
private final MutableLiveData<Integer> inputLength = new MutableLiveData<>(0);
|
||||
private ItemTouchHelper itemTouchHelper;
|
||||
private LiveData<Boolean> pendingLiveData;
|
||||
private LiveData<DirectThread> threadLiveData;
|
||||
private LiveData<Integer> inputModeLiveData;
|
||||
private LiveData<String> threadTitleLiveData;
|
||||
private LiveData<Resource<Object>> fetchingLiveData;
|
||||
private LiveData<List<DirectItem>> itemsLiveData;
|
||||
private LiveData<DirectItem> replyToItemLiveData;
|
||||
private LiveData<Integer> pendingRequestsCountLiveData;
|
||||
private LiveData<List<User>> usersLiveData;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
fragmentActivity = (MainActivity) requireActivity();
|
||||
appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class);
|
||||
viewModel = new ViewModelProvider(this).get(DirectThreadViewModel.class);
|
||||
final Bundle arguments = getArguments();
|
||||
if (arguments == null) return;
|
||||
final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments);
|
||||
viewModel = new ViewModelProvider(this, new DirectThreadViewModelFactory(fragmentActivity.getApplication(),
|
||||
fragmentArgs.getThreadId(),
|
||||
fragmentArgs.getPending(),
|
||||
appStateViewModel.getCurrentUser()))
|
||||
.get(DirectThreadViewModel.class);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@ -332,7 +345,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
init();
|
||||
binding.send.post(() -> initialSendX = binding.send.getX());
|
||||
shouldRefresh = false;
|
||||
setObservers();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -406,6 +418,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
wasKbShowing = true;
|
||||
binding.emojiPicker.setAlpha(0);
|
||||
}
|
||||
removeObservers();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@ -423,7 +436,8 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
}
|
||||
binding.send.stopScale();
|
||||
setupBackStackResultObserver();
|
||||
attachPendingRequestsBadge(viewModel.getPendingRequestsCount().getValue());
|
||||
setObservers();
|
||||
// attachPendingRequestsBadge(viewModel.getPendingRequestsCount().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -463,42 +477,38 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
if (context == null) return;
|
||||
if (getArguments() == null) return;
|
||||
actionBar = fragmentActivity.getSupportActionBar();
|
||||
final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(getArguments());
|
||||
viewModel.getThreadTitle().postValue(fragmentArgs.getTitle());
|
||||
final String threadId = fragmentArgs.getThreadId();
|
||||
viewModel.setThreadId(threadId);
|
||||
setupList();
|
||||
root.post(this::setupInput);
|
||||
root.post(this::getInitialData);
|
||||
// root.post(this::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 ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
||||
final List<DirectThread> threads;
|
||||
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
|
||||
? threads.stream()
|
||||
.filter(thread -> thread.getThreadId().equals(viewModel.getThreadId()))
|
||||
.findFirst()
|
||||
: Optional.empty();
|
||||
if (first.isPresent()) {
|
||||
final DirectThread thread = first.get();
|
||||
viewModel.setThread(thread);
|
||||
return;
|
||||
}
|
||||
viewModel.fetchChats();
|
||||
}
|
||||
// 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 ViewModelStoreOwner viewModelStoreOwner = navController.getViewModelStoreOwner(R.id.direct_messages_nav_graph);
|
||||
// final List<DirectThread> threads;
|
||||
// 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
|
||||
// ? threads.stream()
|
||||
// .filter(thread -> thread.getThreadId().equals(viewModel.getThreadId()))
|
||||
// .findFirst()
|
||||
// : Optional.empty();
|
||||
// if (first.isPresent()) {
|
||||
// final DirectThread thread = first.get();
|
||||
// viewModel.setThread(thread);
|
||||
// return;
|
||||
// }
|
||||
// viewModel.fetchChats();
|
||||
// }
|
||||
|
||||
private void setupList() {
|
||||
final Context context = getContext();
|
||||
@ -542,7 +552,14 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
}
|
||||
|
||||
private void setObservers() {
|
||||
viewModel.isPending().observe(getViewLifecycleOwner(), isPending -> {
|
||||
threadLiveData = viewModel.getThread();
|
||||
if (threadLiveData == null) {
|
||||
final NavController navController = NavHostFragment.findNavController(this);
|
||||
navController.navigateUp();
|
||||
return;
|
||||
}
|
||||
pendingLiveData = viewModel.isPending();
|
||||
pendingLiveData.observe(getViewLifecycleOwner(), isPending -> {
|
||||
if (isPending == null) {
|
||||
hideInput();
|
||||
return;
|
||||
@ -556,7 +573,8 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
if (inputMode != null && inputMode == 1) return;
|
||||
showInput();
|
||||
});
|
||||
viewModel.getInputMode().observe(getViewLifecycleOwner(), inputMode -> {
|
||||
inputModeLiveData = viewModel.getInputMode();
|
||||
inputModeLiveData.observe(getViewLifecycleOwner(), inputMode -> {
|
||||
final Boolean isPending = viewModel.isPending().getValue();
|
||||
if (isPending != null && isPending) return;
|
||||
if (inputMode == null || inputMode == 0) return;
|
||||
@ -564,21 +582,34 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
hideInput();
|
||||
}
|
||||
});
|
||||
viewModel.getThreadTitle().observe(getViewLifecycleOwner(), this::setTitle);
|
||||
viewModel.getFetching().observe(getViewLifecycleOwner(), fetching -> {
|
||||
if (fetching) {
|
||||
setTitle(UPDATING_TITLE);
|
||||
return;
|
||||
threadTitleLiveData = viewModel.getThreadTitle();
|
||||
threadTitleLiveData.observe(getViewLifecycleOwner(), this::setTitle);
|
||||
fetchingLiveData = viewModel.isFetching();
|
||||
fetchingLiveData.observe(getViewLifecycleOwner(), fetchingResource -> {
|
||||
if (fetchingResource == null) return;
|
||||
switch (fetchingResource.status) {
|
||||
case SUCCESS:
|
||||
case ERROR:
|
||||
setTitle(viewModel.getThreadTitle().getValue());
|
||||
if (fetchingResource.message != null) {
|
||||
Snackbar.make(binding.getRoot(), fetchingResource.message, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
break;
|
||||
case LOADING:
|
||||
setTitle(UPDATING_TITLE);
|
||||
break;
|
||||
}
|
||||
setTitle(viewModel.getThreadTitle().getValue());
|
||||
});
|
||||
final ItemsAdapterDataMerger itemsAdapterDataMerger = new ItemsAdapterDataMerger(appStateViewModel.getCurrentUser(), viewModel.getThread());
|
||||
itemsAdapterDataMerger.observe(getViewLifecycleOwner(), userThreadPair -> {
|
||||
viewModel.setCurrentUser(userThreadPair.first);
|
||||
setupItemsAdapter(userThreadPair.first, userThreadPair.second);
|
||||
});
|
||||
viewModel.getItems().observe(getViewLifecycleOwner(), this::submitItemsToAdapter);
|
||||
viewModel.getReplyToItem().observe(getViewLifecycleOwner(), item -> {
|
||||
// final ItemsAdapterDataMerger itemsAdapterDataMerger = new ItemsAdapterDataMerger(appStateViewModel.getCurrentUser(), viewModel.getThread());
|
||||
// itemsAdapterDataMerger.observe(getViewLifecycleOwner(), userThreadPair -> {
|
||||
// viewModel.setCurrentUser(userThreadPair.first);
|
||||
// setupItemsAdapter(userThreadPair.first, userThreadPair.second);
|
||||
// });
|
||||
threadLiveData.observe(getViewLifecycleOwner(), this::setupItemsAdapter);
|
||||
itemsLiveData = viewModel.getItems();
|
||||
itemsLiveData.observe(getViewLifecycleOwner(), this::submitItemsToAdapter);
|
||||
replyToItemLiveData = viewModel.getReplyToItem();
|
||||
replyToItemLiveData.observe(getViewLifecycleOwner(), item -> {
|
||||
if (item == null) {
|
||||
if (binding.input.length() == 0) {
|
||||
showExtraInputOption(true);
|
||||
@ -633,14 +664,30 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
}
|
||||
prevLength = length;
|
||||
});
|
||||
viewModel.getPendingRequestsCount().observe(getViewLifecycleOwner(), this::attachPendingRequestsBadge);
|
||||
viewModel.getUsers().observe(getViewLifecycleOwner(), users -> {
|
||||
pendingRequestsCountLiveData = viewModel.getPendingRequestsCount();
|
||||
pendingRequestsCountLiveData.observe(getViewLifecycleOwner(), this::attachPendingRequestsBadge);
|
||||
usersLiveData = viewModel.getUsers();
|
||||
usersLiveData.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 removeObservers() {
|
||||
pendingLiveData.removeObservers(getViewLifecycleOwner());
|
||||
inputModeLiveData.removeObservers(getViewLifecycleOwner());
|
||||
threadTitleLiveData.removeObservers(getViewLifecycleOwner());
|
||||
fetchingLiveData.removeObservers(getViewLifecycleOwner());
|
||||
threadLiveData.removeObservers(getViewLifecycleOwner());
|
||||
itemsLiveData.removeObservers(getViewLifecycleOwner());
|
||||
replyToItemLiveData.removeObservers(getViewLifecycleOwner());
|
||||
inputLength.removeObservers(getViewLifecycleOwner());
|
||||
pendingRequestsCountLiveData.removeObservers(getViewLifecycleOwner());
|
||||
usersLiveData.removeObservers(getViewLifecycleOwner());
|
||||
|
||||
}
|
||||
|
||||
private void hidePendingOptions() {
|
||||
binding.acceptPendingRequestQuestion.setVisibility(View.GONE);
|
||||
binding.decline.setVisibility(View.GONE);
|
||||
@ -669,9 +716,15 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
case SUCCESS:
|
||||
resourceLiveData.removeObservers(getViewLifecycleOwner());
|
||||
if (isDecline) {
|
||||
removeObservers();
|
||||
viewModel.removeThread();
|
||||
final NavController navController = NavHostFragment.findNavController(this);
|
||||
navController.navigateUp();
|
||||
return;
|
||||
}
|
||||
removeObservers();
|
||||
viewModel.moveFromPending();
|
||||
setObservers();
|
||||
break;
|
||||
case LOADING:
|
||||
break;
|
||||
@ -838,12 +891,15 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
});
|
||||
}
|
||||
|
||||
private void setupItemsAdapter(final User currentUser, final DirectThread thread) {
|
||||
private void setupItemsAdapter(final DirectThread thread) {
|
||||
if (thread == null) return;
|
||||
if (itemsAdapter != null) {
|
||||
if (itemsAdapter.getThread() == thread) return;
|
||||
itemsAdapter.setThread(thread);
|
||||
return;
|
||||
}
|
||||
final User currentUser = appStateViewModel.getCurrentUser();
|
||||
if (currentUser == null) return;
|
||||
itemsAdapter = new DirectItemsAdapter(currentUser, thread, directItemCallback, directItemLongClickListener);
|
||||
itemsAdapter.setHasStableIds(true);
|
||||
itemsAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY);
|
||||
@ -958,7 +1014,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
binding.send.setOnRecordClickListener(v -> {
|
||||
final Editable text = binding.input.getText();
|
||||
if (TextUtils.isEmpty(text)) return;
|
||||
final LiveData<Resource<DirectItem>> resourceLiveData = viewModel.sendText(text.toString());
|
||||
final LiveData<Resource<Object>> resourceLiveData = viewModel.sendText(text.toString());
|
||||
resourceLiveData.observe(getViewLifecycleOwner(), resource -> handleSentMessage(resourceLiveData));
|
||||
binding.input.setText("");
|
||||
viewModel.setReplyToItem(null);
|
||||
@ -1031,8 +1087,8 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
navController.navigate(navDirections);
|
||||
}
|
||||
|
||||
private void handleSentMessage(final LiveData<Resource<DirectItem>> resourceLiveData) {
|
||||
final Resource<DirectItem> resource = resourceLiveData.getValue();
|
||||
private void handleSentMessage(final LiveData<Resource<Object>> resourceLiveData) {
|
||||
final Resource<Object> resource = resourceLiveData.getValue();
|
||||
if (resource == null) return;
|
||||
final Resource.Status status = resource.status;
|
||||
switch (status) {
|
||||
@ -1380,10 +1436,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
animatorSet.start();
|
||||
}
|
||||
|
||||
private void showLongClickOptions(final View itemView) {
|
||||
|
||||
}
|
||||
|
||||
private void showReactionsDialog(final DirectItem item) {
|
||||
final LiveData<List<User>> users = viewModel.getUsers();
|
||||
final LiveData<List<User>> leftUsers = viewModel.getLeftUsers();
|
||||
@ -1410,7 +1462,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
}
|
||||
if (reaction == null) return;
|
||||
if (reaction.getSenderId() == viewModel.getViewerId()) {
|
||||
final LiveData<Resource<DirectItem>> resourceLiveData = viewModel.sendDeleteReaction(itemId);
|
||||
final LiveData<Resource<Object>> resourceLiveData = viewModel.sendDeleteReaction(itemId);
|
||||
if (resourceLiveData != null) {
|
||||
resourceLiveData.observe(getViewLifecycleOwner(), directItemResource -> handleSentMessage(resourceLiveData));
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
@ -102,16 +105,41 @@ public class DirectPendingInboxFragment extends Fragment implements SwipeRefresh
|
||||
}
|
||||
|
||||
private void setupObservers() {
|
||||
removeViewModelObservers();
|
||||
threadsObserver = list -> {
|
||||
if (inboxAdapter == null) return;
|
||||
inboxAdapter.submitList(list, () -> {
|
||||
if (binding.swipeRefreshLayout.getVisibility() == View.GONE) {
|
||||
binding.swipeRefreshLayout.setVisibility(View.VISIBLE);
|
||||
binding.empty.setVisibility(View.GONE);
|
||||
}
|
||||
inboxAdapter.submitList(list == null ? Collections.emptyList() : list, () -> {
|
||||
if (!scrollToTop) return;
|
||||
binding.pendingInboxList.smoothScrollToPosition(0);
|
||||
scrollToTop = false;
|
||||
});
|
||||
if (list == null || list.isEmpty()) {
|
||||
binding.swipeRefreshLayout.setVisibility(View.GONE);
|
||||
binding.empty.setVisibility(View.VISIBLE);
|
||||
}
|
||||
};
|
||||
viewModel.getThreads().observe(fragmentActivity, threadsObserver);
|
||||
viewModel.getFetchingInbox().observe(getViewLifecycleOwner(), fetching -> binding.swipeRefreshLayout.setRefreshing(fetching));
|
||||
viewModel.getInbox().observe(getViewLifecycleOwner(), inboxResource -> {
|
||||
if (inboxResource == null) return;
|
||||
switch (inboxResource.status) {
|
||||
case SUCCESS:
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
break;
|
||||
case ERROR:
|
||||
if (inboxResource.message != null) {
|
||||
Snackbar.make(binding.getRoot(), inboxResource.message, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
break;
|
||||
case LOADING:
|
||||
binding.swipeRefreshLayout.setRefreshing(true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void removeViewModelObservers() {
|
||||
|
@ -0,0 +1,81 @@
|
||||
package awais.instagrabber.managers;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
|
||||
public final class DirectMessagesManager {
|
||||
private static final String TAG = DirectMessagesManager.class.getSimpleName();
|
||||
private static final Object LOCK = new Object();
|
||||
|
||||
private static DirectMessagesManager instance;
|
||||
|
||||
private final InboxManager inboxManager;
|
||||
private final InboxManager pendingInboxManager;
|
||||
|
||||
public static DirectMessagesManager getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (LOCK) {
|
||||
if (instance == null) {
|
||||
instance = new DirectMessagesManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private DirectMessagesManager() {
|
||||
inboxManager = InboxManager.getInstance(false);
|
||||
pendingInboxManager = InboxManager.getInstance(true);
|
||||
}
|
||||
|
||||
public void moveThreadFromPending(@NonNull final String threadId) {
|
||||
final List<DirectThread> pendingThreads = pendingInboxManager.getThreads().getValue();
|
||||
if (pendingThreads == null) return;
|
||||
final int index = Iterables.indexOf(pendingThreads, t -> t.getThreadId().equals(threadId));
|
||||
if (index < 0) return;
|
||||
final DirectThread thread = pendingThreads.get(index);
|
||||
final DirectItem threadFirstDirectItem = thread.getFirstDirectItem();
|
||||
if (threadFirstDirectItem == null) return;
|
||||
final List<DirectThread> threads = inboxManager.getThreads().getValue();
|
||||
int insertIndex = 0;
|
||||
for (final DirectThread tempThread : threads) {
|
||||
final DirectItem firstDirectItem = tempThread.getFirstDirectItem();
|
||||
if (firstDirectItem == null) continue;
|
||||
final long timestamp = firstDirectItem.getTimestamp();
|
||||
if (timestamp < threadFirstDirectItem.getTimestamp()) {
|
||||
break;
|
||||
}
|
||||
insertIndex++;
|
||||
}
|
||||
thread.setPending(false);
|
||||
inboxManager.addThread(thread, insertIndex);
|
||||
pendingInboxManager.removeThread(threadId);
|
||||
final Integer currentTotal = inboxManager.getPendingRequestsTotal().getValue();
|
||||
if (currentTotal == null) return;
|
||||
inboxManager.setPendingRequestsTotal(currentTotal - 1);
|
||||
}
|
||||
|
||||
public InboxManager getInboxManager() {
|
||||
return inboxManager;
|
||||
}
|
||||
|
||||
public InboxManager getPendingInboxManager() {
|
||||
return pendingInboxManager;
|
||||
}
|
||||
|
||||
public ThreadManager getThreadManager(@NonNull final String threadId,
|
||||
final boolean pending,
|
||||
@NonNull final User currentUser,
|
||||
@NonNull final ContentResolver contentResolver) {
|
||||
return ThreadManager.getInstance(threadId, pending, currentUser, contentResolver);
|
||||
}
|
||||
}
|
358
app/src/main/java/awais/instagrabber/managers/InboxManager.java
Normal file
358
app/src/main/java/awais/instagrabber/managers/InboxManager.java
Normal file
@ -0,0 +1,358 @@
|
||||
package awais.instagrabber.managers;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Transformations;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.models.Resource;
|
||||
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.DirectItem;
|
||||
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 androidx.lifecycle.Transformations.distinctUntilChanged;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public final class InboxManager {
|
||||
private static final String TAG = InboxManager.class.getSimpleName();
|
||||
private static final LoadingCache<String, Object> THREAD_LOCKS = CacheBuilder
|
||||
.newBuilder()
|
||||
.expireAfterAccess(1, TimeUnit.MINUTES) // max lock time ever expected
|
||||
.build(CacheLoader.from(Object::new));
|
||||
private static final Comparator<DirectThread> THREAD_COMPARATOR = (t1, t2) -> {
|
||||
final DirectItem t1FirstDirectItem = t1.getFirstDirectItem();
|
||||
final DirectItem t2FirstDirectItem = t2.getFirstDirectItem();
|
||||
if (t1FirstDirectItem == null && t2FirstDirectItem == null) return 0;
|
||||
if (t1FirstDirectItem == null) return 1;
|
||||
if (t2FirstDirectItem == null) return -1;
|
||||
return Long.compare(t2FirstDirectItem.getTimestamp(), t1FirstDirectItem.getTimestamp());
|
||||
};
|
||||
|
||||
private final MutableLiveData<Resource<DirectInbox>> inbox = new MutableLiveData<>();
|
||||
private final MutableLiveData<Resource<Integer>> unseenCount = new MutableLiveData<>();
|
||||
private final MutableLiveData<Integer> pendingRequestsTotal = new MutableLiveData<>(0);
|
||||
|
||||
private final LiveData<List<DirectThread>> threads;
|
||||
private final DirectMessagesService service;
|
||||
private final boolean pending;
|
||||
|
||||
private Call<DirectInboxResponse> inboxRequest;
|
||||
private Call<DirectBadgeCount> unseenCountRequest;
|
||||
private long seqId;
|
||||
private String cursor;
|
||||
private boolean hasOlder = true;
|
||||
private User viewer;
|
||||
|
||||
@NonNull
|
||||
public static InboxManager getInstance(final boolean pending) {
|
||||
return new InboxManager(pending);
|
||||
}
|
||||
|
||||
private InboxManager(final boolean pending) {
|
||||
this.pending = pending;
|
||||
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);
|
||||
|
||||
// Transformations
|
||||
threads = distinctUntilChanged(Transformations.map(inbox, inboxResource -> {
|
||||
if (inboxResource == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final DirectInbox inbox = inboxResource.data;
|
||||
if (inbox == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return ImmutableList.sortedCopyOf(THREAD_COMPARATOR, inbox.getThreads());
|
||||
}));
|
||||
|
||||
fetchInbox();
|
||||
if (!pending) {
|
||||
fetchUnseenCount();
|
||||
}
|
||||
}
|
||||
|
||||
public LiveData<Resource<DirectInbox>> getInbox() {
|
||||
return distinctUntilChanged(inbox);
|
||||
}
|
||||
|
||||
public LiveData<List<DirectThread>> getThreads() {
|
||||
return threads;
|
||||
}
|
||||
|
||||
public LiveData<Resource<Integer>> getUnseenCount() {
|
||||
return distinctUntilChanged(unseenCount);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getPendingRequestsTotal() {
|
||||
return distinctUntilChanged(pendingRequestsTotal);
|
||||
}
|
||||
|
||||
public User getViewer() {
|
||||
return viewer;
|
||||
}
|
||||
|
||||
public void fetchInbox() {
|
||||
final Resource<DirectInbox> inboxResource = inbox.getValue();
|
||||
if ((inboxResource != null && inboxResource.status == Resource.Status.LOADING) || !hasOlder) return;
|
||||
stopCurrentInboxRequest();
|
||||
inbox.postValue(Resource.loading(getCurrentDirectInbox()));
|
||||
inboxRequest = pending ? service.fetchPendingInbox(cursor, seqId) : service.fetchInbox(cursor, seqId);
|
||||
inboxRequest.enqueue(new Callback<DirectInboxResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<DirectInboxResponse> call, @NonNull final Response<DirectInboxResponse> response) {
|
||||
parseInboxResponse(response.body());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<DirectInboxResponse> call, @NonNull final Throwable t) {
|
||||
Log.e(TAG, "Failed fetching dm inbox", t);
|
||||
inbox.postValue(Resource.error(t.getMessage(), getCurrentDirectInbox()));
|
||||
hasOlder = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void fetchUnseenCount() {
|
||||
final Resource<Integer> unseenCountResource = unseenCount.getValue();
|
||||
if ((unseenCountResource != null && unseenCountResource.status == Resource.Status.LOADING)) return;
|
||||
stopCurrentUnseenCountRequest();
|
||||
unseenCount.postValue(Resource.loading(getCurrentUnseenCount()));
|
||||
unseenCountRequest = service.fetchUnseenCount();
|
||||
unseenCountRequest.enqueue(new Callback<DirectBadgeCount>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<DirectBadgeCount> call, @NonNull final Response<DirectBadgeCount> response) {
|
||||
final DirectBadgeCount directBadgeCount = response.body();
|
||||
if (directBadgeCount == null) {
|
||||
Log.e(TAG, "onResponse: directBadgeCount Response is null");
|
||||
unseenCount.postValue(Resource.error("Unseen count response is null", getCurrentUnseenCount()));
|
||||
return;
|
||||
}
|
||||
unseenCount.postValue(Resource.success(directBadgeCount.getBadgeCount()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<DirectBadgeCount> call, @NonNull final Throwable t) {
|
||||
Log.e(TAG, "Failed fetching unseen count", t);
|
||||
unseenCount.postValue(Resource.error(t.getMessage(), getCurrentUnseenCount()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
cursor = null;
|
||||
seqId = 0;
|
||||
hasOlder = true;
|
||||
fetchInbox();
|
||||
if (!pending) {
|
||||
fetchUnseenCount();
|
||||
}
|
||||
}
|
||||
|
||||
private DirectInbox getCurrentDirectInbox() {
|
||||
final Resource<DirectInbox> inboxResource = inbox.getValue();
|
||||
return inboxResource != null ? inboxResource.data : null;
|
||||
}
|
||||
|
||||
private void parseInboxResponse(final DirectInboxResponse response) {
|
||||
if (response == null) {
|
||||
Log.e(TAG, "parseInboxResponse: Response is null");
|
||||
inbox.postValue(Resource.error("Response is null", getCurrentDirectInbox()));
|
||||
hasOlder = false;
|
||||
return;
|
||||
}
|
||||
if (!response.getStatus().equals("ok")) {
|
||||
final String msg = "DM inbox fetch response: status not ok";
|
||||
Log.e(TAG, msg);
|
||||
inbox.postValue(Resource.error(msg, getCurrentDirectInbox()));
|
||||
hasOlder = false;
|
||||
return;
|
||||
}
|
||||
seqId = response.getSeqId();
|
||||
if (viewer == null) {
|
||||
viewer = response.getViewer();
|
||||
}
|
||||
final DirectInbox inbox = response.getInbox();
|
||||
if (!TextUtils.isEmpty(cursor)) {
|
||||
final DirectInbox currentDirectInbox = getCurrentDirectInbox();
|
||||
if (currentDirectInbox != null) {
|
||||
List<DirectThread> threads = currentDirectInbox.getThreads();
|
||||
threads = threads == null ? new LinkedList<>() : new LinkedList<>(threads);
|
||||
threads.addAll(inbox.getThreads());
|
||||
inbox.setThreads(threads);
|
||||
}
|
||||
}
|
||||
this.inbox.postValue(Resource.success(inbox));
|
||||
cursor = inbox.getOldestCursor();
|
||||
hasOlder = inbox.hasOlder();
|
||||
pendingRequestsTotal.postValue(response.getPendingRequestsTotal());
|
||||
}
|
||||
|
||||
public void setThread(@NonNull final String threadId,
|
||||
@NonNull final DirectThread thread) {
|
||||
final DirectInbox inbox = getCurrentDirectInbox();
|
||||
if (inbox == null) return;
|
||||
final int index = getThreadIndex(threadId, inbox);
|
||||
setThread(inbox, index, thread);
|
||||
}
|
||||
|
||||
private void setThread(@NonNull final DirectInbox inbox,
|
||||
final int index,
|
||||
@NonNull final DirectThread thread) {
|
||||
if (index < 0) return;
|
||||
synchronized (this.inbox) {
|
||||
final List<DirectThread> threadsCopy = new LinkedList<>(inbox.getThreads());
|
||||
threadsCopy.set(index, thread);
|
||||
try {
|
||||
final DirectInbox clone = (DirectInbox) inbox.clone();
|
||||
clone.setThreads(threadsCopy);
|
||||
this.inbox.postValue(Resource.success(clone));
|
||||
} catch (CloneNotSupportedException e) {
|
||||
Log.e(TAG, "setThread: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addItemsToThread(@NonNull final String threadId,
|
||||
final int insertIndex,
|
||||
@NonNull final Collection<DirectItem> items) {
|
||||
final DirectInbox inbox = getCurrentDirectInbox();
|
||||
if (inbox == null) return;
|
||||
synchronized (THREAD_LOCKS.getUnchecked(threadId)) {
|
||||
final int index = getThreadIndex(threadId, inbox);
|
||||
if (index < 0) return;
|
||||
final List<DirectThread> threads = inbox.getThreads();
|
||||
final DirectThread thread = threads.get(index);
|
||||
List<DirectItem> list = thread.getItems();
|
||||
list = list == null ? new LinkedList<>() : new LinkedList<>(list);
|
||||
if (insertIndex >= 0) {
|
||||
list.addAll(insertIndex, items);
|
||||
} else {
|
||||
list.addAll(items);
|
||||
}
|
||||
try {
|
||||
final DirectThread threadClone = (DirectThread) thread.clone();
|
||||
threadClone.setItems(list);
|
||||
setThread(inbox, index, threadClone);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "addItemsToThread: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setItemsToThread(@NonNull final String threadId,
|
||||
@NonNull final List<DirectItem> updatedItems) {
|
||||
final DirectInbox inbox = getCurrentDirectInbox();
|
||||
if (inbox == null) return;
|
||||
synchronized (THREAD_LOCKS.getUnchecked(threadId)) {
|
||||
final int index = getThreadIndex(threadId, inbox);
|
||||
if (index < 0) return;
|
||||
final List<DirectThread> threads = inbox.getThreads();
|
||||
final DirectThread thread = threads.get(index);
|
||||
thread.setItems(updatedItems);
|
||||
setThread(inbox, index, thread);
|
||||
}
|
||||
}
|
||||
|
||||
private int getThreadIndex(@NonNull final String threadId,
|
||||
@NonNull final DirectInbox inbox) {
|
||||
final List<DirectThread> threads = inbox.getThreads();
|
||||
if (threads == null || threads.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
return Iterables.indexOf(threads, t -> {
|
||||
if (t == null) return false;
|
||||
return t.getThreadId().equals(threadId);
|
||||
});
|
||||
}
|
||||
|
||||
private Integer getCurrentUnseenCount() {
|
||||
final Resource<Integer> unseenCountResource = unseenCount.getValue();
|
||||
return unseenCountResource != null ? unseenCountResource.data : null;
|
||||
}
|
||||
|
||||
private void stopCurrentInboxRequest() {
|
||||
if (inboxRequest == null || inboxRequest.isCanceled() || inboxRequest.isExecuted()) return;
|
||||
inboxRequest.cancel();
|
||||
inboxRequest = null;
|
||||
}
|
||||
|
||||
private void stopCurrentUnseenCountRequest() {
|
||||
if (unseenCountRequest == null || unseenCountRequest.isCanceled() || unseenCountRequest.isExecuted()) return;
|
||||
unseenCountRequest.cancel();
|
||||
unseenCountRequest = null;
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
stopCurrentInboxRequest();
|
||||
stopCurrentUnseenCountRequest();
|
||||
}
|
||||
|
||||
public void addThread(@NonNull final DirectThread thread, final int insertIndex) {
|
||||
if (insertIndex < 0) return;
|
||||
synchronized (this.inbox) {
|
||||
final DirectInbox currentDirectInbox = getCurrentDirectInbox();
|
||||
final List<DirectThread> threadsCopy = new LinkedList<>(currentDirectInbox.getThreads());
|
||||
threadsCopy.add(insertIndex, thread);
|
||||
try {
|
||||
final DirectInbox clone = (DirectInbox) currentDirectInbox.clone();
|
||||
clone.setThreads(threadsCopy);
|
||||
this.inbox.setValue(Resource.success(clone));
|
||||
} catch (CloneNotSupportedException e) {
|
||||
Log.e(TAG, "setThread: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeThread(@NonNull final String threadId) {
|
||||
synchronized (this.inbox) {
|
||||
final DirectInbox currentDirectInbox = getCurrentDirectInbox();
|
||||
final List<DirectThread> threadsCopy = currentDirectInbox.getThreads()
|
||||
.stream()
|
||||
.filter(t -> !t.getThreadId().equals(threadId))
|
||||
.collect(Collectors.toList());
|
||||
try {
|
||||
final DirectInbox clone = (DirectInbox) currentDirectInbox.clone();
|
||||
clone.setThreads(threadsCopy);
|
||||
this.inbox.postValue(Resource.success(clone));
|
||||
} catch (CloneNotSupportedException e) {
|
||||
Log.e(TAG, "setThread: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setPendingRequestsTotal(final int total) {
|
||||
pendingRequestsTotal.postValue(total);
|
||||
}
|
||||
}
|
1780
app/src/main/java/awais/instagrabber/managers/ThreadManager.java
Normal file
1780
app/src/main/java/awais/instagrabber/managers/ThreadManager.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,8 @@ package awais.instagrabber.models;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Resource<T> {
|
||||
public final Status status;
|
||||
public final T data;
|
||||
@ -31,6 +33,21 @@ public class Resource<T> {
|
||||
return new Resource<>(Status.LOADING, data, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final Resource<?> resource = (Resource<?>) o;
|
||||
return status == resource.status &&
|
||||
Objects.equals(data, resource.data) &&
|
||||
Objects.equals(message, resource.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(status, data, message);
|
||||
}
|
||||
|
||||
public enum Status {
|
||||
SUCCESS,
|
||||
ERROR,
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class AnimatedMediaFixedHeight {
|
||||
private final int height;
|
||||
private final int width;
|
||||
@ -34,4 +36,21 @@ public class AnimatedMediaFixedHeight {
|
||||
public String getWebp() {
|
||||
return webp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final AnimatedMediaFixedHeight that = (AnimatedMediaFixedHeight) o;
|
||||
return height == that.height &&
|
||||
width == that.width &&
|
||||
Objects.equals(mp4, that.mp4) &&
|
||||
Objects.equals(url, that.url) &&
|
||||
Objects.equals(webp, that.webp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(height, width, mp4, url, webp);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class AnimatedMediaImages {
|
||||
private final AnimatedMediaFixedHeight fixedHeight;
|
||||
|
||||
@ -10,4 +12,17 @@ public class AnimatedMediaImages {
|
||||
public AnimatedMediaFixedHeight getFixedHeight() {
|
||||
return fixedHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final AnimatedMediaImages that = (AnimatedMediaImages) o;
|
||||
return Objects.equals(fixedHeight, that.fixedHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(fixedHeight);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Audio implements Serializable {
|
||||
private final String audioSrc;
|
||||
@ -41,4 +42,21 @@ public class Audio implements Serializable {
|
||||
public long getAudioSrcExpirationTimestampUs() {
|
||||
return audioSrcExpirationTimestampUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final Audio audio = (Audio) o;
|
||||
return duration == audio.duration &&
|
||||
waveformSamplingFrequencyHz == audio.waveformSamplingFrequencyHz &&
|
||||
audioSrcExpirationTimestampUs == audio.audioSrcExpirationTimestampUs &&
|
||||
Objects.equals(audioSrc, audio.audioSrc) &&
|
||||
Objects.equals(waveformData, audio.waveformData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(audioSrc, duration, waveformData, waveformSamplingFrequencyHz, audioSrcExpirationTimestampUs);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import com.google.gson.JsonParseException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Caption implements Serializable {
|
||||
private long mPk;
|
||||
@ -42,6 +43,21 @@ public class Caption implements Serializable {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final Caption caption = (Caption) o;
|
||||
return mPk == caption.mPk &&
|
||||
userId == caption.userId &&
|
||||
Objects.equals(text, caption.text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mPk, userId, text);
|
||||
}
|
||||
|
||||
public static class CaptionDeserializer implements JsonDeserializer<Caption> {
|
||||
|
||||
private static final String TAG = CaptionDeserializer.class.getSimpleName();
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class EndOfFeedDemarcator implements Serializable {
|
||||
private final long id;
|
||||
@ -18,4 +19,18 @@ public class EndOfFeedDemarcator implements Serializable {
|
||||
public EndOfFeedGroupSet getGroupSet() {
|
||||
return groupSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final EndOfFeedDemarcator that = (EndOfFeedDemarcator) o;
|
||||
return id == that.id &&
|
||||
Objects.equals(groupSet, that.groupSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, groupSet);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class EndOfFeedGroup implements Serializable {
|
||||
private final String id;
|
||||
@ -31,4 +32,20 @@ public class EndOfFeedGroup implements Serializable {
|
||||
public List<Media> getFeedItems() {
|
||||
return feedItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final EndOfFeedGroup that = (EndOfFeedGroup) o;
|
||||
return Objects.equals(id, that.id) &&
|
||||
Objects.equals(title, that.title) &&
|
||||
Objects.equals(nextMaxId, that.nextMaxId) &&
|
||||
Objects.equals(feedItems, that.feedItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, title, nextMaxId, feedItems);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class EndOfFeedGroupSet implements Serializable {
|
||||
private final long id;
|
||||
@ -48,4 +49,22 @@ public class EndOfFeedGroupSet implements Serializable {
|
||||
public List<EndOfFeedGroup> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final EndOfFeedGroupSet that = (EndOfFeedGroupSet) o;
|
||||
return id == that.id &&
|
||||
Objects.equals(activeGroupId, that.activeGroupId) &&
|
||||
Objects.equals(connectedGroupId, that.connectedGroupId) &&
|
||||
Objects.equals(nextMaxId, that.nextMaxId) &&
|
||||
Objects.equals(paginationSource, that.paginationSource) &&
|
||||
Objects.equals(groups, that.groups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, activeGroupId, connectedGroupId, nextMaxId, paginationSource, groups);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package awais.instagrabber.repositories.responses;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FriendshipStatus implements Serializable {
|
||||
private final boolean following;
|
||||
@ -78,6 +79,29 @@ public class FriendshipStatus implements Serializable {
|
||||
return isMutingReel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final FriendshipStatus that = (FriendshipStatus) o;
|
||||
return following == that.following &&
|
||||
followedBy == that.followedBy &&
|
||||
blocking == that.blocking &&
|
||||
muting == that.muting &&
|
||||
isPrivate == that.isPrivate &&
|
||||
incomingRequest == that.incomingRequest &&
|
||||
outgoingRequest == that.outgoingRequest &&
|
||||
isBestie == that.isBestie &&
|
||||
isRestricted == that.isRestricted &&
|
||||
isMutingReel == that.isMutingReel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(following, followedBy, blocking, muting, isPrivate, incomingRequest, outgoingRequest, isBestie, isRestricted,
|
||||
isMutingReel);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -2,6 +2,7 @@ package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ImageVersions2 implements Serializable {
|
||||
private final List<MediaCandidate> candidates;
|
||||
@ -13,4 +14,17 @@ public class ImageVersions2 implements Serializable {
|
||||
public List<MediaCandidate> getCandidates() {
|
||||
return candidates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final ImageVersions2 that = (ImageVersions2) o;
|
||||
return Objects.equals(candidates, that.candidates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(candidates);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Location implements Serializable {
|
||||
private final long pk;
|
||||
@ -54,4 +55,23 @@ public class Location implements Serializable {
|
||||
public float getLat() {
|
||||
return lat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final Location location = (Location) o;
|
||||
return pk == location.pk &&
|
||||
Float.compare(location.lng, lng) == 0 &&
|
||||
Float.compare(location.lat, lat) == 0 &&
|
||||
Objects.equals(shortName, location.shortName) &&
|
||||
Objects.equals(name, location.name) &&
|
||||
Objects.equals(address, location.address) &&
|
||||
Objects.equals(city, location.city);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(pk, shortName, name, address, city, lng, lat);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
@ -272,4 +273,52 @@ public class Media implements Serializable {
|
||||
final Caption caption1 = getCaption();
|
||||
caption1.setText(caption);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final Media media = (Media) o;
|
||||
return takenAt == media.takenAt &&
|
||||
canViewerReshare == media.canViewerReshare &&
|
||||
commentLikesEnabled == media.commentLikesEnabled &&
|
||||
commentsDisabled == media.commentsDisabled &&
|
||||
nextMaxId == media.nextMaxId &&
|
||||
commentCount == media.commentCount &&
|
||||
originalWidth == media.originalWidth &&
|
||||
originalHeight == media.originalHeight &&
|
||||
likeCount == media.likeCount &&
|
||||
hasLiked == media.hasLiked &&
|
||||
isReelMedia == media.isReelMedia &&
|
||||
hasAudio == media.hasAudio &&
|
||||
Double.compare(media.videoDuration, videoDuration) == 0 &&
|
||||
viewCount == media.viewCount &&
|
||||
canViewerSave == media.canViewerSave &&
|
||||
isSidecarChild == media.isSidecarChild &&
|
||||
hasViewerSaved == media.hasViewerSaved &&
|
||||
Objects.equals(pk, media.pk) &&
|
||||
Objects.equals(id, media.id) &&
|
||||
Objects.equals(code, media.code) &&
|
||||
Objects.equals(user, media.user) &&
|
||||
mediaType == media.mediaType &&
|
||||
Objects.equals(imageVersions2, media.imageVersions2) &&
|
||||
Objects.equals(videoVersions, media.videoVersions) &&
|
||||
Objects.equals(caption, media.caption) &&
|
||||
Objects.equals(audio, media.audio) &&
|
||||
Objects.equals(title, media.title) &&
|
||||
Objects.equals(location, media.location) &&
|
||||
Objects.equals(usertags, media.usertags) &&
|
||||
Objects.equals(carouselMedia, media.carouselMedia) &&
|
||||
Objects.equals(injected, media.injected) &&
|
||||
Objects.equals(endOfFeedDemarcator, media.endOfFeedDemarcator) &&
|
||||
Objects.equals(dateString, media.dateString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(pk, id, code, takenAt, user, mediaType, canViewerReshare, commentLikesEnabled, commentsDisabled, nextMaxId, commentCount,
|
||||
imageVersions2, originalWidth, originalHeight, likeCount, hasLiked, isReelMedia, videoVersions, hasAudio, videoDuration,
|
||||
viewCount, caption, canViewerSave, audio, title, location, usertags, carouselMedia, isSidecarChild, hasViewerSaved,
|
||||
injected, endOfFeedDemarcator, dateString);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class MediaCandidate implements Serializable {
|
||||
private final int width;
|
||||
@ -24,4 +25,19 @@ public class MediaCandidate implements Serializable {
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final MediaCandidate that = (MediaCandidate) o;
|
||||
return width == that.width &&
|
||||
height == that.height &&
|
||||
Objects.equals(url, that.url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(width, height, url);
|
||||
}
|
||||
}
|
||||
|
@ -207,17 +207,40 @@ public class User implements Serializable {
|
||||
// null);
|
||||
// }
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final User that = (User) o;
|
||||
return pk == that.pk &&
|
||||
Objects.equals(username, that.username);
|
||||
final User user = (User) o;
|
||||
return pk == user.pk &&
|
||||
isPrivate == user.isPrivate &&
|
||||
isVerified == user.isVerified &&
|
||||
hasAnonymousProfilePicture == user.hasAnonymousProfilePicture &&
|
||||
isUnpublished == user.isUnpublished &&
|
||||
isFavorite == user.isFavorite &&
|
||||
isDirectappInstalled == user.isDirectappInstalled &&
|
||||
mediaCount == user.mediaCount &&
|
||||
followerCount == user.followerCount &&
|
||||
followingCount == user.followingCount &&
|
||||
followingTagCount == user.followingTagCount &&
|
||||
usertagsCount == user.usertagsCount &&
|
||||
Objects.equals(username, user.username) &&
|
||||
Objects.equals(fullName, user.fullName) &&
|
||||
Objects.equals(profilePicUrl, user.profilePicUrl) &&
|
||||
Objects.equals(profilePicId, user.profilePicId) &&
|
||||
Objects.equals(friendshipStatus, user.friendshipStatus) &&
|
||||
Objects.equals(reelAutoArchive, user.reelAutoArchive) &&
|
||||
Objects.equals(allowedCommenterType, user.allowedCommenterType) &&
|
||||
Objects.equals(biography, user.biography) &&
|
||||
Objects.equals(externalUrl, user.externalUrl) &&
|
||||
Objects.equals(publicEmail, user.publicEmail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(pk, username);
|
||||
return Objects.hash(pk, username, fullName, isPrivate, profilePicUrl, profilePicId, friendshipStatus, isVerified, hasAnonymousProfilePicture,
|
||||
isUnpublished, isFavorite, isDirectappInstalled, reelAutoArchive, allowedCommenterType, mediaCount, followerCount,
|
||||
followingCount, followingTagCount, biography, externalUrl, usertagsCount, publicEmail);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class UsertagIn implements Serializable {
|
||||
private final User user;
|
||||
@ -19,4 +20,18 @@ public class UsertagIn implements Serializable {
|
||||
public List<String> getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final UsertagIn usertagIn = (UsertagIn) o;
|
||||
return Objects.equals(user, usertagIn.user) &&
|
||||
Objects.equals(position, usertagIn.position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(user, position);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Usertags implements Serializable {
|
||||
private final List<UsertagIn> in;
|
||||
@ -13,4 +14,17 @@ public class Usertags implements Serializable {
|
||||
public List<UsertagIn> getIn() {
|
||||
return in;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final Usertags usertags = (Usertags) o;
|
||||
return Objects.equals(in, usertags.in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(in);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class VideoVersion implements Serializable {
|
||||
private final String id;
|
||||
@ -36,4 +37,21 @@ public class VideoVersion implements Serializable {
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final VideoVersion that = (VideoVersion) o;
|
||||
return width == that.width &&
|
||||
height == that.height &&
|
||||
Objects.equals(id, that.id) &&
|
||||
Objects.equals(type, that.type) &&
|
||||
Objects.equals(url, that.url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, type, width, height, url);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DirectInbox {
|
||||
private final List<DirectThread> threads;
|
||||
public class DirectInbox implements Cloneable {
|
||||
private List<DirectThread> threads;
|
||||
private final boolean hasOlder;
|
||||
private final int unseenCount;
|
||||
private final String unseenCountTs;
|
||||
@ -28,6 +30,10 @@ public class DirectInbox {
|
||||
return threads;
|
||||
}
|
||||
|
||||
public void setThreads(final List<DirectThread> threads) {
|
||||
this.threads = threads;
|
||||
}
|
||||
|
||||
public boolean hasOlder() {
|
||||
return hasOlder;
|
||||
}
|
||||
@ -47,4 +53,10 @@ public class DirectInbox {
|
||||
public boolean isBlendedInboxEnabled() {
|
||||
return blendedInboxEnabled;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.models.enums.DirectItemType;
|
||||
import awais.instagrabber.repositories.responses.Location;
|
||||
@ -239,21 +240,47 @@ public class DirectItem implements Cloneable {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean equals(final Object o) {
|
||||
// if (this == o) return true;
|
||||
// if (o == null || getClass() != o.getClass()) return false;
|
||||
// final DirectItem that = (DirectItem) o;
|
||||
// return userId == that.userId &&
|
||||
// timestamp == that.timestamp &&
|
||||
// isPending == that.isPending &&
|
||||
// Objects.equals(itemId, that.itemId) &&
|
||||
// itemType == that.itemType &&
|
||||
// Objects.equals(clientContext, that.clientContext);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int hashCode() {
|
||||
// return Objects.hash(itemId, userId, timestamp, itemType, clientContext, isPending);
|
||||
// }
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItem that = (DirectItem) o;
|
||||
return userId == that.userId &&
|
||||
timestamp == that.timestamp &&
|
||||
hideInThread == that.hideInThread &&
|
||||
isPending == that.isPending &&
|
||||
showForwardAttribution == that.showForwardAttribution &&
|
||||
Objects.equals(itemId, that.itemId) &&
|
||||
itemType == that.itemType &&
|
||||
Objects.equals(text, that.text) &&
|
||||
Objects.equals(like, that.like) &&
|
||||
Objects.equals(link, that.link) &&
|
||||
Objects.equals(clientContext, that.clientContext) &&
|
||||
Objects.equals(reelShare, that.reelShare) &&
|
||||
Objects.equals(storyShare, that.storyShare) &&
|
||||
Objects.equals(mediaShare, that.mediaShare) &&
|
||||
Objects.equals(profile, that.profile) &&
|
||||
Objects.equals(placeholder, that.placeholder) &&
|
||||
Objects.equals(media, that.media) &&
|
||||
Objects.equals(previewMedias, that.previewMedias) &&
|
||||
Objects.equals(actionLog, that.actionLog) &&
|
||||
Objects.equals(videoCallEvent, that.videoCallEvent) &&
|
||||
Objects.equals(clip, that.clip) &&
|
||||
Objects.equals(felixShare, that.felixShare) &&
|
||||
Objects.equals(visualMedia, that.visualMedia) &&
|
||||
Objects.equals(animatedMedia, that.animatedMedia) &&
|
||||
Objects.equals(reactions, that.reactions) &&
|
||||
Objects.equals(repliedToMessage, that.repliedToMessage) &&
|
||||
Objects.equals(voiceMedia, that.voiceMedia) &&
|
||||
Objects.equals(location, that.location) &&
|
||||
Objects.equals(date, that.date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects
|
||||
.hash(itemId, userId, timestamp, itemType, text, like, link, clientContext, reelShare, storyShare, mediaShare, profile, placeholder,
|
||||
media, previewMedias, actionLog, videoCallEvent, clip, felixShare, visualMedia, animatedMedia, reactions, repliedToMessage,
|
||||
voiceMedia, location, hideInThread, date, isPending, showForwardAttribution);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class DirectItemActionLog {
|
||||
private final String description;
|
||||
@ -27,6 +28,21 @@ public class DirectItemActionLog {
|
||||
return textAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemActionLog that = (DirectItemActionLog) o;
|
||||
return Objects.equals(description, that.description) &&
|
||||
Objects.equals(bold, that.bold) &&
|
||||
Objects.equals(textAttributes, that.textAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(description, bold, textAttributes);
|
||||
}
|
||||
|
||||
public static class TextRange {
|
||||
private final int start;
|
||||
private final int end;
|
||||
@ -55,5 +71,21 @@ public class DirectItemActionLog {
|
||||
public String getIntent() {
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final TextRange textRange = (TextRange) o;
|
||||
return start == textRange.start &&
|
||||
end == textRange.end &&
|
||||
Objects.equals(color, textRange.color) &&
|
||||
Objects.equals(intent, textRange.intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(start, end, color, intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.responses.AnimatedMediaImages;
|
||||
|
||||
public final class DirectItemAnimatedMedia {
|
||||
@ -31,4 +33,20 @@ public final class DirectItemAnimatedMedia {
|
||||
public boolean isSticker() {
|
||||
return isSticker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemAnimatedMedia that = (DirectItemAnimatedMedia) o;
|
||||
return isRandom == that.isRandom &&
|
||||
isSticker == that.isSticker &&
|
||||
Objects.equals(id, that.id) &&
|
||||
Objects.equals(images, that.images);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, images, isRandom, isSticker);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public class DirectItemClip {
|
||||
@ -12,4 +14,17 @@ public class DirectItemClip {
|
||||
public Media getClip() {
|
||||
return clip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemClip that = (DirectItemClip) o;
|
||||
return Objects.equals(clip, that.clip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(clip);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public class DirectItemFelixShare {
|
||||
@ -12,4 +14,17 @@ public class DirectItemFelixShare {
|
||||
public Media getVideo() {
|
||||
return video;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemFelixShare that = (DirectItemFelixShare) o;
|
||||
return Objects.equals(video, that.video);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(video);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DirectItemLink {
|
||||
private final String text;
|
||||
private final DirectItemLinkContext linkContext;
|
||||
@ -31,4 +33,20 @@ public class DirectItemLink {
|
||||
public String getMutationToken() {
|
||||
return mutationToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemLink that = (DirectItemLink) o;
|
||||
return Objects.equals(text, that.text) &&
|
||||
Objects.equals(linkContext, that.linkContext) &&
|
||||
Objects.equals(clientContext, that.clientContext) &&
|
||||
Objects.equals(mutationToken, that.mutationToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(text, linkContext, clientContext, mutationToken);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DirectItemLinkContext {
|
||||
private final String linkUrl;
|
||||
private final String linkTitle;
|
||||
@ -31,4 +33,20 @@ public class DirectItemLinkContext {
|
||||
public String getLinkImageUrl() {
|
||||
return linkImageUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemLinkContext that = (DirectItemLinkContext) o;
|
||||
return Objects.equals(linkUrl, that.linkUrl) &&
|
||||
Objects.equals(linkTitle, that.linkTitle) &&
|
||||
Objects.equals(linkSummary, that.linkSummary) &&
|
||||
Objects.equals(linkImageUrl, that.linkImageUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(linkUrl, linkTitle, linkSummary, linkImageUrl);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DirectItemPlaceholder {
|
||||
private final boolean isLinked;
|
||||
private final String title;
|
||||
@ -24,4 +26,19 @@ public class DirectItemPlaceholder {
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemPlaceholder that = (DirectItemPlaceholder) o;
|
||||
return isLinked == that.isLinked &&
|
||||
Objects.equals(title, that.title) &&
|
||||
Objects.equals(message, that.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(isLinked, title, message);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public class DirectItemReelShare {
|
||||
@ -61,4 +63,24 @@ public class DirectItemReelShare {
|
||||
public long getMentionedUserId() {
|
||||
return mentionedUserId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemReelShare that = (DirectItemReelShare) o;
|
||||
return reelOwnerId == that.reelOwnerId &&
|
||||
mentionedUserId == that.mentionedUserId &&
|
||||
isReelPersisted == that.isReelPersisted &&
|
||||
Objects.equals(text, that.text) &&
|
||||
Objects.equals(type, that.type) &&
|
||||
Objects.equals(reelType, that.reelType) &&
|
||||
Objects.equals(media, that.media) &&
|
||||
Objects.equals(reactionInfo, that.reactionInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(text, type, reelOwnerId, mentionedUserId, isReelPersisted, reelType, media, reactionInfo);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DirectItemReelShareReactionInfo {
|
||||
private final String emoji;
|
||||
private final String intensity;
|
||||
@ -16,4 +18,18 @@ public class DirectItemReelShareReactionInfo {
|
||||
public String getIntensity() {
|
||||
return intensity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemReelShareReactionInfo that = (DirectItemReelShareReactionInfo) o;
|
||||
return Objects.equals(emoji, that.emoji) &&
|
||||
Objects.equals(intensity, that.intensity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(emoji, intensity);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public class DirectItemStoryShare {
|
||||
@ -54,4 +56,23 @@ public class DirectItemStoryShare {
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemStoryShare that = (DirectItemStoryShare) o;
|
||||
return isReelPersisted == that.isReelPersisted &&
|
||||
Objects.equals(reelId, that.reelId) &&
|
||||
Objects.equals(reelType, that.reelType) &&
|
||||
Objects.equals(text, that.text) &&
|
||||
Objects.equals(media, that.media) &&
|
||||
Objects.equals(title, that.title) &&
|
||||
Objects.equals(message, that.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(reelId, reelType, text, isReelPersisted, media, title, message);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class DirectItemVideoCallEvent {
|
||||
private final String action;
|
||||
@ -40,4 +41,21 @@ public final class DirectItemVideoCallEvent {
|
||||
public List<DirectItemActionLog.TextRange> getTextAttributes() {
|
||||
return textAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemVideoCallEvent that = (DirectItemVideoCallEvent) o;
|
||||
return threadHasAudioOnlyCall == that.threadHasAudioOnlyCall &&
|
||||
Objects.equals(action, that.action) &&
|
||||
Objects.equals(encodedServerDataInfo, that.encodedServerDataInfo) &&
|
||||
Objects.equals(description, that.description) &&
|
||||
Objects.equals(textAttributes, that.textAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(action, encodedServerDataInfo, description, threadHasAudioOnlyCall, textAttributes);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.models.enums.RavenMediaViewMode;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
@ -64,4 +65,25 @@ public class DirectItemVisualMedia {
|
||||
public Media getMedia() {
|
||||
return media;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemVisualMedia media1 = (DirectItemVisualMedia) o;
|
||||
return urlExpireAtSecs == media1.urlExpireAtSecs &&
|
||||
playbackDurationSecs == media1.playbackDurationSecs &&
|
||||
seenCount == media1.seenCount &&
|
||||
replayExpiringAtUs == media1.replayExpiringAtUs &&
|
||||
Objects.equals(seenUserIds, media1.seenUserIds) &&
|
||||
viewMode == media1.viewMode &&
|
||||
Objects.equals(expiringMediaActionSummary, media1.expiringMediaActionSummary) &&
|
||||
Objects.equals(media, media1.media);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects
|
||||
.hash(urlExpireAtSecs, playbackDurationSecs, seenUserIds, viewMode, seenCount, replayExpiringAtUs, expiringMediaActionSummary, media);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public class DirectItemVoiceMedia {
|
||||
@ -24,4 +26,19 @@ public class DirectItemVoiceMedia {
|
||||
public String getViewMode() {
|
||||
return viewMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectItemVoiceMedia that = (DirectItemVoiceMedia) o;
|
||||
return seenCount == that.seenCount &&
|
||||
Objects.equals(media, that.media) &&
|
||||
Objects.equals(viewMode, that.viewMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(media, seenCount, viewMode);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -9,13 +10,13 @@ import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
|
||||
public class DirectThread implements Serializable {
|
||||
public class DirectThread implements Serializable, Cloneable {
|
||||
private final String threadId;
|
||||
private final String threadV2Id;
|
||||
private final List<User> users;
|
||||
private final List<User> leftUsers;
|
||||
private final List<Long> adminUserIds;
|
||||
private final List<DirectItem> items;
|
||||
private List<User> users;
|
||||
private List<User> leftUsers;
|
||||
private List<Long> adminUserIds;
|
||||
private List<DirectItem> items;
|
||||
private final long lastActivityAt;
|
||||
private boolean muted;
|
||||
private final boolean isPin;
|
||||
@ -127,18 +128,34 @@ public class DirectThread implements Serializable {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(final List<User> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public List<User> getLeftUsers() {
|
||||
return leftUsers;
|
||||
}
|
||||
|
||||
public void setLeftUsers(final List<User> leftUsers) {
|
||||
this.leftUsers = leftUsers;
|
||||
}
|
||||
|
||||
public List<Long> getAdminUserIds() {
|
||||
return adminUserIds;
|
||||
}
|
||||
|
||||
public void setAdminUserIds(final List<Long> adminUserIds) {
|
||||
this.adminUserIds = adminUserIds;
|
||||
}
|
||||
|
||||
public List<DirectItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(final List<DirectItem> items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public long getLastActivityAt() {
|
||||
return lastActivityAt;
|
||||
}
|
||||
@ -284,17 +301,59 @@ public class DirectThread implements Serializable {
|
||||
return firstItem;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectThread that = (DirectThread) o;
|
||||
return Objects.equals(threadId, that.threadId) &&
|
||||
Objects.equals(threadV2Id, that.threadV2Id);
|
||||
return lastActivityAt == that.lastActivityAt &&
|
||||
muted == that.muted &&
|
||||
isPin == that.isPin &&
|
||||
named == that.named &&
|
||||
canonical == that.canonical &&
|
||||
pending == that.pending &&
|
||||
archived == that.archived &&
|
||||
valuedRequest == that.valuedRequest &&
|
||||
viewerId == that.viewerId &&
|
||||
folder == that.folder &&
|
||||
vcMuted == that.vcMuted &&
|
||||
isGroup == that.isGroup &&
|
||||
mentionsMuted == that.mentionsMuted &&
|
||||
hasOlder == that.hasOlder &&
|
||||
hasNewer == that.hasNewer &&
|
||||
isSpam == that.isSpam &&
|
||||
approvalRequiredForNewMembers == that.approvalRequiredForNewMembers &&
|
||||
inputMode == that.inputMode &&
|
||||
Objects.equals(threadId, that.threadId) &&
|
||||
Objects.equals(threadV2Id, that.threadV2Id) &&
|
||||
Objects.equals(users, that.users) &&
|
||||
Objects.equals(leftUsers, that.leftUsers) &&
|
||||
Objects.equals(adminUserIds, that.adminUserIds) &&
|
||||
Objects.equals(items, that.items) &&
|
||||
Objects.equals(threadType, that.threadType) &&
|
||||
Objects.equals(threadTitle, that.threadTitle) &&
|
||||
Objects.equals(pendingScore, that.pendingScore) &&
|
||||
Objects.equals(inviter, that.inviter) &&
|
||||
Objects.equals(lastSeenAt, that.lastSeenAt) &&
|
||||
Objects.equals(newestCursor, that.newestCursor) &&
|
||||
Objects.equals(oldestCursor, that.oldestCursor) &&
|
||||
Objects.equals(lastPermanentItem, that.lastPermanentItem) &&
|
||||
Objects.equals(directStory, that.directStory) &&
|
||||
Objects.equals(threadContextItems, that.threadContextItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(threadId, threadV2Id);
|
||||
return Objects
|
||||
.hash(threadId, threadV2Id, users, leftUsers, adminUserIds, items, lastActivityAt, muted, isPin, named, canonical, pending, archived,
|
||||
valuedRequest, threadType, viewerId, threadTitle, pendingScore, folder, vcMuted, isGroup, mentionsMuted, inviter, hasOlder,
|
||||
hasNewer, lastSeenAt, newestCursor, oldestCursor, isSpam, lastPermanentItem, directStory, approvalRequiredForNewMembers,
|
||||
inputMode, threadContextItems);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class DirectThreadDirectStory {
|
||||
private final List<DirectItem> items;
|
||||
@ -18,4 +19,18 @@ public class DirectThreadDirectStory {
|
||||
public int getUnseenCount() {
|
||||
return unseenCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectThreadDirectStory that = (DirectThreadDirectStory) o;
|
||||
return unseenCount == that.unseenCount &&
|
||||
Objects.equals(items, that.items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(items, unseenCount);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DirectThreadLastSeenAt {
|
||||
private final String timestamp;
|
||||
private final String itemId;
|
||||
@ -16,4 +18,18 @@ public class DirectThreadLastSeenAt {
|
||||
public String getItemId() {
|
||||
return itemId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final DirectThreadLastSeenAt that = (DirectThreadLastSeenAt) o;
|
||||
return Objects.equals(timestamp, that.timestamp) &&
|
||||
Objects.equals(itemId, that.itemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(timestamp, itemId);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ public class DirectThreadParticipantRequestsResponse implements Serializable, Cl
|
||||
private final Map<Long, String> requesterUsernames;
|
||||
private final String cursor;
|
||||
private final int totalThreadParticipants;
|
||||
private final int totalParticipantRequests;
|
||||
private int totalParticipantRequests;
|
||||
private final String status;
|
||||
|
||||
public DirectThreadParticipantRequestsResponse(final List<User> users,
|
||||
@ -54,6 +54,10 @@ public class DirectThreadParticipantRequestsResponse implements Serializable, Cl
|
||||
return totalParticipantRequests;
|
||||
}
|
||||
|
||||
public void setTotalParticipantRequests(final int totalParticipantRequests) {
|
||||
this.totalParticipantRequests = totalParticipantRequests;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class RavenExpiringMediaActionSummary {
|
||||
private final ActionType type;
|
||||
private final long timestamp;
|
||||
@ -25,6 +27,21 @@ public final class RavenExpiringMediaActionSummary {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final RavenExpiringMediaActionSummary that = (RavenExpiringMediaActionSummary) o;
|
||||
return timestamp == that.timestamp &&
|
||||
count == that.count &&
|
||||
type == that.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, timestamp, count);
|
||||
}
|
||||
|
||||
// thanks to http://github.com/warifp/InstagramAutoPostImageUrl/blob/master/vendor/mgp25/instagram-php/src/Response/Model/ActionBadge.php
|
||||
public enum ActionType {
|
||||
@SerializedName("raven_delivered")
|
||||
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.repositories.responses.directmessages;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ThreadContext implements Serializable {
|
||||
private final int type;
|
||||
@ -18,4 +19,18 @@ public class ThreadContext implements Serializable {
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final ThreadContext that = (ThreadContext) o;
|
||||
return type == that.type &&
|
||||
Objects.equals(text, that.text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, text);
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
@ -32,7 +32,6 @@ import awais.instagrabber.repositories.responses.MediaCandidate;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.VideoVersion;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDirectStory;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadLastSeenAt;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
@ -1126,34 +1125,32 @@ public final class ResponseBodyUtils {
|
||||
|
||||
public static boolean isRead(final DirectItem item,
|
||||
final Map<Long, DirectThreadLastSeenAt> lastSeenAt,
|
||||
final List<Long> userIdsToCheck,
|
||||
final DirectThreadDirectStory directStory) {
|
||||
boolean read = lastSeenAt.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> userIdsToCheck.contains(entry.getKey()))
|
||||
.anyMatch(entry -> {
|
||||
final String userLastSeenTsString = entry.getValue().getTimestamp();
|
||||
if (userLastSeenTsString == null) return false;
|
||||
final long userTs = Long.parseLong(userLastSeenTsString);
|
||||
final long itemTs = item.getTimestamp();
|
||||
return userTs >= itemTs;
|
||||
});
|
||||
final List<Long> userIdsToCheck) {
|
||||
// Further check if directStory exists
|
||||
if (read && directStory != null) {
|
||||
read = false;
|
||||
}
|
||||
return read;
|
||||
// if (read && directStory != null) {
|
||||
// read = false;
|
||||
// }
|
||||
return lastSeenAt.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> userIdsToCheck.contains(entry.getKey()))
|
||||
.anyMatch(entry -> {
|
||||
final String userLastSeenTsString = entry.getValue().getTimestamp();
|
||||
if (userLastSeenTsString == null) return false;
|
||||
final long userTs = Long.parseLong(userLastSeenTsString);
|
||||
final long itemTs = item.getTimestamp();
|
||||
return userTs >= itemTs;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static StoryModel parseBroadcastItem(final JSONObject data) throws JSONException {
|
||||
final StoryModel model = new StoryModel(data.getString("id"),
|
||||
data.getString("cover_frame_url"),
|
||||
data.getString("cover_frame_url"),
|
||||
MediaItemType.MEDIA_TYPE_LIVE,
|
||||
data.optLong("published_time", 0),
|
||||
data.getJSONObject("broadcast_owner").getString("username"),
|
||||
data.getJSONObject("broadcast_owner").getLong("pk"),
|
||||
false);
|
||||
data.getString("cover_frame_url"),
|
||||
data.getString("cover_frame_url"),
|
||||
MediaItemType.MEDIA_TYPE_LIVE,
|
||||
data.optLong("published_time", 0),
|
||||
data.getJSONObject("broadcast_owner").getString("username"),
|
||||
data.getJSONObject("broadcast_owner").getLong("pk"),
|
||||
false);
|
||||
model.setVideoUrl(data.getString("dash_playback_url"));
|
||||
return model;
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ import android.os.AsyncTask;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import awais.instagrabber.asyncs.ProfileFetcher;
|
||||
import awais.instagrabber.asyncs.UsernameFetcher;
|
||||
@ -25,10 +23,10 @@ import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
public class AppStateViewModel extends AndroidViewModel {
|
||||
private static final String TAG = AppStateViewModel.class.getSimpleName();
|
||||
|
||||
private final MutableLiveData<User> currentUser = new MutableLiveData<>();
|
||||
private final String cookie;
|
||||
private final boolean isLoggedIn;
|
||||
|
||||
private User currentUser;
|
||||
private AccountRepository accountRepository;
|
||||
private String username;
|
||||
|
||||
@ -52,7 +50,7 @@ public class AppStateViewModel extends AndroidViewModel {
|
||||
fetchUsername(usernameListener);
|
||||
}
|
||||
|
||||
public LiveData<User> getCurrentUser() {
|
||||
public User getCurrentUser() {
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
@ -84,7 +82,7 @@ public class AppStateViewModel extends AndroidViewModel {
|
||||
new ProfileFetcher(
|
||||
username.trim().substring(1),
|
||||
true,
|
||||
currentUser::postValue
|
||||
user -> this.currentUser = user
|
||||
).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
|
@ -1,188 +1,56 @@
|
||||
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.managers.DirectMessagesManager;
|
||||
import awais.instagrabber.managers.InboxManager;
|
||||
import awais.instagrabber.models.Resource;
|
||||
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 DirectInboxViewModel extends ViewModel {
|
||||
private static final String TAG = DirectInboxViewModel.class.getSimpleName();
|
||||
|
||||
private final DirectMessagesService service;
|
||||
private final MutableLiveData<Boolean> fetchingInbox = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<List<DirectThread>> threads = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> fetchingUnseenCount = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Integer> unseenCount = new MutableLiveData<>(0);
|
||||
private final MutableLiveData<Integer> pendingRequestsTotal = new MutableLiveData<>(0);
|
||||
|
||||
private Call<DirectInboxResponse> inboxRequest;
|
||||
private Call<DirectBadgeCount> unseenCountRequest;
|
||||
private long seqId;
|
||||
private String cursor;
|
||||
private boolean hasOlder = true;
|
||||
private User viewer;
|
||||
private final InboxManager inboxManager;
|
||||
|
||||
public DirectInboxViewModel() {
|
||||
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();
|
||||
fetchUnseenCount();
|
||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
||||
inboxManager = messagesManager.getInboxManager();
|
||||
}
|
||||
|
||||
public LiveData<Resource<DirectInbox>> getInbox() {
|
||||
return inboxManager.getInbox();
|
||||
}
|
||||
|
||||
public LiveData<List<DirectThread>> getThreads() {
|
||||
return threads;
|
||||
return inboxManager.getThreads();
|
||||
}
|
||||
|
||||
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<Integer> getUnseenCount() {
|
||||
return unseenCount;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getFetchingInbox() {
|
||||
return fetchingInbox;
|
||||
public LiveData<Resource<Integer>> getUnseenCount() {
|
||||
return inboxManager.getUnseenCount();
|
||||
}
|
||||
|
||||
public LiveData<Integer> getPendingRequestsTotal() {
|
||||
return pendingRequestsTotal;
|
||||
return inboxManager.getPendingRequestsTotal();
|
||||
}
|
||||
|
||||
public User getViewer() {
|
||||
return viewer;
|
||||
return inboxManager.getViewer();
|
||||
}
|
||||
|
||||
public void fetchInbox() {
|
||||
if ((fetchingInbox.getValue() != null && fetchingInbox.getValue()) || !hasOlder) return;
|
||||
stopCurrentInboxRequest();
|
||||
fetchingInbox.postValue(true);
|
||||
inboxRequest = service.fetchInbox(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 dm 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 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();
|
||||
pendingRequestsTotal.postValue(response.getPendingRequestsTotal());
|
||||
// unseenCount.postValue(inbox.getUnseenCount());
|
||||
}
|
||||
|
||||
private void stopCurrentInboxRequest() {
|
||||
if (inboxRequest == null || inboxRequest.isCanceled() || inboxRequest.isExecuted()) return;
|
||||
inboxRequest.cancel();
|
||||
inboxRequest = null;
|
||||
}
|
||||
|
||||
public void fetchUnseenCount() {
|
||||
if ((fetchingUnseenCount.getValue() != null && fetchingUnseenCount.getValue())) return;
|
||||
stopCurrentUnseenCountRequest();
|
||||
fetchingUnseenCount.postValue(true);
|
||||
unseenCountRequest = service.fetchUnseenCount();
|
||||
unseenCountRequest.enqueue(new Callback<DirectBadgeCount>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<DirectBadgeCount> call, @NonNull final Response<DirectBadgeCount> response) {
|
||||
parseUnseenCountResponse(response.body());
|
||||
fetchingUnseenCount.postValue(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<DirectBadgeCount> call, @NonNull final Throwable t) {
|
||||
Log.e(TAG, "Failed fetching unseen count", t);
|
||||
fetchingUnseenCount.postValue(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void parseUnseenCountResponse(final DirectBadgeCount directBadgeCount) {
|
||||
if (directBadgeCount == null) return;
|
||||
unseenCount.postValue(directBadgeCount.getBadgeCount());
|
||||
}
|
||||
|
||||
private void stopCurrentUnseenCountRequest() {
|
||||
if (unseenCountRequest == null || unseenCountRequest.isCanceled() || unseenCountRequest.isExecuted()) return;
|
||||
unseenCountRequest.cancel();
|
||||
unseenCountRequest = null;
|
||||
inboxManager.fetchInbox();
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
cursor = null;
|
||||
seqId = 0;
|
||||
hasOlder = true;
|
||||
fetchInbox();
|
||||
fetchUnseenCount();
|
||||
inboxManager.refresh();
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
stopCurrentInboxRequest();
|
||||
// getThreads().postValue(Collections.emptyList());
|
||||
inboxManager.onDestroy();
|
||||
}
|
||||
}
|
||||
|
@ -1,141 +1,48 @@
|
||||
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.managers.DirectMessagesManager;
|
||||
import awais.instagrabber.managers.InboxManager;
|
||||
import awais.instagrabber.models.Resource;
|
||||
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;
|
||||
private final InboxManager inboxManager;
|
||||
|
||||
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();
|
||||
inboxManager = DirectMessagesManager.getInstance().getPendingInboxManager();
|
||||
inboxManager.fetchInbox();
|
||||
}
|
||||
|
||||
public LiveData<List<DirectThread>> getThreads() {
|
||||
return threads;
|
||||
return inboxManager.getThreads();
|
||||
}
|
||||
|
||||
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 LiveData<Resource<DirectInbox>> getInbox() {
|
||||
return inboxManager.getInbox();
|
||||
}
|
||||
|
||||
public User getViewer() {
|
||||
return viewer;
|
||||
return inboxManager.getViewer();
|
||||
}
|
||||
|
||||
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;
|
||||
inboxManager.fetchInbox();
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
cursor = null;
|
||||
seqId = 0;
|
||||
hasOlder = true;
|
||||
fetchInbox();
|
||||
inboxManager.refresh();
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
stopCurrentInboxRequest();
|
||||
inboxManager.onDestroy();
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +1,30 @@
|
||||
package awais.instagrabber.viewmodels;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.dialogs.MultiOptionDialogFragment.Option;
|
||||
import awais.instagrabber.managers.DirectMessagesManager;
|
||||
import awais.instagrabber.managers.ThreadManager;
|
||||
import awais.instagrabber.models.Resource;
|
||||
import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
|
||||
import awais.instagrabber.repositories.responses.FriendshipRestrictResponse;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.webservices.DirectMessagesService;
|
||||
import awais.instagrabber.webservices.FriendshipService;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
@ -58,573 +39,186 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
||||
private static final String ACTION_RESTRICT = "restrict";
|
||||
private static final String ACTION_UNRESTRICT = "unrestrict";
|
||||
|
||||
private final MutableLiveData<Pair<List<User>, List<User>>> users = new MutableLiveData<>(
|
||||
new Pair<>(Collections.emptyList(), Collections.emptyList()));
|
||||
private final MutableLiveData<String> title = new MutableLiveData<>("");
|
||||
private final MutableLiveData<List<Long>> adminUserIds = new MutableLiveData<>(Collections.emptyList());
|
||||
private final MutableLiveData<Boolean> muted = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Boolean> mentionsMuted = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Boolean> approvalRequiredToJoin = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<DirectThreadParticipantRequestsResponse> pendingRequests = 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 long userId;
|
||||
private final long viewerId;
|
||||
private final Resources resources;
|
||||
private final FriendshipService friendshipService;
|
||||
private final String csrfToken;
|
||||
private final ThreadManager threadManager;
|
||||
|
||||
private DirectThread thread;
|
||||
private boolean viewerIsAdmin;
|
||||
private User viewer;
|
||||
|
||||
public DirectSettingsViewModel(final Application application) {
|
||||
public DirectSettingsViewModel(final Application application,
|
||||
@NonNull final String threadId,
|
||||
final boolean pending,
|
||||
@NonNull final User currentUser) {
|
||||
super(application);
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||
viewerId = CookieUtils.getUserIdFromCookie(cookie);
|
||||
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
|
||||
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||
if (TextUtils.isEmpty(csrfToken) || userId <= 0 || TextUtils.isEmpty(deviceUuid)) {
|
||||
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||
if (TextUtils.isEmpty(csrfToken) || viewerId <= 0 || TextUtils.isEmpty(deviceUuid)) {
|
||||
throw new IllegalArgumentException("User is not logged in!");
|
||||
}
|
||||
directMessagesService = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid);
|
||||
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
|
||||
final ContentResolver contentResolver = application.getContentResolver();
|
||||
resources = getApplication().getResources();
|
||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
||||
threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public DirectThread getThread() {
|
||||
return thread;
|
||||
public LiveData<DirectThread> getThread() {
|
||||
return threadManager.getThread();
|
||||
}
|
||||
|
||||
public void setThread(@NonNull final DirectThread thread) {
|
||||
this.thread = thread;
|
||||
inputMode.postValue(thread.getInputMode());
|
||||
List<User> users = thread.getUsers();
|
||||
if (viewer != null) {
|
||||
final ImmutableList.Builder<User> builder = ImmutableList.<User>builder().add(viewer);
|
||||
if (users != null) {
|
||||
builder.addAll(users);
|
||||
}
|
||||
users = builder.build();
|
||||
}
|
||||
this.users.postValue(new Pair<>(users, thread.getLeftUsers()));
|
||||
setTitle(thread.getThreadTitle());
|
||||
final List<Long> adminUserIds = thread.getAdminUserIds();
|
||||
this.adminUserIds.postValue(adminUserIds);
|
||||
viewerIsAdmin = adminUserIds.contains(userId);
|
||||
muted.postValue(thread.isMuted());
|
||||
mentionsMuted.postValue(thread.isMentionsMuted());
|
||||
approvalRequiredToJoin.postValue(thread.isApprovalRequiredForNewMembers());
|
||||
isPending.postValue(thread.isPending());
|
||||
if (thread.getInputMode() != 1 && thread.isGroup() && viewerIsAdmin) {
|
||||
fetchPendingRequests();
|
||||
}
|
||||
}
|
||||
// public void setThread(@NonNull final DirectThread thread) {
|
||||
// this.thread = thread;
|
||||
// inputMode.postValue(thread.getInputMode());
|
||||
// List<User> users = thread.getUsers();
|
||||
// final ImmutableList.Builder<User> builder = ImmutableList.<User>builder().add(currentUser);
|
||||
// if (users != null) {
|
||||
// builder.addAll(users);
|
||||
// }
|
||||
// users = builder.build();
|
||||
// this.users.postValue(new Pair<>(users, thread.getLeftUsers()));
|
||||
// // setTitle(thread.getThreadTitle());
|
||||
// final List<Long> adminUserIds = thread.getAdminUserIds();
|
||||
// this.adminUserIds.postValue(adminUserIds);
|
||||
// viewerIsAdmin = adminUserIds.contains(viewerId);
|
||||
// muted.postValue(thread.isMuted());
|
||||
// mentionsMuted.postValue(thread.isMentionsMuted());
|
||||
// approvalRequiredToJoin.postValue(thread.isApprovalRequiredForNewMembers());
|
||||
// isPending.postValue(thread.isPending());
|
||||
// if (thread.getInputMode() != 1 && thread.isGroup() && viewerIsAdmin) {
|
||||
// fetchPendingRequests();
|
||||
// }
|
||||
// }
|
||||
|
||||
public LiveData<Integer> getInputMode() {
|
||||
return inputMode;
|
||||
return threadManager.getInputMode();
|
||||
}
|
||||
|
||||
public boolean isGroup() {
|
||||
if (thread != null) {
|
||||
return thread.isGroup();
|
||||
}
|
||||
return false;
|
||||
public LiveData<Boolean> isGroup() {
|
||||
return threadManager.isGroup();
|
||||
}
|
||||
|
||||
public LiveData<Pair<List<User>, List<User>>> getUsers() {
|
||||
return users;
|
||||
public LiveData<List<User>> getUsers() {
|
||||
return threadManager.getUsersWithCurrent();
|
||||
}
|
||||
|
||||
public LiveData<List<User>> getLeftUsers() {
|
||||
return threadManager.getLeftUsers();
|
||||
}
|
||||
|
||||
public LiveData<Pair<List<User>, List<User>>> getUsersAndLeftUsers() {
|
||||
return threadManager.getUsersAndLeftUsers();
|
||||
}
|
||||
|
||||
public LiveData<String> getTitle() {
|
||||
return title;
|
||||
return threadManager.getThreadTitle();
|
||||
}
|
||||
|
||||
public void setTitle(final String title) {
|
||||
if (title == null) {
|
||||
this.title.postValue("");
|
||||
return;
|
||||
}
|
||||
this.title.postValue(title.trim());
|
||||
}
|
||||
// public void setTitle(final String title) {
|
||||
// if (title == null) {
|
||||
// this.title.postValue("");
|
||||
// return;
|
||||
// }
|
||||
// this.title.postValue(title.trim());
|
||||
// }
|
||||
|
||||
public LiveData<List<Long>> getAdminUserIds() {
|
||||
return adminUserIds;
|
||||
return threadManager.getAdminUserIds();
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getMuted() {
|
||||
return muted;
|
||||
public LiveData<Boolean> isMuted() {
|
||||
return threadManager.isMuted();
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getApprovalRequiredToJoin() {
|
||||
return approvalRequiredToJoin;
|
||||
return threadManager.isApprovalRequiredToJoin();
|
||||
}
|
||||
|
||||
public LiveData<DirectThreadParticipantRequestsResponse> getPendingRequests() {
|
||||
return pendingRequests;
|
||||
return threadManager.getPendingRequests();
|
||||
}
|
||||
|
||||
public LiveData<Boolean> isPending() {
|
||||
return isPending;
|
||||
return threadManager.isPending();
|
||||
}
|
||||
|
||||
public boolean isViewerAdmin() {
|
||||
return viewerIsAdmin;
|
||||
public LiveData<Boolean> isViewerAdmin() {
|
||||
return threadManager.isViewerAdmin();
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> updateTitle(final String newTitle) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
final Call<DirectThreadDetailsChangeResponse> addUsersRequest = directMessagesService
|
||||
.updateTitle(thread.getThreadId(), newTitle.trim());
|
||||
handleDetailsChangeRequest(data, addUsersRequest);
|
||||
return data;
|
||||
return threadManager.updateTitle(newTitle);
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> addMembers(final Set<User> users) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
final Call<DirectThreadDetailsChangeResponse> addUsersRequest = directMessagesService
|
||||
.addUsers(thread.getThreadId(), users.stream().map(User::getPk).collect(Collectors.toList()));
|
||||
handleDetailsChangeRequest(data, addUsersRequest);
|
||||
return data;
|
||||
return threadManager.addMembers(users);
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> removeMember(final User user) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
final Call<String> request = directMessagesService
|
||||
.removeUsers(thread.getThreadId(), Collections.singleton(user.getPk()));
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleSettingChangeResponseError(response, data);
|
||||
return;
|
||||
}
|
||||
Pair<List<User>, List<User>> usersValue = users.getValue();
|
||||
if (usersValue == null) {
|
||||
usersValue = new Pair<>(Collections.emptyList(), Collections.emptyList());
|
||||
}
|
||||
List<User> activeUsers = usersValue.first;
|
||||
if (activeUsers == null) {
|
||||
activeUsers = Collections.emptyList();
|
||||
}
|
||||
final List<User> updatedActiveUsers = activeUsers.stream()
|
||||
.filter(user1 -> user1.getPk() != user.getPk())
|
||||
.collect(Collectors.toList());
|
||||
List<User> leftUsers = usersValue.second;
|
||||
if (leftUsers == null) {
|
||||
leftUsers = Collections.emptyList();
|
||||
}
|
||||
final ImmutableList<User> updateLeftUsers = ImmutableList.<User>builder()
|
||||
.addAll(leftUsers)
|
||||
.add(user)
|
||||
.build();
|
||||
users.postValue(new Pair<>(updatedActiveUsers, updateLeftUsers));
|
||||
}
|
||||
|
||||
@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;
|
||||
return threadManager.removeMember(user);
|
||||
}
|
||||
|
||||
private LiveData<Resource<Object>> makeAdmin(final User user) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
if (isAdmin(user)) return data;
|
||||
final Call<String> request = directMessagesService.addAdmins(thread.getThreadId(), Collections.singleton(user.getPk()));
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleSettingChangeResponseError(response, data);
|
||||
return;
|
||||
}
|
||||
final List<Long> currentAdmins = adminUserIds.getValue();
|
||||
adminUserIds.postValue(ImmutableList.<Long>builder()
|
||||
.addAll(currentAdmins != null ? currentAdmins : Collections.emptyList())
|
||||
.add(user.getPk())
|
||||
.build());
|
||||
}
|
||||
|
||||
@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;
|
||||
return threadManager.makeAdmin(user);
|
||||
}
|
||||
|
||||
private LiveData<Resource<Object>> removeAdmin(final User user) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
if (!isAdmin(user)) return data;
|
||||
final Call<String> request = directMessagesService.removeAdmins(thread.getThreadId(), Collections.singleton(user.getPk()));
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleSettingChangeResponseError(response, data);
|
||||
return;
|
||||
}
|
||||
final List<Long> currentAdmins = adminUserIds.getValue();
|
||||
if (currentAdmins == null) return;
|
||||
adminUserIds.postValue(currentAdmins.stream()
|
||||
.filter(userId1 -> userId1 != user.getPk())
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@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;
|
||||
return threadManager.removeAdmin(user);
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> mute() {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
if (thread.isMuted()) {
|
||||
data.postValue(Resource.success(new Object()));
|
||||
return data;
|
||||
}
|
||||
final Call<String> request = directMessagesService.mute(thread.getThreadId());
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleSettingChangeResponseError(response, data);
|
||||
return;
|
||||
}
|
||||
thread.setMuted(true);
|
||||
muted.postValue(true);
|
||||
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;
|
||||
return threadManager.mute();
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> unmute() {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
if (!thread.isMuted()) {
|
||||
data.postValue(Resource.success(new Object()));
|
||||
return data;
|
||||
}
|
||||
final Call<String> request = directMessagesService.unmute(thread.getThreadId());
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleSettingChangeResponseError(response, data);
|
||||
return;
|
||||
}
|
||||
thread.setMuted(false);
|
||||
muted.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;
|
||||
return threadManager.unmute();
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> muteMentions() {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
if (thread.isMentionsMuted()) {
|
||||
data.postValue(Resource.success(new Object()));
|
||||
return data;
|
||||
}
|
||||
final Call<String> request = directMessagesService.muteMentions(thread.getThreadId());
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleSettingChangeResponseError(response, data);
|
||||
return;
|
||||
}
|
||||
thread.setMentionsMuted(true);
|
||||
mentionsMuted.postValue(true);
|
||||
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;
|
||||
return threadManager.muteMentions();
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> unmuteMentions() {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
if (!thread.isMentionsMuted()) {
|
||||
data.postValue(Resource.success(new Object()));
|
||||
return data;
|
||||
}
|
||||
final Call<String> request = directMessagesService.unmuteMentions(thread.getThreadId());
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleSettingChangeResponseError(response, data);
|
||||
return;
|
||||
}
|
||||
thread.setMentionsMuted(false);
|
||||
mentionsMuted.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;
|
||||
}
|
||||
|
||||
private void handleSettingChangeResponseError(@NonNull final Response<String> response,
|
||||
final MutableLiveData<Resource<Object>> data) {
|
||||
final ResponseBody errorBody = response.errorBody();
|
||||
if (errorBody == null) {
|
||||
handleErrorResponse(response, data);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final JSONObject json = new JSONObject(errorBody.string());
|
||||
if (json.has("message")) {
|
||||
data.postValue(Resource.error(json.getString("message"), null));
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
Log.e(TAG, "onResponse: ", e);
|
||||
data.postValue(Resource.error(e.getMessage(), null));
|
||||
}
|
||||
return threadManager.unmuteMentions();
|
||||
}
|
||||
|
||||
private LiveData<Resource<Object>> blockUser(final User user) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
friendshipService.block(user.getPk(), new ServiceCallback<FriendshipChangeResponse>() {
|
||||
@Override
|
||||
public void onSuccess(final FriendshipChangeResponse result) {
|
||||
// refresh thread
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
Log.e(TAG, "onFailure: ", t);
|
||||
data.postValue(Resource.error(t.getMessage(), null));
|
||||
}
|
||||
});
|
||||
return data;
|
||||
return threadManager.blockUser(user);
|
||||
}
|
||||
|
||||
private LiveData<Resource<Object>> unblockUser(final User user) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
friendshipService.unblock(user.getPk(), new ServiceCallback<FriendshipChangeResponse>() {
|
||||
@Override
|
||||
public void onSuccess(final FriendshipChangeResponse result) {
|
||||
// refresh thread
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
Log.e(TAG, "onFailure: ", t);
|
||||
data.postValue(Resource.error(t.getMessage(), null));
|
||||
}
|
||||
});
|
||||
return data;
|
||||
return threadManager.unblockUser(user);
|
||||
}
|
||||
|
||||
private LiveData<Resource<Object>> restrictUser(final User user) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
friendshipService.toggleRestrict(user.getPk(), true, new ServiceCallback<FriendshipRestrictResponse>() {
|
||||
@Override
|
||||
public void onSuccess(final FriendshipRestrictResponse result) {
|
||||
// refresh thread
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
Log.e(TAG, "onFailure: ", t);
|
||||
data.postValue(Resource.error(t.getMessage(), null));
|
||||
}
|
||||
});
|
||||
return data;
|
||||
return threadManager.restrictUser(user);
|
||||
}
|
||||
|
||||
private LiveData<Resource<Object>> unRestrictUser(final User user) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
friendshipService.toggleRestrict(user.getPk(), false, new ServiceCallback<FriendshipRestrictResponse>() {
|
||||
@Override
|
||||
public void onSuccess(final FriendshipRestrictResponse result) {
|
||||
// refresh thread
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
Log.e(TAG, "onFailure: ", t);
|
||||
data.postValue(Resource.error(t.getMessage(), null));
|
||||
}
|
||||
});
|
||||
return data;
|
||||
return threadManager.unRestrictUser(user);
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> approveUsers(final List<User> users) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
final Call<DirectThreadDetailsChangeResponse> approveUsersRequest = directMessagesService
|
||||
.approveParticipantRequests(thread.getThreadId(), users.stream().map(User::getPk).collect(Collectors.toList()));
|
||||
handleDetailsChangeRequest(data, approveUsersRequest);
|
||||
return data;
|
||||
return threadManager.approveUsers(users);
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> denyUsers(final List<User> users) {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
final Call<DirectThreadDetailsChangeResponse> approveUsersRequest = directMessagesService
|
||||
.declineParticipantRequests(thread.getThreadId(), users.stream().map(User::getPk).collect(Collectors.toList()));
|
||||
handleDetailsChangeRequest(data, approveUsersRequest, () -> {
|
||||
final DirectThreadParticipantRequestsResponse pendingRequestsValue = pendingRequests.getValue();
|
||||
if (pendingRequestsValue == null) return;
|
||||
final List<User> pendingUsers = pendingRequestsValue.getUsers();
|
||||
if (pendingUsers == null || pendingUsers.isEmpty()) return;
|
||||
final List<User> filtered = pendingUsers.stream()
|
||||
.filter(o -> !users.contains(o))
|
||||
.collect(Collectors.toList());
|
||||
try {
|
||||
final DirectThreadParticipantRequestsResponse clone = (DirectThreadParticipantRequestsResponse) pendingRequestsValue.clone();
|
||||
clone.setUsers(filtered);
|
||||
pendingRequests.postValue(clone);
|
||||
} catch (CloneNotSupportedException e) {
|
||||
Log.e(TAG, "denyUsers: ", e);
|
||||
}
|
||||
});
|
||||
return data;
|
||||
return threadManager.denyUsers(users);
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> approvalRequired() {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
if (thread.isApprovalRequiredForNewMembers()) {
|
||||
data.postValue(Resource.success(new Object()));
|
||||
return data;
|
||||
}
|
||||
final Call<DirectThreadDetailsChangeResponse> request = directMessagesService.approvalRequired(thread.getThreadId());
|
||||
handleDetailsChangeRequest(data, request, () -> {
|
||||
thread.setApprovalRequiredForNewMembers(true);
|
||||
approvalRequiredToJoin.postValue(true);
|
||||
});
|
||||
return data;
|
||||
return threadManager.approvalRequired();
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> approvalNotRequired() {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
if (!thread.isApprovalRequiredForNewMembers()) {
|
||||
data.postValue(Resource.success(new Object()));
|
||||
return data;
|
||||
}
|
||||
final Call<DirectThreadDetailsChangeResponse> request = directMessagesService.approvalNotRequired(thread.getThreadId());
|
||||
handleDetailsChangeRequest(data, request, () -> {
|
||||
thread.setApprovalRequiredForNewMembers(false);
|
||||
approvalRequiredToJoin.postValue(false);
|
||||
});
|
||||
return data;
|
||||
return threadManager.approvalNotRequired();
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> leave() {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
final Call<DirectThreadDetailsChangeResponse> request = directMessagesService.leave(thread.getThreadId());
|
||||
handleDetailsChangeRequest(data, request);
|
||||
return data;
|
||||
return threadManager.leave();
|
||||
}
|
||||
|
||||
public LiveData<Resource<Object>> end() {
|
||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||
data.postValue(Resource.loading(null));
|
||||
final Call<DirectThreadDetailsChangeResponse> request = directMessagesService.end(thread.getThreadId());
|
||||
handleDetailsChangeRequest(data, request, () -> {
|
||||
thread.setInputMode(1);
|
||||
inputMode.postValue(1);
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
private interface OnSuccessAction {
|
||||
void onSuccess();
|
||||
}
|
||||
|
||||
private void handleDetailsChangeRequest(final MutableLiveData<Resource<Object>> data,
|
||||
final Call<DirectThreadDetailsChangeResponse> request) {
|
||||
handleDetailsChangeRequest(data, request, null);
|
||||
}
|
||||
|
||||
private void handleDetailsChangeRequest(final MutableLiveData<Resource<Object>> data,
|
||||
final Call<DirectThreadDetailsChangeResponse> request,
|
||||
@Nullable final OnSuccessAction action) {
|
||||
request.enqueue(new Callback<DirectThreadDetailsChangeResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<DirectThreadDetailsChangeResponse> call,
|
||||
@NonNull final Response<DirectThreadDetailsChangeResponse> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleErrorResponse(response, data);
|
||||
return;
|
||||
}
|
||||
final DirectThreadDetailsChangeResponse changeResponse = response.body();
|
||||
if (changeResponse == null) {
|
||||
data.postValue(Resource.error("Response is null", null));
|
||||
return;
|
||||
}
|
||||
data.postValue(Resource.success(new Object()));
|
||||
final DirectThread thread = changeResponse.getThread();
|
||||
if (thread != null) {
|
||||
setThread(thread);
|
||||
}
|
||||
if (action != null) {
|
||||
action.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<DirectThreadDetailsChangeResponse> call, @NonNull final Throwable t) {
|
||||
Log.e(TAG, "onFailure: ", t);
|
||||
data.postValue(Resource.error(t.getMessage(), null));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleErrorResponse(@NonNull final Response<?> response,
|
||||
final MutableLiveData<Resource<Object>> data) {
|
||||
final ResponseBody errorBody = response.errorBody();
|
||||
if (errorBody == null) {
|
||||
data.postValue(Resource.error("Request failed!", null));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
data.postValue(Resource.error(errorBody.string(), null));
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "onResponse: ", e);
|
||||
data.postValue(Resource.error(e.getMessage(), null));
|
||||
}
|
||||
return threadManager.end();
|
||||
}
|
||||
|
||||
public ArrayList<Option<String>> createUserOptions(final User user) {
|
||||
@ -632,10 +226,11 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
||||
if (user == null || isSelf(user) || hasLeft(user)) {
|
||||
return options;
|
||||
}
|
||||
if (viewerIsAdmin) {
|
||||
final Boolean viewerIsAdmin = threadManager.isViewerAdmin().getValue();
|
||||
if (viewerIsAdmin != null && viewerIsAdmin) {
|
||||
options.add(new Option<>(getString(R.string.dms_action_kick), ACTION_KICK));
|
||||
|
||||
final boolean isAdmin = isAdmin(user);
|
||||
final boolean isAdmin = threadManager.isAdmin(user);
|
||||
options.add(new Option<>(
|
||||
isAdmin ? getString(R.string.dms_action_remove_admin) : getString(R.string.dms_action_make_admin),
|
||||
isAdmin ? ACTION_REMOVE_ADMIN : ACTION_MAKE_ADMIN
|
||||
@ -649,8 +244,8 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
||||
));
|
||||
|
||||
// options.add(new Option<>(getString(R.string.report), ACTION_REPORT));
|
||||
|
||||
if (!isGroup()) {
|
||||
final Boolean isGroup = threadManager.isGroup().getValue();
|
||||
if (isGroup != null && isGroup) {
|
||||
final boolean restricted = user.getFriendshipStatus().isRestricted();
|
||||
options.add(new Option<>(
|
||||
restricted ? getString(R.string.unrestrict) : getString(R.string.restrict),
|
||||
@ -661,18 +256,13 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
||||
}
|
||||
|
||||
private boolean hasLeft(final User user) {
|
||||
final Pair<List<User>, List<User>> users = this.users.getValue();
|
||||
if (users == null || users.second == null) return false;
|
||||
return users.second.contains(user);
|
||||
}
|
||||
|
||||
private boolean isAdmin(final User user) {
|
||||
final List<Long> adminUserIdsValue = adminUserIds.getValue();
|
||||
return adminUserIdsValue != null && adminUserIdsValue.contains(user.getPk());
|
||||
final List<User> leftUsers = getLeftUsers().getValue();
|
||||
if (leftUsers == null) return false;
|
||||
return leftUsers.contains(user);
|
||||
}
|
||||
|
||||
private boolean isSelf(final User user) {
|
||||
return user.getPk() == userId;
|
||||
return user.getPk() == viewerId;
|
||||
}
|
||||
|
||||
private String getString(@StringRes final int resId) {
|
||||
@ -703,47 +293,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewer(final User viewer) {
|
||||
this.viewer = viewer;
|
||||
}
|
||||
|
||||
private void fetchPendingRequests() {
|
||||
final Call<DirectThreadParticipantRequestsResponse> request = directMessagesService.participantRequests(thread.getThreadId(), 5, null);
|
||||
request.enqueue(new Callback<DirectThreadParticipantRequestsResponse>() {
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<DirectThreadParticipantRequestsResponse> call,
|
||||
@NonNull final Response<DirectThreadParticipantRequestsResponse> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
if (response.errorBody() != null) {
|
||||
try {
|
||||
final String string = 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);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "onResponse: ", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Log.e(TAG, "onResponse: request was not successful and response error body was null");
|
||||
return;
|
||||
}
|
||||
final DirectThreadParticipantRequestsResponse body = response.body();
|
||||
if (body == null) {
|
||||
Log.e(TAG, "onResponse: response body was null");
|
||||
return;
|
||||
}
|
||||
pendingRequests.postValue(body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<DirectThreadParticipantRequestsResponse> call, @NonNull final Throwable t) {
|
||||
Log.e(TAG, "onFailure: ", t);
|
||||
}
|
||||
});
|
||||
public LiveData<User> getInviter() {
|
||||
return threadManager.getInviter();
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@
|
||||
package awais.instagrabber.viewmodels.factories;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.viewmodels.DirectSettingsViewModel;
|
||||
|
||||
public class DirectSettingsViewModelFactory implements ViewModelProvider.Factory {
|
||||
|
||||
private final Application application;
|
||||
private final String threadId;
|
||||
private final boolean pending;
|
||||
private final User currentUser;
|
||||
|
||||
public DirectSettingsViewModelFactory(@NonNull final Application application,
|
||||
@NonNull final String threadId,
|
||||
final boolean pending,
|
||||
@NonNull final User currentUser) {
|
||||
this.application = application;
|
||||
this.threadId = threadId;
|
||||
this.pending = pending;
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T extends ViewModel> T create(@NonNull final Class<T> modelClass) {
|
||||
//noinspection unchecked
|
||||
return (T) new DirectSettingsViewModel(application, threadId, pending, currentUser);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package awais.instagrabber.viewmodels.factories;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.viewmodels.DirectThreadViewModel;
|
||||
|
||||
public class DirectThreadViewModelFactory implements ViewModelProvider.Factory {
|
||||
|
||||
private final Application application;
|
||||
private final String threadId;
|
||||
private final boolean pending;
|
||||
private final User currentUser;
|
||||
|
||||
public DirectThreadViewModelFactory(@NonNull final Application application,
|
||||
@NonNull final String threadId,
|
||||
final boolean pending,
|
||||
@NonNull final User currentUser) {
|
||||
this.application = application;
|
||||
this.threadId = threadId;
|
||||
this.pending = pending;
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T extends ViewModel> T create(@NonNull final Class<T> modelClass) {
|
||||
//noinspection unchecked
|
||||
return (T) new DirectThreadViewModel(application, threadId, pending, currentUser);
|
||||
}
|
||||
}
|
@ -20,4 +20,14 @@
|
||||
android:paddingBottom="?attr/actionBarSize"
|
||||
tools:listitem="@layout/layout_dm_inbox_item" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:text="@string/no_pending_requests"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:visibility="gone" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
@ -428,4 +428,5 @@
|
||||
<string name="accept_request_from_user">Accept request from %1s (%2s)?</string>
|
||||
<string name="decline">Decline</string>
|
||||
<string name="accept">Accept</string>
|
||||
<string name="no_pending_requests">No pending requests</string>
|
||||
</resources>
|
||||
|
@ -5,7 +5,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||
classpath 'com.android.tools.build:gradle:4.1.2'
|
||||
def nav_version = "2.3.2"
|
||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user