diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index 4239c24e..9a6ab1f0 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -164,7 +164,7 @@ public class StoryViewerFragment extends Fragment { fragmentActivity = (AppCompatActivity) requireActivity(); storiesService = StoriesService.INSTANCE; mediaService = MediaService.INSTANCE; - directMessagesService = DirectMessagesService.getInstance(csrfToken, userId, deviceId); + directMessagesService = DirectMessagesService.INSTANCE; setHasOptionsMenu(true); } @@ -222,6 +222,9 @@ public class StoryViewerFragment extends Fragment { .setTitle(R.string.reply_story) .setView(input) .setPositiveButton(R.string.confirm, (d, w) -> directMessagesService.createThread( + csrfToken, + userId, + deviceId, Collections.singletonList(currentStory.getUserId()), null, CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { @@ -231,6 +234,9 @@ public class StoryViewerFragment extends Fragment { return; } directMessagesService.broadcastStoryReply( + csrfToken, + userId, + deviceId, ThreadIdOrUserIds.of(thread.getThreadId()), input.getText().toString(), currentStory.getStoryMediaId(), diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index ee3640a0..077e77da 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -335,7 +335,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); fragmentActivity = (MainActivity) requireActivity(); friendshipService = isLoggedIn ? FriendshipService.INSTANCE : null; - directMessagesService = isLoggedIn ? DirectMessagesService.getInstance(csrfToken, myId, deviceUuid) : null; + directMessagesService = isLoggedIn ? DirectMessagesService.INSTANCE : null; storiesService = isLoggedIn ? StoriesService.INSTANCE : null; mediaService = isLoggedIn ? MediaService.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.setEnabled(false); directMessagesService.createThread( + csrfToken, + myId, + deviceUuid, Collections.singletonList(profileModel.getPk()), null, CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { diff --git a/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt b/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt index fafc6e6e..99c099c0 100644 --- a/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt +++ b/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt @@ -4,7 +4,6 @@ import android.content.ContentResolver import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import awais.instagrabber.managers.ThreadManager.Companion.getInstance import awais.instagrabber.models.Resource import awais.instagrabber.models.Resource.Companion.error 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.getUserIdFromCookie import awais.instagrabber.webservices.DirectMessagesService -import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.util.* object DirectMessagesManager { - val inboxManager: InboxManager by lazy { InboxManager.getInstance(false) } - val pendingInboxManager: InboxManager by lazy { InboxManager.getInstance(true) } + val inboxManager: InboxManager by lazy { InboxManager(false) } + val pendingInboxManager: InboxManager by lazy { InboxManager(true) } private val TAG = DirectMessagesManager::class.java.simpleName private val viewerId: Long private val deviceUuid: String private val csrfToken: String - private val service: DirectMessagesService fun moveThreadFromPending(threadId: String) { val pendingThreads = pendingInboxManager.threads.value ?: return @@ -65,10 +62,10 @@ object DirectMessagesManager { currentUser: User, contentResolver: ContentResolver, ): 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, mediaId: String, scope: CoroutineScope) { val resultsCount = intArrayOf(0) @@ -134,7 +131,10 @@ object DirectMessagesManager { data.postValue(loading(null)) scope.launch(Dispatchers.IO) { try { - service.broadcastMediaShare( + DirectMessagesService.broadcastMediaShare( + csrfToken, + viewerId, + deviceUuid, UUID.randomUUID().toString(), of(threadId), mediaId @@ -157,6 +157,5 @@ object DirectMessagesManager { val csrfToken = getCsrfTokenFromCookie(cookie) require(!csrfToken.isNullOrBlank() && viewerId != 0L && deviceUuid.isNotBlank()) { "User is not logged in!" } this.csrfToken = csrfToken - service = getInstance(csrfToken, viewerId, deviceUuid) } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/managers/InboxManager.kt b/app/src/main/java/awais/instagrabber/managers/InboxManager.kt index 9630151d..9769ec93 100644 --- a/app/src/main/java/awais/instagrabber/managers/InboxManager.kt +++ b/app/src/main/java/awais/instagrabber/managers/InboxManager.kt @@ -12,8 +12,8 @@ import awais.instagrabber.models.Resource.Companion.success import awais.instagrabber.repositories.responses.User import awais.instagrabber.repositories.responses.directmessages.* import awais.instagrabber.utils.* +import awais.instagrabber.utils.extensions.TAG import awais.instagrabber.webservices.DirectMessagesService -import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader import com.google.common.collect.ImmutableList @@ -24,14 +24,13 @@ import retrofit2.Call import java.util.* import java.util.concurrent.TimeUnit -class InboxManager private constructor(private val pending: Boolean) { +class InboxManager(private val pending: Boolean) { // private val fetchInboxControlledRunner: ControlledRunner> = ControlledRunner() // private val fetchPendingInboxControlledRunner: ControlledRunner> = ControlledRunner() private val inbox = MutableLiveData>(success(null)) private val unseenCount = MutableLiveData>() private val pendingRequestsTotal = MutableLiveData(0) val threads: LiveData> - private val service: DirectMessagesService private var inboxRequest: Call? = null private var unseenCountRequest: Call? = null private var seqId: Long = 0 @@ -58,7 +57,11 @@ class InboxManager private constructor(private val pending: Boolean) { inbox.postValue(loading(currentDirectInbox)) scope.launch(Dispatchers.IO) { 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) } catch (e: Exception) { inbox.postValue(error(e.message, currentDirectInbox)) @@ -74,7 +77,7 @@ class InboxManager private constructor(private val pending: Boolean) { unseenCount.postValue(loading(currentUnseenCount)) scope.launch(Dispatchers.IO) { try { - val directBadgeCount = service.fetchUnseenCount() + val directBadgeCount = DirectMessagesService.fetchUnseenCount() unseenCount.postValue(success(directBadgeCount.badgeCount)) } catch (e: Exception) { Log.e(TAG, "Failed fetching unseen count", e) @@ -286,7 +289,6 @@ class InboxManager private constructor(private val pending: Boolean) { } companion object { - private val TAG = InboxManager::class.java.simpleName private val THREAD_LOCKS = CacheBuilder .newBuilder() .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 t2FirstDirectItem.getTimestamp().compareTo(t1FirstDirectItem.getTimestamp()) } - - fun getInstance(pending: Boolean): InboxManager { - return InboxManager(pending) - } } init { @@ -311,7 +309,6 @@ class InboxManager private constructor(private val pending: Boolean) { val deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID) val csrfToken = getCsrfTokenFromCookie(cookie) require(!csrfToken.isNullOrBlank() && viewerId != 0L && deviceUuid.isNotBlank()) { "User is not logged in!" } - service = getInstance(csrfToken, viewerId, deviceUuid) // Transformations threads = Transformations.distinctUntilChanged(Transformations.map(inbox) { inboxResource: Resource -> diff --git a/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt b/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt index 0a3ce95d..52bff758 100644 --- a/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt +++ b/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt @@ -29,6 +29,7 @@ import awais.instagrabber.utils.MediaUploader.uploadVideo import awais.instagrabber.utils.MediaUtils.OnInfoLoadListener import awais.instagrabber.utils.MediaUtils.VideoInfo import awais.instagrabber.utils.TextUtils.isEmpty +import awais.instagrabber.utils.extensions.TAG import awais.instagrabber.webservices.DirectMessagesService import awais.instagrabber.webservices.FriendshipService import awais.instagrabber.webservices.MediaService @@ -42,15 +43,14 @@ import java.io.File import java.io.IOException import java.net.HttpURLConnection import java.util.* -import java.util.concurrent.ConcurrentHashMap import java.util.stream.Collectors -class ThreadManager private constructor( +class ThreadManager( private val threadId: String, pending: Boolean, - currentUser: User, - contentResolver: ContentResolver, - viewerId: Long, + private val currentUser: User?, + private val contentResolver: ContentResolver, + private val viewerId: Long, private val csrfToken: String, private val deviceUuid: String, ) { @@ -61,11 +61,7 @@ class ThreadManager private constructor( private val _pendingRequests = MutableLiveData(null) val pendingRequests: LiveData = _pendingRequests private val inboxManager: InboxManager = if (pending) DirectMessagesManager.pendingInboxManager else DirectMessagesManager.inboxManager - private val viewerId: Long private val threadIdOrUserIds: ThreadIdOrUserIds = of(threadId) - private val currentUser: User? - private val contentResolver: ContentResolver - private val service: DirectMessagesService val thread: LiveData by lazy { distinctUntilChanged(map(inboxManager.getInbox()) { inboxResource: Resource? -> @@ -130,7 +126,7 @@ class ThreadManager private constructor( _fetching.postValue(loading(null)) scope.launch(Dispatchers.IO) { try { - val threadFeedResponse = service.fetchThread(threadId, cursor) + val threadFeedResponse = DirectMessagesService.fetchThread(threadId, cursor) if (threadFeedResponse.status != null && threadFeedResponse.status != "ok") { _fetching.postValue(error(R.string.generic_not_ok_response, null)) return@launch @@ -158,7 +154,7 @@ class ThreadManager private constructor( if (isGroup == null || !isGroup) return scope.launch(Dispatchers.IO) { try { - val response = service.participantRequests(threadId, 1) + val response = DirectMessagesService.participantRequests(threadId, 1) _pendingRequests.postValue(response) } catch (e: Exception) { Log.e(TAG, "fetchPendingRequests: ", e) @@ -350,7 +346,10 @@ class ThreadManager private constructor( val repliedToClientContext = replyToItemValue?.clientContext scope.launch(Dispatchers.IO) { try { - val response = service.broadcastText( + val response = DirectMessagesService.broadcastText( + csrfToken, + viewerId, + deviceUuid, clientContext, threadIdOrUserIds, text, @@ -405,7 +404,10 @@ class ThreadManager private constructor( data.postValue(loading(directItem)) scope.launch(Dispatchers.IO) { try { - val request = service.broadcastAnimatedMedia( + val request = DirectMessagesService.broadcastAnimatedMedia( + csrfToken, + userId, + deviceUuid, clientContext, threadIdOrUserIds, giphyGif @@ -451,7 +453,10 @@ class ThreadManager private constructor( null ) MediaService.uploadFinish(csrfToken, userId, deviceUuid, uploadFinishOptions) - val broadcastResponse = service.broadcastVoice( + val broadcastResponse = DirectMessagesService.broadcastVoice( + csrfToken, + viewerId, + deviceUuid, clientContext, threadIdOrUserIds, uploadDmVoiceOptions.uploadId, @@ -492,7 +497,10 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - service.broadcastReaction( + DirectMessagesService.broadcastReaction( + csrfToken, + userId, + deviceUuid, clientContext, threadIdOrUserIds, itemId, @@ -529,7 +537,16 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - service.broadcastReaction(clientContext, threadIdOrUserIds, itemId1, null, true) + DirectMessagesService.broadcastReaction( + csrfToken, + viewerId, + deviceUuid, + clientContext, + threadIdOrUserIds, + itemId1, + null, + true + ) } catch (e: Exception) { data.postValue(error(e.message, null)) Log.e(TAG, "sendDeleteReaction: ", e) @@ -548,7 +565,7 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - service.deleteItem(threadId, itemId) + DirectMessagesService.deleteItem(csrfToken, deviceUuid, threadId, itemId) } catch (e: Exception) { // add the item back if unsuccessful addItems(index, listOf(item)) @@ -624,7 +641,7 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - service.forward( + DirectMessagesService.forward( thread.threadId, itemTypeName, threadId, @@ -643,7 +660,7 @@ class ThreadManager private constructor( val data = MutableLiveData>() scope.launch(Dispatchers.IO) { try { - service.approveRequest(threadId) + DirectMessagesService.approveRequest(csrfToken, deviceUuid, threadId) data.postValue(success(Any())) } catch (e: Exception) { Log.e(TAG, "acceptRequest: ", e) @@ -657,7 +674,7 @@ class ThreadManager private constructor( val data = MutableLiveData>() scope.launch(Dispatchers.IO) { try { - service.declineRequest(threadId) + DirectMessagesService.declineRequest(csrfToken, deviceUuid, threadId) data.postValue(success(Any())) } catch (e: Exception) { Log.e(TAG, "declineRequest: ", e) @@ -702,9 +719,8 @@ class ThreadManager private constructor( height: Int, scope: CoroutineScope, ) { - val userId = getCurrentUserId(data) ?: return 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 addItems(0, listOf(directItem)) data.postValue(loading(directItem)) @@ -714,7 +730,7 @@ class ThreadManager private constructor( if (handleInvalidResponse(data, response)) return@launch val response1 = response.response ?: return@launch 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) } catch (e: Exception) { data.postValue(error(e.message, null)) @@ -775,7 +791,10 @@ class ThreadManager private constructor( VideoOptions(duration / 1000f, emptyList(), 0, false) ) MediaService.uploadFinish(csrfToken, userId, deviceUuid, uploadFinishOptions) - val broadcastResponse = service.broadcastVideo( + val broadcastResponse = DirectMessagesService.broadcastVideo( + csrfToken, + viewerId, + deviceUuid, clientContext, threadIdOrUserIds, uploadDmVideoOptions.uploadId, @@ -902,7 +921,7 @@ class ThreadManager private constructor( val data = MutableLiveData>() scope.launch(Dispatchers.IO) { try { - val response = service.updateTitle(threadId, newTitle.trim()) + val response = DirectMessagesService.updateTitle(csrfToken, deviceUuid, threadId, newTitle.trim()) handleDetailsChangeResponse(data, response) } catch (e: Exception) { } @@ -914,7 +933,9 @@ class ThreadManager private constructor( val data = MutableLiveData>() scope.launch(Dispatchers.IO) { try { - val response = service.addUsers( + val response = DirectMessagesService.addUsers( + csrfToken, + deviceUuid, threadId, users.map { obj: User -> obj.pk } ) @@ -931,7 +952,7 @@ class ThreadManager private constructor( val data = MutableLiveData>() scope.launch(Dispatchers.IO) { try { - service.removeUsers(threadId, setOf(user.pk)) + DirectMessagesService.removeUsers(csrfToken, deviceUuid, threadId, setOf(user.pk)) data.postValue(success(Any())) var activeUsers = users.value var leftUsersValue = leftUsers.value @@ -966,7 +987,7 @@ class ThreadManager private constructor( if (isAdmin(user)) return data scope.launch(Dispatchers.IO) { try { - service.addAdmins(threadId, setOf(user.pk)) + DirectMessagesService.addAdmins(csrfToken, deviceUuid, threadId, setOf(user.pk)) val currentAdminIds = adminUserIds.value val updatedAdminIds = ImmutableList.builder() .addAll(currentAdminIds ?: emptyList()) @@ -994,7 +1015,7 @@ class ThreadManager private constructor( if (!isAdmin(user)) return data scope.launch(Dispatchers.IO) { try { - service.removeAdmins(threadId, setOf(user.pk)) + DirectMessagesService.removeAdmins(csrfToken, deviceUuid, threadId, setOf(user.pk)) val currentAdmins = adminUserIds.value ?: return@launch val updatedAdminUserIds = currentAdmins.filter { userId1: Long -> userId1 != user.pk } val currentThread = thread.value ?: return@launch @@ -1024,7 +1045,7 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - service.mute(threadId) + DirectMessagesService.mute(csrfToken, deviceUuid, threadId) data.postValue(success(Any())) val currentThread = thread.value ?: return@launch try { @@ -1052,7 +1073,7 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - service.unmute(threadId) + DirectMessagesService.unmute(csrfToken, deviceUuid, threadId) data.postValue(success(Any())) val currentThread = thread.value ?: return@launch try { @@ -1080,7 +1101,7 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - service.muteMentions(threadId) + DirectMessagesService.muteMentions(csrfToken, deviceUuid, threadId) data.postValue(success(Any())) val currentThread = thread.value ?: return@launch try { @@ -1108,7 +1129,7 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - service.unmuteMentions(threadId) + DirectMessagesService.unmuteMentions(csrfToken, deviceUuid, threadId) data.postValue(success(Any())) val currentThread = thread.value ?: return@launch try { @@ -1187,7 +1208,9 @@ class ThreadManager private constructor( data.postValue(loading(null)) scope.launch(Dispatchers.IO) { try { - val response = service.approveParticipantRequests( + val response = DirectMessagesService.approveParticipantRequests( + csrfToken, + deviceUuid, threadId, users.map { obj: User -> obj.pk } ) @@ -1206,7 +1229,9 @@ class ThreadManager private constructor( data.postValue(loading(null)) scope.launch(Dispatchers.IO) { try { - val response = service.declineParticipantRequests( + val response = DirectMessagesService.declineParticipantRequests( + csrfToken, + deviceUuid, threadId, users.map { obj: User -> obj.pk } ) @@ -1246,7 +1271,7 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - val response = service.approvalRequired(threadId) + val response = DirectMessagesService.approvalRequired(csrfToken, deviceUuid, threadId) handleDetailsChangeResponse(data, response) val currentThread = thread.value ?: return@launch try { @@ -1274,7 +1299,7 @@ class ThreadManager private constructor( } scope.launch(Dispatchers.IO) { try { - val request = service.approvalNotRequired(threadId) + val request = DirectMessagesService.approvalNotRequired(csrfToken, deviceUuid, threadId) handleDetailsChangeResponse(data, request) val currentThread = thread.value ?: return@launch try { @@ -1297,7 +1322,7 @@ class ThreadManager private constructor( data.postValue(loading(null)) scope.launch(Dispatchers.IO) { try { - val request = service.leave(threadId) + val request = DirectMessagesService.leave(csrfToken, deviceUuid, threadId) handleDetailsChangeResponse(data, request) } catch (e: Exception) { Log.e(TAG, "leave: ", e) @@ -1312,7 +1337,7 @@ class ThreadManager private constructor( data.postValue(loading(null)) scope.launch(Dispatchers.IO) { try { - val request = service.end(threadId) + val request = DirectMessagesService.end(csrfToken, deviceUuid, threadId) handleDetailsChangeResponse(data, request) val currentThread = thread.value ?: return@launch try { @@ -1349,7 +1374,7 @@ class ThreadManager private constructor( data.postValue(loading(null)) scope.launch(Dispatchers.IO) { try { - val response = service.markAsSeen(threadId, directItem) + val response = DirectMessagesService.markAsSeen(csrfToken, deviceUuid, threadId, directItem) if (response == null) { data.postValue(error(R.string.generic_null_response, null)) return@launch @@ -1372,41 +1397,4 @@ class ThreadManager private constructor( } return data } - - companion object { - private val TAG = ThreadManager::class.java.simpleName - private val LOCK = Any() - private val INSTANCE_MAP: MutableMap = 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(); - } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/viewmodels/UserSearchViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/UserSearchViewModel.java index aef2d8ca..ea012d27 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/UserSearchViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/UserSearchViewModel.java @@ -71,7 +71,7 @@ public class UserSearchViewModel extends ViewModel { throw new IllegalArgumentException("User is not logged in!"); } userService = UserService.INSTANCE; - directMessagesService = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid); + directMessagesService = DirectMessagesService.INSTANCE; rankedRecipientsCache = RankedRecipientsCache.INSTANCE; if ((rankedRecipientsCache.isFailed() || rankedRecipientsCache.isExpired()) && !rankedRecipientsCache.isUpdateInitiated()) { updateRankedRecipientCache(); diff --git a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.kt b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.kt index 8005ad10..ae45ca61 100644 --- a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.kt +++ b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.kt @@ -5,16 +5,11 @@ import awais.instagrabber.repositories.requests.directmessages.* import awais.instagrabber.repositories.responses.directmessages.* import awais.instagrabber.repositories.responses.giphy.GiphyGif import awais.instagrabber.utils.TextUtils.extractUrls -import awais.instagrabber.utils.TextUtils.isEmpty import awais.instagrabber.utils.Utils import org.json.JSONArray import java.util.* -class DirectMessagesService private constructor( - val csrfToken: String, - val userId: Long, - val deviceUuid: String, -) : BaseService() { +object DirectMessagesService : BaseService() { private val repository: DirectMessagesRepository = RetrofitFactory.retrofit.create(DirectMessagesRepository::class.java) suspend fun fetchInbox( @@ -55,6 +50,9 @@ class DirectMessagesService private constructor( suspend fun fetchUnseenCount(): DirectBadgeCount = repository.fetchUnseenCount() suspend fun broadcastText( + csrfToken: String, + userId: Long, + deviceUuid: String, clientContext: String, threadIdOrUserIds: ThreadIdOrUserIds, text: String, @@ -63,17 +61,20 @@ class DirectMessagesService private constructor( ): DirectThreadBroadcastResponse { val urls = extractUrls(text) 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) if (!repliedToItemId.isNullOrBlank() && !repliedToClientContext.isNullOrBlank()) { broadcastOptions.repliedToItemId = repliedToItemId broadcastOptions.repliedToClientContext = repliedToClientContext } - return broadcast(broadcastOptions) + return broadcast(csrfToken, userId, deviceUuid, broadcastOptions) } private suspend fun broadcastLink( + csrfToken: String, + userId: Long, + deviceUuid: String, clientContext: String, threadIdOrUserIds: ThreadIdOrUserIds, linkText: String, @@ -86,75 +87,100 @@ class DirectMessagesService private constructor( broadcastOptions.repliedToItemId = repliedToItemId broadcastOptions.repliedToClientContext = repliedToClientContext } - return broadcast(broadcastOptions) + return broadcast(csrfToken, userId, deviceUuid, broadcastOptions) } suspend fun broadcastPhoto( + csrfToken: String, + userId: Long, + deviceUuid: String, clientContext: String, threadIdOrUserIds: ThreadIdOrUserIds, uploadId: String, - ): DirectThreadBroadcastResponse { - return broadcast(PhotoBroadcastOptions(clientContext, threadIdOrUserIds, true, uploadId)) - } + ): DirectThreadBroadcastResponse = + broadcast(csrfToken, userId, deviceUuid, PhotoBroadcastOptions(clientContext, threadIdOrUserIds, true, uploadId)) suspend fun broadcastVideo( + csrfToken: String, + userId: Long, + deviceUuid: String, clientContext: String, threadIdOrUserIds: ThreadIdOrUserIds, uploadId: String, videoResult: String, sampled: Boolean, - ): DirectThreadBroadcastResponse { - return broadcast(VideoBroadcastOptions(clientContext, threadIdOrUserIds, videoResult, uploadId, sampled)) - } + ): DirectThreadBroadcastResponse = + broadcast(csrfToken, userId, deviceUuid, VideoBroadcastOptions(clientContext, threadIdOrUserIds, videoResult, uploadId, sampled)) suspend fun broadcastVoice( + csrfToken: String, + userId: Long, + deviceUuid: String, clientContext: String, threadIdOrUserIds: ThreadIdOrUserIds, uploadId: String, waveform: List, samplingFreq: Int, - ): DirectThreadBroadcastResponse { - return broadcast(VoiceBroadcastOptions(clientContext, threadIdOrUserIds, uploadId, waveform, samplingFreq)) - } + ): DirectThreadBroadcastResponse = + broadcast(csrfToken, userId, deviceUuid, VoiceBroadcastOptions(clientContext, threadIdOrUserIds, uploadId, waveform, samplingFreq)) suspend fun broadcastStoryReply( + csrfToken: String, + userId: Long, + deviceUuid: String, threadIdOrUserIds: ThreadIdOrUserIds, text: String, mediaId: String, reelId: String, - ): DirectThreadBroadcastResponse { - return broadcast(StoryReplyBroadcastOptions(UUID.randomUUID().toString(), threadIdOrUserIds, text, mediaId, reelId)) - } + ): DirectThreadBroadcastResponse = + broadcast(csrfToken, userId, deviceUuid, StoryReplyBroadcastOptions(UUID.randomUUID().toString(), threadIdOrUserIds, text, mediaId, reelId)) suspend fun broadcastReaction( + csrfToken: String, + userId: Long, + deviceUuid: String, clientContext: String, threadIdOrUserIds: ThreadIdOrUserIds, itemId: String, emoji: String?, delete: Boolean, - ): DirectThreadBroadcastResponse { - return broadcast(ReactionBroadcastOptions(clientContext, threadIdOrUserIds, itemId, emoji, delete)) - } + ): DirectThreadBroadcastResponse = + broadcast(csrfToken, userId, deviceUuid, ReactionBroadcastOptions(clientContext, threadIdOrUserIds, itemId, emoji, delete)) suspend fun broadcastAnimatedMedia( + csrfToken: String, + userId: Long, + deviceUuid: String, clientContext: String, threadIdOrUserIds: ThreadIdOrUserIds, giphyGif: GiphyGif, - ): DirectThreadBroadcastResponse { - return broadcast(AnimatedMediaBroadcastOptions(clientContext, threadIdOrUserIds, giphyGif)) - } + ): DirectThreadBroadcastResponse = + broadcast(csrfToken, userId, deviceUuid, AnimatedMediaBroadcastOptions(clientContext, threadIdOrUserIds, giphyGif)) suspend fun broadcastMediaShare( + csrfToken: String, + userId: Long, + deviceUuid: String, clientContext: String, threadIdOrUserIds: ThreadIdOrUserIds, mediaId: String, + ): DirectThreadBroadcastResponse = + broadcast(csrfToken, userId, deviceUuid, MediaShareBroadcastOptions(clientContext, threadIdOrUserIds, mediaId)) + + private suspend fun broadcast( + csrfToken: String, + userId: Long, + deviceUuid: String, + broadcastOptions: BroadcastOptions, ): DirectThreadBroadcastResponse { - return broadcast(MediaShareBroadcastOptions(clientContext, threadIdOrUserIds, mediaId)) - } - - private suspend fun broadcast(broadcastOptions: BroadcastOptions): DirectThreadBroadcastResponse { - require(!isEmpty(broadcastOptions.clientContext)) { "Broadcast requires a valid client context value" } - val form = mutableMapOf() + require(broadcastOptions.clientContext.isNotBlank()) { "Broadcast requires a valid client context value" } + val form = mutableMapOf( + "_csrftoken" to csrfToken, + "_uid" to userId, + "__uuid" to deviceUuid, + "client_context" to broadcastOptions.clientContext, + "mutation_token" to broadcastOptions.clientContext, + ) val threadId = broadcastOptions.threadId if (!threadId.isNullOrBlank()) { form["thread_id"] = threadId @@ -165,11 +191,6 @@ class DirectMessagesService private constructor( } 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 repliedToClientContext = broadcastOptions.repliedToClientContext if (!repliedToItemId.isNullOrBlank() && !repliedToClientContext.isNullOrBlank()) { @@ -183,6 +204,8 @@ class DirectMessagesService private constructor( } suspend fun addUsers( + csrfToken: String, + deviceUuid: String, threadId: String, userIds: Collection, ): DirectThreadDetailsChangeResponse { @@ -195,6 +218,8 @@ class DirectMessagesService private constructor( } suspend fun removeUsers( + csrfToken: String, + deviceUuid: String, threadId: String, userIds: Collection, ): String { @@ -207,6 +232,8 @@ class DirectMessagesService private constructor( } suspend fun updateTitle( + csrfToken: String, + deviceUuid: String, threadId: String, title: String, ): DirectThreadDetailsChangeResponse { @@ -219,6 +246,8 @@ class DirectMessagesService private constructor( } suspend fun addAdmins( + csrfToken: String, + deviceUuid: String, threadId: String, userIds: Collection, ): String { @@ -231,6 +260,8 @@ class DirectMessagesService private constructor( } suspend fun removeAdmins( + csrfToken: String, + deviceUuid: String, threadId: String, userIds: Collection, ): String { @@ -243,6 +274,8 @@ class DirectMessagesService private constructor( } suspend fun deleteItem( + csrfToken: String, + deviceUuid: String, threadId: String, itemId: String, ): String { @@ -292,6 +325,9 @@ class DirectMessagesService private constructor( } suspend fun createThread( + csrfToken: String, + userId: Long, + deviceUuid: String, userIds: List, threadTitle: String?, ): DirectThread { @@ -309,7 +345,11 @@ class DirectMessagesService private constructor( return repository.createThread(signedForm) } - suspend fun mute(threadId: String): String { + suspend fun mute( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): String { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid @@ -317,7 +357,11 @@ class DirectMessagesService private constructor( return repository.mute(threadId, form) } - suspend fun unmute(threadId: String): String { + suspend fun unmute( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): String { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -325,7 +369,11 @@ class DirectMessagesService private constructor( return repository.unmute(threadId, form) } - suspend fun muteMentions(threadId: String): String { + suspend fun muteMentions( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): String { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -333,7 +381,11 @@ class DirectMessagesService private constructor( return repository.muteMentions(threadId, form) } - suspend fun unmuteMentions(threadId: String): String { + suspend fun unmuteMentions( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): String { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -350,6 +402,8 @@ class DirectMessagesService private constructor( } suspend fun approveParticipantRequests( + csrfToken: String, + deviceUuid: String, threadId: String, userIds: List, ): DirectThreadDetailsChangeResponse { @@ -363,6 +417,8 @@ class DirectMessagesService private constructor( } suspend fun declineParticipantRequests( + csrfToken: String, + deviceUuid: String, threadId: String, userIds: List, ): DirectThreadDetailsChangeResponse { @@ -374,7 +430,11 @@ class DirectMessagesService private constructor( return repository.declineParticipantRequests(threadId, form) } - suspend fun approvalRequired(threadId: String): DirectThreadDetailsChangeResponse { + suspend fun approvalRequired( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): DirectThreadDetailsChangeResponse { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -382,7 +442,11 @@ class DirectMessagesService private constructor( return repository.approvalRequired(threadId, form) } - suspend fun approvalNotRequired(threadId: String): DirectThreadDetailsChangeResponse { + suspend fun approvalNotRequired( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): DirectThreadDetailsChangeResponse { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -390,7 +454,11 @@ class DirectMessagesService private constructor( return repository.approvalNotRequired(threadId, form) } - suspend fun leave(threadId: String): DirectThreadDetailsChangeResponse { + suspend fun leave( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): DirectThreadDetailsChangeResponse { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -398,7 +466,11 @@ class DirectMessagesService private constructor( return repository.leave(threadId, form) } - suspend fun end(threadId: String): DirectThreadDetailsChangeResponse { + suspend fun end( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): DirectThreadDetailsChangeResponse { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -423,7 +495,11 @@ class DirectMessagesService private constructor( return repository.fetchPendingInbox(queryMap) } - suspend fun approveRequest(threadId: String): String { + suspend fun approveRequest( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): String { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -431,7 +507,11 @@ class DirectMessagesService private constructor( return repository.approveRequest(threadId, form) } - suspend fun declineRequest(threadId: String): String { + suspend fun declineRequest( + csrfToken: String, + deviceUuid: String, + threadId: String, + ): String { val form = mapOf( "_csrftoken" to csrfToken, "_uuid" to deviceUuid, @@ -440,6 +520,8 @@ class DirectMessagesService private constructor( } suspend fun markAsSeen( + csrfToken: String, + deviceUuid: String, threadId: String, directItem: DirectItem, ): DirectItemSeenResponse? { @@ -454,25 +536,4 @@ class DirectMessagesService private constructor( ) 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 - } - } - } \ No newline at end of file