Migrate DirectMessagesService to object

This commit is contained in:
Ammar Githam 2021-06-06 20:11:36 +09:00
parent cae457aa9a
commit 6b499e3dfc
7 changed files with 223 additions and 169 deletions

View File

@ -164,7 +164,7 @@ public class StoryViewerFragment extends Fragment {
fragmentActivity = (AppCompatActivity) requireActivity(); fragmentActivity = (AppCompatActivity) requireActivity();
storiesService = StoriesService.INSTANCE; storiesService = StoriesService.INSTANCE;
mediaService = MediaService.INSTANCE; mediaService = MediaService.INSTANCE;
directMessagesService = DirectMessagesService.getInstance(csrfToken, userId, deviceId); directMessagesService = DirectMessagesService.INSTANCE;
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@ -222,6 +222,9 @@ public class StoryViewerFragment extends Fragment {
.setTitle(R.string.reply_story) .setTitle(R.string.reply_story)
.setView(input) .setView(input)
.setPositiveButton(R.string.confirm, (d, w) -> directMessagesService.createThread( .setPositiveButton(R.string.confirm, (d, w) -> directMessagesService.createThread(
csrfToken,
userId,
deviceId,
Collections.singletonList(currentStory.getUserId()), Collections.singletonList(currentStory.getUserId()),
null, null,
CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
@ -231,6 +234,9 @@ public class StoryViewerFragment extends Fragment {
return; return;
} }
directMessagesService.broadcastStoryReply( directMessagesService.broadcastStoryReply(
csrfToken,
userId,
deviceId,
ThreadIdOrUserIds.of(thread.getThreadId()), ThreadIdOrUserIds.of(thread.getThreadId()),
input.getText().toString(), input.getText().toString(),
currentStory.getStoryMediaId(), currentStory.getStoryMediaId(),

View File

@ -335,7 +335,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
fragmentActivity = (MainActivity) requireActivity(); fragmentActivity = (MainActivity) requireActivity();
friendshipService = isLoggedIn ? FriendshipService.INSTANCE : null; friendshipService = isLoggedIn ? FriendshipService.INSTANCE : null;
directMessagesService = isLoggedIn ? DirectMessagesService.getInstance(csrfToken, myId, deviceUuid) : null; directMessagesService = isLoggedIn ? DirectMessagesService.INSTANCE : null;
storiesService = isLoggedIn ? StoriesService.INSTANCE : null; storiesService = isLoggedIn ? StoriesService.INSTANCE : null;
mediaService = isLoggedIn ? MediaService.INSTANCE : null; mediaService = isLoggedIn ? MediaService.INSTANCE : null;
userService = isLoggedIn ? UserService.INSTANCE : null; userService = isLoggedIn ? UserService.INSTANCE : null;
@ -1146,6 +1146,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
profileDetailsBinding.btnDM.setOnClickListener(v -> { profileDetailsBinding.btnDM.setOnClickListener(v -> {
profileDetailsBinding.btnDM.setEnabled(false); profileDetailsBinding.btnDM.setEnabled(false);
directMessagesService.createThread( directMessagesService.createThread(
csrfToken,
myId,
deviceUuid,
Collections.singletonList(profileModel.getPk()), Collections.singletonList(profileModel.getPk()),
null, null,
CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {

View File

@ -4,7 +4,6 @@ import android.content.ContentResolver
import android.util.Log import android.util.Log
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import awais.instagrabber.managers.ThreadManager.Companion.getInstance
import awais.instagrabber.models.Resource import awais.instagrabber.models.Resource
import awais.instagrabber.models.Resource.Companion.error import awais.instagrabber.models.Resource.Companion.error
import awais.instagrabber.models.Resource.Companion.loading import awais.instagrabber.models.Resource.Companion.loading
@ -18,21 +17,19 @@ import awais.instagrabber.utils.Utils
import awais.instagrabber.utils.getCsrfTokenFromCookie import awais.instagrabber.utils.getCsrfTokenFromCookie
import awais.instagrabber.utils.getUserIdFromCookie import awais.instagrabber.utils.getUserIdFromCookie
import awais.instagrabber.webservices.DirectMessagesService import awais.instagrabber.webservices.DirectMessagesService
import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance
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 java.util.* import java.util.*
object DirectMessagesManager { object DirectMessagesManager {
val inboxManager: InboxManager by lazy { InboxManager.getInstance(false) } val inboxManager: InboxManager by lazy { InboxManager(false) }
val pendingInboxManager: InboxManager by lazy { InboxManager.getInstance(true) } val pendingInboxManager: InboxManager by lazy { InboxManager(true) }
private val TAG = DirectMessagesManager::class.java.simpleName private val TAG = DirectMessagesManager::class.java.simpleName
private val viewerId: Long private val viewerId: Long
private val deviceUuid: String private val deviceUuid: String
private val csrfToken: String private val csrfToken: String
private val service: DirectMessagesService
fun moveThreadFromPending(threadId: String) { fun moveThreadFromPending(threadId: String) {
val pendingThreads = pendingInboxManager.threads.value ?: return val pendingThreads = pendingInboxManager.threads.value ?: return
@ -65,10 +62,10 @@ object DirectMessagesManager {
currentUser: User, currentUser: User,
contentResolver: ContentResolver, contentResolver: ContentResolver,
): ThreadManager { ): ThreadManager {
return getInstance(threadId, pending, currentUser, contentResolver, viewerId, csrfToken, deviceUuid) return ThreadManager(threadId, pending, currentUser, contentResolver, viewerId, csrfToken, deviceUuid)
} }
suspend fun createThread(userPk: Long): DirectThread = service.createThread(listOf(userPk), null) suspend fun createThread(userPk: Long): DirectThread = DirectMessagesService.createThread(csrfToken, viewerId, deviceUuid, listOf(userPk), null)
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)
@ -134,7 +131,10 @@ object DirectMessagesManager {
data.postValue(loading(null)) data.postValue(loading(null))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.broadcastMediaShare( DirectMessagesService.broadcastMediaShare(
csrfToken,
viewerId,
deviceUuid,
UUID.randomUUID().toString(), UUID.randomUUID().toString(),
of(threadId), of(threadId),
mediaId mediaId
@ -157,6 +157,5 @@ object DirectMessagesManager {
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!" }
this.csrfToken = csrfToken this.csrfToken = csrfToken
service = getInstance(csrfToken, viewerId, deviceUuid)
} }
} }

View File

@ -12,8 +12,8 @@ import awais.instagrabber.models.Resource.Companion.success
import awais.instagrabber.repositories.responses.User import awais.instagrabber.repositories.responses.User
import awais.instagrabber.repositories.responses.directmessages.* import awais.instagrabber.repositories.responses.directmessages.*
import awais.instagrabber.utils.* import awais.instagrabber.utils.*
import awais.instagrabber.utils.extensions.TAG
import awais.instagrabber.webservices.DirectMessagesService import awais.instagrabber.webservices.DirectMessagesService
import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance
import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader import com.google.common.cache.CacheLoader
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
@ -24,14 +24,13 @@ import retrofit2.Call
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class InboxManager private constructor(private val pending: Boolean) { class InboxManager(private val pending: Boolean) {
// private val fetchInboxControlledRunner: ControlledRunner<Resource<DirectInbox>> = ControlledRunner() // private val fetchInboxControlledRunner: ControlledRunner<Resource<DirectInbox>> = ControlledRunner()
// private val fetchPendingInboxControlledRunner: ControlledRunner<Resource<DirectInbox>> = ControlledRunner() // private val fetchPendingInboxControlledRunner: ControlledRunner<Resource<DirectInbox>> = ControlledRunner()
private val inbox = MutableLiveData<Resource<DirectInbox?>>(success(null)) private val inbox = MutableLiveData<Resource<DirectInbox?>>(success(null))
private val unseenCount = MutableLiveData<Resource<Int?>>() private val unseenCount = MutableLiveData<Resource<Int?>>()
private val pendingRequestsTotal = MutableLiveData(0) private val pendingRequestsTotal = MutableLiveData(0)
val threads: LiveData<List<DirectThread>> val threads: LiveData<List<DirectThread>>
private val service: DirectMessagesService
private var inboxRequest: Call<DirectInboxResponse?>? = null private var inboxRequest: Call<DirectInboxResponse?>? = null
private var unseenCountRequest: Call<DirectBadgeCount?>? = null private var unseenCountRequest: Call<DirectBadgeCount?>? = null
private var seqId: Long = 0 private var seqId: Long = 0
@ -58,7 +57,11 @@ class InboxManager private constructor(private val pending: Boolean) {
inbox.postValue(loading(currentDirectInbox)) inbox.postValue(loading(currentDirectInbox))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val inboxValue = if (pending) service.fetchPendingInbox(cursor, seqId) else service.fetchInbox(cursor, seqId) val inboxValue = if (pending) {
DirectMessagesService.fetchPendingInbox(cursor, seqId)
} else {
DirectMessagesService.fetchInbox(cursor, seqId)
}
parseInboxResponse(inboxValue) parseInboxResponse(inboxValue)
} catch (e: Exception) { } catch (e: Exception) {
inbox.postValue(error(e.message, currentDirectInbox)) inbox.postValue(error(e.message, currentDirectInbox))
@ -74,7 +77,7 @@ class InboxManager private constructor(private val pending: Boolean) {
unseenCount.postValue(loading(currentUnseenCount)) unseenCount.postValue(loading(currentUnseenCount))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val directBadgeCount = service.fetchUnseenCount() val directBadgeCount = DirectMessagesService.fetchUnseenCount()
unseenCount.postValue(success(directBadgeCount.badgeCount)) unseenCount.postValue(success(directBadgeCount.badgeCount))
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed fetching unseen count", e) Log.e(TAG, "Failed fetching unseen count", e)
@ -286,7 +289,6 @@ class InboxManager private constructor(private val pending: Boolean) {
} }
companion object { companion object {
private val TAG = InboxManager::class.java.simpleName
private val THREAD_LOCKS = CacheBuilder private val THREAD_LOCKS = CacheBuilder
.newBuilder() .newBuilder()
.expireAfterAccess(1, TimeUnit.MINUTES) // max lock time ever expected .expireAfterAccess(1, TimeUnit.MINUTES) // max lock time ever expected
@ -299,10 +301,6 @@ class InboxManager private constructor(private val pending: Boolean) {
if (t2FirstDirectItem == null) return@Comparator -1 if (t2FirstDirectItem == null) return@Comparator -1
t2FirstDirectItem.getTimestamp().compareTo(t1FirstDirectItem.getTimestamp()) t2FirstDirectItem.getTimestamp().compareTo(t1FirstDirectItem.getTimestamp())
} }
fun getInstance(pending: Boolean): InboxManager {
return InboxManager(pending)
}
} }
init { init {
@ -311,7 +309,6 @@ class InboxManager private constructor(private val pending: Boolean) {
val deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID) val deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
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!" }
service = getInstance(csrfToken, viewerId, deviceUuid)
// Transformations // Transformations
threads = Transformations.distinctUntilChanged(Transformations.map(inbox) { inboxResource: Resource<DirectInbox?> -> threads = Transformations.distinctUntilChanged(Transformations.map(inbox) { inboxResource: Resource<DirectInbox?> ->

View File

@ -29,6 +29,7 @@ import awais.instagrabber.utils.MediaUploader.uploadVideo
import awais.instagrabber.utils.MediaUtils.OnInfoLoadListener import awais.instagrabber.utils.MediaUtils.OnInfoLoadListener
import awais.instagrabber.utils.MediaUtils.VideoInfo import awais.instagrabber.utils.MediaUtils.VideoInfo
import awais.instagrabber.utils.TextUtils.isEmpty import awais.instagrabber.utils.TextUtils.isEmpty
import awais.instagrabber.utils.extensions.TAG
import awais.instagrabber.webservices.DirectMessagesService import awais.instagrabber.webservices.DirectMessagesService
import awais.instagrabber.webservices.FriendshipService import awais.instagrabber.webservices.FriendshipService
import awais.instagrabber.webservices.MediaService import awais.instagrabber.webservices.MediaService
@ -42,15 +43,14 @@ import java.io.File
import java.io.IOException import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.stream.Collectors import java.util.stream.Collectors
class ThreadManager private constructor( class ThreadManager(
private val threadId: String, private val threadId: String,
pending: Boolean, pending: Boolean,
currentUser: User, private val currentUser: User?,
contentResolver: ContentResolver, private val contentResolver: ContentResolver,
viewerId: Long, private val viewerId: Long,
private val csrfToken: String, private val csrfToken: String,
private val deviceUuid: String, private val deviceUuid: String,
) { ) {
@ -61,11 +61,7 @@ class ThreadManager private constructor(
private val _pendingRequests = MutableLiveData<DirectThreadParticipantRequestsResponse?>(null) private val _pendingRequests = MutableLiveData<DirectThreadParticipantRequestsResponse?>(null)
val pendingRequests: LiveData<DirectThreadParticipantRequestsResponse?> = _pendingRequests val pendingRequests: LiveData<DirectThreadParticipantRequestsResponse?> = _pendingRequests
private val inboxManager: InboxManager = if (pending) DirectMessagesManager.pendingInboxManager else DirectMessagesManager.inboxManager private val inboxManager: InboxManager = if (pending) DirectMessagesManager.pendingInboxManager else DirectMessagesManager.inboxManager
private val viewerId: Long
private val threadIdOrUserIds: ThreadIdOrUserIds = of(threadId) private val threadIdOrUserIds: ThreadIdOrUserIds = of(threadId)
private val currentUser: User?
private val contentResolver: ContentResolver
private val service: DirectMessagesService
val thread: LiveData<DirectThread?> by lazy { val thread: LiveData<DirectThread?> by lazy {
distinctUntilChanged(map(inboxManager.getInbox()) { inboxResource: Resource<DirectInbox?>? -> distinctUntilChanged(map(inboxManager.getInbox()) { inboxResource: Resource<DirectInbox?>? ->
@ -130,7 +126,7 @@ class ThreadManager private constructor(
_fetching.postValue(loading(null)) _fetching.postValue(loading(null))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val threadFeedResponse = service.fetchThread(threadId, cursor) val threadFeedResponse = DirectMessagesService.fetchThread(threadId, cursor)
if (threadFeedResponse.status != null && threadFeedResponse.status != "ok") { if (threadFeedResponse.status != null && threadFeedResponse.status != "ok") {
_fetching.postValue(error(R.string.generic_not_ok_response, null)) _fetching.postValue(error(R.string.generic_not_ok_response, null))
return@launch return@launch
@ -158,7 +154,7 @@ class ThreadManager private constructor(
if (isGroup == null || !isGroup) return if (isGroup == null || !isGroup) return
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val response = service.participantRequests(threadId, 1) val response = DirectMessagesService.participantRequests(threadId, 1)
_pendingRequests.postValue(response) _pendingRequests.postValue(response)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "fetchPendingRequests: ", e) Log.e(TAG, "fetchPendingRequests: ", e)
@ -350,7 +346,10 @@ class ThreadManager private constructor(
val repliedToClientContext = replyToItemValue?.clientContext val repliedToClientContext = replyToItemValue?.clientContext
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val response = service.broadcastText( val response = DirectMessagesService.broadcastText(
csrfToken,
viewerId,
deviceUuid,
clientContext, clientContext,
threadIdOrUserIds, threadIdOrUserIds,
text, text,
@ -405,7 +404,10 @@ class ThreadManager private constructor(
data.postValue(loading(directItem)) data.postValue(loading(directItem))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val request = service.broadcastAnimatedMedia( val request = DirectMessagesService.broadcastAnimatedMedia(
csrfToken,
userId,
deviceUuid,
clientContext, clientContext,
threadIdOrUserIds, threadIdOrUserIds,
giphyGif giphyGif
@ -451,7 +453,10 @@ class ThreadManager private constructor(
null null
) )
MediaService.uploadFinish(csrfToken, userId, deviceUuid, uploadFinishOptions) MediaService.uploadFinish(csrfToken, userId, deviceUuid, uploadFinishOptions)
val broadcastResponse = service.broadcastVoice( val broadcastResponse = DirectMessagesService.broadcastVoice(
csrfToken,
viewerId,
deviceUuid,
clientContext, clientContext,
threadIdOrUserIds, threadIdOrUserIds,
uploadDmVoiceOptions.uploadId, uploadDmVoiceOptions.uploadId,
@ -492,7 +497,10 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.broadcastReaction( DirectMessagesService.broadcastReaction(
csrfToken,
userId,
deviceUuid,
clientContext, clientContext,
threadIdOrUserIds, threadIdOrUserIds,
itemId, itemId,
@ -529,7 +537,16 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.broadcastReaction(clientContext, threadIdOrUserIds, itemId1, null, true) DirectMessagesService.broadcastReaction(
csrfToken,
viewerId,
deviceUuid,
clientContext,
threadIdOrUserIds,
itemId1,
null,
true
)
} catch (e: Exception) { } catch (e: Exception) {
data.postValue(error(e.message, null)) data.postValue(error(e.message, null))
Log.e(TAG, "sendDeleteReaction: ", e) Log.e(TAG, "sendDeleteReaction: ", e)
@ -548,7 +565,7 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.deleteItem(threadId, itemId) DirectMessagesService.deleteItem(csrfToken, deviceUuid, threadId, itemId)
} catch (e: Exception) { } catch (e: Exception) {
// add the item back if unsuccessful // add the item back if unsuccessful
addItems(index, listOf(item)) addItems(index, listOf(item))
@ -624,7 +641,7 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.forward( DirectMessagesService.forward(
thread.threadId, thread.threadId,
itemTypeName, itemTypeName,
threadId, threadId,
@ -643,7 +660,7 @@ class ThreadManager private constructor(
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.approveRequest(threadId) DirectMessagesService.approveRequest(csrfToken, deviceUuid, threadId)
data.postValue(success(Any())) data.postValue(success(Any()))
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "acceptRequest: ", e) Log.e(TAG, "acceptRequest: ", e)
@ -657,7 +674,7 @@ class ThreadManager private constructor(
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.declineRequest(threadId) DirectMessagesService.declineRequest(csrfToken, deviceUuid, threadId)
data.postValue(success(Any())) data.postValue(success(Any()))
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "declineRequest: ", e) Log.e(TAG, "declineRequest: ", e)
@ -702,9 +719,8 @@ class ThreadManager private constructor(
height: Int, height: Int,
scope: CoroutineScope, scope: CoroutineScope,
) { ) {
val userId = getCurrentUserId(data) ?: return
val clientContext = UUID.randomUUID().toString() val clientContext = UUID.randomUUID().toString()
val directItem = createImageOrVideo(userId, clientContext, uri, width, height, false) val directItem = createImageOrVideo(viewerId, clientContext, uri, width, height, false)
directItem.isPending = true directItem.isPending = true
addItems(0, listOf(directItem)) addItems(0, listOf(directItem))
data.postValue(loading(directItem)) data.postValue(loading(directItem))
@ -714,7 +730,7 @@ class ThreadManager private constructor(
if (handleInvalidResponse(data, response)) return@launch if (handleInvalidResponse(data, response)) return@launch
val response1 = response.response ?: return@launch val response1 = response.response ?: return@launch
val uploadId = response1.optString("upload_id") val uploadId = response1.optString("upload_id")
val response2 = service.broadcastPhoto(clientContext, threadIdOrUserIds, uploadId) val response2 = DirectMessagesService.broadcastPhoto(csrfToken, viewerId, deviceUuid, clientContext, threadIdOrUserIds, uploadId)
parseResponse(response2, data, directItem) parseResponse(response2, data, directItem)
} catch (e: Exception) { } catch (e: Exception) {
data.postValue(error(e.message, null)) data.postValue(error(e.message, null))
@ -775,7 +791,10 @@ class ThreadManager private constructor(
VideoOptions(duration / 1000f, emptyList(), 0, false) VideoOptions(duration / 1000f, emptyList(), 0, false)
) )
MediaService.uploadFinish(csrfToken, userId, deviceUuid, uploadFinishOptions) MediaService.uploadFinish(csrfToken, userId, deviceUuid, uploadFinishOptions)
val broadcastResponse = service.broadcastVideo( val broadcastResponse = DirectMessagesService.broadcastVideo(
csrfToken,
viewerId,
deviceUuid,
clientContext, clientContext,
threadIdOrUserIds, threadIdOrUserIds,
uploadDmVideoOptions.uploadId, uploadDmVideoOptions.uploadId,
@ -902,7 +921,7 @@ class ThreadManager private constructor(
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val response = service.updateTitle(threadId, newTitle.trim()) val response = DirectMessagesService.updateTitle(csrfToken, deviceUuid, threadId, newTitle.trim())
handleDetailsChangeResponse(data, response) handleDetailsChangeResponse(data, response)
} catch (e: Exception) { } catch (e: Exception) {
} }
@ -914,7 +933,9 @@ class ThreadManager private constructor(
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val response = service.addUsers( val response = DirectMessagesService.addUsers(
csrfToken,
deviceUuid,
threadId, threadId,
users.map { obj: User -> obj.pk } users.map { obj: User -> obj.pk }
) )
@ -931,7 +952,7 @@ class ThreadManager private constructor(
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.removeUsers(threadId, setOf(user.pk)) DirectMessagesService.removeUsers(csrfToken, deviceUuid, threadId, setOf(user.pk))
data.postValue(success(Any())) data.postValue(success(Any()))
var activeUsers = users.value var activeUsers = users.value
var leftUsersValue = leftUsers.value var leftUsersValue = leftUsers.value
@ -966,7 +987,7 @@ class ThreadManager private constructor(
if (isAdmin(user)) return data if (isAdmin(user)) return data
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.addAdmins(threadId, setOf(user.pk)) DirectMessagesService.addAdmins(csrfToken, deviceUuid, threadId, setOf(user.pk))
val currentAdminIds = adminUserIds.value val currentAdminIds = adminUserIds.value
val updatedAdminIds = ImmutableList.builder<Long>() val updatedAdminIds = ImmutableList.builder<Long>()
.addAll(currentAdminIds ?: emptyList()) .addAll(currentAdminIds ?: emptyList())
@ -994,7 +1015,7 @@ class ThreadManager private constructor(
if (!isAdmin(user)) return data if (!isAdmin(user)) return data
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.removeAdmins(threadId, setOf(user.pk)) DirectMessagesService.removeAdmins(csrfToken, deviceUuid, threadId, setOf(user.pk))
val currentAdmins = adminUserIds.value ?: return@launch val currentAdmins = adminUserIds.value ?: return@launch
val updatedAdminUserIds = currentAdmins.filter { userId1: Long -> userId1 != user.pk } val updatedAdminUserIds = currentAdmins.filter { userId1: Long -> userId1 != user.pk }
val currentThread = thread.value ?: return@launch val currentThread = thread.value ?: return@launch
@ -1024,7 +1045,7 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.mute(threadId) DirectMessagesService.mute(csrfToken, deviceUuid, threadId)
data.postValue(success(Any())) data.postValue(success(Any()))
val currentThread = thread.value ?: return@launch val currentThread = thread.value ?: return@launch
try { try {
@ -1052,7 +1073,7 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.unmute(threadId) DirectMessagesService.unmute(csrfToken, deviceUuid, threadId)
data.postValue(success(Any())) data.postValue(success(Any()))
val currentThread = thread.value ?: return@launch val currentThread = thread.value ?: return@launch
try { try {
@ -1080,7 +1101,7 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.muteMentions(threadId) DirectMessagesService.muteMentions(csrfToken, deviceUuid, threadId)
data.postValue(success(Any())) data.postValue(success(Any()))
val currentThread = thread.value ?: return@launch val currentThread = thread.value ?: return@launch
try { try {
@ -1108,7 +1129,7 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
service.unmuteMentions(threadId) DirectMessagesService.unmuteMentions(csrfToken, deviceUuid, threadId)
data.postValue(success(Any())) data.postValue(success(Any()))
val currentThread = thread.value ?: return@launch val currentThread = thread.value ?: return@launch
try { try {
@ -1187,7 +1208,9 @@ class ThreadManager private constructor(
data.postValue(loading(null)) data.postValue(loading(null))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val response = service.approveParticipantRequests( val response = DirectMessagesService.approveParticipantRequests(
csrfToken,
deviceUuid,
threadId, threadId,
users.map { obj: User -> obj.pk } users.map { obj: User -> obj.pk }
) )
@ -1206,7 +1229,9 @@ class ThreadManager private constructor(
data.postValue(loading(null)) data.postValue(loading(null))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val response = service.declineParticipantRequests( val response = DirectMessagesService.declineParticipantRequests(
csrfToken,
deviceUuid,
threadId, threadId,
users.map { obj: User -> obj.pk } users.map { obj: User -> obj.pk }
) )
@ -1246,7 +1271,7 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val response = service.approvalRequired(threadId) val response = DirectMessagesService.approvalRequired(csrfToken, deviceUuid, threadId)
handleDetailsChangeResponse(data, response) handleDetailsChangeResponse(data, response)
val currentThread = thread.value ?: return@launch val currentThread = thread.value ?: return@launch
try { try {
@ -1274,7 +1299,7 @@ class ThreadManager private constructor(
} }
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val request = service.approvalNotRequired(threadId) val request = DirectMessagesService.approvalNotRequired(csrfToken, deviceUuid, threadId)
handleDetailsChangeResponse(data, request) handleDetailsChangeResponse(data, request)
val currentThread = thread.value ?: return@launch val currentThread = thread.value ?: return@launch
try { try {
@ -1297,7 +1322,7 @@ class ThreadManager private constructor(
data.postValue(loading(null)) data.postValue(loading(null))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val request = service.leave(threadId) val request = DirectMessagesService.leave(csrfToken, deviceUuid, threadId)
handleDetailsChangeResponse(data, request) handleDetailsChangeResponse(data, request)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "leave: ", e) Log.e(TAG, "leave: ", e)
@ -1312,7 +1337,7 @@ class ThreadManager private constructor(
data.postValue(loading(null)) data.postValue(loading(null))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val request = service.end(threadId) val request = DirectMessagesService.end(csrfToken, deviceUuid, threadId)
handleDetailsChangeResponse(data, request) handleDetailsChangeResponse(data, request)
val currentThread = thread.value ?: return@launch val currentThread = thread.value ?: return@launch
try { try {
@ -1349,7 +1374,7 @@ class ThreadManager private constructor(
data.postValue(loading(null)) data.postValue(loading(null))
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
try { try {
val response = service.markAsSeen(threadId, directItem) val response = DirectMessagesService.markAsSeen(csrfToken, deviceUuid, threadId, directItem)
if (response == null) { if (response == null) {
data.postValue(error(R.string.generic_null_response, null)) data.postValue(error(R.string.generic_null_response, null))
return@launch return@launch
@ -1372,41 +1397,4 @@ class ThreadManager private constructor(
} }
return data return data
} }
companion object {
private val TAG = ThreadManager::class.java.simpleName
private val LOCK = Any()
private val INSTANCE_MAP: MutableMap<String, ThreadManager> = ConcurrentHashMap()
@JvmStatic
fun getInstance(
threadId: String,
pending: Boolean,
currentUser: User,
contentResolver: ContentResolver,
viewerId: Long,
csrfToken: String,
deviceUuid: String,
): ThreadManager {
var instance = INSTANCE_MAP[threadId]
if (instance == null) {
synchronized(LOCK) {
instance = INSTANCE_MAP[threadId]
if (instance == null) {
instance = ThreadManager(threadId, pending, currentUser, contentResolver, viewerId, csrfToken, deviceUuid)
INSTANCE_MAP[threadId] = instance!!
}
}
}
return instance!!
}
}
init {
this.currentUser = currentUser
this.contentResolver = contentResolver
this.viewerId = viewerId
service = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid)
// fetchChats();
}
} }

View File

@ -71,7 +71,7 @@ public class UserSearchViewModel extends ViewModel {
throw new IllegalArgumentException("User is not logged in!"); throw new IllegalArgumentException("User is not logged in!");
} }
userService = UserService.INSTANCE; userService = UserService.INSTANCE;
directMessagesService = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid); directMessagesService = DirectMessagesService.INSTANCE;
rankedRecipientsCache = RankedRecipientsCache.INSTANCE; rankedRecipientsCache = RankedRecipientsCache.INSTANCE;
if ((rankedRecipientsCache.isFailed() || rankedRecipientsCache.isExpired()) && !rankedRecipientsCache.isUpdateInitiated()) { if ((rankedRecipientsCache.isFailed() || rankedRecipientsCache.isExpired()) && !rankedRecipientsCache.isUpdateInitiated()) {
updateRankedRecipientCache(); updateRankedRecipientCache();

View File

@ -5,16 +5,11 @@ import awais.instagrabber.repositories.requests.directmessages.*
import awais.instagrabber.repositories.responses.directmessages.* import awais.instagrabber.repositories.responses.directmessages.*
import awais.instagrabber.repositories.responses.giphy.GiphyGif import awais.instagrabber.repositories.responses.giphy.GiphyGif
import awais.instagrabber.utils.TextUtils.extractUrls import awais.instagrabber.utils.TextUtils.extractUrls
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 java.util.* import java.util.*
class DirectMessagesService private constructor( object DirectMessagesService : BaseService() {
val csrfToken: String,
val userId: Long,
val deviceUuid: String,
) : BaseService() {
private val repository: DirectMessagesRepository = RetrofitFactory.retrofit.create(DirectMessagesRepository::class.java) private val repository: DirectMessagesRepository = RetrofitFactory.retrofit.create(DirectMessagesRepository::class.java)
suspend fun fetchInbox( suspend fun fetchInbox(
@ -55,6 +50,9 @@ class DirectMessagesService private constructor(
suspend fun fetchUnseenCount(): DirectBadgeCount = repository.fetchUnseenCount() suspend fun fetchUnseenCount(): DirectBadgeCount = repository.fetchUnseenCount()
suspend fun broadcastText( suspend fun broadcastText(
csrfToken: String,
userId: Long,
deviceUuid: String,
clientContext: String, clientContext: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
text: String, text: String,
@ -63,17 +61,20 @@ class DirectMessagesService private constructor(
): DirectThreadBroadcastResponse { ): DirectThreadBroadcastResponse {
val urls = extractUrls(text) val urls = extractUrls(text)
if (urls.isNotEmpty()) { if (urls.isNotEmpty()) {
return broadcastLink(clientContext, threadIdOrUserIds, text, urls, repliedToItemId, repliedToClientContext) return broadcastLink(csrfToken, userId, deviceUuid, clientContext, threadIdOrUserIds, text, urls, repliedToItemId, repliedToClientContext)
} }
val broadcastOptions = TextBroadcastOptions(clientContext, threadIdOrUserIds, text) val broadcastOptions = TextBroadcastOptions(clientContext, threadIdOrUserIds, text)
if (!repliedToItemId.isNullOrBlank() && !repliedToClientContext.isNullOrBlank()) { if (!repliedToItemId.isNullOrBlank() && !repliedToClientContext.isNullOrBlank()) {
broadcastOptions.repliedToItemId = repliedToItemId broadcastOptions.repliedToItemId = repliedToItemId
broadcastOptions.repliedToClientContext = repliedToClientContext broadcastOptions.repliedToClientContext = repliedToClientContext
} }
return broadcast(broadcastOptions) return broadcast(csrfToken, userId, deviceUuid, broadcastOptions)
} }
private suspend fun broadcastLink( private suspend fun broadcastLink(
csrfToken: String,
userId: Long,
deviceUuid: String,
clientContext: String, clientContext: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
linkText: String, linkText: String,
@ -86,75 +87,100 @@ class DirectMessagesService private constructor(
broadcastOptions.repliedToItemId = repliedToItemId broadcastOptions.repliedToItemId = repliedToItemId
broadcastOptions.repliedToClientContext = repliedToClientContext broadcastOptions.repliedToClientContext = repliedToClientContext
} }
return broadcast(broadcastOptions) return broadcast(csrfToken, userId, deviceUuid, broadcastOptions)
} }
suspend fun broadcastPhoto( suspend fun broadcastPhoto(
csrfToken: String,
userId: Long,
deviceUuid: String,
clientContext: String, clientContext: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
uploadId: String, uploadId: String,
): DirectThreadBroadcastResponse { ): DirectThreadBroadcastResponse =
return broadcast(PhotoBroadcastOptions(clientContext, threadIdOrUserIds, true, uploadId)) broadcast(csrfToken, userId, deviceUuid, PhotoBroadcastOptions(clientContext, threadIdOrUserIds, true, uploadId))
}
suspend fun broadcastVideo( suspend fun broadcastVideo(
csrfToken: String,
userId: Long,
deviceUuid: String,
clientContext: String, clientContext: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
uploadId: String, uploadId: String,
videoResult: String, videoResult: String,
sampled: Boolean, sampled: Boolean,
): DirectThreadBroadcastResponse { ): DirectThreadBroadcastResponse =
return broadcast(VideoBroadcastOptions(clientContext, threadIdOrUserIds, videoResult, uploadId, sampled)) broadcast(csrfToken, userId, deviceUuid, VideoBroadcastOptions(clientContext, threadIdOrUserIds, videoResult, uploadId, sampled))
}
suspend fun broadcastVoice( suspend fun broadcastVoice(
csrfToken: String,
userId: Long,
deviceUuid: String,
clientContext: String, clientContext: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
uploadId: String, uploadId: String,
waveform: List<Float>, waveform: List<Float>,
samplingFreq: Int, samplingFreq: Int,
): DirectThreadBroadcastResponse { ): DirectThreadBroadcastResponse =
return broadcast(VoiceBroadcastOptions(clientContext, threadIdOrUserIds, uploadId, waveform, samplingFreq)) broadcast(csrfToken, userId, deviceUuid, VoiceBroadcastOptions(clientContext, threadIdOrUserIds, uploadId, waveform, samplingFreq))
}
suspend fun broadcastStoryReply( suspend fun broadcastStoryReply(
csrfToken: String,
userId: Long,
deviceUuid: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
text: String, text: String,
mediaId: String, mediaId: String,
reelId: String, reelId: String,
): DirectThreadBroadcastResponse { ): DirectThreadBroadcastResponse =
return broadcast(StoryReplyBroadcastOptions(UUID.randomUUID().toString(), threadIdOrUserIds, text, mediaId, reelId)) broadcast(csrfToken, userId, deviceUuid, StoryReplyBroadcastOptions(UUID.randomUUID().toString(), threadIdOrUserIds, text, mediaId, reelId))
}
suspend fun broadcastReaction( suspend fun broadcastReaction(
csrfToken: String,
userId: Long,
deviceUuid: String,
clientContext: String, clientContext: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
itemId: String, itemId: String,
emoji: String?, emoji: String?,
delete: Boolean, delete: Boolean,
): DirectThreadBroadcastResponse { ): DirectThreadBroadcastResponse =
return broadcast(ReactionBroadcastOptions(clientContext, threadIdOrUserIds, itemId, emoji, delete)) broadcast(csrfToken, userId, deviceUuid, ReactionBroadcastOptions(clientContext, threadIdOrUserIds, itemId, emoji, delete))
}
suspend fun broadcastAnimatedMedia( suspend fun broadcastAnimatedMedia(
csrfToken: String,
userId: Long,
deviceUuid: String,
clientContext: String, clientContext: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
giphyGif: GiphyGif, giphyGif: GiphyGif,
): DirectThreadBroadcastResponse { ): DirectThreadBroadcastResponse =
return broadcast(AnimatedMediaBroadcastOptions(clientContext, threadIdOrUserIds, giphyGif)) broadcast(csrfToken, userId, deviceUuid, AnimatedMediaBroadcastOptions(clientContext, threadIdOrUserIds, giphyGif))
}
suspend fun broadcastMediaShare( suspend fun broadcastMediaShare(
csrfToken: String,
userId: Long,
deviceUuid: String,
clientContext: String, clientContext: String,
threadIdOrUserIds: ThreadIdOrUserIds, threadIdOrUserIds: ThreadIdOrUserIds,
mediaId: String, mediaId: String,
): DirectThreadBroadcastResponse { ): DirectThreadBroadcastResponse =
return broadcast(MediaShareBroadcastOptions(clientContext, threadIdOrUserIds, mediaId)) broadcast(csrfToken, userId, deviceUuid, MediaShareBroadcastOptions(clientContext, threadIdOrUserIds, mediaId))
}
private suspend fun broadcast(broadcastOptions: BroadcastOptions): DirectThreadBroadcastResponse { private suspend fun broadcast(
require(!isEmpty(broadcastOptions.clientContext)) { "Broadcast requires a valid client context value" } csrfToken: String,
val form = mutableMapOf<String, Any>() userId: Long,
deviceUuid: String,
broadcastOptions: BroadcastOptions,
): DirectThreadBroadcastResponse {
require(broadcastOptions.clientContext.isNotBlank()) { "Broadcast requires a valid client context value" }
val form = mutableMapOf<String, Any>(
"_csrftoken" to csrfToken,
"_uid" to userId,
"__uuid" to deviceUuid,
"client_context" to broadcastOptions.clientContext,
"mutation_token" to broadcastOptions.clientContext,
)
val threadId = broadcastOptions.threadId val threadId = broadcastOptions.threadId
if (!threadId.isNullOrBlank()) { if (!threadId.isNullOrBlank()) {
form["thread_id"] = threadId form["thread_id"] = threadId
@ -165,11 +191,6 @@ class DirectMessagesService private constructor(
} }
form["recipient_users"] = JSONArray(userIds).toString() form["recipient_users"] = JSONArray(userIds).toString()
} }
form["_csrftoken"] = csrfToken
form["_uid"] = userId
form["__uuid"] = deviceUuid
form["client_context"] = broadcastOptions.clientContext
form["mutation_token"] = broadcastOptions.clientContext
val repliedToItemId = broadcastOptions.repliedToItemId val repliedToItemId = broadcastOptions.repliedToItemId
val repliedToClientContext = broadcastOptions.repliedToClientContext val repliedToClientContext = broadcastOptions.repliedToClientContext
if (!repliedToItemId.isNullOrBlank() && !repliedToClientContext.isNullOrBlank()) { if (!repliedToItemId.isNullOrBlank() && !repliedToClientContext.isNullOrBlank()) {
@ -183,6 +204,8 @@ class DirectMessagesService private constructor(
} }
suspend fun addUsers( suspend fun addUsers(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
userIds: Collection<Long>, userIds: Collection<Long>,
): DirectThreadDetailsChangeResponse { ): DirectThreadDetailsChangeResponse {
@ -195,6 +218,8 @@ class DirectMessagesService private constructor(
} }
suspend fun removeUsers( suspend fun removeUsers(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
userIds: Collection<Long>, userIds: Collection<Long>,
): String { ): String {
@ -207,6 +232,8 @@ class DirectMessagesService private constructor(
} }
suspend fun updateTitle( suspend fun updateTitle(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
title: String, title: String,
): DirectThreadDetailsChangeResponse { ): DirectThreadDetailsChangeResponse {
@ -219,6 +246,8 @@ class DirectMessagesService private constructor(
} }
suspend fun addAdmins( suspend fun addAdmins(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
userIds: Collection<Long>, userIds: Collection<Long>,
): String { ): String {
@ -231,6 +260,8 @@ class DirectMessagesService private constructor(
} }
suspend fun removeAdmins( suspend fun removeAdmins(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
userIds: Collection<Long>, userIds: Collection<Long>,
): String { ): String {
@ -243,6 +274,8 @@ class DirectMessagesService private constructor(
} }
suspend fun deleteItem( suspend fun deleteItem(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
itemId: String, itemId: String,
): String { ): String {
@ -292,6 +325,9 @@ class DirectMessagesService private constructor(
} }
suspend fun createThread( suspend fun createThread(
csrfToken: String,
userId: Long,
deviceUuid: String,
userIds: List<Long>, userIds: List<Long>,
threadTitle: String?, threadTitle: String?,
): DirectThread { ): DirectThread {
@ -309,7 +345,11 @@ class DirectMessagesService private constructor(
return repository.createThread(signedForm) return repository.createThread(signedForm)
} }
suspend fun mute(threadId: String): String { suspend fun mute(
csrfToken: String,
deviceUuid: String,
threadId: String,
): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid "_uuid" to deviceUuid
@ -317,7 +357,11 @@ class DirectMessagesService private constructor(
return repository.mute(threadId, form) return repository.mute(threadId, form)
} }
suspend fun unmute(threadId: String): String { suspend fun unmute(
csrfToken: String,
deviceUuid: String,
threadId: String,
): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -325,7 +369,11 @@ class DirectMessagesService private constructor(
return repository.unmute(threadId, form) return repository.unmute(threadId, form)
} }
suspend fun muteMentions(threadId: String): String { suspend fun muteMentions(
csrfToken: String,
deviceUuid: String,
threadId: String,
): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -333,7 +381,11 @@ class DirectMessagesService private constructor(
return repository.muteMentions(threadId, form) return repository.muteMentions(threadId, form)
} }
suspend fun unmuteMentions(threadId: String): String { suspend fun unmuteMentions(
csrfToken: String,
deviceUuid: String,
threadId: String,
): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -350,6 +402,8 @@ class DirectMessagesService private constructor(
} }
suspend fun approveParticipantRequests( suspend fun approveParticipantRequests(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
userIds: List<Long>, userIds: List<Long>,
): DirectThreadDetailsChangeResponse { ): DirectThreadDetailsChangeResponse {
@ -363,6 +417,8 @@ class DirectMessagesService private constructor(
} }
suspend fun declineParticipantRequests( suspend fun declineParticipantRequests(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
userIds: List<Long>, userIds: List<Long>,
): DirectThreadDetailsChangeResponse { ): DirectThreadDetailsChangeResponse {
@ -374,7 +430,11 @@ class DirectMessagesService private constructor(
return repository.declineParticipantRequests(threadId, form) return repository.declineParticipantRequests(threadId, form)
} }
suspend fun approvalRequired(threadId: String): DirectThreadDetailsChangeResponse { suspend fun approvalRequired(
csrfToken: String,
deviceUuid: String,
threadId: String,
): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -382,7 +442,11 @@ class DirectMessagesService private constructor(
return repository.approvalRequired(threadId, form) return repository.approvalRequired(threadId, form)
} }
suspend fun approvalNotRequired(threadId: String): DirectThreadDetailsChangeResponse { suspend fun approvalNotRequired(
csrfToken: String,
deviceUuid: String,
threadId: String,
): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -390,7 +454,11 @@ class DirectMessagesService private constructor(
return repository.approvalNotRequired(threadId, form) return repository.approvalNotRequired(threadId, form)
} }
suspend fun leave(threadId: String): DirectThreadDetailsChangeResponse { suspend fun leave(
csrfToken: String,
deviceUuid: String,
threadId: String,
): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -398,7 +466,11 @@ class DirectMessagesService private constructor(
return repository.leave(threadId, form) return repository.leave(threadId, form)
} }
suspend fun end(threadId: String): DirectThreadDetailsChangeResponse { suspend fun end(
csrfToken: String,
deviceUuid: String,
threadId: String,
): DirectThreadDetailsChangeResponse {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -423,7 +495,11 @@ class DirectMessagesService private constructor(
return repository.fetchPendingInbox(queryMap) return repository.fetchPendingInbox(queryMap)
} }
suspend fun approveRequest(threadId: String): String { suspend fun approveRequest(
csrfToken: String,
deviceUuid: String,
threadId: String,
): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -431,7 +507,11 @@ class DirectMessagesService private constructor(
return repository.approveRequest(threadId, form) return repository.approveRequest(threadId, form)
} }
suspend fun declineRequest(threadId: String): String { suspend fun declineRequest(
csrfToken: String,
deviceUuid: String,
threadId: String,
): String {
val form = mapOf( val form = mapOf(
"_csrftoken" to csrfToken, "_csrftoken" to csrfToken,
"_uuid" to deviceUuid, "_uuid" to deviceUuid,
@ -440,6 +520,8 @@ class DirectMessagesService private constructor(
} }
suspend fun markAsSeen( suspend fun markAsSeen(
csrfToken: String,
deviceUuid: String,
threadId: String, threadId: String,
directItem: DirectItem, directItem: DirectItem,
): DirectItemSeenResponse? { ): DirectItemSeenResponse? {
@ -454,25 +536,4 @@ class DirectMessagesService private constructor(
) )
return repository.markItemSeen(threadId, itemId, form) return repository.markItemSeen(threadId, itemId, form)
} }
companion object {
private lateinit var instance: DirectMessagesService
@JvmStatic
fun getInstance(
csrfToken: String,
userId: Long,
deviceUuid: String,
): DirectMessagesService {
if (!this::instance.isInitialized
|| instance.csrfToken != csrfToken
|| instance.userId != userId
|| instance.deviceUuid != deviceUuid
) {
instance = DirectMessagesService(csrfToken, userId, deviceUuid)
}
return instance
}
}
} }