Auto mark dm seen if enabled in settings. Fixes https://github.com/austinhuang0131/barinsta/issues/797
This commit is contained in:
parent
321af4cad4
commit
dfa3a50893
@ -9,6 +9,7 @@ import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectInboxItemViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
||||
@ -29,6 +30,8 @@ public final class DirectMessageInboxAdapter extends ListAdapter<DirectThread, D
|
||||
@NonNull final DirectThread newThread) {
|
||||
final boolean titleEqual = oldThread.getThreadTitle().equals(newThread.getThreadTitle());
|
||||
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> newItems = newThread.getItems();
|
||||
if (oldItems == null || newItems == null) return false;
|
||||
|
@ -58,7 +58,6 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.ProfileNavGraphDirections;
|
||||
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.RankedRecipient;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.PermissionUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
@ -146,6 +146,17 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
private int prevLength;
|
||||
private BadgeDrawable pendingRequestCountBadgeDrawable;
|
||||
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 Animatable2Compat.AnimationCallback micToSendAnimationCallback = new Animatable2Compat.AnimationCallback() {
|
||||
@ -306,22 +317,13 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
backStackSavedStateResultLiveData.postValue(null);
|
||||
};
|
||||
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);
|
||||
autoMarkAsSeen = Utils.settingsHelper.getBoolean(Constants.DM_MARK_AS_SEEN);
|
||||
final Bundle arguments = getArguments();
|
||||
if (arguments == null) return;
|
||||
final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments);
|
||||
@ -895,6 +897,9 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
}
|
||||
|
||||
private void submitItemsToAdapter(final List<DirectItem> items) {
|
||||
if (autoMarkAsSeen) {
|
||||
binding.chats.post(() -> viewModel.markAsSeen());
|
||||
}
|
||||
if (itemsAdapter == null) return;
|
||||
itemsAdapter.submitList(items, () -> {
|
||||
itemOrHeaders = itemsAdapter.getList();
|
||||
|
@ -22,6 +22,7 @@ import java.net.HttpURLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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.DirectItemEmojiReaction;
|
||||
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.DirectThreadBroadcastResponse;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponseMessageMetadata;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponsePayload;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse;
|
||||
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.RankedRecipient;
|
||||
import awais.instagrabber.repositories.responses.giphy.GiphyGif;
|
||||
@ -1187,7 +1191,7 @@ public final class ThreadManager {
|
||||
|
||||
private void handleErrorBody(@NonNull final Call<?> call,
|
||||
@NonNull final Response<?> response,
|
||||
@NonNull final MutableLiveData<Resource<Object>> data) {
|
||||
final MutableLiveData<Resource<Object>> data) {
|
||||
try {
|
||||
final String string = response.errorBody() != null ? response.errorBody().string() : "";
|
||||
final String msg = String.format(Locale.US,
|
||||
@ -1195,10 +1199,14 @@ public final class ThreadManager {
|
||||
call.request().url().toString(),
|
||||
response.code(),
|
||||
string);
|
||||
if (data != null) {
|
||||
data.postValue(Resource.error(msg, null));
|
||||
}
|
||||
Log.e(TAG, msg);
|
||||
} catch (IOException e) {
|
||||
if (data != null) {
|
||||
data.postValue(Resource.error(e.getMessage(), null));
|
||||
}
|
||||
Log.e(TAG, "onResponse: ", e);
|
||||
}
|
||||
}
|
||||
@ -1794,6 +1802,39 @@ public final class ThreadManager {
|
||||
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 {
|
||||
void onSuccess();
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.util.Map;
|
||||
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectBadgeCount;
|
||||
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.DirectThreadBroadcastResponse;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse;
|
||||
@ -145,4 +146,10 @@ public interface DirectMessagesRepository {
|
||||
@POST("/api/v1/direct_v2/threads/{threadId}/decline/")
|
||||
Call<String> declineRequest(@Path("threadId") String threadId,
|
||||
@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);
|
||||
}
|
||||
|
@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ public class DirectThread implements Serializable, Cloneable {
|
||||
private final User inviter;
|
||||
private final boolean hasOlder;
|
||||
private final boolean hasNewer;
|
||||
private final Map<Long, DirectThreadLastSeenAt> lastSeenAt;
|
||||
private Map<Long, DirectThreadLastSeenAt> lastSeenAt;
|
||||
private final String newestCursor;
|
||||
private final String oldestCursor;
|
||||
private final boolean isSpam;
|
||||
@ -248,6 +248,10 @@ public class DirectThread implements Serializable, Cloneable {
|
||||
return lastSeenAt;
|
||||
}
|
||||
|
||||
public void setLastSeenAt(final Map<Long, DirectThreadLastSeenAt> lastSeenAt) {
|
||||
this.lastSeenAt = lastSeenAt;
|
||||
}
|
||||
|
||||
public String getNewestCursor() {
|
||||
return newestCursor;
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ import androidx.lifecycle.Transformations;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
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.directmessages.DirectItem;
|
||||
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.giphy.GiphyGif;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
@ -273,4 +277,28 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
||||
public LiveData<Resource<Object>> 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);
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ import awais.instagrabber.repositories.requests.directmessages.VideoBroadcastOpt
|
||||
import awais.instagrabber.repositories.requests.directmessages.VoiceBroadcastOptions;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectBadgeCount;
|
||||
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.DirectThreadBroadcastResponse;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDetailsChangeResponse;
|
||||
@ -448,4 +450,17 @@ public class DirectMessagesService extends BaseService {
|
||||
);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user