1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-11-22 14:47:29 +00:00

Auto mark dm seen if enabled in settings. Fixes https://github.com/austinhuang0131/barinsta/issues/797

This commit is contained in:
Ammar Githam 2021-03-18 01:41:29 +09:00
parent 321af4cad4
commit dfa3a50893
8 changed files with 213 additions and 15 deletions

View File

@ -9,6 +9,7 @@ import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter; import androidx.recyclerview.widget.ListAdapter;
import java.util.List; import java.util.List;
import java.util.Objects;
import awais.instagrabber.adapters.viewholder.directmessages.DirectInboxItemViewHolder; import awais.instagrabber.adapters.viewholder.directmessages.DirectInboxItemViewHolder;
import awais.instagrabber.databinding.LayoutDmInboxItemBinding; import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
@ -29,6 +30,8 @@ public final class DirectMessageInboxAdapter extends ListAdapter<DirectThread, D
@NonNull final DirectThread newThread) { @NonNull final DirectThread newThread) {
final boolean titleEqual = oldThread.getThreadTitle().equals(newThread.getThreadTitle()); final boolean titleEqual = oldThread.getThreadTitle().equals(newThread.getThreadTitle());
if (!titleEqual) return false; if (!titleEqual) return false;
final boolean lastSeenAtEqual = Objects.equals(oldThread.getLastSeenAt(), newThread.getLastSeenAt());
if (!lastSeenAtEqual) return false;
final List<DirectItem> oldItems = oldThread.getItems(); final List<DirectItem> oldItems = oldThread.getItems();
final List<DirectItem> newItems = newThread.getItems(); final List<DirectItem> newItems = newThread.getItems();
if (oldItems == null || newItems == null) return false; if (oldItems == null || newItems == null) return false;

View File

@ -58,7 +58,6 @@ import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import awais.instagrabber.ProfileNavGraphDirections; import awais.instagrabber.ProfileNavGraphDirections;
import awais.instagrabber.R; import awais.instagrabber.R;
@ -100,6 +99,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectItemVisual
import awais.instagrabber.repositories.responses.directmessages.DirectThread; import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.AppExecutors;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.PermissionUtils; import awais.instagrabber.utils.PermissionUtils;
import awais.instagrabber.utils.ResponseBodyUtils; import awais.instagrabber.utils.ResponseBodyUtils;
@ -146,6 +146,17 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
private int prevLength; private int prevLength;
private BadgeDrawable pendingRequestCountBadgeDrawable; private BadgeDrawable pendingRequestCountBadgeDrawable;
private boolean isPendingRequestCountBadgeAttached = false; private boolean isPendingRequestCountBadgeAttached = false;
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;
private boolean autoMarkAsSeen = false;
private final AppExecutors appExecutors = AppExecutors.getInstance(); private final AppExecutors appExecutors = AppExecutors.getInstance();
private final Animatable2Compat.AnimationCallback micToSendAnimationCallback = new Animatable2Compat.AnimationCallback() { private final Animatable2Compat.AnimationCallback micToSendAnimationCallback = new Animatable2Compat.AnimationCallback() {
@ -306,22 +317,13 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
backStackSavedStateResultLiveData.postValue(null); backStackSavedStateResultLiveData.postValue(null);
}; };
private final MutableLiveData<Integer> inputLength = new MutableLiveData<>(0); 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 @Override
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) requireActivity(); fragmentActivity = (MainActivity) requireActivity();
appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class); appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class);
autoMarkAsSeen = Utils.settingsHelper.getBoolean(Constants.DM_MARK_AS_SEEN);
final Bundle arguments = getArguments(); final Bundle arguments = getArguments();
if (arguments == null) return; if (arguments == null) return;
final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments); final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments);
@ -895,6 +897,9 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
} }
private void submitItemsToAdapter(final List<DirectItem> items) { private void submitItemsToAdapter(final List<DirectItem> items) {
if (autoMarkAsSeen) {
binding.chats.post(() -> viewModel.markAsSeen());
}
if (itemsAdapter == null) return; if (itemsAdapter == null) return;
itemsAdapter.submitList(items, () -> { itemsAdapter.submitList(items, () -> {
itemOrHeaders = itemsAdapter.getList(); itemOrHeaders = itemsAdapter.getList();

View File

@ -22,6 +22,7 @@ import java.net.HttpURLConnection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -45,12 +46,15 @@ import awais.instagrabber.repositories.responses.directmessages.DirectInbox;
import awais.instagrabber.repositories.responses.directmessages.DirectItem; import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction; import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction;
import awais.instagrabber.repositories.responses.directmessages.DirectItemReactions; import awais.instagrabber.repositories.responses.directmessages.DirectItemReactions;
import awais.instagrabber.repositories.responses.directmessages.DirectItemSeenResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectItemSeenResponse.DirectItemSeenResponsePayload;
import awais.instagrabber.repositories.responses.directmessages.DirectThread; import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponseMessageMetadata; import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponseMessageMetadata;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponsePayload; import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponsePayload;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadFeedResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadFeedResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadLastSeenAt;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.repositories.responses.giphy.GiphyGif; import awais.instagrabber.repositories.responses.giphy.GiphyGif;
@ -1187,7 +1191,7 @@ public final class ThreadManager {
private void handleErrorBody(@NonNull final Call<?> call, private void handleErrorBody(@NonNull final Call<?> call,
@NonNull final Response<?> response, @NonNull final Response<?> response,
@NonNull final MutableLiveData<Resource<Object>> data) { final MutableLiveData<Resource<Object>> data) {
try { try {
final String string = response.errorBody() != null ? response.errorBody().string() : ""; final String string = response.errorBody() != null ? response.errorBody().string() : "";
final String msg = String.format(Locale.US, final String msg = String.format(Locale.US,
@ -1195,10 +1199,14 @@ public final class ThreadManager {
call.request().url().toString(), call.request().url().toString(),
response.code(), response.code(),
string); string);
data.postValue(Resource.error(msg, null)); if (data != null) {
data.postValue(Resource.error(msg, null));
}
Log.e(TAG, msg); Log.e(TAG, msg);
} catch (IOException e) { } catch (IOException e) {
data.postValue(Resource.error(e.getMessage(), null)); if (data != null) {
data.postValue(Resource.error(e.getMessage(), null));
}
Log.e(TAG, "onResponse: ", e); Log.e(TAG, "onResponse: ", e);
} }
} }
@ -1794,6 +1802,39 @@ public final class ThreadManager {
return inviter; return inviter;
} }
public void markAsSeen(@NonNull final DirectItem directItem) {
final Call<DirectItemSeenResponse> request = service.markAsSeen(threadId, directItem);
request.enqueue(new Callback<DirectItemSeenResponse>() {
@Override
public void onResponse(@NonNull final Call<DirectItemSeenResponse> call,
@NonNull final Response<DirectItemSeenResponse> response) {
if (!response.isSuccessful()) {
handleErrorBody(call, response, null);
return;
}
final DirectItemSeenResponse seenResponse = response.body();
if (seenResponse == null) return;
inboxManager.fetchUnseenCount();
final DirectItemSeenResponsePayload payload = seenResponse.getPayload();
if (payload == null) return;
final String timestamp = payload.getTimestamp();
final DirectThread thread = ThreadManager.this.thread.getValue();
if (thread == null) return;
Map<Long, DirectThreadLastSeenAt> lastSeenAt = thread.getLastSeenAt();
lastSeenAt = lastSeenAt == null ? new HashMap<>() : new HashMap<>(lastSeenAt);
lastSeenAt.put(currentUser.getPk(), new DirectThreadLastSeenAt(timestamp, directItem.getItemId()));
thread.setLastSeenAt(lastSeenAt);
setThread(thread, true);
}
@Override
public void onFailure(@NonNull final Call<DirectItemSeenResponse> call,
@NonNull final Throwable t) {
Log.e(TAG, "onFailure: ", t);
}
});
}
private interface OnSuccessAction { private interface OnSuccessAction {
void onSuccess(); void onSuccess();
} }

View File

@ -4,6 +4,7 @@ import java.util.Map;
import awais.instagrabber.repositories.responses.directmessages.DirectBadgeCount; import awais.instagrabber.repositories.responses.directmessages.DirectBadgeCount;
import awais.instagrabber.repositories.responses.directmessages.DirectInboxResponse; import awais.instagrabber.repositories.responses.directmessages.DirectInboxResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectItemSeenResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThread; import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse;
@ -145,4 +146,10 @@ public interface DirectMessagesRepository {
@POST("/api/v1/direct_v2/threads/{threadId}/decline/") @POST("/api/v1/direct_v2/threads/{threadId}/decline/")
Call<String> declineRequest(@Path("threadId") String threadId, Call<String> declineRequest(@Path("threadId") String threadId,
@FieldMap final Map<String, String> form); @FieldMap final Map<String, String> form);
@FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/items/{itemId}/seen/")
Call<DirectItemSeenResponse> markItemSeen(@Path("threadId") String threadId,
@Path("itemId") String itemId,
@FieldMap final Map<String, String> form);
} }

View File

@ -0,0 +1,95 @@
package awais.instagrabber.repositories.responses.directmessages;
import androidx.annotation.NonNull;
import java.util.Objects;
public class DirectItemSeenResponse {
private final String action;
private final DirectItemSeenResponsePayload payload;
private final String status;
public DirectItemSeenResponse(final String action, final DirectItemSeenResponsePayload payload, final String status) {
this.action = action;
this.payload = payload;
this.status = status;
}
public String getAction() {
return action;
}
public DirectItemSeenResponsePayload getPayload() {
return payload;
}
public String getStatus() {
return status;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final DirectItemSeenResponse that = (DirectItemSeenResponse) o;
return Objects.equals(action, that.action) &&
Objects.equals(payload, that.payload) &&
Objects.equals(status, that.status);
}
@Override
public int hashCode() {
return Objects.hash(action, payload, status);
}
@NonNull
@Override
public String toString() {
return "DirectItemSeenResponse{" +
"action='" + action + '\'' +
", payload=" + payload +
", status='" + status + '\'' +
'}';
}
public static class DirectItemSeenResponsePayload {
private final int count;
private final String timestamp;
public DirectItemSeenResponsePayload(final int count, final String timestamp) {
this.count = count;
this.timestamp = timestamp;
}
public int getCount() {
return count;
}
public String getTimestamp() {
return timestamp;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final DirectItemSeenResponsePayload that = (DirectItemSeenResponsePayload) o;
return count == that.count &&
Objects.equals(timestamp, that.timestamp);
}
@Override
public int hashCode() {
return Objects.hash(count, timestamp);
}
@NonNull
@Override
public String toString() {
return "DirectItemSeenResponsePayload{" +
"count=" + count +
", timestamp='" + timestamp + '\'' +
'}';
}
}
}

View File

@ -36,7 +36,7 @@ public class DirectThread implements Serializable, Cloneable {
private final User inviter; private final User inviter;
private final boolean hasOlder; private final boolean hasOlder;
private final boolean hasNewer; private final boolean hasNewer;
private final Map<Long, DirectThreadLastSeenAt> lastSeenAt; private Map<Long, DirectThreadLastSeenAt> lastSeenAt;
private final String newestCursor; private final String newestCursor;
private final String oldestCursor; private final String oldestCursor;
private final boolean isSpam; private final boolean isSpam;
@ -248,6 +248,10 @@ public class DirectThread implements Serializable, Cloneable {
return lastSeenAt; return lastSeenAt;
} }
public void setLastSeenAt(final Map<Long, DirectThreadLastSeenAt> lastSeenAt) {
this.lastSeenAt = lastSeenAt;
}
public String getNewestCursor() { public String getNewestCursor() {
return newestCursor; return newestCursor;
} }

View File

@ -15,6 +15,9 @@ import androidx.lifecycle.Transformations;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -25,6 +28,7 @@ import awais.instagrabber.models.Resource;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectItem; import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectThread; import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadLastSeenAt;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.repositories.responses.giphy.GiphyGif; import awais.instagrabber.repositories.responses.giphy.GiphyGif;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
@ -273,4 +277,28 @@ public class DirectThreadViewModel extends AndroidViewModel {
public LiveData<Resource<Object>> declineRequest() { public LiveData<Resource<Object>> declineRequest() {
return threadManager.declineRequest(); return threadManager.declineRequest();
} }
public void markAsSeen() {
final DirectThread thread = getThread().getValue();
if (thread == null) return;
final List<DirectItem> items = thread.getItems();
if (items == null || items.isEmpty()) return;
final Optional<DirectItem> itemOptional = items.stream()
.filter(item -> item.getUserId() != currentUser.getPk())
.findFirst();
if (!itemOptional.isPresent()) return;
final DirectItem directItem = itemOptional.get();
final Map<Long, DirectThreadLastSeenAt> lastSeenAt = thread.getLastSeenAt();
if (lastSeenAt != null) {
final DirectThreadLastSeenAt seenAt = lastSeenAt.get(currentUser.getPk());
try {
if (seenAt != null
&& (Objects.equals(seenAt.getItemId(), directItem.getItemId())
|| Long.parseLong(seenAt.getTimestamp()) >= directItem.getTimestamp())) {
return;
}
} catch (Exception ignored) {}
}
threadManager.markAsSeen(directItem);
}
} }

View File

@ -29,6 +29,8 @@ import awais.instagrabber.repositories.requests.directmessages.VideoBroadcastOpt
import awais.instagrabber.repositories.requests.directmessages.VoiceBroadcastOptions; import awais.instagrabber.repositories.requests.directmessages.VoiceBroadcastOptions;
import awais.instagrabber.repositories.responses.directmessages.DirectBadgeCount; import awais.instagrabber.repositories.responses.directmessages.DirectBadgeCount;
import awais.instagrabber.repositories.responses.directmessages.DirectInboxResponse; import awais.instagrabber.repositories.responses.directmessages.DirectInboxResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectItemSeenResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThread; import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse;
@ -448,4 +450,17 @@ public class DirectMessagesService extends BaseService {
); );
return repository.declineRequest(threadId, form); return repository.declineRequest(threadId, form);
} }
public Call<DirectItemSeenResponse> markAsSeen(@NonNull final String threadId,
@NonNull final DirectItem directItem) {
final ImmutableMap<String, String> form = ImmutableMap.<String, String>builder()
.put("_csrftoken", csrfToken)
.put("_uuid", deviceUuid)
.put("use_unified_inbox", "true")
.put("action", "mark_seen")
.put("thread_id", threadId)
.put("item_id", directItem.getItemId())
.build();
return repository.markItemSeen(threadId, directItem.getItemId(), form);
}
} }