1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-11-14 02:37:30 +00:00

DirectMessagesRepository migrated to suspend functions

This commit is contained in:
Ammar Githam 2021-06-01 06:45:36 +09:00
parent 0c77611e22
commit cc1741005b
9 changed files with 427 additions and 673 deletions

View File

@ -87,7 +87,6 @@ import awais.instagrabber.repositories.requests.StoryViewerOptions.Type;
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds; import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.StoryStickerResponse; import awais.instagrabber.repositories.responses.StoryStickerResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.CoroutineUtilsKt; import awais.instagrabber.utils.CoroutineUtilsKt;
@ -102,9 +101,7 @@ import awais.instagrabber.webservices.DirectMessagesService;
import awais.instagrabber.webservices.MediaService; import awais.instagrabber.webservices.MediaService;
import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.ServiceCallback;
import awais.instagrabber.webservices.StoriesService; import awais.instagrabber.webservices.StoriesService;
import retrofit2.Call; import kotlinx.coroutines.Dispatchers;
import retrofit2.Callback;
import retrofit2.Response;
import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_THRESHOLD; import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_THRESHOLD;
import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD; import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD;
@ -220,40 +217,32 @@ public class StoryViewerFragment extends Fragment {
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
.setTitle(R.string.reply_story) .setTitle(R.string.reply_story)
.setView(input) .setView(input)
.setPositiveButton(R.string.confirm, (d, w) -> { .setPositiveButton(R.string.confirm, (d, w) -> directMessagesService.createThread(
final Call<DirectThread> createThreadRequest = Collections.singletonList(currentStory.getUserId()),
directMessagesService.createThread(Collections.singletonList(currentStory.getUserId()), null); null,
createThreadRequest.enqueue(new Callback<DirectThread>() { CoroutineUtilsKt.getContinuation((thread, throwable) -> {
@Override if (throwable != null) {
public void onResponse(@NonNull final Call<DirectThread> call, @NonNull final Response<DirectThread> response) { Log.e(TAG, "onOptionsItemSelected: ", throwable);
if (!response.isSuccessful() || response.body() == null) {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
return; return;
} }
final DirectThread thread = response.body();
directMessagesService.broadcastStoryReply( directMessagesService.broadcastStoryReply(
ThreadIdOrUserIds.of(thread.getThreadId()), ThreadIdOrUserIds.of(thread.getThreadId()),
input.getText().toString(), input.getText().toString(),
currentStory.getStoryMediaId(), currentStory.getStoryMediaId(),
String.valueOf(currentStory.getUserId()), String.valueOf(currentStory.getUserId()),
CoroutineUtilsKt.getContinuation((directThreadBroadcastResponse, throwable) -> { CoroutineUtilsKt.getContinuation((directThreadBroadcastResponse, throwable1) -> {
if (throwable != null) { if (throwable1 != null) {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
Log.e(TAG, "onFailure: ", throwable); Log.e(TAG, "onFailure: ", throwable1);
return; return;
} }
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
}) }, Dispatchers.getIO())
); );
} }, Dispatchers.getIO())
))
@Override
public void onFailure(@NonNull final Call<DirectThread> call, @NonNull final Throwable t) {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
});
})
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show(); .show();
return true; return true;

View File

@ -84,9 +84,9 @@ import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.UserProfileContextLink; import awais.instagrabber.repositories.responses.UserProfileContextLink;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
@ -99,9 +99,7 @@ import awais.instagrabber.webservices.MediaService;
import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.ServiceCallback;
import awais.instagrabber.webservices.StoriesService; import awais.instagrabber.webservices.StoriesService;
import awais.instagrabber.webservices.UserService; import awais.instagrabber.webservices.UserService;
import retrofit2.Call; import kotlinx.coroutines.Dispatchers;
import retrofit2.Callback;
import retrofit2.Response;
import static androidx.core.content.PermissionChecker.checkSelfPermission; import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG;
@ -1078,30 +1076,24 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
if (!disableDm) { if (!disableDm) {
profileDetailsBinding.btnDM.setOnClickListener(v -> { profileDetailsBinding.btnDM.setOnClickListener(v -> {
profileDetailsBinding.btnDM.setEnabled(false); profileDetailsBinding.btnDM.setEnabled(false);
final Call<DirectThread> createThreadRequest = directMessagesService.createThread(
directMessagesService.createThread(Collections.singletonList(profileModel.getPk()), null); Collections.singletonList(profileModel.getPk()),
createThreadRequest.enqueue(new Callback<DirectThread>() { null,
@Override CoroutineUtilsKt.getContinuation((thread, throwable) -> {
public void onResponse(@NonNull final Call<DirectThread> call, @NonNull final Response<DirectThread> response) { if (throwable != null) {
profileDetailsBinding.btnDM.setEnabled(true); Log.e(TAG, "setupCommonListeners: ", throwable);
if (!response.isSuccessful() || response.body() == null) { Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); return;
return; }
} profileDetailsBinding.btnDM.setEnabled(true);
final InboxManager inboxManager = DirectMessagesManager.INSTANCE.getInboxManager(); final InboxManager inboxManager = DirectMessagesManager.INSTANCE.getInboxManager();
final DirectThread thread = response.body(); if (!inboxManager.containsThread(thread.getThreadId())) {
if (!inboxManager.containsThread(thread.getThreadId())) { thread.setTemp(true);
thread.setTemp(true); inboxManager.addThread(thread, 0);
inboxManager.addThread(thread, 0); }
} fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername()); }, Dispatchers.getIO())
} );
@Override
public void onFailure(@NonNull final Call<DirectThread> call, @NonNull final Throwable t) {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
});
}); });
} }
profileDetailsBinding.mainProfileImage.setOnClickListener(v -> { profileDetailsBinding.mainProfileImage.setOnClickListener(v -> {

View File

@ -22,10 +22,6 @@ import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstanc
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.IOException
import java.util.* import java.util.*
object DirectMessagesManager { object DirectMessagesManager {
@ -72,43 +68,7 @@ object DirectMessagesManager {
return getInstance(threadId, pending, currentUser, contentResolver, viewerId, csrfToken, deviceUuid) return getInstance(threadId, pending, currentUser, contentResolver, viewerId, csrfToken, deviceUuid)
} }
fun createThread( suspend fun createThread(userPk: Long): DirectThread = service.createThread(listOf(userPk), null)
userPk: Long,
callback: ((DirectThread) -> Unit)?,
) {
val createThreadRequest = service.createThread(listOf(userPk), null)
createThreadRequest.enqueue(object : Callback<DirectThread?> {
override fun onResponse(call: Call<DirectThread?>, response: Response<DirectThread?>) {
if (!response.isSuccessful) {
val errorBody = response.errorBody()
if (errorBody != null) {
try {
val string = errorBody.string()
val msg = String.format(Locale.US,
"onResponse: url: %s, responseCode: %d, errorBody: %s",
call.request().url().toString(),
response.code(),
string)
Log.e(TAG, msg)
} catch (e: IOException) {
Log.e(TAG, "onResponse: ", e)
}
return
}
Log.e(TAG, "onResponse: request was not successful and response error body was null")
return
}
val thread = response.body()
if (thread == null) {
Log.e(TAG, "onResponse: thread is null")
return
}
callback?.invoke(thread)
}
override fun onFailure(call: Call<DirectThread?>, t: Throwable) {}
})
}
fun sendMedia(recipients: Set<RankedRecipient>, mediaId: String, scope: CoroutineScope) { fun sendMedia(recipients: Set<RankedRecipient>, mediaId: String, scope: CoroutineScope) {
val resultsCount = intArrayOf(0) val resultsCount = intArrayOf(0)
@ -136,12 +96,18 @@ object DirectMessagesManager {
) { ) {
if (recipient.thread == null && recipient.user != null) { if (recipient.thread == null && recipient.user != null) {
// create thread and forward // create thread and forward
createThread(recipient.user.pk) { (threadId) -> scope.launch(Dispatchers.IO) {
val threadIdTemp = threadId ?: return@createThread try {
sendMedia(threadIdTemp, mediaId, scope) { val (threadId) = createThread(recipient.user.pk)
if (refreshInbox) { val threadIdTemp = threadId ?: return@launch
inboxManager.refresh(scope) sendMedia(threadIdTemp, mediaId, scope) {
if (refreshInbox) {
inboxManager.refresh(scope)
}
callback?.invoke()
} }
} catch (e: Exception) {
Log.e(TAG, "sendMedia: ", e)
callback?.invoke() callback?.invoke()
} }
} }

View File

@ -155,79 +155,23 @@ class ThreadManager private constructor(
_fetching.postValue(error(e.message, null)) _fetching.postValue(error(e.message, null))
hasOlder = false hasOlder = false
} }
// chatsRequest?.enqueue(object : Callback<DirectThreadFeedResponse?> {
// override fun onResponse(call: Call<DirectThreadFeedResponse?>, response: Response<DirectThreadFeedResponse?>) {
// val feedResponse = response.body()
// if (feedResponse == null) {
// fetching.postValue(error(R.string.generic_null_response, null))
// Log.e(TAG, "onResponse: response was null!")
// return
// }
// if (feedResponse.status != null && feedResponse.status != "ok") {
// fetching.postValue(error(R.string.generic_not_ok_response, null))
// return
// }
// val thread = feedResponse.thread
// if (thread == null) {
// fetching.postValue(error("thread is null!", null))
// return
// }
// setThread(thread)
// fetching.postValue(success(Any()))
// }
//
// override fun onFailure(call: Call<DirectThreadFeedResponse?>, t: Throwable) {
// Log.e(TAG, "Failed fetching dm chats", t)
// fetching.postValue(error(t.message, null))
// hasOlder = false
// }
// })
} }
if (cursor == null) { if (cursor == null) {
fetchPendingRequests() fetchPendingRequests(scope)
} }
} }
fun fetchPendingRequests() { fun fetchPendingRequests(scope: CoroutineScope) {
val isGroup = isGroup.value val isGroup = isGroup.value
if (isGroup == null || !isGroup) return if (isGroup == null || !isGroup) return
val request = service.participantRequests(threadId, 1, null) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<DirectThreadParticipantRequestsResponse?> { try {
override fun onResponse( val response = service.participantRequests(threadId, 1)
call: Call<DirectThreadParticipantRequestsResponse?>, _pendingRequests.postValue(response)
response: Response<DirectThreadParticipantRequestsResponse?>, } catch (e: Exception) {
) { Log.e(TAG, "fetchPendingRequests: ", e)
if (!response.isSuccessful) {
if (response.errorBody() != null) {
try {
val string = response.errorBody()?.string() ?: ""
val msg = String.format(Locale.US,
"onResponse: url: %s, responseCode: %d, errorBody: %s",
call.request().url().toString(),
response.code(),
string)
Log.e(TAG, msg)
} catch (e: IOException) {
Log.e(TAG, "onResponse: ", e)
}
return
}
Log.e(TAG, "onResponse: request was not successful and response error body was null")
return
}
val body = response.body()
if (body == null) {
Log.e(TAG, "onResponse: response body was null")
return
}
_pendingRequests.postValue(body)
} }
}
override fun onFailure(call: Call<DirectThreadParticipantRequestsResponse?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
}
})
} }
private fun setThread(thread: DirectThread, skipItems: Boolean) { private fun setThread(thread: DirectThread, skipItems: Boolean) {
@ -628,7 +572,7 @@ class ThreadManager private constructor(
return data return data
} }
fun unsend(item: DirectItem): LiveData<Resource<Any?>> { fun unsend(item: DirectItem, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val index = removeItem(item) val index = removeItem(item)
val itemId = item.itemId val itemId = item.itemId
@ -636,45 +580,46 @@ class ThreadManager private constructor(
data.postValue(error("itemId is null", null)) data.postValue(error("itemId is null", null))
return data return data
} }
val request = service.deleteItem(threadId, itemId) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse(call: Call<String?>, response: Response<String?>) { service.deleteItem(threadId, itemId)
if (response.isSuccessful) { } catch (e: Exception) {
// Log.d(TAG, "onResponse: " + response.body());
return
}
// add the item back if unsuccessful // add the item back if unsuccessful
addItems(index, listOf(item)) addItems(index, listOf(item))
if (response.errorBody() != null) { data.postValue(error(e.message, item))
handleErrorBody(call, response, data) Log.e(TAG, "unsend: ", e)
return
}
data.postValue(error(R.string.generic_failed_request, item))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
data.postValue(error(t.message, item))
Log.e(TAG, "enqueueRequest: onFailure: ", t)
}
})
return data return data
} }
fun forward(recipients: Set<RankedRecipient>, itemToForward: DirectItem) { fun forward(
recipients: Set<RankedRecipient>,
itemToForward: DirectItem,
scope: CoroutineScope,
) {
for (recipient in recipients) { for (recipient in recipients) {
forward(recipient, itemToForward) forward(recipient, itemToForward, scope)
} }
} }
fun forward(recipient: RankedRecipient, itemToForward: DirectItem) { fun forward(
recipient: RankedRecipient,
itemToForward: DirectItem,
scope: CoroutineScope,
) {
if (recipient.thread == null && recipient.user != null) { if (recipient.thread == null && recipient.user != null) {
// create thread and forward scope.launch(Dispatchers.IO) {
DirectMessagesManager.createThread(recipient.user.pk) { forward(it, itemToForward) } // create thread and forward
val thread = DirectMessagesManager.createThread(recipient.user.pk)
forward(thread, itemToForward, scope)
}
return
} }
if (recipient.thread != null) { if (recipient.thread != null) {
// just forward // just forward
val thread = recipient.thread val thread = recipient.thread
forward(thread, itemToForward) forward(thread, itemToForward, scope)
} }
} }
@ -683,7 +628,11 @@ class ThreadManager private constructor(
_replyToItem.postValue(item) _replyToItem.postValue(item)
} }
private fun forward(thread: DirectThread, itemToForward: DirectItem): LiveData<Resource<Any?>> { private fun forward(
thread: DirectThread,
itemToForward: DirectItem,
scope: CoroutineScope,
): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val forwardItemId = itemToForward.itemId val forwardItemId = itemToForward.itemId
if (forwardItemId == null) { if (forwardItemId == null) {
@ -707,116 +656,48 @@ class ThreadManager private constructor(
data.postValue(error("threadId is null", null)) data.postValue(error("threadId is null", null))
return data return data
} }
val request = service.forward(thread.threadId, scope.launch(Dispatchers.IO) {
itemTypeName, try {
threadId, service.forward(
forwardItemId) thread.threadId,
request.enqueue(object : Callback<DirectThreadBroadcastResponse?> { itemTypeName,
override fun onResponse( threadId,
call: Call<DirectThreadBroadcastResponse?>, forwardItemId
response: Response<DirectThreadBroadcastResponse?>, )
) { data.postValue(success(Any()))
if (response.isSuccessful) { } catch (e: Exception) {
data.postValue(success(Any())) Log.e(TAG, "forward: ", e)
return data.postValue(error(e.message, null))
}
val errorBody = response.errorBody()
if (errorBody != null) {
try {
val string = errorBody.string()
val msg = String.format(Locale.US,
"onResponse: url: %s, responseCode: %d, errorBody: %s",
call.request().url().toString(),
response.code(),
string)
Log.e(TAG, msg)
data.postValue(error(msg, null))
} catch (e: IOException) {
Log.e(TAG, "onResponse: ", e)
data.postValue(error(e.message, null))
}
return
}
val msg = "onResponse: request was not successful and response error body was null"
Log.e(TAG, msg)
data.postValue(error(msg, null))
} }
}
override fun onFailure(call: Call<DirectThreadBroadcastResponse?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
fun acceptRequest(): LiveData<Resource<Any?>> { fun acceptRequest(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val request = service.approveRequest(threadId) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse( service.approveRequest(threadId)
call: Call<String?>,
response: Response<String?>,
) {
if (!response.isSuccessful) {
try {
val string = response.errorBody()?.string() ?: ""
val msg = String.format(Locale.US,
"onResponse: url: %s, responseCode: %d, errorBody: %s",
call.request().url().toString(),
response.code(),
string)
Log.e(TAG, msg)
data.postValue(error(msg, null))
return
} catch (e: IOException) {
Log.e(TAG, "onResponse: ", e)
}
return
}
data.postValue(success(Any())) data.postValue(success(Any()))
} catch (e: Exception) {
Log.e(TAG, "acceptRequest: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
fun declineRequest(): LiveData<Resource<Any?>> { fun declineRequest(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val request = service.declineRequest(threadId) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse( service.declineRequest(threadId)
call: Call<String?>,
response: Response<String?>,
) {
if (!response.isSuccessful) {
try {
val string = response.errorBody()?.string() ?: ""
val msg = String.format(Locale.US,
"onResponse: url: %s, responseCode: %d, errorBody: %s",
call.request().url().toString(),
response.code(),
string)
Log.e(TAG, msg)
data.postValue(error(msg, null))
return
} catch (e: IOException) {
Log.e(TAG, "onResponse: ", e)
}
return
}
data.postValue(success(Any())) data.postValue(success(Any()))
} catch (e: Exception) {
Log.e(TAG, "declineRequest: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
@ -1105,32 +986,40 @@ class ThreadManager private constructor(
} }
} }
fun updateTitle(newTitle: String): LiveData<Resource<Any?>> { fun updateTitle(newTitle: String, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val addUsersRequest = service.updateTitle(threadId, newTitle.trim { it <= ' ' }) scope.launch(Dispatchers.IO) {
handleDetailsChangeRequest(data, addUsersRequest) try {
val response = service.updateTitle(threadId, newTitle.trim())
handleDetailsChangeResponse(data, response)
} catch (e: Exception) {
}
}
return data return data
} }
fun addMembers(users: Set<User>): LiveData<Resource<Any?>> { fun addMembers(users: Set<User>, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val addUsersRequest = service.addUsers( scope.launch(Dispatchers.IO) {
threadId, try {
users.map { obj: User -> obj.pk } val response = service.addUsers(
) threadId,
handleDetailsChangeRequest(data, addUsersRequest) users.map { obj: User -> obj.pk }
)
handleDetailsChangeResponse(data, response)
} catch (e: Exception) {
Log.e(TAG, "addMembers: ", e)
data.postValue(error(e.message, null))
}
}
return data return data
} }
fun removeMember(user: User): LiveData<Resource<Any?>> { fun removeMember(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val request = service.removeUsers(threadId, setOf(user.pk)) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse(call: Call<String?>, response: Response<String?>) { service.removeUsers(threadId, setOf(user.pk))
if (!response.isSuccessful) {
handleErrorBody(call, response, data)
return
}
data.postValue(success(Any())) data.postValue(success(Any()))
var activeUsers = users.value var activeUsers = users.value
var leftUsersValue = leftUsers.value var leftUsersValue = leftUsers.value
@ -1147,13 +1036,11 @@ class ThreadManager private constructor(
} }
val updatedLeftUsers = updatedLeftUsersBuilder.build() val updatedLeftUsers = updatedLeftUsersBuilder.build()
setThreadUsers(updatedActiveUsers, updatedLeftUsers) setThreadUsers(updatedActiveUsers, updatedLeftUsers)
} catch (e: Exception) {
Log.e(TAG, "removeMember: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
@ -1162,70 +1049,60 @@ class ThreadManager private constructor(
return adminUserIdsValue != null && adminUserIdsValue.contains(user.pk) return adminUserIdsValue != null && adminUserIdsValue.contains(user.pk)
} }
fun makeAdmin(user: User): LiveData<Resource<Any?>> { fun makeAdmin(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
if (isAdmin(user)) return data if (isAdmin(user)) return data
val request = service.addAdmins(threadId, setOf(user.pk)) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse(call: Call<String?>, response: Response<String?>) { service.addAdmins(threadId, setOf(user.pk))
if (!response.isSuccessful) {
handleErrorBody(call, response, data)
return
}
val currentAdminIds = adminUserIds.value val currentAdminIds = adminUserIds.value
val updatedAdminIds = ImmutableList.builder<Long>() val updatedAdminIds = ImmutableList.builder<Long>()
.addAll(currentAdminIds ?: emptyList()) .addAll(currentAdminIds ?: emptyList())
.add(user.pk) .add(user.pk)
.build() .build()
val currentThread = thread.value ?: return val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.adminUserIds = updatedAdminIds thread.adminUserIds = updatedAdminIds
inboxManager.setThread(threadId, thread) inboxManager.setThread(threadId, thread)
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "makeAdmin: ", e)
} }
data.postValue(success(Any()))
} catch (e: Exception) {
Log.e(TAG, "makeAdmin: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
fun removeAdmin(user: User): LiveData<Resource<Any?>> { fun removeAdmin(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
if (!isAdmin(user)) return data if (!isAdmin(user)) return data
val request = service.removeAdmins(threadId, setOf(user.pk)) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse(call: Call<String?>, response: Response<String?>) { service.removeAdmins(threadId, setOf(user.pk))
if (!response.isSuccessful) { val currentAdmins = adminUserIds.value ?: return@launch
handleErrorBody(call, response, data)
return
}
val currentAdmins = adminUserIds.value ?: return
val updatedAdminUserIds = currentAdmins.filter { userId1: Long -> userId1 != user.pk } val updatedAdminUserIds = currentAdmins.filter { userId1: Long -> userId1 != user.pk }
val currentThread = thread.value ?: return val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.adminUserIds = updatedAdminUserIds thread.adminUserIds = updatedAdminUserIds
inboxManager.setThread(threadId, thread) inboxManager.setThread(threadId, thread)
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "removeAdmin: ", e)
} }
data.postValue(success(Any()))
} catch (e: Exception) {
Log.e(TAG, "removeAdmin: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
fun mute(): LiveData<Resource<Any?>> { fun mute(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val muted = isMuted.value val muted = isMuted.value
@ -1233,33 +1110,27 @@ class ThreadManager private constructor(
data.postValue(success(Any())) data.postValue(success(Any()))
return data return data
} }
val request = service.mute(threadId) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse(call: Call<String?>, response: Response<String?>) { service.mute(threadId)
if (!response.isSuccessful) {
handleErrorBody(call, response, data)
return
}
data.postValue(success(Any())) data.postValue(success(Any()))
val currentThread = thread.value ?: return val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.muted = true thread.muted = true
inboxManager.setThread(threadId, thread) inboxManager.setThread(threadId, thread)
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "mute: ", e)
} }
} catch (e: Exception) {
Log.e(TAG, "mute: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
fun unmute(): LiveData<Resource<Any?>> { fun unmute(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val muted = isMuted.value val muted = isMuted.value
@ -1267,33 +1138,27 @@ class ThreadManager private constructor(
data.postValue(success(Any())) data.postValue(success(Any()))
return data return data
} }
val request = service.unmute(threadId) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse(call: Call<String?>, response: Response<String?>) { service.unmute(threadId)
if (!response.isSuccessful) {
handleErrorBody(call, response, data)
return
}
data.postValue(success(Any())) data.postValue(success(Any()))
val currentThread = thread.value ?: return val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.muted = false thread.muted = false
inboxManager.setThread(threadId, thread) inboxManager.setThread(threadId, thread)
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "unmute: ", e)
} }
} catch (e: Exception) {
Log.e(TAG, "unmute: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
fun muteMentions(): LiveData<Resource<Any?>> { fun muteMentions(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val mentionsMuted = isMentionsMuted.value val mentionsMuted = isMentionsMuted.value
@ -1301,33 +1166,27 @@ class ThreadManager private constructor(
data.postValue(success(Any())) data.postValue(success(Any()))
return data return data
} }
val request = service.muteMentions(threadId) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse(call: Call<String?>, response: Response<String?>) { service.muteMentions(threadId)
if (!response.isSuccessful) {
handleErrorBody(call, response, data)
return
}
data.postValue(success(Any())) data.postValue(success(Any()))
val currentThread = thread.value ?: return val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.mentionsMuted = true thread.mentionsMuted = true
inboxManager.setThread(threadId, thread) inboxManager.setThread(threadId, thread)
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "muteMentions: ", e)
} }
} catch (e: Exception) {
Log.e(TAG, "muteMentions: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
fun unmuteMentions(): LiveData<Resource<Any?>> { fun unmuteMentions(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val mentionsMuted = isMentionsMuted.value val mentionsMuted = isMentionsMuted.value
@ -1335,29 +1194,23 @@ class ThreadManager private constructor(
data.postValue(success(Any())) data.postValue(success(Any()))
return data return data
} }
val request = service.unmuteMentions(threadId) scope.launch(Dispatchers.IO) {
request.enqueue(object : Callback<String?> { try {
override fun onResponse(call: Call<String?>, response: Response<String?>) { service.unmuteMentions(threadId)
if (!response.isSuccessful) {
handleErrorBody(call, response, data)
return
}
data.postValue(success(Any())) data.postValue(success(Any()))
val currentThread = thread.value ?: return val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.mentionsMuted = false thread.mentionsMuted = false
inboxManager.setThread(threadId, thread) inboxManager.setThread(threadId, thread)
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "unmuteMentions: ", e)
} }
} catch (e: Exception) {
Log.e(TAG, "unmuteMentions: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(call: Call<String?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
@ -1421,33 +1274,41 @@ class ThreadManager private constructor(
return data return data
} }
fun approveUsers(users: List<User>): LiveData<Resource<Any?>> { fun approveUsers(users: List<User>, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val approveUsersRequest = service.approveParticipantRequests( scope.launch(Dispatchers.IO) {
threadId, try {
users.map { obj: User -> obj.pk } val response = service.approveParticipantRequests(
) threadId,
handleDetailsChangeRequest(data, approveUsersRequest, object : OnSuccessAction { users.map { obj: User -> obj.pk }
override fun onSuccess() { )
handleDetailsChangeResponse(data, response)
pendingUserApproveDenySuccessAction(users) pendingUserApproveDenySuccessAction(users)
} catch (e: Exception) {
Log.e(TAG, "approveUsers: ", e)
data.postValue(error(e.message, null))
} }
}) }
return data return data
} }
fun denyUsers(users: List<User>): LiveData<Resource<Any?>> { fun denyUsers(users: List<User>, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val approveUsersRequest = service.declineParticipantRequests( scope.launch(Dispatchers.IO) {
threadId, try {
users.map { obj: User -> obj.pk } val response = service.declineParticipantRequests(
) threadId,
handleDetailsChangeRequest(data, approveUsersRequest, object : OnSuccessAction { users.map { obj: User -> obj.pk }
override fun onSuccess() { )
handleDetailsChangeResponse(data, response)
pendingUserApproveDenySuccessAction(users) pendingUserApproveDenySuccessAction(users)
} catch (e: Exception) {
Log.e(TAG, "denyUsers: ", e)
data.postValue(error(e.message, null))
} }
}) }
return data return data
} }
@ -1467,7 +1328,7 @@ class ThreadManager private constructor(
} }
} }
fun approvalRequired(): LiveData<Resource<Any?>> { fun approvalRequired(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val approvalRequiredToJoin = isApprovalRequiredToJoin.value val approvalRequiredToJoin = isApprovalRequiredToJoin.value
@ -1475,10 +1336,11 @@ class ThreadManager private constructor(
data.postValue(success(Any())) data.postValue(success(Any()))
return data return data
} }
val request = service.approvalRequired(threadId) scope.launch(Dispatchers.IO) {
handleDetailsChangeRequest(data, request, object : OnSuccessAction { try {
override fun onSuccess() { val response = service.approvalRequired(threadId)
val currentThread = thread.value ?: return handleDetailsChangeResponse(data, response)
val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.approvalRequiredForNewMembers = true thread.approvalRequiredForNewMembers = true
@ -1486,12 +1348,15 @@ class ThreadManager private constructor(
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "onResponse: ", e)
} }
} catch (e: Exception) {
Log.e(TAG, "approvalRequired: ", e)
data.postValue(error(e.message, null))
} }
}) }
return data return data
} }
fun approvalNotRequired(): LiveData<Resource<Any?>> { fun approvalNotRequired(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val approvalRequiredToJoin = isApprovalRequiredToJoin.value val approvalRequiredToJoin = isApprovalRequiredToJoin.value
@ -1499,10 +1364,11 @@ class ThreadManager private constructor(
data.postValue(success(Any())) data.postValue(success(Any()))
return data return data
} }
val request = service.approvalNotRequired(threadId) scope.launch(Dispatchers.IO) {
handleDetailsChangeRequest(data, request, object : OnSuccessAction { try {
override fun onSuccess() { val request = service.approvalNotRequired(threadId)
val currentThread = thread.value ?: return handleDetailsChangeResponse(data, request)
val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.approvalRequiredForNewMembers = false thread.approvalRequiredForNewMembers = false
@ -1510,26 +1376,37 @@ class ThreadManager private constructor(
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "onResponse: ", e)
} }
} catch (e: Exception) {
Log.e(TAG, "approvalNotRequired: ", e)
data.postValue(error(e.message, null))
} }
}) }
return data return data
} }
fun leave(): LiveData<Resource<Any?>> { fun leave(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val request = service.leave(threadId) scope.launch(Dispatchers.IO) {
handleDetailsChangeRequest(data, request) try {
val request = service.leave(threadId)
handleDetailsChangeResponse(data, request)
} catch (e: Exception) {
Log.e(TAG, "leave: ", e)
data.postValue(error(e.message, null))
}
}
return data return data
} }
fun end(): LiveData<Resource<Any?>> { fun end(scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val request = service.end(threadId) scope.launch(Dispatchers.IO) {
handleDetailsChangeRequest(data, request, object : OnSuccessAction { try {
override fun onSuccess() { val request = service.end(threadId)
val currentThread = thread.value ?: return handleDetailsChangeResponse(data, request)
val currentThread = thread.value ?: return@launch
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
thread.inputMode = 1 thread.inputMode = 1
@ -1537,95 +1414,57 @@ class ThreadManager private constructor(
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "onResponse: ", e) Log.e(TAG, "onResponse: ", e)
} }
} catch (e: Exception) {
Log.e(TAG, "leave: ", e)
data.postValue(error(e.message, null))
} }
}) }
return data return data
} }
private fun handleDetailsChangeRequest( private fun handleDetailsChangeResponse(
data: MutableLiveData<Resource<Any?>>, data: MutableLiveData<Resource<Any?>>,
request: Call<DirectThreadDetailsChangeResponse?>, response: DirectThreadDetailsChangeResponse,
action: OnSuccessAction? = null,
) { ) {
request.enqueue(object : Callback<DirectThreadDetailsChangeResponse?> { data.postValue(success(Any()))
override fun onResponse( val thread = response.thread
call: Call<DirectThreadDetailsChangeResponse?>, if (thread != null) {
response: Response<DirectThreadDetailsChangeResponse?>, setThread(thread, true)
) { }
if (!response.isSuccessful) {
handleErrorBody(call, response, data)
return
}
val changeResponse = response.body()
if (changeResponse == null) {
data.postValue(error(R.string.generic_null_response, null))
return
}
data.postValue(success(Any()))
val thread = changeResponse.thread
if (thread != null) {
setThread(thread, true)
}
action?.onSuccess()
}
override fun onFailure(call: Call<DirectThreadDetailsChangeResponse?>, t: Throwable) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
} }
fun markAsSeen(directItem: DirectItem, scope: CoroutineScope): LiveData<Resource<Any?>> { fun markAsSeen(
directItem: DirectItem,
scope: CoroutineScope,
): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null)) data.postValue(loading(null))
val request = service.markAsSeen(threadId, directItem) scope.launch(Dispatchers.IO) {
if (request == null) { try {
data.postValue(error("request was null", null)) val response = service.markAsSeen(threadId, directItem)
return data if (response == null) {
}
request.enqueue(object : Callback<DirectItemSeenResponse?> {
override fun onResponse(
call: Call<DirectItemSeenResponse?>,
response: Response<DirectItemSeenResponse?>,
) {
if (currentUser == null) return
if (!response.isSuccessful) {
handleErrorBody(call, response, data)
return
}
val seenResponse = response.body()
if (seenResponse == null) {
data.postValue(error(R.string.generic_null_response, null)) data.postValue(error(R.string.generic_null_response, null))
return return@launch
} }
if (currentUser == null) return@launch
inboxManager.fetchUnseenCount(scope) inboxManager.fetchUnseenCount(scope)
val payload = seenResponse.payload ?: return val payload = response.payload ?: return@launch
val timestamp = payload.timestamp val timestamp = payload.timestamp
val thread = thread.value ?: return val thread = thread.value ?: return@launch
val currentLastSeenAt = thread.lastSeenAt val currentLastSeenAt = thread.lastSeenAt
val lastSeenAt = if (currentLastSeenAt == null) HashMap() else HashMap(currentLastSeenAt) val lastSeenAt = if (currentLastSeenAt == null) HashMap() else HashMap(currentLastSeenAt)
lastSeenAt[currentUser.pk] = DirectThreadLastSeenAt(timestamp, directItem.itemId) lastSeenAt[currentUser.pk] = DirectThreadLastSeenAt(timestamp, directItem.itemId)
thread.lastSeenAt = lastSeenAt thread.lastSeenAt = lastSeenAt
setThread(thread, true) setThread(thread, true)
data.postValue(success(Any())) data.postValue(success(Any()))
} catch (e: Exception) {
Log.e(TAG, "markAsSeen: ", e)
data.postValue(error(e.message, null))
} }
}
override fun onFailure(
call: Call<DirectItemSeenResponse?>,
t: Throwable,
) {
Log.e(TAG, "onFailure: ", t)
data.postValue(error(t.message, null))
}
})
return data return data
} }
private interface OnSuccessAction {
fun onSuccess()
}
companion object { companion object {
private val TAG = ThreadManager::class.java.simpleName private val TAG = ThreadManager::class.java.simpleName
private val LOCK = Any() private val LOCK = Any()

View File

@ -1,7 +1,6 @@
package awais.instagrabber.repositories package awais.instagrabber.repositories
import awais.instagrabber.repositories.responses.directmessages.* import awais.instagrabber.repositories.responses.directmessages.*
import retrofit2.Call
import retrofit2.http.* import retrofit2.http.*
interface DirectMessagesRepository { interface DirectMessagesRepository {
@ -29,154 +28,154 @@ interface DirectMessagesRepository {
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/add_user/") @POST("/api/v1/direct_v2/threads/{threadId}/add_user/")
fun addUsers( suspend fun addUsers(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectThreadDetailsChangeResponse?> ): DirectThreadDetailsChangeResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/remove_users/") @POST("/api/v1/direct_v2/threads/{threadId}/remove_users/")
fun removeUsers( suspend fun removeUsers(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/update_title/") @POST("/api/v1/direct_v2/threads/{threadId}/update_title/")
fun updateTitle( suspend fun updateTitle(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectThreadDetailsChangeResponse?> ): DirectThreadDetailsChangeResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/add_admins/") @POST("/api/v1/direct_v2/threads/{threadId}/add_admins/")
fun addAdmins( suspend fun addAdmins(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/remove_admins/") @POST("/api/v1/direct_v2/threads/{threadId}/remove_admins/")
fun removeAdmins( suspend fun removeAdmins(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/items/{itemId}/delete/") @POST("/api/v1/direct_v2/threads/{threadId}/items/{itemId}/delete/")
fun deleteItem( suspend fun deleteItem(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@Path("itemId") itemId: String, @Path("itemId") itemId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@GET("/api/v1/direct_v2/ranked_recipients/") @GET("/api/v1/direct_v2/ranked_recipients/")
fun rankedRecipients(@QueryMap queryMap: Map<String, String>): Call<RankedRecipientsResponse?> suspend fun rankedRecipients(@QueryMap queryMap: Map<String, String>): RankedRecipientsResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/broadcast/forward/") @POST("/api/v1/direct_v2/threads/broadcast/forward/")
fun forward(@FieldMap form: Map<String, String>): Call<DirectThreadBroadcastResponse?> suspend fun forward(@FieldMap form: Map<String, String>): DirectThreadBroadcastResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/create_group_thread/") @POST("/api/v1/direct_v2/create_group_thread/")
fun createThread(@FieldMap signedForm: Map<String, String>): Call<DirectThread?> suspend fun createThread(@FieldMap signedForm: Map<String, String>): DirectThread
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/mute/") @POST("/api/v1/direct_v2/threads/{threadId}/mute/")
fun mute( suspend fun mute(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/unmute/") @POST("/api/v1/direct_v2/threads/{threadId}/unmute/")
fun unmute( suspend fun unmute(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/mute_mentions/") @POST("/api/v1/direct_v2/threads/{threadId}/mute_mentions/")
fun muteMentions( suspend fun muteMentions(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String?>, @FieldMap form: Map<String, String?>,
): Call<String?> ): String
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/unmute_mentions/") @POST("/api/v1/direct_v2/threads/{threadId}/unmute_mentions/")
fun unmuteMentions( suspend fun unmuteMentions(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@GET("/api/v1/direct_v2/threads/{threadId}/participant_requests/") @GET("/api/v1/direct_v2/threads/{threadId}/participant_requests/")
fun participantRequests( suspend fun participantRequests(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@Query("page_size") pageSize: Int, @Query("page_size") pageSize: Int,
@Query("cursor") cursor: String?, @Query("cursor") cursor: String?,
): Call<DirectThreadParticipantRequestsResponse?> ): DirectThreadParticipantRequestsResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/approve_participant_requests/") @POST("/api/v1/direct_v2/threads/{threadId}/approve_participant_requests/")
fun approveParticipantRequests( suspend fun approveParticipantRequests(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectThreadDetailsChangeResponse?> ): DirectThreadDetailsChangeResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/deny_participant_requests/") @POST("/api/v1/direct_v2/threads/{threadId}/deny_participant_requests/")
fun declineParticipantRequests( suspend fun declineParticipantRequests(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectThreadDetailsChangeResponse?> ): DirectThreadDetailsChangeResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/approval_required_for_new_members/") @POST("/api/v1/direct_v2/threads/{threadId}/approval_required_for_new_members/")
fun approvalRequired( suspend fun approvalRequired(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectThreadDetailsChangeResponse?> ): DirectThreadDetailsChangeResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/approval_not_required_for_new_members/") @POST("/api/v1/direct_v2/threads/{threadId}/approval_not_required_for_new_members/")
fun approvalNotRequired( suspend fun approvalNotRequired(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectThreadDetailsChangeResponse?> ): DirectThreadDetailsChangeResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/leave/") @POST("/api/v1/direct_v2/threads/{threadId}/leave/")
fun leave( suspend fun leave(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectThreadDetailsChangeResponse?> ): DirectThreadDetailsChangeResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/remove_all_users/") @POST("/api/v1/direct_v2/threads/{threadId}/remove_all_users/")
fun end( suspend fun end(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectThreadDetailsChangeResponse?> ): DirectThreadDetailsChangeResponse
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/approve/") @POST("/api/v1/direct_v2/threads/{threadId}/approve/")
fun approveRequest( suspend fun approveRequest(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/decline/") @POST("/api/v1/direct_v2/threads/{threadId}/decline/")
fun declineRequest( suspend fun declineRequest(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<String?> ): String
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/direct_v2/threads/{threadId}/items/{itemId}/seen/") @POST("/api/v1/direct_v2/threads/{threadId}/items/{itemId}/seen/")
fun markItemSeen( suspend fun markItemSeen(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@Path("itemId") itemId: String, @Path("itemId") itemId: String,
@FieldMap form: Map<String, String>, @FieldMap form: Map<String, String>,
): Call<DirectItemSeenResponse?> ): DirectItemSeenResponse
} }

View File

@ -83,23 +83,23 @@ class DirectSettingsViewModel(
fun isViewerAdmin(): LiveData<Boolean> = threadManager.isViewerAdmin fun isViewerAdmin(): LiveData<Boolean> = threadManager.isViewerAdmin
fun updateTitle(newTitle: String): LiveData<Resource<Any?>> = threadManager.updateTitle(newTitle) fun updateTitle(newTitle: String): LiveData<Resource<Any?>> = threadManager.updateTitle(newTitle, viewModelScope)
fun addMembers(users: Set<User>): LiveData<Resource<Any?>> = threadManager.addMembers(users) fun addMembers(users: Set<User>): LiveData<Resource<Any?>> = threadManager.addMembers(users, viewModelScope)
fun removeMember(user: User): LiveData<Resource<Any?>> = threadManager.removeMember(user) fun removeMember(user: User): LiveData<Resource<Any?>> = threadManager.removeMember(user, viewModelScope)
private fun makeAdmin(user: User): LiveData<Resource<Any?>> = threadManager.makeAdmin(user) private fun makeAdmin(user: User): LiveData<Resource<Any?>> = threadManager.makeAdmin(user, viewModelScope)
private fun removeAdmin(user: User): LiveData<Resource<Any?>> = threadManager.removeAdmin(user) private fun removeAdmin(user: User): LiveData<Resource<Any?>> = threadManager.removeAdmin(user, viewModelScope)
fun mute(): LiveData<Resource<Any?>> = threadManager.mute() fun mute(): LiveData<Resource<Any?>> = threadManager.mute(viewModelScope)
fun unmute(): LiveData<Resource<Any?>> = threadManager.unmute() fun unmute(): LiveData<Resource<Any?>> = threadManager.unmute(viewModelScope)
fun muteMentions(): LiveData<Resource<Any?>> = threadManager.muteMentions() fun muteMentions(): LiveData<Resource<Any?>> = threadManager.muteMentions(viewModelScope)
fun unmuteMentions(): LiveData<Resource<Any?>> = threadManager.unmuteMentions() fun unmuteMentions(): LiveData<Resource<Any?>> = threadManager.unmuteMentions(viewModelScope)
private fun blockUser(user: User): LiveData<Resource<Any?>> = threadManager.blockUser(user, viewModelScope) private fun blockUser(user: User): LiveData<Resource<Any?>> = threadManager.blockUser(user, viewModelScope)
@ -109,17 +109,17 @@ class DirectSettingsViewModel(
private fun unRestrictUser(user: User): LiveData<Resource<Any?>> = threadManager.unRestrictUser(user, viewModelScope) private fun unRestrictUser(user: User): LiveData<Resource<Any?>> = threadManager.unRestrictUser(user, viewModelScope)
fun approveUsers(users: List<User>): LiveData<Resource<Any?>> = threadManager.approveUsers(users) fun approveUsers(users: List<User>): LiveData<Resource<Any?>> = threadManager.approveUsers(users, viewModelScope)
fun denyUsers(users: List<User>): LiveData<Resource<Any?>> = threadManager.denyUsers(users) fun denyUsers(users: List<User>): LiveData<Resource<Any?>> = threadManager.denyUsers(users, viewModelScope)
fun approvalRequired(): LiveData<Resource<Any?>> = threadManager.approvalRequired() fun approvalRequired(): LiveData<Resource<Any?>> = threadManager.approvalRequired(viewModelScope)
fun approvalNotRequired(): LiveData<Resource<Any?>> = threadManager.approvalNotRequired() fun approvalNotRequired(): LiveData<Resource<Any?>> = threadManager.approvalNotRequired(viewModelScope)
fun leave(): LiveData<Resource<Any?>> = threadManager.leave() fun leave(): LiveData<Resource<Any?>> = threadManager.leave(viewModelScope)
fun end(): LiveData<Resource<Any?>> = threadManager.end() fun end(): LiveData<Resource<Any?>> = threadManager.end(viewModelScope)
fun createUserOptions(user: User?): ArrayList<Option<String>> { fun createUserOptions(user: User?): ArrayList<Option<String>> {
val options: ArrayList<Option<String>> = ArrayList() val options: ArrayList<Option<String>> = ArrayList()

View File

@ -144,7 +144,7 @@ class DirectThreadViewModel(
} }
fun unsend(item: DirectItem): LiveData<Resource<Any?>> { fun unsend(item: DirectItem): LiveData<Resource<Any?>> {
return threadManager.unsend(item) return threadManager.unsend(item, viewModelScope)
} }
fun sendAnimatedMedia(giphyGif: GiphyGif): LiveData<Resource<Any?>> { fun sendAnimatedMedia(giphyGif: GiphyGif): LiveData<Resource<Any?>> {
@ -161,11 +161,11 @@ class DirectThreadViewModel(
} }
fun forward(recipients: Set<RankedRecipient>, itemToForward: DirectItem) { fun forward(recipients: Set<RankedRecipient>, itemToForward: DirectItem) {
threadManager.forward(recipients, itemToForward) threadManager.forward(recipients, itemToForward, viewModelScope)
} }
fun forward(recipient: RankedRecipient, itemToForward: DirectItem) { fun forward(recipient: RankedRecipient, itemToForward: DirectItem) {
threadManager.forward(recipient, itemToForward) threadManager.forward(recipient, itemToForward, viewModelScope)
} }
fun setReplyToItem(item: DirectItem?) { fun setReplyToItem(item: DirectItem?) {
@ -174,11 +174,11 @@ class DirectThreadViewModel(
} }
fun acceptRequest(): LiveData<Resource<Any?>> { fun acceptRequest(): LiveData<Resource<Any?>> {
return threadManager.acceptRequest() return threadManager.acceptRequest(viewModelScope)
} }
fun declineRequest(): LiveData<Resource<Any?>> { fun declineRequest(): LiveData<Resource<Any?>> {
return threadManager.declineRequest() return threadManager.declineRequest(viewModelScope)
} }
fun markAsSeen(): LiveData<Resource<Any?>> { fun markAsSeen(): LiveData<Resource<Any?>> {
@ -225,6 +225,6 @@ class DirectThreadViewModel(
val csrfToken = getCsrfTokenFromCookie(cookie) val csrfToken = getCsrfTokenFromCookie(cookie)
require(!csrfToken.isNullOrBlank() && viewerId != 0L && deviceUuid.isNotBlank()) { "User is not logged in!" } require(!csrfToken.isNullOrBlank() && viewerId != 0L && deviceUuid.isNotBlank()) { "User is not logged in!" }
threadManager = DirectMessagesManager.getThreadManager(threadId, pending, currentUser, contentResolver) threadManager = DirectMessagesManager.getThreadManager(threadId, pending, currentUser, contentResolver)
threadManager.fetchPendingRequests() threadManager.fetchPendingRequests(viewModelScope)
} }
} }

View File

@ -26,14 +26,15 @@ import awais.instagrabber.models.Resource;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.UserSearchResponse; import awais.instagrabber.repositories.responses.UserSearchResponse;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipientsResponse;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.utils.Debouncer; import awais.instagrabber.utils.Debouncer;
import awais.instagrabber.utils.RankedRecipientsCache; import awais.instagrabber.utils.RankedRecipientsCache;
import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.webservices.DirectMessagesService; import awais.instagrabber.webservices.DirectMessagesService;
import awais.instagrabber.webservices.UserService; import awais.instagrabber.webservices.UserService;
import kotlinx.coroutines.Dispatchers;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
@ -95,37 +96,23 @@ public class UserSearchViewModel extends ViewModel {
private void updateRankedRecipientCache() { private void updateRankedRecipientCache() {
rankedRecipientsCache.setUpdateInitiated(true); rankedRecipientsCache.setUpdateInitiated(true);
final Call<RankedRecipientsResponse> request = directMessagesService.rankedRecipients(null, null, null); directMessagesService.rankedRecipients(
request.enqueue(new Callback<RankedRecipientsResponse>() { null,
@Override null,
public void onResponse(@NonNull final Call<RankedRecipientsResponse> call, @NonNull final Response<RankedRecipientsResponse> response) { null,
if (!response.isSuccessful()) { CoroutineUtilsKt.getContinuation((response, throwable) -> {
handleErrorResponse(response, false); if (throwable != null) {
rankedRecipientsCache.setFailed(true); Log.e(TAG, "updateRankedRecipientCache: ", throwable);
rankedRecipientsCache.setUpdateInitiated(false);
rankedRecipientsCache.setFailed(true);
continueSearchIfRequired();
return;
}
rankedRecipientsCache.setResponse(response);
rankedRecipientsCache.setUpdateInitiated(false); rankedRecipientsCache.setUpdateInitiated(false);
continueSearchIfRequired(); continueSearchIfRequired();
return; }, Dispatchers.getIO())
} );
if (response.body() == null) {
Log.e(TAG, "onResponse: response body is null");
rankedRecipientsCache.setUpdateInitiated(false);
rankedRecipientsCache.setFailed(true);
continueSearchIfRequired();
return;
}
rankedRecipientsCache.setResponse(response.body());
rankedRecipientsCache.setUpdateInitiated(false);
continueSearchIfRequired();
}
@Override
public void onFailure(@NonNull final Call<RankedRecipientsResponse> call, @NonNull final Throwable t) {
Log.e(TAG, "onFailure: ", t);
rankedRecipientsCache.setUpdateInitiated(false);
rankedRecipientsCache.setFailed(true);
continueSearchIfRequired();
}
});
} }
private void continueSearchIfRequired() { private void continueSearchIfRequired() {
@ -189,39 +176,22 @@ public class UserSearchViewModel extends ViewModel {
} }
private void rankedRecipientSearch() { private void rankedRecipientSearch() {
searchRequest = directMessagesService.rankedRecipients(searchMode.getName(), showGroups, currentQuery); directMessagesService.rankedRecipients(
//noinspection unchecked searchMode.getName(),
handleRankedRecipientRequest((Call<RankedRecipientsResponse>) searchRequest); showGroups,
} currentQuery,
CoroutineUtilsKt.getContinuation((response, throwable) -> {
if (throwable != null) {
private void handleRankedRecipientRequest(@NonNull final Call<RankedRecipientsResponse> request) { Log.e(TAG, "rankedRecipientSearch: ", throwable);
request.enqueue(new Callback<RankedRecipientsResponse>() { recipients.postValue(Resource.error(throwable.getMessage(), getCachedRecipients()));
@Override return;
public void onResponse(@NonNull final Call<RankedRecipientsResponse> call, @NonNull final Response<RankedRecipientsResponse> response) { }
if (!response.isSuccessful()) { final List<RankedRecipient> list = response.getRankedRecipients();
handleErrorResponse(response, true); if (list != null) {
searchRequest = null; recipients.postValue(Resource.success(mergeResponseWithCache(list)));
return; }
} }, Dispatchers.getIO())
final RankedRecipientsResponse rankedRecipientsResponse = response.body(); );
if (rankedRecipientsResponse == null) {
recipients.postValue(Resource.error(R.string.generic_null_response, getCachedRecipients()));
searchRequest = null;
return;
}
final List<RankedRecipient> list = rankedRecipientsResponse.getRankedRecipients();
recipients.postValue(Resource.success(mergeResponseWithCache(list)));
searchRequest = null;
}
@Override
public void onFailure(@NonNull final Call<RankedRecipientsResponse> call, @NonNull final Throwable t) {
Log.e(TAG, "onFailure: ", t);
recipients.postValue(Resource.error(t.getMessage(), getCachedRecipients()));
searchRequest = null;
}
});
} }
private void handleRequest(@NonNull final Call<UserSearchResponse> request) { private void handleRequest(@NonNull final Call<UserSearchResponse> request) {

View File

@ -8,7 +8,6 @@ import awais.instagrabber.utils.TextUtils.extractUrls
import awais.instagrabber.utils.TextUtils.isEmpty import awais.instagrabber.utils.TextUtils.isEmpty
import awais.instagrabber.utils.Utils import awais.instagrabber.utils.Utils
import org.json.JSONArray import org.json.JSONArray
import retrofit2.Call
import java.util.* import java.util.*
class DirectMessagesService private constructor( class DirectMessagesService private constructor(
@ -183,10 +182,10 @@ class DirectMessagesService private constructor(
return repository.broadcast(broadcastOptions.itemType.value, signedForm) return repository.broadcast(broadcastOptions.itemType.value, signedForm)
} }
fun addUsers( suspend fun addUsers(
threadId: String, threadId: String,
userIds: Collection<Long>, userIds: Collection<Long>,
): Call<DirectThreadDetailsChangeResponse?> { ): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -195,10 +194,10 @@ class DirectMessagesService private constructor(
return repository.addUsers(threadId, form) return repository.addUsers(threadId, form)
} }
fun removeUsers( suspend fun removeUsers(
threadId: String, threadId: String,
userIds: Collection<Long>, userIds: Collection<Long>,
): Call<String?> { ): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -207,10 +206,10 @@ class DirectMessagesService private constructor(
return repository.removeUsers(threadId, form) return repository.removeUsers(threadId, form)
} }
fun updateTitle( suspend fun updateTitle(
threadId: String, threadId: String,
title: String, title: String,
): Call<DirectThreadDetailsChangeResponse?> { ): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -219,10 +218,10 @@ class DirectMessagesService private constructor(
return repository.updateTitle(threadId, form) return repository.updateTitle(threadId, form)
} }
fun addAdmins( suspend fun addAdmins(
threadId: String, threadId: String,
userIds: Collection<Long>, userIds: Collection<Long>,
): Call<String?> { ): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -231,10 +230,10 @@ class DirectMessagesService private constructor(
return repository.addAdmins(threadId, form) return repository.addAdmins(threadId, form)
} }
fun removeAdmins( suspend fun removeAdmins(
threadId: String, threadId: String,
userIds: Collection<Long>, userIds: Collection<Long>,
): Call<String?> { ): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -243,10 +242,10 @@ class DirectMessagesService private constructor(
return repository.removeAdmins(threadId, form) return repository.removeAdmins(threadId, form)
} }
fun deleteItem( suspend fun deleteItem(
threadId: String, threadId: String,
itemId: String, itemId: String,
): Call<String?> { ): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -254,11 +253,11 @@ class DirectMessagesService private constructor(
return repository.deleteItem(threadId, itemId, form) return repository.deleteItem(threadId, itemId, form)
} }
fun rankedRecipients( suspend fun rankedRecipients(
mode: String?, mode: String?,
showThreads: Boolean?, showThreads: Boolean?,
query: String?, query: String?,
): Call<RankedRecipientsResponse?> { ): RankedRecipientsResponse {
// String correctedMode = mode; // String correctedMode = mode;
// if (TextUtils.isEmpty(mode) || (!mode.equals("raven") && !mode.equals("reshare"))) { // if (TextUtils.isEmpty(mode) || (!mode.equals("raven") && !mode.equals("reshare"))) {
// correctedMode = "raven"; // correctedMode = "raven";
@ -276,12 +275,12 @@ class DirectMessagesService private constructor(
return repository.rankedRecipients(queryMap) return repository.rankedRecipients(queryMap)
} }
fun forward( suspend fun forward(
toThreadId: String, toThreadId: String,
itemType: String, itemType: String,
fromThreadId: String, fromThreadId: String,
itemId: String, itemId: String,
): Call<DirectThreadBroadcastResponse?> { ): DirectThreadBroadcastResponse {
val form = mapOf( val form = mapOf(
"action" to "forward_item", "action" to "forward_item",
"thread_id" to toThreadId, "thread_id" to toThreadId,
@ -292,10 +291,10 @@ class DirectMessagesService private constructor(
return repository.forward(form) return repository.forward(form)
} }
fun createThread( suspend fun createThread(
userIds: List<Long>, userIds: List<Long>,
threadTitle: String?, threadTitle: String?,
): Call<DirectThread?> { ): DirectThread {
val userIdStringList = userIds.map { it.toString() } val userIdStringList = userIds.map { it.toString() }
val form = mutableMapOf<String, Any>( val form = mutableMapOf<String, Any>(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
@ -310,7 +309,7 @@ class DirectMessagesService private constructor(
return repository.createThread(signedForm) return repository.createThread(signedForm)
} }
fun mute(threadId: String): Call<String?> { suspend fun mute(threadId: String): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid "_uuid" to deviceUuid
@ -318,7 +317,7 @@ class DirectMessagesService private constructor(
return repository.mute(threadId, form) return repository.mute(threadId, form)
} }
fun unmute(threadId: String): Call<String?> { suspend fun unmute(threadId: String): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -326,7 +325,7 @@ class DirectMessagesService private constructor(
return repository.unmute(threadId, form) return repository.unmute(threadId, form)
} }
fun muteMentions(threadId: String): Call<String?> { suspend fun muteMentions(threadId: String): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -334,7 +333,7 @@ class DirectMessagesService private constructor(
return repository.muteMentions(threadId, form) return repository.muteMentions(threadId, form)
} }
fun unmuteMentions(threadId: String): Call<String?> { suspend fun unmuteMentions(threadId: String): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -342,18 +341,18 @@ class DirectMessagesService private constructor(
return repository.unmuteMentions(threadId, form) return repository.unmuteMentions(threadId, form)
} }
fun participantRequests( suspend fun participantRequests(
threadId: String, threadId: String,
pageSize: Int, pageSize: Int,
cursor: String?, cursor: String? = null,
): Call<DirectThreadParticipantRequestsResponse?> { ): DirectThreadParticipantRequestsResponse {
return repository.participantRequests(threadId, pageSize, cursor) return repository.participantRequests(threadId, pageSize, cursor)
} }
fun approveParticipantRequests( suspend fun approveParticipantRequests(
threadId: String, threadId: String,
userIds: List<Long>, userIds: List<Long>,
): Call<DirectThreadDetailsChangeResponse?> { ): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -363,10 +362,10 @@ class DirectMessagesService private constructor(
return repository.approveParticipantRequests(threadId, form) return repository.approveParticipantRequests(threadId, form)
} }
fun declineParticipantRequests( suspend fun declineParticipantRequests(
threadId: String, threadId: String,
userIds: List<Long>, userIds: List<Long>,
): Call<DirectThreadDetailsChangeResponse?> { ): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -375,7 +374,7 @@ class DirectMessagesService private constructor(
return repository.declineParticipantRequests(threadId, form) return repository.declineParticipantRequests(threadId, form)
} }
fun approvalRequired(threadId: String): Call<DirectThreadDetailsChangeResponse?> { suspend fun approvalRequired(threadId: String): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -383,7 +382,7 @@ class DirectMessagesService private constructor(
return repository.approvalRequired(threadId, form) return repository.approvalRequired(threadId, form)
} }
fun approvalNotRequired(threadId: String): Call<DirectThreadDetailsChangeResponse?> { suspend fun approvalNotRequired(threadId: String): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -391,7 +390,7 @@ class DirectMessagesService private constructor(
return repository.approvalNotRequired(threadId, form) return repository.approvalNotRequired(threadId, form)
} }
fun leave(threadId: String): Call<DirectThreadDetailsChangeResponse?> { suspend fun leave(threadId: String): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -399,7 +398,7 @@ class DirectMessagesService private constructor(
return repository.leave(threadId, form) return repository.leave(threadId, form)
} }
fun end(threadId: String): Call<DirectThreadDetailsChangeResponse?> { suspend fun end(threadId: String): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -424,7 +423,7 @@ class DirectMessagesService private constructor(
return repository.fetchPendingInbox(queryMap) return repository.fetchPendingInbox(queryMap)
} }
fun approveRequest(threadId: String): Call<String?> { suspend fun approveRequest(threadId: String): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -432,7 +431,7 @@ class DirectMessagesService private constructor(
return repository.approveRequest(threadId, form) return repository.approveRequest(threadId, form)
} }
fun declineRequest(threadId: String): Call<String?> { suspend fun declineRequest(threadId: String): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -440,10 +439,10 @@ class DirectMessagesService private constructor(
return repository.declineRequest(threadId, form) return repository.declineRequest(threadId, form)
} }
fun markAsSeen( suspend fun markAsSeen(
threadId: String, threadId: String,
directItem: DirectItem, directItem: DirectItem,
): Call<DirectItemSeenResponse?>? { ): DirectItemSeenResponse? {
val itemId = directItem.itemId ?: return null val itemId = directItem.itemId ?: return null
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,