mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-10-31 03:25:34 +00:00 
			
		
		
		
	DirectMessagesRepository migrated to suspend functions
This commit is contained in:
		
							parent
							
								
									0c77611e22
								
							
						
					
					
						commit
						cc1741005b
					
				| @ -87,7 +87,6 @@ import awais.instagrabber.repositories.requests.StoryViewerOptions.Type; | ||||
| import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds; | ||||
| import awais.instagrabber.repositories.responses.Media; | ||||
| import awais.instagrabber.repositories.responses.StoryStickerResponse; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectThread; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.CoroutineUtilsKt; | ||||
| @ -102,9 +101,7 @@ import awais.instagrabber.webservices.DirectMessagesService; | ||||
| import awais.instagrabber.webservices.MediaService; | ||||
| import awais.instagrabber.webservices.ServiceCallback; | ||||
| import awais.instagrabber.webservices.StoriesService; | ||||
| import retrofit2.Call; | ||||
| import retrofit2.Callback; | ||||
| import retrofit2.Response; | ||||
| import kotlinx.coroutines.Dispatchers; | ||||
| 
 | ||||
| import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_THRESHOLD; | ||||
| import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD; | ||||
| @ -220,40 +217,32 @@ public class StoryViewerFragment extends Fragment { | ||||
|             new AlertDialog.Builder(context) | ||||
|                     .setTitle(R.string.reply_story) | ||||
|                     .setView(input) | ||||
|                     .setPositiveButton(R.string.confirm, (d, w) -> { | ||||
|                         final Call<DirectThread> createThreadRequest = | ||||
|                                 directMessagesService.createThread(Collections.singletonList(currentStory.getUserId()), null); | ||||
|                         createThreadRequest.enqueue(new Callback<DirectThread>() { | ||||
|                             @Override | ||||
|                             public void onResponse(@NonNull final Call<DirectThread> call, @NonNull final Response<DirectThread> response) { | ||||
|                                 if (!response.isSuccessful() || response.body() == null) { | ||||
|                     .setPositiveButton(R.string.confirm, (d, w) -> directMessagesService.createThread( | ||||
|                             Collections.singletonList(currentStory.getUserId()), | ||||
|                             null, | ||||
|                             CoroutineUtilsKt.getContinuation((thread, throwable) -> { | ||||
|                                 if (throwable != null) { | ||||
|                                     Log.e(TAG, "onOptionsItemSelected: ", throwable); | ||||
|                                     Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                     return; | ||||
|                                 } | ||||
|                                 final DirectThread thread = response.body(); | ||||
|                                 directMessagesService.broadcastStoryReply( | ||||
|                                         ThreadIdOrUserIds.of(thread.getThreadId()), | ||||
|                                         input.getText().toString(), | ||||
|                                         currentStory.getStoryMediaId(), | ||||
|                                         String.valueOf(currentStory.getUserId()), | ||||
|                                         CoroutineUtilsKt.getContinuation((directThreadBroadcastResponse, throwable) -> { | ||||
|                                             if (throwable != null) { | ||||
|                                         CoroutineUtilsKt.getContinuation((directThreadBroadcastResponse, throwable1) -> { | ||||
|                                             if (throwable1 != null) { | ||||
|                                                 Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                                 Log.e(TAG, "onFailure: ", throwable); | ||||
|                                                 Log.e(TAG, "onFailure: ", throwable1); | ||||
|                                                 return; | ||||
|                                             } | ||||
|                                             Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); | ||||
|                                         }) | ||||
|                                         }, 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(); | ||||
|                             } | ||||
|                         }); | ||||
|                     }) | ||||
|                             }, Dispatchers.getIO()) | ||||
|                     )) | ||||
|                     .setNegativeButton(R.string.cancel, null) | ||||
|                     .show(); | ||||
|             return true; | ||||
|  | ||||
| @ -84,9 +84,9 @@ import awais.instagrabber.repositories.responses.FriendshipStatus; | ||||
| import awais.instagrabber.repositories.responses.Media; | ||||
| import awais.instagrabber.repositories.responses.User; | ||||
| import awais.instagrabber.repositories.responses.UserProfileContextLink; | ||||
| import awais.instagrabber.repositories.responses.directmessages.DirectThread; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.CoroutineUtilsKt; | ||||
| import awais.instagrabber.utils.DownloadUtils; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| @ -99,9 +99,7 @@ import awais.instagrabber.webservices.MediaService; | ||||
| import awais.instagrabber.webservices.ServiceCallback; | ||||
| import awais.instagrabber.webservices.StoriesService; | ||||
| import awais.instagrabber.webservices.UserService; | ||||
| import retrofit2.Call; | ||||
| import retrofit2.Callback; | ||||
| import retrofit2.Response; | ||||
| import kotlinx.coroutines.Dispatchers; | ||||
| 
 | ||||
| import static androidx.core.content.PermissionChecker.checkSelfPermission; | ||||
| import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; | ||||
| @ -1078,30 +1076,24 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe | ||||
|         if (!disableDm) { | ||||
|             profileDetailsBinding.btnDM.setOnClickListener(v -> { | ||||
|                 profileDetailsBinding.btnDM.setEnabled(false); | ||||
|                 final Call<DirectThread> createThreadRequest = | ||||
|                         directMessagesService.createThread(Collections.singletonList(profileModel.getPk()), null); | ||||
|                 createThreadRequest.enqueue(new Callback<DirectThread>() { | ||||
|                     @Override | ||||
|                     public void onResponse(@NonNull final Call<DirectThread> call, @NonNull final Response<DirectThread> response) { | ||||
|                         profileDetailsBinding.btnDM.setEnabled(true); | ||||
|                         if (!response.isSuccessful() || response.body() == null) { | ||||
|                             Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                             return; | ||||
|                         } | ||||
|                         final InboxManager inboxManager = DirectMessagesManager.INSTANCE.getInboxManager(); | ||||
|                         final DirectThread thread = response.body(); | ||||
|                         if (!inboxManager.containsThread(thread.getThreadId())) { | ||||
|                             thread.setTemp(true); | ||||
|                             inboxManager.addThread(thread, 0); | ||||
|                         } | ||||
|                         fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername()); | ||||
|                     } | ||||
| 
 | ||||
|                     @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(); | ||||
|                     } | ||||
|                 }); | ||||
|                 directMessagesService.createThread( | ||||
|                         Collections.singletonList(profileModel.getPk()), | ||||
|                         null, | ||||
|                         CoroutineUtilsKt.getContinuation((thread, throwable) -> { | ||||
|                             if (throwable != null) { | ||||
|                                 Log.e(TAG, "setupCommonListeners: ", throwable); | ||||
|                                 Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                 return; | ||||
|                             } | ||||
|                             profileDetailsBinding.btnDM.setEnabled(true); | ||||
|                             final InboxManager inboxManager = DirectMessagesManager.INSTANCE.getInboxManager(); | ||||
|                             if (!inboxManager.containsThread(thread.getThreadId())) { | ||||
|                                 thread.setTemp(true); | ||||
|                                 inboxManager.addThread(thread, 0); | ||||
|                             } | ||||
|                             fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername()); | ||||
|                         }, Dispatchers.getIO()) | ||||
|                 ); | ||||
|             }); | ||||
|         } | ||||
|         profileDetailsBinding.mainProfileImage.setOnClickListener(v -> { | ||||
|  | ||||
| @ -22,10 +22,6 @@ import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstanc | ||||
| import kotlinx.coroutines.CoroutineScope | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.launch | ||||
| import retrofit2.Call | ||||
| import retrofit2.Callback | ||||
| import retrofit2.Response | ||||
| import java.io.IOException | ||||
| import java.util.* | ||||
| 
 | ||||
| object DirectMessagesManager { | ||||
| @ -72,43 +68,7 @@ object DirectMessagesManager { | ||||
|         return getInstance(threadId, pending, currentUser, contentResolver, viewerId, csrfToken, deviceUuid) | ||||
|     } | ||||
| 
 | ||||
|     fun createThread( | ||||
|         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) {} | ||||
|         }) | ||||
|     } | ||||
|     suspend fun createThread(userPk: Long): DirectThread = service.createThread(listOf(userPk), null) | ||||
| 
 | ||||
|     fun sendMedia(recipients: Set<RankedRecipient>, mediaId: String, scope: CoroutineScope) { | ||||
|         val resultsCount = intArrayOf(0) | ||||
| @ -136,12 +96,18 @@ object DirectMessagesManager { | ||||
|     ) { | ||||
|         if (recipient.thread == null && recipient.user != null) { | ||||
|             // create thread and forward | ||||
|             createThread(recipient.user.pk) { (threadId) -> | ||||
|                 val threadIdTemp = threadId ?: return@createThread | ||||
|                 sendMedia(threadIdTemp, mediaId, scope) { | ||||
|                     if (refreshInbox) { | ||||
|                         inboxManager.refresh(scope) | ||||
|             scope.launch(Dispatchers.IO) { | ||||
|                 try { | ||||
|                     val (threadId) = createThread(recipient.user.pk) | ||||
|                     val threadIdTemp = threadId ?: return@launch | ||||
|                     sendMedia(threadIdTemp, mediaId, scope) { | ||||
|                         if (refreshInbox) { | ||||
|                             inboxManager.refresh(scope) | ||||
|                         } | ||||
|                         callback?.invoke() | ||||
|                     } | ||||
|                 } catch (e: Exception) { | ||||
|                     Log.e(TAG, "sendMedia: ", e) | ||||
|                     callback?.invoke() | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @ -155,79 +155,23 @@ class ThreadManager private constructor( | ||||
|                 _fetching.postValue(error(e.message, null)) | ||||
|                 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) { | ||||
|             fetchPendingRequests() | ||||
|             fetchPendingRequests(scope) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun fetchPendingRequests() { | ||||
|     fun fetchPendingRequests(scope: CoroutineScope) { | ||||
|         val isGroup = isGroup.value | ||||
|         if (isGroup == null || !isGroup) return | ||||
|         val request = service.participantRequests(threadId, 1, null) | ||||
|         request.enqueue(object : Callback<DirectThreadParticipantRequestsResponse?> { | ||||
|             override fun onResponse( | ||||
|                 call: Call<DirectThreadParticipantRequestsResponse?>, | ||||
|                 response: Response<DirectThreadParticipantRequestsResponse?>, | ||||
|             ) { | ||||
|                 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) | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val response = service.participantRequests(threadId, 1) | ||||
|                 _pendingRequests.postValue(response) | ||||
|             } catch (e: Exception) { | ||||
|                 Log.e(TAG, "fetchPendingRequests: ", e) | ||||
|             } | ||||
| 
 | ||||
|             override fun onFailure(call: Call<DirectThreadParticipantRequestsResponse?>, t: Throwable) { | ||||
|                 Log.e(TAG, "onFailure: ", t) | ||||
|             } | ||||
|         }) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun setThread(thread: DirectThread, skipItems: Boolean) { | ||||
| @ -628,7 +572,7 @@ class ThreadManager private constructor( | ||||
|         return data | ||||
|     } | ||||
| 
 | ||||
|     fun unsend(item: DirectItem): LiveData<Resource<Any?>> { | ||||
|     fun unsend(item: DirectItem, scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         val index = removeItem(item) | ||||
|         val itemId = item.itemId | ||||
| @ -636,45 +580,46 @@ class ThreadManager private constructor( | ||||
|             data.postValue(error("itemId is null", null)) | ||||
|             return data | ||||
|         } | ||||
|         val request = service.deleteItem(threadId, itemId) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse(call: Call<String?>, response: Response<String?>) { | ||||
|                 if (response.isSuccessful) { | ||||
|                     // Log.d(TAG, "onResponse: " + response.body()); | ||||
|                     return | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.deleteItem(threadId, itemId) | ||||
|             } catch (e: Exception) { | ||||
|                 // add the item back if unsuccessful | ||||
|                 addItems(index, listOf(item)) | ||||
|                 if (response.errorBody() != null) { | ||||
|                     handleErrorBody(call, response, data) | ||||
|                     return | ||||
|                 } | ||||
|                 data.postValue(error(R.string.generic_failed_request, item)) | ||||
|                 data.postValue(error(e.message, item)) | ||||
|                 Log.e(TAG, "unsend: ", e) | ||||
|             } | ||||
| 
 | ||||
|             override fun onFailure(call: Call<String?>, t: Throwable) { | ||||
|                 data.postValue(error(t.message, item)) | ||||
|                 Log.e(TAG, "enqueueRequest: onFailure: ", t) | ||||
|             } | ||||
|         }) | ||||
|         } | ||||
|         return data | ||||
|     } | ||||
| 
 | ||||
|     fun forward(recipients: Set<RankedRecipient>, itemToForward: DirectItem) { | ||||
|     fun forward( | ||||
|         recipients: Set<RankedRecipient>, | ||||
|         itemToForward: DirectItem, | ||||
|         scope: CoroutineScope, | ||||
|     ) { | ||||
|         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) { | ||||
|             // create thread and forward | ||||
|             DirectMessagesManager.createThread(recipient.user.pk) { forward(it, itemToForward) } | ||||
|             scope.launch(Dispatchers.IO) { | ||||
|                 // create thread and forward | ||||
|                 val thread = DirectMessagesManager.createThread(recipient.user.pk) | ||||
|                 forward(thread, itemToForward, scope) | ||||
|             } | ||||
|             return | ||||
|         } | ||||
|         if (recipient.thread != null) { | ||||
|             // just forward | ||||
|             val thread = recipient.thread | ||||
|             forward(thread, itemToForward) | ||||
|             forward(thread, itemToForward, scope) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -683,7 +628,11 @@ class ThreadManager private constructor( | ||||
|         _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 forwardItemId = itemToForward.itemId | ||||
|         if (forwardItemId == null) { | ||||
| @ -707,116 +656,48 @@ class ThreadManager private constructor( | ||||
|             data.postValue(error("threadId is null", null)) | ||||
|             return data | ||||
|         } | ||||
|         val request = service.forward(thread.threadId, | ||||
|             itemTypeName, | ||||
|             threadId, | ||||
|             forwardItemId) | ||||
|         request.enqueue(object : Callback<DirectThreadBroadcastResponse?> { | ||||
|             override fun onResponse( | ||||
|                 call: Call<DirectThreadBroadcastResponse?>, | ||||
|                 response: Response<DirectThreadBroadcastResponse?>, | ||||
|             ) { | ||||
|                 if (response.isSuccessful) { | ||||
|                     data.postValue(success(Any())) | ||||
|                     return | ||||
|                 } | ||||
|                 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)) | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.forward( | ||||
|                     thread.threadId, | ||||
|                     itemTypeName, | ||||
|                     threadId, | ||||
|                     forwardItemId | ||||
|                 ) | ||||
|                 data.postValue(success(Any())) | ||||
|             } catch (e: Exception) { | ||||
|                 Log.e(TAG, "forward: ", e) | ||||
|                 data.postValue(error(e.message, null)) | ||||
|             } | ||||
| 
 | ||||
|             override fun onFailure(call: Call<DirectThreadBroadcastResponse?>, t: Throwable) { | ||||
|                 Log.e(TAG, "onFailure: ", t) | ||||
|                 data.postValue(error(t.message, null)) | ||||
|             } | ||||
|         }) | ||||
|         } | ||||
|         return data | ||||
|     } | ||||
| 
 | ||||
|     fun acceptRequest(): LiveData<Resource<Any?>> { | ||||
|     fun acceptRequest(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         val request = service.approveRequest(threadId) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse( | ||||
|                 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 | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.approveRequest(threadId) | ||||
|                 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 | ||||
|     } | ||||
| 
 | ||||
|     fun declineRequest(): LiveData<Resource<Any?>> { | ||||
|     fun declineRequest(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         val request = service.declineRequest(threadId) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse( | ||||
|                 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 | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.declineRequest(threadId) | ||||
|                 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 | ||||
|     } | ||||
| 
 | ||||
| @ -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 addUsersRequest = service.updateTitle(threadId, newTitle.trim { it <= ' ' }) | ||||
|         handleDetailsChangeRequest(data, addUsersRequest) | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val response = service.updateTitle(threadId, newTitle.trim()) | ||||
|                 handleDetailsChangeResponse(data, response) | ||||
|             } catch (e: Exception) { | ||||
|             } | ||||
|         } | ||||
|         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 addUsersRequest = service.addUsers( | ||||
|             threadId, | ||||
|             users.map { obj: User -> obj.pk } | ||||
|         ) | ||||
|         handleDetailsChangeRequest(data, addUsersRequest) | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val response = service.addUsers( | ||||
|                     threadId, | ||||
|                     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 | ||||
|     } | ||||
| 
 | ||||
|     fun removeMember(user: User): LiveData<Resource<Any?>> { | ||||
|     fun removeMember(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         val request = service.removeUsers(threadId, setOf(user.pk)) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse(call: Call<String?>, response: Response<String?>) { | ||||
|                 if (!response.isSuccessful) { | ||||
|                     handleErrorBody(call, response, data) | ||||
|                     return | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.removeUsers(threadId, setOf(user.pk)) | ||||
|                 data.postValue(success(Any())) | ||||
|                 var activeUsers = users.value | ||||
|                 var leftUsersValue = leftUsers.value | ||||
| @ -1147,13 +1036,11 @@ class ThreadManager private constructor( | ||||
|                 } | ||||
|                 val updatedLeftUsers = updatedLeftUsersBuilder.build() | ||||
|                 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 | ||||
|     } | ||||
| 
 | ||||
| @ -1162,70 +1049,60 @@ class ThreadManager private constructor( | ||||
|         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?>>() | ||||
|         if (isAdmin(user)) return data | ||||
|         val request = service.addAdmins(threadId, setOf(user.pk)) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse(call: Call<String?>, response: Response<String?>) { | ||||
|                 if (!response.isSuccessful) { | ||||
|                     handleErrorBody(call, response, data) | ||||
|                     return | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.addAdmins(threadId, setOf(user.pk)) | ||||
|                 val currentAdminIds = adminUserIds.value | ||||
|                 val updatedAdminIds = ImmutableList.builder<Long>() | ||||
|                     .addAll(currentAdminIds ?: emptyList()) | ||||
|                     .add(user.pk) | ||||
|                     .build() | ||||
|                 val currentThread = thread.value ?: return | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.adminUserIds = updatedAdminIds | ||||
|                     inboxManager.setThread(threadId, thread) | ||||
|                 } 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 | ||||
|     } | ||||
| 
 | ||||
|     fun removeAdmin(user: User): LiveData<Resource<Any?>> { | ||||
|     fun removeAdmin(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         if (!isAdmin(user)) return data | ||||
|         val request = service.removeAdmins(threadId, setOf(user.pk)) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse(call: Call<String?>, response: Response<String?>) { | ||||
|                 if (!response.isSuccessful) { | ||||
|                     handleErrorBody(call, response, data) | ||||
|                     return | ||||
|                 } | ||||
|                 val currentAdmins = adminUserIds.value ?: return | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.removeAdmins(threadId, setOf(user.pk)) | ||||
|                 val currentAdmins = adminUserIds.value ?: return@launch | ||||
|                 val updatedAdminUserIds = currentAdmins.filter { userId1: Long -> userId1 != user.pk } | ||||
|                 val currentThread = thread.value ?: return | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.adminUserIds = updatedAdminUserIds | ||||
|                     inboxManager.setThread(threadId, thread) | ||||
|                 } 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 | ||||
|     } | ||||
| 
 | ||||
|     fun mute(): LiveData<Resource<Any?>> { | ||||
|     fun mute(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val muted = isMuted.value | ||||
| @ -1233,33 +1110,27 @@ class ThreadManager private constructor( | ||||
|             data.postValue(success(Any())) | ||||
|             return data | ||||
|         } | ||||
|         val request = service.mute(threadId) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse(call: Call<String?>, response: Response<String?>) { | ||||
|                 if (!response.isSuccessful) { | ||||
|                     handleErrorBody(call, response, data) | ||||
|                     return | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.mute(threadId) | ||||
|                 data.postValue(success(Any())) | ||||
|                 val currentThread = thread.value ?: return | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.muted = true | ||||
|                     inboxManager.setThread(threadId, thread) | ||||
|                 } 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 | ||||
|     } | ||||
| 
 | ||||
|     fun unmute(): LiveData<Resource<Any?>> { | ||||
|     fun unmute(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val muted = isMuted.value | ||||
| @ -1267,33 +1138,27 @@ class ThreadManager private constructor( | ||||
|             data.postValue(success(Any())) | ||||
|             return data | ||||
|         } | ||||
|         val request = service.unmute(threadId) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse(call: Call<String?>, response: Response<String?>) { | ||||
|                 if (!response.isSuccessful) { | ||||
|                     handleErrorBody(call, response, data) | ||||
|                     return | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.unmute(threadId) | ||||
|                 data.postValue(success(Any())) | ||||
|                 val currentThread = thread.value ?: return | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.muted = false | ||||
|                     inboxManager.setThread(threadId, thread) | ||||
|                 } 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 | ||||
|     } | ||||
| 
 | ||||
|     fun muteMentions(): LiveData<Resource<Any?>> { | ||||
|     fun muteMentions(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val mentionsMuted = isMentionsMuted.value | ||||
| @ -1301,33 +1166,27 @@ class ThreadManager private constructor( | ||||
|             data.postValue(success(Any())) | ||||
|             return data | ||||
|         } | ||||
|         val request = service.muteMentions(threadId) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse(call: Call<String?>, response: Response<String?>) { | ||||
|                 if (!response.isSuccessful) { | ||||
|                     handleErrorBody(call, response, data) | ||||
|                     return | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.muteMentions(threadId) | ||||
|                 data.postValue(success(Any())) | ||||
|                 val currentThread = thread.value ?: return | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.mentionsMuted = true | ||||
|                     inboxManager.setThread(threadId, thread) | ||||
|                 } 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 | ||||
|     } | ||||
| 
 | ||||
|     fun unmuteMentions(): LiveData<Resource<Any?>> { | ||||
|     fun unmuteMentions(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val mentionsMuted = isMentionsMuted.value | ||||
| @ -1335,29 +1194,23 @@ class ThreadManager private constructor( | ||||
|             data.postValue(success(Any())) | ||||
|             return data | ||||
|         } | ||||
|         val request = service.unmuteMentions(threadId) | ||||
|         request.enqueue(object : Callback<String?> { | ||||
|             override fun onResponse(call: Call<String?>, response: Response<String?>) { | ||||
|                 if (!response.isSuccessful) { | ||||
|                     handleErrorBody(call, response, data) | ||||
|                     return | ||||
|                 } | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 service.unmuteMentions(threadId) | ||||
|                 data.postValue(success(Any())) | ||||
|                 val currentThread = thread.value ?: return | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.mentionsMuted = false | ||||
|                     inboxManager.setThread(threadId, thread) | ||||
|                 } 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 | ||||
|     } | ||||
| 
 | ||||
| @ -1421,33 +1274,41 @@ class ThreadManager private constructor( | ||||
|         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?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val approveUsersRequest = service.approveParticipantRequests( | ||||
|             threadId, | ||||
|             users.map { obj: User -> obj.pk } | ||||
|         ) | ||||
|         handleDetailsChangeRequest(data, approveUsersRequest, object : OnSuccessAction { | ||||
|             override fun onSuccess() { | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val response = service.approveParticipantRequests( | ||||
|                     threadId, | ||||
|                     users.map { obj: User -> obj.pk } | ||||
|                 ) | ||||
|                 handleDetailsChangeResponse(data, response) | ||||
|                 pendingUserApproveDenySuccessAction(users) | ||||
|             } catch (e: Exception) { | ||||
|                 Log.e(TAG, "approveUsers: ", e) | ||||
|                 data.postValue(error(e.message, null)) | ||||
|             } | ||||
|         }) | ||||
|         } | ||||
|         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?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val approveUsersRequest = service.declineParticipantRequests( | ||||
|             threadId, | ||||
|             users.map { obj: User -> obj.pk } | ||||
|         ) | ||||
|         handleDetailsChangeRequest(data, approveUsersRequest, object : OnSuccessAction { | ||||
|             override fun onSuccess() { | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val response = service.declineParticipantRequests( | ||||
|                     threadId, | ||||
|                     users.map { obj: User -> obj.pk } | ||||
|                 ) | ||||
|                 handleDetailsChangeResponse(data, response) | ||||
|                 pendingUserApproveDenySuccessAction(users) | ||||
|             } catch (e: Exception) { | ||||
|                 Log.e(TAG, "denyUsers: ", e) | ||||
|                 data.postValue(error(e.message, null)) | ||||
|             } | ||||
|         }) | ||||
|         } | ||||
|         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?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val approvalRequiredToJoin = isApprovalRequiredToJoin.value | ||||
| @ -1475,10 +1336,11 @@ class ThreadManager private constructor( | ||||
|             data.postValue(success(Any())) | ||||
|             return data | ||||
|         } | ||||
|         val request = service.approvalRequired(threadId) | ||||
|         handleDetailsChangeRequest(data, request, object : OnSuccessAction { | ||||
|             override fun onSuccess() { | ||||
|                 val currentThread = thread.value ?: return | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val response = service.approvalRequired(threadId) | ||||
|                 handleDetailsChangeResponse(data, response) | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.approvalRequiredForNewMembers = true | ||||
| @ -1486,12 +1348,15 @@ class ThreadManager private constructor( | ||||
|                 } catch (e: CloneNotSupportedException) { | ||||
|                     Log.e(TAG, "onResponse: ", e) | ||||
|                 } | ||||
|             } catch (e: Exception) { | ||||
|                 Log.e(TAG, "approvalRequired: ", e) | ||||
|                 data.postValue(error(e.message, null)) | ||||
|             } | ||||
|         }) | ||||
|         } | ||||
|         return data | ||||
|     } | ||||
| 
 | ||||
|     fun approvalNotRequired(): LiveData<Resource<Any?>> { | ||||
|     fun approvalNotRequired(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val approvalRequiredToJoin = isApprovalRequiredToJoin.value | ||||
| @ -1499,10 +1364,11 @@ class ThreadManager private constructor( | ||||
|             data.postValue(success(Any())) | ||||
|             return data | ||||
|         } | ||||
|         val request = service.approvalNotRequired(threadId) | ||||
|         handleDetailsChangeRequest(data, request, object : OnSuccessAction { | ||||
|             override fun onSuccess() { | ||||
|                 val currentThread = thread.value ?: return | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val request = service.approvalNotRequired(threadId) | ||||
|                 handleDetailsChangeResponse(data, request) | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.approvalRequiredForNewMembers = false | ||||
| @ -1510,26 +1376,37 @@ class ThreadManager private constructor( | ||||
|                 } catch (e: CloneNotSupportedException) { | ||||
|                     Log.e(TAG, "onResponse: ", e) | ||||
|                 } | ||||
|             } catch (e: Exception) { | ||||
|                 Log.e(TAG, "approvalNotRequired: ", e) | ||||
|                 data.postValue(error(e.message, null)) | ||||
|             } | ||||
|         }) | ||||
|         } | ||||
|         return data | ||||
|     } | ||||
| 
 | ||||
|     fun leave(): LiveData<Resource<Any?>> { | ||||
|     fun leave(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val request = service.leave(threadId) | ||||
|         handleDetailsChangeRequest(data, request) | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             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 | ||||
|     } | ||||
| 
 | ||||
|     fun end(): LiveData<Resource<Any?>> { | ||||
|     fun end(scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val request = service.end(threadId) | ||||
|         handleDetailsChangeRequest(data, request, object : OnSuccessAction { | ||||
|             override fun onSuccess() { | ||||
|                 val currentThread = thread.value ?: return | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val request = service.end(threadId) | ||||
|                 handleDetailsChangeResponse(data, request) | ||||
|                 val currentThread = thread.value ?: return@launch | ||||
|                 try { | ||||
|                     val thread = currentThread.clone() as DirectThread | ||||
|                     thread.inputMode = 1 | ||||
| @ -1537,95 +1414,57 @@ class ThreadManager private constructor( | ||||
|                 } catch (e: CloneNotSupportedException) { | ||||
|                     Log.e(TAG, "onResponse: ", e) | ||||
|                 } | ||||
|             } catch (e: Exception) { | ||||
|                 Log.e(TAG, "leave: ", e) | ||||
|                 data.postValue(error(e.message, null)) | ||||
|             } | ||||
|         }) | ||||
|         } | ||||
|         return data | ||||
|     } | ||||
| 
 | ||||
|     private fun handleDetailsChangeRequest( | ||||
|     private fun handleDetailsChangeResponse( | ||||
|         data: MutableLiveData<Resource<Any?>>, | ||||
|         request: Call<DirectThreadDetailsChangeResponse?>, | ||||
|         action: OnSuccessAction? = null, | ||||
|         response: DirectThreadDetailsChangeResponse, | ||||
|     ) { | ||||
|         request.enqueue(object : Callback<DirectThreadDetailsChangeResponse?> { | ||||
|             override fun onResponse( | ||||
|                 call: Call<DirectThreadDetailsChangeResponse?>, | ||||
|                 response: Response<DirectThreadDetailsChangeResponse?>, | ||||
|             ) { | ||||
|                 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)) | ||||
|             } | ||||
|         }) | ||||
|         data.postValue(success(Any())) | ||||
|         val thread = response.thread | ||||
|         if (thread != null) { | ||||
|             setThread(thread, true) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun markAsSeen(directItem: DirectItem, scope: CoroutineScope): LiveData<Resource<Any?>> { | ||||
|     fun markAsSeen( | ||||
|         directItem: DirectItem, | ||||
|         scope: CoroutineScope, | ||||
|     ): LiveData<Resource<Any?>> { | ||||
|         val data = MutableLiveData<Resource<Any?>>() | ||||
|         data.postValue(loading(null)) | ||||
|         val request = service.markAsSeen(threadId, directItem) | ||||
|         if (request == null) { | ||||
|             data.postValue(error("request was null", null)) | ||||
|             return data | ||||
|         } | ||||
|         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) { | ||||
|         scope.launch(Dispatchers.IO) { | ||||
|             try { | ||||
|                 val response = service.markAsSeen(threadId, directItem) | ||||
|                 if (response == null) { | ||||
|                     data.postValue(error(R.string.generic_null_response, null)) | ||||
|                     return | ||||
|                     return@launch | ||||
|                 } | ||||
|                 if (currentUser == null) return@launch | ||||
|                 inboxManager.fetchUnseenCount(scope) | ||||
|                 val payload = seenResponse.payload ?: return | ||||
|                 val payload = response.payload ?: return@launch | ||||
|                 val timestamp = payload.timestamp | ||||
|                 val thread = thread.value ?: return | ||||
|                 val thread = thread.value ?: return@launch | ||||
|                 val currentLastSeenAt = thread.lastSeenAt | ||||
|                 val lastSeenAt = if (currentLastSeenAt == null) HashMap() else HashMap(currentLastSeenAt) | ||||
|                 lastSeenAt[currentUser.pk] = DirectThreadLastSeenAt(timestamp, directItem.itemId) | ||||
|                 thread.lastSeenAt = lastSeenAt | ||||
|                 setThread(thread, true) | ||||
|                 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 | ||||
|     } | ||||
| 
 | ||||
|     private interface OnSuccessAction { | ||||
|         fun onSuccess() | ||||
|     } | ||||
| 
 | ||||
|     companion object { | ||||
|         private val TAG = ThreadManager::class.java.simpleName | ||||
|         private val LOCK = Any() | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| package awais.instagrabber.repositories | ||||
| 
 | ||||
| import awais.instagrabber.repositories.responses.directmessages.* | ||||
| import retrofit2.Call | ||||
| import retrofit2.http.* | ||||
| 
 | ||||
| interface DirectMessagesRepository { | ||||
| @ -29,154 +28,154 @@ interface DirectMessagesRepository { | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/add_user/") | ||||
|     fun addUsers( | ||||
|     suspend fun addUsers( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> | ||||
|     ): DirectThreadDetailsChangeResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/remove_users/") | ||||
|     fun removeUsers( | ||||
|     suspend fun removeUsers( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/update_title/") | ||||
|     fun updateTitle( | ||||
|     suspend fun updateTitle( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> | ||||
|     ): DirectThreadDetailsChangeResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/add_admins/") | ||||
|     fun addAdmins( | ||||
|     suspend fun addAdmins( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/remove_admins/") | ||||
|     fun removeAdmins( | ||||
|     suspend fun removeAdmins( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/items/{itemId}/delete/") | ||||
|     fun deleteItem( | ||||
|     suspend fun deleteItem( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @Path("itemId") itemId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @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 | ||||
|     @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 | ||||
|     @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 | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/mute/") | ||||
|     fun mute( | ||||
|     suspend fun mute( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/unmute/") | ||||
|     fun unmute( | ||||
|     suspend fun unmute( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/mute_mentions/") | ||||
|     fun muteMentions( | ||||
|     suspend fun muteMentions( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String?>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/unmute_mentions/") | ||||
|     fun unmuteMentions( | ||||
|     suspend fun unmuteMentions( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @GET("/api/v1/direct_v2/threads/{threadId}/participant_requests/") | ||||
|     fun participantRequests( | ||||
|     suspend fun participantRequests( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @Query("page_size") pageSize: Int, | ||||
|         @Query("cursor") cursor: String?, | ||||
|     ): Call<DirectThreadParticipantRequestsResponse?> | ||||
|     ): DirectThreadParticipantRequestsResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/approve_participant_requests/") | ||||
|     fun approveParticipantRequests( | ||||
|     suspend fun approveParticipantRequests( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> | ||||
|     ): DirectThreadDetailsChangeResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/deny_participant_requests/") | ||||
|     fun declineParticipantRequests( | ||||
|     suspend fun declineParticipantRequests( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> | ||||
|     ): DirectThreadDetailsChangeResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/approval_required_for_new_members/") | ||||
|     fun approvalRequired( | ||||
|     suspend fun approvalRequired( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> | ||||
|     ): DirectThreadDetailsChangeResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/approval_not_required_for_new_members/") | ||||
|     fun approvalNotRequired( | ||||
|     suspend fun approvalNotRequired( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> | ||||
|     ): DirectThreadDetailsChangeResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/leave/") | ||||
|     fun leave( | ||||
|     suspend fun leave( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> | ||||
|     ): DirectThreadDetailsChangeResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/remove_all_users/") | ||||
|     fun end( | ||||
|     suspend fun end( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> | ||||
|     ): DirectThreadDetailsChangeResponse | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/approve/") | ||||
|     fun approveRequest( | ||||
|     suspend fun approveRequest( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/decline/") | ||||
|     fun declineRequest( | ||||
|     suspend fun declineRequest( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<String?> | ||||
|     ): String | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/direct_v2/threads/{threadId}/items/{itemId}/seen/") | ||||
|     fun markItemSeen( | ||||
|     suspend fun markItemSeen( | ||||
|         @Path("threadId") threadId: String, | ||||
|         @Path("itemId") itemId: String, | ||||
|         @FieldMap form: Map<String, String>, | ||||
|     ): Call<DirectItemSeenResponse?> | ||||
|     ): DirectItemSeenResponse | ||||
| } | ||||
| @ -83,23 +83,23 @@ class DirectSettingsViewModel( | ||||
| 
 | ||||
|     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) | ||||
| 
 | ||||
| @ -109,17 +109,17 @@ class DirectSettingsViewModel( | ||||
| 
 | ||||
|     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>> { | ||||
|         val options: ArrayList<Option<String>> = ArrayList() | ||||
|  | ||||
| @ -144,7 +144,7 @@ class DirectThreadViewModel( | ||||
|     } | ||||
| 
 | ||||
|     fun unsend(item: DirectItem): LiveData<Resource<Any?>> { | ||||
|         return threadManager.unsend(item) | ||||
|         return threadManager.unsend(item, viewModelScope) | ||||
|     } | ||||
| 
 | ||||
|     fun sendAnimatedMedia(giphyGif: GiphyGif): LiveData<Resource<Any?>> { | ||||
| @ -161,11 +161,11 @@ class DirectThreadViewModel( | ||||
|     } | ||||
| 
 | ||||
|     fun forward(recipients: Set<RankedRecipient>, itemToForward: DirectItem) { | ||||
|         threadManager.forward(recipients, itemToForward) | ||||
|         threadManager.forward(recipients, itemToForward, viewModelScope) | ||||
|     } | ||||
| 
 | ||||
|     fun forward(recipient: RankedRecipient, itemToForward: DirectItem) { | ||||
|         threadManager.forward(recipient, itemToForward) | ||||
|         threadManager.forward(recipient, itemToForward, viewModelScope) | ||||
|     } | ||||
| 
 | ||||
|     fun setReplyToItem(item: DirectItem?) { | ||||
| @ -174,11 +174,11 @@ class DirectThreadViewModel( | ||||
|     } | ||||
| 
 | ||||
|     fun acceptRequest(): LiveData<Resource<Any?>> { | ||||
|         return threadManager.acceptRequest() | ||||
|         return threadManager.acceptRequest(viewModelScope) | ||||
|     } | ||||
| 
 | ||||
|     fun declineRequest(): LiveData<Resource<Any?>> { | ||||
|         return threadManager.declineRequest() | ||||
|         return threadManager.declineRequest(viewModelScope) | ||||
|     } | ||||
| 
 | ||||
|     fun markAsSeen(): LiveData<Resource<Any?>> { | ||||
| @ -225,6 +225,6 @@ class DirectThreadViewModel( | ||||
|         val csrfToken = getCsrfTokenFromCookie(cookie) | ||||
|         require(!csrfToken.isNullOrBlank() && viewerId != 0L && deviceUuid.isNotBlank()) { "User is not logged in!" } | ||||
|         threadManager = DirectMessagesManager.getThreadManager(threadId, pending, currentUser, contentResolver) | ||||
|         threadManager.fetchPendingRequests() | ||||
|         threadManager.fetchPendingRequests(viewModelScope) | ||||
|     } | ||||
| } | ||||
| @ -26,14 +26,15 @@ import awais.instagrabber.models.Resource; | ||||
| import awais.instagrabber.repositories.responses.User; | ||||
| import awais.instagrabber.repositories.responses.UserSearchResponse; | ||||
| import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; | ||||
| import awais.instagrabber.repositories.responses.directmessages.RankedRecipientsResponse; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.CoroutineUtilsKt; | ||||
| import awais.instagrabber.utils.Debouncer; | ||||
| import awais.instagrabber.utils.RankedRecipientsCache; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| import awais.instagrabber.webservices.DirectMessagesService; | ||||
| import awais.instagrabber.webservices.UserService; | ||||
| import kotlinx.coroutines.Dispatchers; | ||||
| import okhttp3.ResponseBody; | ||||
| import retrofit2.Call; | ||||
| import retrofit2.Callback; | ||||
| @ -95,37 +96,23 @@ public class UserSearchViewModel extends ViewModel { | ||||
| 
 | ||||
|     private void updateRankedRecipientCache() { | ||||
|         rankedRecipientsCache.setUpdateInitiated(true); | ||||
|         final Call<RankedRecipientsResponse> request = directMessagesService.rankedRecipients(null, null, null); | ||||
|         request.enqueue(new Callback<RankedRecipientsResponse>() { | ||||
|             @Override | ||||
|             public void onResponse(@NonNull final Call<RankedRecipientsResponse> call, @NonNull final Response<RankedRecipientsResponse> response) { | ||||
|                 if (!response.isSuccessful()) { | ||||
|                     handleErrorResponse(response, false); | ||||
|                     rankedRecipientsCache.setFailed(true); | ||||
|         directMessagesService.rankedRecipients( | ||||
|                 null, | ||||
|                 null, | ||||
|                 null, | ||||
|                 CoroutineUtilsKt.getContinuation((response, throwable) -> { | ||||
|                     if (throwable != null) { | ||||
|                         Log.e(TAG, "updateRankedRecipientCache: ", throwable); | ||||
|                         rankedRecipientsCache.setUpdateInitiated(false); | ||||
|                         rankedRecipientsCache.setFailed(true); | ||||
|                         continueSearchIfRequired(); | ||||
|                         return; | ||||
|                     } | ||||
|                     rankedRecipientsCache.setResponse(response); | ||||
|                     rankedRecipientsCache.setUpdateInitiated(false); | ||||
|                     continueSearchIfRequired(); | ||||
|                     return; | ||||
|                 } | ||||
|                 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(); | ||||
|             } | ||||
|         }); | ||||
|                 }, Dispatchers.getIO()) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     private void continueSearchIfRequired() { | ||||
| @ -189,39 +176,22 @@ public class UserSearchViewModel extends ViewModel { | ||||
|     } | ||||
| 
 | ||||
|     private void rankedRecipientSearch() { | ||||
|         searchRequest = directMessagesService.rankedRecipients(searchMode.getName(), showGroups, currentQuery); | ||||
|         //noinspection unchecked | ||||
|         handleRankedRecipientRequest((Call<RankedRecipientsResponse>) searchRequest); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private void handleRankedRecipientRequest(@NonNull final Call<RankedRecipientsResponse> request) { | ||||
|         request.enqueue(new Callback<RankedRecipientsResponse>() { | ||||
|             @Override | ||||
|             public void onResponse(@NonNull final Call<RankedRecipientsResponse> call, @NonNull final Response<RankedRecipientsResponse> response) { | ||||
|                 if (!response.isSuccessful()) { | ||||
|                     handleErrorResponse(response, true); | ||||
|                     searchRequest = null; | ||||
|                     return; | ||||
|                 } | ||||
|                 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; | ||||
|             } | ||||
|         }); | ||||
|         directMessagesService.rankedRecipients( | ||||
|                 searchMode.getName(), | ||||
|                 showGroups, | ||||
|                 currentQuery, | ||||
|                 CoroutineUtilsKt.getContinuation((response, throwable) -> { | ||||
|                     if (throwable != null) { | ||||
|                         Log.e(TAG, "rankedRecipientSearch: ", throwable); | ||||
|                         recipients.postValue(Resource.error(throwable.getMessage(), getCachedRecipients())); | ||||
|                         return; | ||||
|                     } | ||||
|                     final List<RankedRecipient> list = response.getRankedRecipients(); | ||||
|                     if (list != null) { | ||||
|                         recipients.postValue(Resource.success(mergeResponseWithCache(list))); | ||||
|                     } | ||||
|                 }, Dispatchers.getIO()) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     private void handleRequest(@NonNull final Call<UserSearchResponse> request) { | ||||
|  | ||||
| @ -8,7 +8,6 @@ import awais.instagrabber.utils.TextUtils.extractUrls | ||||
| import awais.instagrabber.utils.TextUtils.isEmpty | ||||
| import awais.instagrabber.utils.Utils | ||||
| import org.json.JSONArray | ||||
| import retrofit2.Call | ||||
| import java.util.* | ||||
| 
 | ||||
| class DirectMessagesService private constructor( | ||||
| @ -183,10 +182,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.broadcast(broadcastOptions.itemType.value, signedForm) | ||||
|     } | ||||
| 
 | ||||
|     fun addUsers( | ||||
|     suspend fun addUsers( | ||||
|         threadId: String, | ||||
|         userIds: Collection<Long>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> { | ||||
|     ): DirectThreadDetailsChangeResponse { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -195,10 +194,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.addUsers(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun removeUsers( | ||||
|     suspend fun removeUsers( | ||||
|         threadId: String, | ||||
|         userIds: Collection<Long>, | ||||
|     ): Call<String?> { | ||||
|     ): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -207,10 +206,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.removeUsers(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun updateTitle( | ||||
|     suspend fun updateTitle( | ||||
|         threadId: String, | ||||
|         title: String, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> { | ||||
|     ): DirectThreadDetailsChangeResponse { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -219,10 +218,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.updateTitle(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun addAdmins( | ||||
|     suspend fun addAdmins( | ||||
|         threadId: String, | ||||
|         userIds: Collection<Long>, | ||||
|     ): Call<String?> { | ||||
|     ): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -231,10 +230,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.addAdmins(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun removeAdmins( | ||||
|     suspend fun removeAdmins( | ||||
|         threadId: String, | ||||
|         userIds: Collection<Long>, | ||||
|     ): Call<String?> { | ||||
|     ): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -243,10 +242,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.removeAdmins(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun deleteItem( | ||||
|     suspend fun deleteItem( | ||||
|         threadId: String, | ||||
|         itemId: String, | ||||
|     ): Call<String?> { | ||||
|     ): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -254,11 +253,11 @@ class DirectMessagesService private constructor( | ||||
|         return repository.deleteItem(threadId, itemId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun rankedRecipients( | ||||
|     suspend fun rankedRecipients( | ||||
|         mode: String?, | ||||
|         showThreads: Boolean?, | ||||
|         query: String?, | ||||
|     ): Call<RankedRecipientsResponse?> { | ||||
|     ): RankedRecipientsResponse { | ||||
|         // String correctedMode = mode; | ||||
|         // if (TextUtils.isEmpty(mode) || (!mode.equals("raven") && !mode.equals("reshare"))) { | ||||
|         //     correctedMode = "raven"; | ||||
| @ -276,12 +275,12 @@ class DirectMessagesService private constructor( | ||||
|         return repository.rankedRecipients(queryMap) | ||||
|     } | ||||
| 
 | ||||
|     fun forward( | ||||
|     suspend fun forward( | ||||
|         toThreadId: String, | ||||
|         itemType: String, | ||||
|         fromThreadId: String, | ||||
|         itemId: String, | ||||
|     ): Call<DirectThreadBroadcastResponse?> { | ||||
|     ): DirectThreadBroadcastResponse { | ||||
|         val form = mapOf( | ||||
|             "action" to "forward_item", | ||||
|             "thread_id" to toThreadId, | ||||
| @ -292,10 +291,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.forward(form) | ||||
|     } | ||||
| 
 | ||||
|     fun createThread( | ||||
|     suspend fun createThread( | ||||
|         userIds: List<Long>, | ||||
|         threadTitle: String?, | ||||
|     ): Call<DirectThread?> { | ||||
|     ): DirectThread { | ||||
|         val userIdStringList = userIds.map { it.toString() } | ||||
|         val form = mutableMapOf<String, Any>( | ||||
|             "_csrftoken" to csrfToken, | ||||
| @ -310,7 +309,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.createThread(signedForm) | ||||
|     } | ||||
| 
 | ||||
|     fun mute(threadId: String): Call<String?> { | ||||
|     suspend fun mute(threadId: String): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid | ||||
| @ -318,7 +317,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.mute(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun unmute(threadId: String): Call<String?> { | ||||
|     suspend fun unmute(threadId: String): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -326,7 +325,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.unmute(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun muteMentions(threadId: String): Call<String?> { | ||||
|     suspend fun muteMentions(threadId: String): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -334,7 +333,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.muteMentions(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun unmuteMentions(threadId: String): Call<String?> { | ||||
|     suspend fun unmuteMentions(threadId: String): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -342,18 +341,18 @@ class DirectMessagesService private constructor( | ||||
|         return repository.unmuteMentions(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun participantRequests( | ||||
|     suspend fun participantRequests( | ||||
|         threadId: String, | ||||
|         pageSize: Int, | ||||
|         cursor: String?, | ||||
|     ): Call<DirectThreadParticipantRequestsResponse?> { | ||||
|         cursor: String? = null, | ||||
|     ): DirectThreadParticipantRequestsResponse { | ||||
|         return repository.participantRequests(threadId, pageSize, cursor) | ||||
|     } | ||||
| 
 | ||||
|     fun approveParticipantRequests( | ||||
|     suspend fun approveParticipantRequests( | ||||
|         threadId: String, | ||||
|         userIds: List<Long>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> { | ||||
|     ): DirectThreadDetailsChangeResponse { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -363,10 +362,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.approveParticipantRequests(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun declineParticipantRequests( | ||||
|     suspend fun declineParticipantRequests( | ||||
|         threadId: String, | ||||
|         userIds: List<Long>, | ||||
|     ): Call<DirectThreadDetailsChangeResponse?> { | ||||
|     ): DirectThreadDetailsChangeResponse { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -375,7 +374,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.declineParticipantRequests(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun approvalRequired(threadId: String): Call<DirectThreadDetailsChangeResponse?> { | ||||
|     suspend fun approvalRequired(threadId: String): DirectThreadDetailsChangeResponse { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -383,7 +382,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.approvalRequired(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun approvalNotRequired(threadId: String): Call<DirectThreadDetailsChangeResponse?> { | ||||
|     suspend fun approvalNotRequired(threadId: String): DirectThreadDetailsChangeResponse { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -391,7 +390,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.approvalNotRequired(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun leave(threadId: String): Call<DirectThreadDetailsChangeResponse?> { | ||||
|     suspend fun leave(threadId: String): DirectThreadDetailsChangeResponse { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -399,7 +398,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.leave(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun end(threadId: String): Call<DirectThreadDetailsChangeResponse?> { | ||||
|     suspend fun end(threadId: String): DirectThreadDetailsChangeResponse { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -424,7 +423,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.fetchPendingInbox(queryMap) | ||||
|     } | ||||
| 
 | ||||
|     fun approveRequest(threadId: String): Call<String?> { | ||||
|     suspend fun approveRequest(threadId: String): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -432,7 +431,7 @@ class DirectMessagesService private constructor( | ||||
|         return repository.approveRequest(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun declineRequest(threadId: String): Call<String?> { | ||||
|     suspend fun declineRequest(threadId: String): String { | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|             "_uuid" to deviceUuid, | ||||
| @ -440,10 +439,10 @@ class DirectMessagesService private constructor( | ||||
|         return repository.declineRequest(threadId, form) | ||||
|     } | ||||
| 
 | ||||
|     fun markAsSeen( | ||||
|     suspend fun markAsSeen( | ||||
|         threadId: String, | ||||
|         directItem: DirectItem, | ||||
|     ): Call<DirectItemSeenResponse?>? { | ||||
|     ): DirectItemSeenResponse? { | ||||
|         val itemId = directItem.itemId ?: return null | ||||
|         val form = mapOf( | ||||
|             "_csrftoken" to csrfToken, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user