mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 06:37:30 +00:00
More suspend funs
This commit is contained in:
parent
538a1406a6
commit
741a997424
@ -88,9 +88,9 @@ 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.repositories.responses.directmessages.DirectThreadBroadcastResponse;
|
||||
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;
|
||||
@ -231,32 +231,21 @@ public class StoryViewerFragment extends Fragment {
|
||||
return;
|
||||
}
|
||||
final DirectThread thread = response.body();
|
||||
final Call<DirectThreadBroadcastResponse> request = directMessagesService.broadcastStoryReply(
|
||||
directMessagesService.broadcastStoryReply(
|
||||
ThreadIdOrUserIds.of(thread.getThreadId()),
|
||||
input.getText().toString(),
|
||||
currentStory.getStoryMediaId(),
|
||||
String.valueOf(currentStory.getUserId())
|
||||
);
|
||||
request.enqueue(new Callback<DirectThreadBroadcastResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<DirectThreadBroadcastResponse> call,
|
||||
@NonNull final Response<DirectThreadBroadcastResponse> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
String.valueOf(currentStory.getUserId()),
|
||||
CoroutineUtilsKt.getContinuation((directThreadBroadcastResponse, throwable) -> {
|
||||
if (throwable != null) {
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
Log.e(TAG, "onFailure: ", throwable);
|
||||
return;
|
||||
}
|
||||
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<DirectThreadBroadcastResponse> call, @NonNull final Throwable t) {
|
||||
try {
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
Log.e(TAG, "onFailure: ", t);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,7 +12,6 @@ import awais.instagrabber.models.Resource.Companion.success
|
||||
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds.Companion.of
|
||||
import awais.instagrabber.repositories.responses.User
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse
|
||||
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient
|
||||
import awais.instagrabber.utils.Constants
|
||||
import awais.instagrabber.utils.Utils
|
||||
@ -21,6 +20,8 @@ import awais.instagrabber.utils.getUserIdFromCookie
|
||||
import awais.instagrabber.webservices.DirectMessagesService
|
||||
import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
@ -137,7 +138,7 @@ object DirectMessagesManager {
|
||||
// create thread and forward
|
||||
createThread(recipient.user.pk) { (threadId) ->
|
||||
val threadIdTemp = threadId ?: return@createThread
|
||||
sendMedia(threadIdTemp, mediaId) {
|
||||
sendMedia(threadIdTemp, mediaId, scope) {
|
||||
if (refreshInbox) {
|
||||
inboxManager.refresh(scope)
|
||||
}
|
||||
@ -149,7 +150,7 @@ object DirectMessagesManager {
|
||||
// just forward
|
||||
val thread = recipient.thread
|
||||
val threadId = thread.threadId ?: return
|
||||
sendMedia(threadId, mediaId) {
|
||||
sendMedia(threadId, mediaId, scope) {
|
||||
if (refreshInbox) {
|
||||
inboxManager.refresh(scope)
|
||||
}
|
||||
@ -160,55 +161,26 @@ object DirectMessagesManager {
|
||||
private fun sendMedia(
|
||||
threadId: String,
|
||||
mediaId: String,
|
||||
scope: CoroutineScope,
|
||||
callback: (() -> Unit)?,
|
||||
): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
data.postValue(loading(null))
|
||||
val request = service.broadcastMediaShare(
|
||||
UUID.randomUUID().toString(),
|
||||
of(threadId),
|
||||
mediaId
|
||||
)
|
||||
request.enqueue(object : Callback<DirectThreadBroadcastResponse?> {
|
||||
override fun onResponse(
|
||||
call: Call<DirectThreadBroadcastResponse?>,
|
||||
response: Response<DirectThreadBroadcastResponse?>,
|
||||
) {
|
||||
if (response.isSuccessful) {
|
||||
data.postValue(success(Any()))
|
||||
callback?.invoke()
|
||||
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))
|
||||
}
|
||||
callback?.invoke()
|
||||
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.broadcastMediaShare(
|
||||
UUID.randomUUID().toString(),
|
||||
of(threadId),
|
||||
mediaId
|
||||
)
|
||||
data.postValue(success(Any()))
|
||||
callback?.invoke()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "sendMedia: ", e)
|
||||
data.postValue(error(e.message, null))
|
||||
callback?.invoke()
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<DirectThreadBroadcastResponse?>, t: Throwable) {
|
||||
Log.e(TAG, "onFailure: ", t)
|
||||
data.postValue(error(t.message, null))
|
||||
callback?.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
|
@ -21,8 +21,6 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@ -66,49 +64,23 @@ class InboxManager private constructor(private val pending: Boolean) {
|
||||
inbox.postValue(error(e.message, currentDirectInbox))
|
||||
hasOlder = false
|
||||
}
|
||||
// inboxRequest?.enqueue(object : Callback<DirectInboxResponse?> {
|
||||
// override fun onResponse(call: Call<DirectInboxResponse?>, response: Response<DirectInboxResponse?>) {
|
||||
// val body = response.body()
|
||||
// if (body == null) {
|
||||
// Log.e(TAG, "parseInboxResponse: Response is null")
|
||||
// inbox.postValue(error(R.string.generic_null_response, currentDirectInbox))
|
||||
// hasOlder = false
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// override fun onFailure(call: Call<DirectInboxResponse?>, t: Throwable) {
|
||||
// Log.e(TAG, "Failed fetching dm inbox", t)
|
||||
// inbox.postValue(error(t.message, currentDirectInbox))
|
||||
// hasOlder = false
|
||||
// }
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchUnseenCount() {
|
||||
fun fetchUnseenCount(scope: CoroutineScope) {
|
||||
val unseenCountResource = unseenCount.value
|
||||
if (unseenCountResource != null && unseenCountResource.status === Resource.Status.LOADING) return
|
||||
stopCurrentUnseenCountRequest()
|
||||
unseenCount.postValue(loading(currentUnseenCount))
|
||||
unseenCountRequest = service.fetchUnseenCount()
|
||||
unseenCountRequest?.enqueue(object : Callback<DirectBadgeCount?> {
|
||||
override fun onResponse(call: Call<DirectBadgeCount?>, response: Response<DirectBadgeCount?>) {
|
||||
val directBadgeCount = response.body()
|
||||
if (directBadgeCount == null) {
|
||||
Log.e(TAG, "onResponse: directBadgeCount Response is null")
|
||||
unseenCount.postValue(error(R.string.dms_inbox_error_null_count, currentUnseenCount))
|
||||
return
|
||||
}
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val directBadgeCount = service.fetchUnseenCount()
|
||||
unseenCount.postValue(success(directBadgeCount.badgeCount))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed fetching unseen count", e)
|
||||
unseenCount.postValue(error(e.message, currentUnseenCount))
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<DirectBadgeCount?>, t: Throwable) {
|
||||
Log.e(TAG, "Failed fetching unseen count", t)
|
||||
unseenCount.postValue(error(t.message, currentUnseenCount))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun refresh(scope: CoroutineScope) {
|
||||
@ -117,7 +89,7 @@ class InboxManager private constructor(private val pending: Boolean) {
|
||||
hasOlder = true
|
||||
fetchInbox(scope)
|
||||
if (!pending) {
|
||||
fetchUnseenCount()
|
||||
fetchUnseenCount(scope)
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,9 +322,5 @@ class InboxManager private constructor(private val pending: Boolean) {
|
||||
val threads = inbox?.threads ?: emptyList()
|
||||
ImmutableList.sortedCopyOf(THREAD_COMPARATOR, threads)
|
||||
})
|
||||
// fetchInbox()
|
||||
if (!pending) {
|
||||
fetchUnseenCount()
|
||||
}
|
||||
}
|
||||
}
|
@ -10,11 +10,11 @@ import androidx.lifecycle.Transformations.distinctUntilChanged
|
||||
import androidx.lifecycle.Transformations.map
|
||||
import awais.instagrabber.R
|
||||
import awais.instagrabber.customviews.emoji.Emoji
|
||||
import awais.instagrabber.models.enums.DirectItemType.Companion.getName
|
||||
import awais.instagrabber.models.Resource
|
||||
import awais.instagrabber.models.Resource.Companion.error
|
||||
import awais.instagrabber.models.Resource.Companion.loading
|
||||
import awais.instagrabber.models.Resource.Companion.success
|
||||
import awais.instagrabber.models.enums.DirectItemType
|
||||
import awais.instagrabber.repositories.requests.UploadFinishOptions
|
||||
import awais.instagrabber.repositories.requests.VideoOptions
|
||||
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds
|
||||
@ -400,7 +400,7 @@ class ThreadManager private constructor(
|
||||
return temp
|
||||
}
|
||||
|
||||
fun sendText(text: String): LiveData<Resource<Any?>> {
|
||||
fun sendText(text: String, scope: CoroutineScope): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
val userId = getCurrentUserId(data) ?: return data
|
||||
val clientContext = UUID.randomUUID().toString()
|
||||
@ -412,29 +412,36 @@ class ThreadManager private constructor(
|
||||
data.postValue(loading(directItem))
|
||||
val repliedToItemId = replyToItemValue?.itemId
|
||||
val repliedToClientContext = replyToItemValue?.clientContext
|
||||
val request = service.broadcastText(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
text,
|
||||
repliedToItemId,
|
||||
repliedToClientContext
|
||||
)
|
||||
enqueueRequest(request, data, directItem)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val response = service.broadcastText(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
text,
|
||||
repliedToItemId,
|
||||
repliedToClientContext
|
||||
)
|
||||
parseResponse(response, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, directItem))
|
||||
Log.e(TAG, "sendText: ", e)
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
fun sendUri(entry: MediaController.MediaEntry): LiveData<Resource<Any?>> {
|
||||
fun sendUri(entry: MediaController.MediaEntry, scope: CoroutineScope): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
val uri = Uri.fromFile(File(entry.path))
|
||||
if (!entry.isVideo) {
|
||||
sendPhoto(data, uri, entry.width, entry.height)
|
||||
sendPhoto(data, uri, entry.width, entry.height, scope)
|
||||
return data
|
||||
}
|
||||
sendVideo(data, uri, entry.size, entry.duration, entry.width, entry.height)
|
||||
sendVideo(data, uri, entry.size, entry.duration, entry.width, entry.height, scope)
|
||||
return data
|
||||
}
|
||||
|
||||
fun sendUri(uri: Uri): LiveData<Resource<Any?>> {
|
||||
fun sendUri(uri: Uri, scope: CoroutineScope): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
val mimeType = Utils.getMimeType(uri, contentResolver)
|
||||
if (isEmpty(mimeType)) {
|
||||
@ -443,16 +450,16 @@ class ThreadManager private constructor(
|
||||
}
|
||||
val isPhoto = mimeType != null && mimeType.startsWith("image")
|
||||
if (isPhoto) {
|
||||
sendPhoto(data, uri)
|
||||
sendPhoto(data, uri, scope)
|
||||
return data
|
||||
}
|
||||
if (mimeType != null && mimeType.startsWith("video")) {
|
||||
sendVideo(data, uri)
|
||||
sendVideo(data, uri, scope)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
fun sendAnimatedMedia(giphyGif: GiphyGif): LiveData<Resource<Any?>> {
|
||||
fun sendAnimatedMedia(giphyGif: GiphyGif, scope: CoroutineScope): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
val userId = getCurrentUserId(data) ?: return data
|
||||
val clientContext = UUID.randomUUID().toString()
|
||||
@ -460,12 +467,19 @@ class ThreadManager private constructor(
|
||||
directItem.isPending = true
|
||||
addItems(0, listOf(directItem))
|
||||
data.postValue(loading(directItem))
|
||||
val request = service.broadcastAnimatedMedia(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
giphyGif
|
||||
)
|
||||
enqueueRequest(request, data, directItem)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val request = service.broadcastAnimatedMedia(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
giphyGif
|
||||
)
|
||||
parseResponse(request, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, directItem))
|
||||
Log.e(TAG, "sendAnimatedMedia: ", e)
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@ -476,6 +490,7 @@ class ThreadManager private constructor(
|
||||
samplingFreq: Int,
|
||||
duration: Long,
|
||||
byteLength: Long,
|
||||
scope: CoroutineScope,
|
||||
) {
|
||||
if (duration > 60000) {
|
||||
// instagram does not allow uploading audio longer than 60 secs for Direct messages
|
||||
@ -502,14 +517,21 @@ class ThreadManager private constructor(
|
||||
uploadFinishRequest.enqueue(object : Callback<String?> {
|
||||
override fun onResponse(call: Call<String?>, response: Response<String?>) {
|
||||
if (response.isSuccessful) {
|
||||
val request = service.broadcastVoice(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
uploadDmVoiceOptions.uploadId,
|
||||
waveform,
|
||||
samplingFreq
|
||||
)
|
||||
enqueueRequest(request, data, directItem)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val request = service.broadcastVoice(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
uploadDmVoiceOptions.uploadId,
|
||||
waveform,
|
||||
samplingFreq
|
||||
)
|
||||
parseResponse(request, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, directItem))
|
||||
Log.e(TAG, "sendVoice: ", e)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if (response.errorBody() != null) {
|
||||
@ -537,6 +559,7 @@ class ThreadManager private constructor(
|
||||
fun sendReaction(
|
||||
item: DirectItem,
|
||||
emoji: Emoji,
|
||||
scope: CoroutineScope,
|
||||
): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
val userId = getCurrentUserId(data)
|
||||
@ -557,18 +580,24 @@ class ThreadManager private constructor(
|
||||
data.postValue(error("itemId is null", null))
|
||||
return data
|
||||
}
|
||||
val request = service.broadcastReaction(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
itemId,
|
||||
emojiUnicode,
|
||||
false
|
||||
)
|
||||
handleBroadcastReactionRequest(data, item, request)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
service.broadcastReaction(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
itemId,
|
||||
emojiUnicode,
|
||||
false
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, null))
|
||||
Log.e(TAG, "sendReaction: ", e)
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
fun sendDeleteReaction(itemId: String): LiveData<Resource<Any?>> {
|
||||
fun sendDeleteReaction(itemId: String, scope: CoroutineScope): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
val item = getItem(itemId)
|
||||
if (item == null) {
|
||||
@ -588,8 +617,14 @@ class ThreadManager private constructor(
|
||||
data.postValue(error("itemId is null", null))
|
||||
return data
|
||||
}
|
||||
val request = service.broadcastReaction(clientContext, threadIdOrUserIds, itemId1, null, true)
|
||||
handleBroadcastReactionRequest(data, item, request)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
service.broadcastReaction(clientContext, threadIdOrUserIds, itemId1, null, true)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, null))
|
||||
Log.e(TAG, "sendDeleteReaction: ", e)
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@ -660,7 +695,7 @@ class ThreadManager private constructor(
|
||||
data.postValue(error("item type is null", null))
|
||||
return data
|
||||
}
|
||||
val itemTypeName = getName(itemType)
|
||||
val itemTypeName = DirectItemType.getName(itemType)
|
||||
if (itemTypeName == null) {
|
||||
Log.e(TAG, "forward: itemTypeName was null!")
|
||||
data.postValue(error("itemTypeName is null", null))
|
||||
@ -798,6 +833,7 @@ class ThreadManager private constructor(
|
||||
private fun sendPhoto(
|
||||
data: MutableLiveData<Resource<Any?>>,
|
||||
uri: Uri,
|
||||
scope: CoroutineScope,
|
||||
) {
|
||||
try {
|
||||
val dimensions = BitmapUtils.decodeDimensions(contentResolver, uri)
|
||||
@ -805,7 +841,7 @@ class ThreadManager private constructor(
|
||||
data.postValue(error("Decoding dimensions failed", null))
|
||||
return
|
||||
}
|
||||
sendPhoto(data, uri, dimensions.first, dimensions.second)
|
||||
sendPhoto(data, uri, dimensions.first, dimensions.second, scope)
|
||||
} catch (e: IOException) {
|
||||
data.postValue(error(e.message, null))
|
||||
Log.e(TAG, "sendPhoto: ", e)
|
||||
@ -817,6 +853,7 @@ class ThreadManager private constructor(
|
||||
uri: Uri,
|
||||
width: Int,
|
||||
height: Int,
|
||||
scope: CoroutineScope,
|
||||
) {
|
||||
val userId = getCurrentUserId(data) ?: return
|
||||
val clientContext = UUID.randomUUID().toString()
|
||||
@ -829,8 +866,15 @@ class ThreadManager private constructor(
|
||||
if (handleInvalidResponse(data, response)) return
|
||||
val response1 = response.response ?: return
|
||||
val uploadId = response1.optString("upload_id")
|
||||
val request = service.broadcastPhoto(clientContext, threadIdOrUserIds, uploadId)
|
||||
enqueueRequest(request, data, directItem)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val response2 = service.broadcastPhoto(clientContext, threadIdOrUserIds, uploadId)
|
||||
parseResponse(response2, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, null))
|
||||
Log.e(TAG, "sendPhoto: ", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(t: Throwable) {
|
||||
@ -843,6 +887,7 @@ class ThreadManager private constructor(
|
||||
private fun sendVideo(
|
||||
data: MutableLiveData<Resource<Any?>>,
|
||||
uri: Uri,
|
||||
scope: CoroutineScope,
|
||||
) {
|
||||
MediaUtils.getVideoInfo(contentResolver, uri, object : OnInfoLoadListener<VideoInfo?> {
|
||||
override fun onLoad(info: VideoInfo?) {
|
||||
@ -850,7 +895,7 @@ class ThreadManager private constructor(
|
||||
data.postValue(error("Could not get the video info", null))
|
||||
return
|
||||
}
|
||||
sendVideo(data, uri, info.size, info.duration, info.width, info.height)
|
||||
sendVideo(data, uri, info.size, info.duration, info.width, info.height, scope)
|
||||
}
|
||||
|
||||
override fun onFailure(t: Throwable) {
|
||||
@ -866,6 +911,7 @@ class ThreadManager private constructor(
|
||||
duration: Long,
|
||||
width: Int,
|
||||
height: Int,
|
||||
scope: CoroutineScope,
|
||||
) {
|
||||
if (duration > 60000) {
|
||||
// instagram does not allow uploading videos longer than 60 secs for Direct messages
|
||||
@ -892,14 +938,21 @@ class ThreadManager private constructor(
|
||||
uploadFinishRequest.enqueue(object : Callback<String?> {
|
||||
override fun onResponse(call: Call<String?>, response: Response<String?>) {
|
||||
if (response.isSuccessful) {
|
||||
val request = service.broadcastVideo(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
uploadDmVideoOptions.uploadId,
|
||||
"",
|
||||
true
|
||||
)
|
||||
enqueueRequest(request, data, directItem)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val response1 = service.broadcastVideo(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
uploadDmVideoOptions.uploadId,
|
||||
"",
|
||||
true
|
||||
)
|
||||
parseResponse(response1, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, null))
|
||||
Log.e(TAG, "sendVideo: ", e)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if (response.errorBody() != null) {
|
||||
@ -924,64 +977,36 @@ class ThreadManager private constructor(
|
||||
})
|
||||
}
|
||||
|
||||
private fun enqueueRequest(
|
||||
request: Call<DirectThreadBroadcastResponse?>,
|
||||
private fun parseResponse(
|
||||
response: DirectThreadBroadcastResponse,
|
||||
data: MutableLiveData<Resource<Any?>>,
|
||||
directItem: DirectItem,
|
||||
) {
|
||||
request.enqueue(object : Callback<DirectThreadBroadcastResponse?> {
|
||||
override fun onResponse(
|
||||
call: Call<DirectThreadBroadcastResponse?>,
|
||||
response: Response<DirectThreadBroadcastResponse?>,
|
||||
) {
|
||||
if (response.isSuccessful) {
|
||||
val broadcastResponse = response.body()
|
||||
if (broadcastResponse == null) {
|
||||
data.postValue(error(R.string.generic_null_response, directItem))
|
||||
Log.e(TAG, "enqueueRequest: onResponse: response body is null")
|
||||
return
|
||||
}
|
||||
val payloadClientContext: String?
|
||||
val timestamp: Long
|
||||
val itemId: String?
|
||||
val payload = broadcastResponse.payload
|
||||
if (payload == null) {
|
||||
val messageMetadata = broadcastResponse.messageMetadata
|
||||
if (messageMetadata == null || messageMetadata.isEmpty()) {
|
||||
data.postValue(success(directItem))
|
||||
return
|
||||
}
|
||||
val (clientContext, itemId1, timestamp1) = messageMetadata[0]
|
||||
payloadClientContext = clientContext
|
||||
itemId = itemId1
|
||||
timestamp = timestamp1
|
||||
} else {
|
||||
payloadClientContext = payload.clientContext
|
||||
timestamp = payload.timestamp
|
||||
itemId = payload.itemId
|
||||
}
|
||||
if (payloadClientContext == null) {
|
||||
data.postValue(error("clientContext in response was null", null))
|
||||
return
|
||||
}
|
||||
updateItemSent(payloadClientContext, timestamp, itemId)
|
||||
data.postValue(success(directItem))
|
||||
return
|
||||
}
|
||||
if (response.errorBody() != null) {
|
||||
handleErrorBody(call, response, data)
|
||||
}
|
||||
data.postValue(error(R.string.generic_failed_request, directItem))
|
||||
val payloadClientContext: String?
|
||||
val timestamp: Long
|
||||
val itemId: String?
|
||||
val payload = response.payload
|
||||
if (payload == null) {
|
||||
val messageMetadata = response.messageMetadata
|
||||
if (messageMetadata == null || messageMetadata.isEmpty()) {
|
||||
data.postValue(success(directItem))
|
||||
return
|
||||
}
|
||||
|
||||
override fun onFailure(
|
||||
call: Call<DirectThreadBroadcastResponse?>,
|
||||
t: Throwable,
|
||||
) {
|
||||
data.postValue(error(t.message, directItem))
|
||||
Log.e(TAG, "enqueueRequest: onFailure: ", t)
|
||||
}
|
||||
})
|
||||
val (clientContext, itemId1, timestamp1) = messageMetadata[0]
|
||||
payloadClientContext = clientContext
|
||||
itemId = itemId1
|
||||
timestamp = timestamp1
|
||||
} else {
|
||||
payloadClientContext = payload.clientContext
|
||||
timestamp = payload.timestamp
|
||||
itemId = payload.itemId
|
||||
}
|
||||
if (payloadClientContext == null) {
|
||||
data.postValue(error("clientContext in response was null", null))
|
||||
return
|
||||
}
|
||||
updateItemSent(payloadClientContext, timestamp, itemId)
|
||||
data.postValue(success(directItem))
|
||||
}
|
||||
|
||||
private fun updateItemSent(
|
||||
@ -1054,38 +1079,6 @@ class ThreadManager private constructor(
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
private fun handleBroadcastReactionRequest(
|
||||
data: MutableLiveData<Resource<Any?>>,
|
||||
item: DirectItem,
|
||||
request: Call<DirectThreadBroadcastResponse?>,
|
||||
) {
|
||||
request.enqueue(object : Callback<DirectThreadBroadcastResponse?> {
|
||||
override fun onResponse(
|
||||
call: Call<DirectThreadBroadcastResponse?>,
|
||||
response: Response<DirectThreadBroadcastResponse?>,
|
||||
) {
|
||||
if (!response.isSuccessful) {
|
||||
if (response.errorBody() != null) {
|
||||
handleErrorBody(call, response, data)
|
||||
return
|
||||
}
|
||||
data.postValue(error(R.string.generic_failed_request, item))
|
||||
return
|
||||
}
|
||||
val body = response.body()
|
||||
if (body == null) {
|
||||
data.postValue(error(R.string.generic_null_response, item))
|
||||
}
|
||||
// otherwise nothing to do? maybe update the timestamp in the emoji?
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<DirectThreadBroadcastResponse?>, t: Throwable) {
|
||||
data.postValue(error(t.message, item))
|
||||
Log.e(TAG, "enqueueRequest: onFailure: ", t)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun stopCurrentRequest() {
|
||||
chatsRequest?.let {
|
||||
if (it.isExecuted || it.isCanceled) return
|
||||
@ -1583,7 +1576,7 @@ class ThreadManager private constructor(
|
||||
})
|
||||
}
|
||||
|
||||
fun markAsSeen(directItem: DirectItem): 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)
|
||||
@ -1606,7 +1599,7 @@ class ThreadManager private constructor(
|
||||
data.postValue(error(R.string.generic_null_response, null))
|
||||
return
|
||||
}
|
||||
inboxManager.fetchUnseenCount()
|
||||
inboxManager.fetchUnseenCount(scope)
|
||||
val payload = seenResponse.payload ?: return
|
||||
val timestamp = payload.timestamp
|
||||
val thread = thread.value ?: return
|
||||
|
@ -1,46 +1,62 @@
|
||||
package awais.instagrabber.models.enums
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
enum class DirectItemType(val id: Int) : Serializable {
|
||||
UNKNOWN(0),
|
||||
|
||||
@SerializedName("text")
|
||||
TEXT(1),
|
||||
|
||||
@SerializedName("like")
|
||||
LIKE(2),
|
||||
|
||||
@SerializedName("link")
|
||||
LINK(3),
|
||||
|
||||
@SerializedName("media")
|
||||
MEDIA(4),
|
||||
|
||||
@SerializedName("raven_media")
|
||||
RAVEN_MEDIA(5),
|
||||
|
||||
@SerializedName("profile")
|
||||
PROFILE(6),
|
||||
|
||||
@SerializedName("video_call_event")
|
||||
VIDEO_CALL_EVENT(7),
|
||||
|
||||
@SerializedName("animated_media")
|
||||
ANIMATED_MEDIA(8),
|
||||
|
||||
@SerializedName("voice_media")
|
||||
VOICE_MEDIA(9),
|
||||
|
||||
@SerializedName("media_share")
|
||||
MEDIA_SHARE(10),
|
||||
|
||||
@SerializedName("reel_share")
|
||||
REEL_SHARE(11),
|
||||
|
||||
@SerializedName("action_log")
|
||||
ACTION_LOG(12),
|
||||
|
||||
@SerializedName("placeholder")
|
||||
PLACEHOLDER(13),
|
||||
|
||||
@SerializedName("story_share")
|
||||
STORY_SHARE(14),
|
||||
|
||||
@SerializedName("clip")
|
||||
CLIP(15), // media_share but reel
|
||||
|
||||
@SerializedName("felix_share")
|
||||
FELIX_SHARE(16), // media_share but igtv
|
||||
|
||||
@SerializedName("location")
|
||||
LOCATION(17),
|
||||
|
||||
@SerializedName("xma")
|
||||
XMA(18); // self avatar stickers
|
||||
|
||||
@ -52,7 +68,6 @@ enum class DirectItemType(val id: Int) : Serializable {
|
||||
return map[id]
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getName(directItemType: DirectItemType): String? {
|
||||
when (directItemType) {
|
||||
TEXT -> return "text"
|
||||
@ -72,12 +87,12 @@ enum class DirectItemType(val id: Int) : Serializable {
|
||||
CLIP -> return "clip"
|
||||
FELIX_SHARE -> return "felix_share"
|
||||
LOCATION -> return "location"
|
||||
else -> return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
init {
|
||||
for (type in DirectItemType.values()) {
|
||||
for (type in values()) {
|
||||
map[type.id] = type
|
||||
}
|
||||
}
|
||||
|
@ -18,14 +18,14 @@ interface DirectMessagesRepository {
|
||||
): DirectThreadFeedResponse
|
||||
|
||||
@GET("/api/v1/direct_v2/get_badge_count/?no_raven=1")
|
||||
fun fetchUnseenCount(): Call<DirectBadgeCount?>
|
||||
suspend fun fetchUnseenCount(): DirectBadgeCount
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/direct_v2/threads/broadcast/{item}/")
|
||||
fun broadcast(
|
||||
suspend fun broadcast(
|
||||
@Path("item") item: String,
|
||||
@FieldMap signedForm: Map<String, String>,
|
||||
): Call<DirectThreadBroadcastResponse?>
|
||||
): DirectThreadBroadcastResponse
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/direct_v2/threads/{threadId}/add_user/")
|
||||
|
19
app/src/main/java/awais/instagrabber/utils/CoroutineUtils.kt
Normal file
19
app/src/main/java/awais/instagrabber/utils/CoroutineUtils.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package awais.instagrabber.utils
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import java.util.function.BiConsumer
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@JvmOverloads
|
||||
fun <R> getContinuation(onFinished: BiConsumer<R?, Throwable?>, dispatcher: CoroutineDispatcher = Dispatchers.Default): Continuation<R> {
|
||||
return object : Continuation<R> {
|
||||
override val context: CoroutineContext
|
||||
get() = dispatcher
|
||||
|
||||
override fun resumeWith(result: Result<R>) {
|
||||
onFinished.accept(result.getOrNull(), result.exceptionOrNull())
|
||||
}
|
||||
}
|
||||
}
|
@ -32,5 +32,6 @@ class DirectInboxViewModel : ViewModel() {
|
||||
|
||||
init {
|
||||
inboxManager.fetchInbox(viewModelScope)
|
||||
inboxManager.fetchUnseenCount(viewModelScope)
|
||||
}
|
||||
}
|
@ -74,15 +74,15 @@ class DirectThreadViewModel(
|
||||
}
|
||||
|
||||
fun sendText(text: String): LiveData<Resource<Any?>> {
|
||||
return threadManager.sendText(text)
|
||||
return threadManager.sendText(text, viewModelScope)
|
||||
}
|
||||
|
||||
fun sendUri(entry: MediaController.MediaEntry): LiveData<Resource<Any?>> {
|
||||
return threadManager.sendUri(entry)
|
||||
return threadManager.sendUri(entry, viewModelScope)
|
||||
}
|
||||
|
||||
fun sendUri(uri: Uri): LiveData<Resource<Any?>> {
|
||||
return threadManager.sendUri(uri)
|
||||
return threadManager.sendUri(uri, viewModelScope)
|
||||
}
|
||||
|
||||
fun startRecording(): LiveData<Resource<Any?>> {
|
||||
@ -106,12 +106,15 @@ class DirectThreadViewModel(
|
||||
MediaUtils.getVoiceInfo(contentResolver, uri, object : OnInfoLoadListener<VideoInfo?> {
|
||||
override fun onLoad(videoInfo: VideoInfo?) {
|
||||
if (videoInfo == null) return
|
||||
threadManager.sendVoice(data,
|
||||
threadManager.sendVoice(
|
||||
data,
|
||||
uri,
|
||||
result.waveform,
|
||||
result.samplingFreq,
|
||||
videoInfo.duration,
|
||||
videoInfo.size)
|
||||
videoInfo.size,
|
||||
viewModelScope,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFailure(t: Throwable) {
|
||||
@ -133,11 +136,11 @@ class DirectThreadViewModel(
|
||||
}
|
||||
|
||||
fun sendReaction(item: DirectItem, emoji: Emoji): LiveData<Resource<Any?>> {
|
||||
return threadManager.sendReaction(item, emoji)
|
||||
return threadManager.sendReaction(item, emoji, viewModelScope)
|
||||
}
|
||||
|
||||
fun sendDeleteReaction(itemId: String): LiveData<Resource<Any?>> {
|
||||
return threadManager.sendDeleteReaction(itemId)
|
||||
return threadManager.sendDeleteReaction(itemId, viewModelScope)
|
||||
}
|
||||
|
||||
fun unsend(item: DirectItem): LiveData<Resource<Any?>> {
|
||||
@ -145,7 +148,7 @@ class DirectThreadViewModel(
|
||||
}
|
||||
|
||||
fun sendAnimatedMedia(giphyGif: GiphyGif): LiveData<Resource<Any?>> {
|
||||
return threadManager.sendAnimatedMedia(giphyGif)
|
||||
return threadManager.sendAnimatedMedia(giphyGif, viewModelScope)
|
||||
}
|
||||
|
||||
fun getUser(userId: Long): User? {
|
||||
@ -197,7 +200,7 @@ class DirectThreadViewModel(
|
||||
return successEventResObjectLiveData
|
||||
}
|
||||
}
|
||||
return threadManager.markAsSeen(directItem)
|
||||
return threadManager.markAsSeen(directItem, viewModelScope)
|
||||
}
|
||||
|
||||
private val successEventResObjectLiveData: MutableLiveData<Resource<Any?>>
|
||||
|
@ -53,17 +53,15 @@ class DirectMessagesService private constructor(
|
||||
return repository.fetchThread(threadId, queryMap)
|
||||
}
|
||||
|
||||
fun fetchUnseenCount(): Call<DirectBadgeCount?> {
|
||||
return repository.fetchUnseenCount()
|
||||
}
|
||||
suspend fun fetchUnseenCount(): DirectBadgeCount = repository.fetchUnseenCount()
|
||||
|
||||
fun broadcastText(
|
||||
suspend fun broadcastText(
|
||||
clientContext: String,
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
text: String,
|
||||
repliedToItemId: String?,
|
||||
repliedToClientContext: String?,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
val urls = extractUrls(text)
|
||||
if (urls.isNotEmpty()) {
|
||||
return broadcastLink(clientContext, threadIdOrUserIds, text, urls, repliedToItemId, repliedToClientContext)
|
||||
@ -76,14 +74,14 @@ class DirectMessagesService private constructor(
|
||||
return broadcast(broadcastOptions)
|
||||
}
|
||||
|
||||
private fun broadcastLink(
|
||||
private suspend fun broadcastLink(
|
||||
clientContext: String,
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
linkText: String,
|
||||
urls: List<String>,
|
||||
repliedToItemId: String?,
|
||||
repliedToClientContext: String?,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
val broadcastOptions = LinkBroadcastOptions(clientContext, threadIdOrUserIds, linkText, urls)
|
||||
if (!repliedToItemId.isNullOrBlank() && !repliedToClientContext.isNullOrBlank()) {
|
||||
broadcastOptions.repliedToItemId = repliedToItemId
|
||||
@ -92,70 +90,70 @@ class DirectMessagesService private constructor(
|
||||
return broadcast(broadcastOptions)
|
||||
}
|
||||
|
||||
fun broadcastPhoto(
|
||||
suspend fun broadcastPhoto(
|
||||
clientContext: String,
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
uploadId: String,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
return broadcast(PhotoBroadcastOptions(clientContext, threadIdOrUserIds, true, uploadId))
|
||||
}
|
||||
|
||||
fun broadcastVideo(
|
||||
suspend fun broadcastVideo(
|
||||
clientContext: String,
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
uploadId: String,
|
||||
videoResult: String,
|
||||
sampled: Boolean,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
return broadcast(VideoBroadcastOptions(clientContext, threadIdOrUserIds, videoResult, uploadId, sampled))
|
||||
}
|
||||
|
||||
fun broadcastVoice(
|
||||
suspend fun broadcastVoice(
|
||||
clientContext: String,
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
uploadId: String,
|
||||
waveform: List<Float>,
|
||||
samplingFreq: Int,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
return broadcast(VoiceBroadcastOptions(clientContext, threadIdOrUserIds, uploadId, waveform, samplingFreq))
|
||||
}
|
||||
|
||||
fun broadcastStoryReply(
|
||||
suspend fun broadcastStoryReply(
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
text: String,
|
||||
mediaId: String,
|
||||
reelId: String,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
return broadcast(StoryReplyBroadcastOptions(UUID.randomUUID().toString(), threadIdOrUserIds, text, mediaId, reelId))
|
||||
}
|
||||
|
||||
fun broadcastReaction(
|
||||
suspend fun broadcastReaction(
|
||||
clientContext: String,
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
itemId: String,
|
||||
emoji: String?,
|
||||
delete: Boolean,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
return broadcast(ReactionBroadcastOptions(clientContext, threadIdOrUserIds, itemId, emoji, delete))
|
||||
}
|
||||
|
||||
fun broadcastAnimatedMedia(
|
||||
suspend fun broadcastAnimatedMedia(
|
||||
clientContext: String,
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
giphyGif: GiphyGif,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
return broadcast(AnimatedMediaBroadcastOptions(clientContext, threadIdOrUserIds, giphyGif))
|
||||
}
|
||||
|
||||
fun broadcastMediaShare(
|
||||
suspend fun broadcastMediaShare(
|
||||
clientContext: String,
|
||||
threadIdOrUserIds: ThreadIdOrUserIds,
|
||||
mediaId: String,
|
||||
): Call<DirectThreadBroadcastResponse?> {
|
||||
): DirectThreadBroadcastResponse {
|
||||
return broadcast(MediaShareBroadcastOptions(clientContext, threadIdOrUserIds, mediaId))
|
||||
}
|
||||
|
||||
private fun broadcast(broadcastOptions: BroadcastOptions): Call<DirectThreadBroadcastResponse?> {
|
||||
private suspend fun broadcast(broadcastOptions: BroadcastOptions): DirectThreadBroadcastResponse {
|
||||
require(!isEmpty(broadcastOptions.clientContext)) { "Broadcast requires a valid client context value" }
|
||||
val form = mutableMapOf<String, Any>()
|
||||
val threadId = broadcastOptions.threadId
|
||||
|
Loading…
Reference in New Issue
Block a user