mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 14:47:29 +00:00
Convert DM managers to kotlin
This commit is contained in:
parent
229cde6074
commit
59750b1026
@ -1088,7 +1088,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager();
|
final InboxManager inboxManager = DirectMessagesManager.INSTANCE.getInboxManager();
|
||||||
final DirectThread thread = response.body();
|
final DirectThread thread = response.body();
|
||||||
if (!inboxManager.containsThread(thread.getThreadId())) {
|
if (!inboxManager.containsThread(thread.getThreadId())) {
|
||||||
thread.setTemp(true);
|
thread.setTemp(true);
|
||||||
|
@ -1,275 +1,222 @@
|
|||||||
package awais.instagrabber.managers;
|
package awais.instagrabber.managers
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver
|
||||||
import android.util.Log;
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import awais.instagrabber.managers.ThreadManager.Companion.getInstance
|
||||||
|
import awais.instagrabber.models.Resource
|
||||||
|
import awais.instagrabber.models.Resource.Companion.error
|
||||||
|
import awais.instagrabber.models.Resource.Companion.loading
|
||||||
|
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
|
||||||
|
import awais.instagrabber.utils.getCsrfTokenFromCookie
|
||||||
|
import awais.instagrabber.utils.getUserIdFromCookie
|
||||||
|
import awais.instagrabber.webservices.DirectMessagesService
|
||||||
|
import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
object DirectMessagesManager {
|
||||||
import androidx.annotation.Nullable;
|
val inboxManager: InboxManager by lazy { InboxManager.getInstance(false) }
|
||||||
import androidx.lifecycle.LiveData;
|
val pendingInboxManager: InboxManager by lazy { InboxManager.getInstance(true) }
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
private val TAG = DirectMessagesManager::class.java.simpleName
|
||||||
|
private val viewerId: Long
|
||||||
|
private val deviceUuid: String
|
||||||
|
private val csrfToken: String
|
||||||
|
private val service: DirectMessagesService
|
||||||
|
|
||||||
import java.io.IOException;
|
fun moveThreadFromPending(threadId: String) {
|
||||||
import java.util.Collections;
|
val pendingThreads = pendingInboxManager.threads.value ?: return
|
||||||
import java.util.List;
|
val index = pendingThreads.indexOfFirst { it.threadId == threadId }
|
||||||
import java.util.Locale;
|
if (index < 0) return
|
||||||
import java.util.Set;
|
val thread = pendingThreads[index]
|
||||||
import java.util.UUID;
|
val threadFirstDirectItem = thread.firstDirectItem ?: return
|
||||||
import java.util.function.Function;
|
val threads = inboxManager.threads.value
|
||||||
|
var insertIndex = 0
|
||||||
import awais.instagrabber.models.Resource;
|
|
||||||
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds;
|
|
||||||
import awais.instagrabber.repositories.responses.User;
|
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
|
||||||
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.CookieUtils;
|
|
||||||
import awais.instagrabber.webservices.DirectMessagesService;
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
|
||||||
|
|
||||||
public final class DirectMessagesManager {
|
|
||||||
private static final String TAG = DirectMessagesManager.class.getSimpleName();
|
|
||||||
private static final Object LOCK = new Object();
|
|
||||||
|
|
||||||
private static DirectMessagesManager instance;
|
|
||||||
|
|
||||||
private final InboxManager inboxManager;
|
|
||||||
private final InboxManager pendingInboxManager;
|
|
||||||
|
|
||||||
private DirectMessagesService service;
|
|
||||||
|
|
||||||
public static DirectMessagesManager getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
synchronized (LOCK) {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new DirectMessagesManager();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DirectMessagesManager() {
|
|
||||||
inboxManager = InboxManager.getInstance(false);
|
|
||||||
pendingInboxManager = InboxManager.getInstance(true);
|
|
||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
|
||||||
final long viewerId = CookieUtils.getUserIdFromCookie(cookie);
|
|
||||||
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
|
|
||||||
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
|
||||||
if (csrfToken == null) return;
|
|
||||||
service = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void moveThreadFromPending(@NonNull final String threadId) {
|
|
||||||
final List<DirectThread> pendingThreads = pendingInboxManager.getThreads().getValue();
|
|
||||||
if (pendingThreads == null) return;
|
|
||||||
final int index = Iterables.indexOf(pendingThreads, t -> t != null && t.getThreadId().equals(threadId));
|
|
||||||
if (index < 0) return;
|
|
||||||
final DirectThread thread = pendingThreads.get(index);
|
|
||||||
final DirectItem threadFirstDirectItem = thread.getFirstDirectItem();
|
|
||||||
if (threadFirstDirectItem == null) return;
|
|
||||||
final List<DirectThread> threads = inboxManager.getThreads().getValue();
|
|
||||||
int insertIndex = 0;
|
|
||||||
if (threads != null) {
|
if (threads != null) {
|
||||||
for (final DirectThread tempThread : threads) {
|
for (tempThread in threads) {
|
||||||
final DirectItem firstDirectItem = tempThread.getFirstDirectItem();
|
val firstDirectItem = tempThread.firstDirectItem ?: continue
|
||||||
if (firstDirectItem == null) continue;
|
val timestamp = firstDirectItem.getTimestamp()
|
||||||
final long timestamp = firstDirectItem.getTimestamp();
|
|
||||||
if (timestamp < threadFirstDirectItem.getTimestamp()) {
|
if (timestamp < threadFirstDirectItem.getTimestamp()) {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
insertIndex++;
|
insertIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thread.setPending(false);
|
thread.pending = false
|
||||||
inboxManager.addThread(thread, insertIndex);
|
inboxManager.addThread(thread, insertIndex)
|
||||||
pendingInboxManager.removeThread(threadId);
|
pendingInboxManager.removeThread(threadId)
|
||||||
final Integer currentTotal = inboxManager.getPendingRequestsTotal().getValue();
|
val currentTotal = inboxManager.getPendingRequestsTotal().value ?: return
|
||||||
if (currentTotal == null) return;
|
inboxManager.setPendingRequestsTotal(currentTotal - 1)
|
||||||
inboxManager.setPendingRequestsTotal(currentTotal - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public InboxManager getInboxManager() {
|
fun getThreadManager(
|
||||||
return inboxManager;
|
threadId: String,
|
||||||
|
pending: Boolean,
|
||||||
|
currentUser: User,
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
): ThreadManager {
|
||||||
|
return getInstance(threadId, pending, currentUser, contentResolver, viewerId, csrfToken, deviceUuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
public InboxManager getPendingInboxManager() {
|
fun createThread(
|
||||||
return pendingInboxManager;
|
userPk: Long,
|
||||||
}
|
callback: ((DirectThread) -> Unit)?,
|
||||||
|
) {
|
||||||
public ThreadManager getThreadManager(@NonNull final String threadId,
|
val createThreadRequest = service.createThread(listOf(userPk), null)
|
||||||
final boolean pending,
|
createThreadRequest.enqueue(object : Callback<DirectThread?> {
|
||||||
@NonNull final User currentUser,
|
override fun onResponse(call: Call<DirectThread?>, response: Response<DirectThread?>) {
|
||||||
@NonNull final ContentResolver contentResolver) {
|
if (!response.isSuccessful) {
|
||||||
return ThreadManager.getInstance(threadId, pending, currentUser, contentResolver);
|
val errorBody = response.errorBody()
|
||||||
}
|
if (errorBody != null) {
|
||||||
|
|
||||||
public void createThread(final long userPk,
|
|
||||||
@Nullable final Function<DirectThread, Void> callback) {
|
|
||||||
if (service == null) return;
|
|
||||||
final Call<DirectThread> createThreadRequest = service.createThread(Collections.singletonList(userPk), null);
|
|
||||||
createThreadRequest.enqueue(new Callback<DirectThread>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull final Call<DirectThread> call, @NonNull final Response<DirectThread> response) {
|
|
||||||
if (!response.isSuccessful()) {
|
|
||||||
if (response.errorBody() != null) {
|
|
||||||
try {
|
try {
|
||||||
final String string = response.errorBody().string();
|
val string = errorBody.string()
|
||||||
final String msg = String.format(Locale.US,
|
val msg = String.format(Locale.US,
|
||||||
"onResponse: url: %s, responseCode: %d, errorBody: %s",
|
"onResponse: url: %s, responseCode: %d, errorBody: %s",
|
||||||
call.request().url().toString(),
|
call.request().url().toString(),
|
||||||
response.code(),
|
response.code(),
|
||||||
string);
|
string)
|
||||||
Log.e(TAG, msg);
|
Log.e(TAG, msg)
|
||||||
} catch (IOException e) {
|
} catch (e: IOException) {
|
||||||
Log.e(TAG, "onResponse: ", e);
|
Log.e(TAG, "onResponse: ", e)
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
Log.e(TAG, "onResponse: request was not successful and response error body was null");
|
Log.e(TAG, "onResponse: request was not successful and response error body was null")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
final DirectThread thread = response.body();
|
val thread = response.body()
|
||||||
if (thread == null) {
|
if (thread == null) {
|
||||||
Log.e(TAG, "onResponse: thread is null");
|
Log.e(TAG, "onResponse: thread is null")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (callback != null) {
|
callback?.invoke(thread)
|
||||||
callback.apply(thread);
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<DirectThread?>, t: Throwable) {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendMedia(recipients: Set<RankedRecipient>, mediaId: String) {
|
||||||
|
val resultsCount = intArrayOf(0)
|
||||||
|
val callback: () -> Unit = {
|
||||||
|
resultsCount[0]++
|
||||||
|
if (resultsCount[0] == recipients.size) {
|
||||||
|
inboxManager.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (recipient in recipients) {
|
||||||
|
sendMedia(recipient, mediaId, false, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
fun sendMedia(recipient: RankedRecipient, mediaId: String) {
|
||||||
public void onFailure(@NonNull final Call<DirectThread> call, @NonNull final Throwable t) {
|
sendMedia(recipient, mediaId, true, null)
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMedia(@NonNull final Set<RankedRecipient> recipients, final String mediaId) {
|
private fun sendMedia(
|
||||||
final int[] resultsCount = {0};
|
recipient: RankedRecipient,
|
||||||
final Function<Void, Void> callback = unused -> {
|
mediaId: String,
|
||||||
resultsCount[0]++;
|
refreshInbox: Boolean,
|
||||||
if (resultsCount[0] == recipients.size()) {
|
callback: (() -> Unit)?,
|
||||||
inboxManager.refresh();
|
) {
|
||||||
}
|
if (recipient.thread == null && recipient.user != null) {
|
||||||
return null;
|
|
||||||
};
|
|
||||||
for (final RankedRecipient recipient : recipients) {
|
|
||||||
if (recipient == null) continue;
|
|
||||||
sendMedia(recipient, mediaId, false, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendMedia(@NonNull final RankedRecipient recipient, final String mediaId) {
|
|
||||||
sendMedia(recipient, mediaId, true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMedia(@NonNull final RankedRecipient recipient,
|
|
||||||
@NonNull final String mediaId,
|
|
||||||
final boolean refreshInbox,
|
|
||||||
@Nullable final Function<Void, Void> callback) {
|
|
||||||
if (recipient.getThread() == null && recipient.getUser() != null) {
|
|
||||||
// create thread and forward
|
// create thread and forward
|
||||||
createThread(recipient.getUser().getPk(), directThread -> {
|
createThread(recipient.user.pk) { (threadId) ->
|
||||||
sendMedia(directThread, mediaId, unused -> {
|
val threadIdTemp = threadId ?: return@createThread
|
||||||
|
sendMedia(threadIdTemp, mediaId) {
|
||||||
if (refreshInbox) {
|
if (refreshInbox) {
|
||||||
inboxManager.refresh();
|
inboxManager.refresh()
|
||||||
}
|
}
|
||||||
if (callback != null) {
|
callback?.invoke()
|
||||||
callback.apply(null);
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (recipient.getThread() == null) return;
|
}
|
||||||
|
if (recipient.thread == null) return
|
||||||
// just forward
|
// just forward
|
||||||
final DirectThread thread = recipient.getThread();
|
val thread = recipient.thread
|
||||||
sendMedia(thread, mediaId, unused -> {
|
val threadId = thread.threadId ?: return
|
||||||
|
sendMedia(threadId, mediaId) {
|
||||||
if (refreshInbox) {
|
if (refreshInbox) {
|
||||||
inboxManager.refresh();
|
inboxManager.refresh()
|
||||||
}
|
}
|
||||||
if (callback != null) {
|
callback?.invoke()
|
||||||
callback.apply(null);
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
private fun sendMedia(
|
||||||
public LiveData<Resource<Object>> sendMedia(@NonNull final DirectThread thread,
|
threadId: String,
|
||||||
@NonNull final String mediaId,
|
mediaId: String,
|
||||||
@Nullable final Function<Void, Void> callback) {
|
callback: (() -> Unit)?,
|
||||||
return sendMedia(thread.getThreadId(), mediaId, callback);
|
): LiveData<Resource<Any?>> {
|
||||||
}
|
val data = MutableLiveData<Resource<Any?>>()
|
||||||
|
data.postValue(loading(null))
|
||||||
@NonNull
|
val request = service.broadcastMediaShare(
|
||||||
public LiveData<Resource<Object>> sendMedia(@NonNull final String threadId,
|
|
||||||
@NonNull final String mediaId,
|
|
||||||
@Nullable final Function<Void, Void> callback) {
|
|
||||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
|
||||||
data.postValue(Resource.loading(null));
|
|
||||||
final Call<DirectThreadBroadcastResponse> request = service.broadcastMediaShare(
|
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
ThreadIdOrUserIds.of(threadId),
|
of(threadId),
|
||||||
mediaId
|
mediaId
|
||||||
);
|
)
|
||||||
request.enqueue(new Callback<DirectThreadBroadcastResponse>() {
|
request.enqueue(object : Callback<DirectThreadBroadcastResponse?> {
|
||||||
@Override
|
override fun onResponse(
|
||||||
public void onResponse(@NonNull final Call<DirectThreadBroadcastResponse> call,
|
call: Call<DirectThreadBroadcastResponse?>,
|
||||||
@NonNull final Response<DirectThreadBroadcastResponse> response) {
|
response: Response<DirectThreadBroadcastResponse?>,
|
||||||
if (response.isSuccessful()) {
|
) {
|
||||||
data.postValue(Resource.success(new Object()));
|
if (response.isSuccessful) {
|
||||||
if (callback != null) {
|
data.postValue(success(Any()))
|
||||||
callback.apply(null);
|
callback?.invoke()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return;
|
val errorBody = response.errorBody()
|
||||||
}
|
if (errorBody != null) {
|
||||||
if (response.errorBody() != null) {
|
|
||||||
try {
|
try {
|
||||||
final String string = response.errorBody().string();
|
val string = errorBody.string()
|
||||||
final String msg = String.format(Locale.US,
|
val msg = String.format(Locale.US,
|
||||||
"onResponse: url: %s, responseCode: %d, errorBody: %s",
|
"onResponse: url: %s, responseCode: %d, errorBody: %s",
|
||||||
call.request().url().toString(),
|
call.request().url().toString(),
|
||||||
response.code(),
|
response.code(),
|
||||||
string);
|
string)
|
||||||
Log.e(TAG, msg);
|
Log.e(TAG, msg)
|
||||||
data.postValue(Resource.error(msg, null));
|
data.postValue(error(msg, null))
|
||||||
} catch (IOException e) {
|
} catch (e: IOException) {
|
||||||
Log.e(TAG, "onResponse: ", e);
|
Log.e(TAG, "onResponse: ", e)
|
||||||
data.postValue(Resource.error(e.getMessage(), null));
|
data.postValue(error(e.message, null))
|
||||||
}
|
}
|
||||||
if (callback != null) {
|
callback?.invoke()
|
||||||
callback.apply(null);
|
return
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final String msg = "onResponse: request was not successful and response error body was null";
|
|
||||||
Log.e(TAG, msg);
|
|
||||||
data.postValue(Resource.error(msg, null));
|
|
||||||
if (callback != null) {
|
|
||||||
callback.apply(null);
|
|
||||||
}
|
}
|
||||||
|
val msg = "onResponse: request was not successful and response error body was null"
|
||||||
|
Log.e(TAG, msg)
|
||||||
|
data.postValue(error(msg, null))
|
||||||
|
callback?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun onFailure(call: Call<DirectThreadBroadcastResponse?>, t: Throwable) {
|
||||||
public void onFailure(@NonNull final Call<DirectThreadBroadcastResponse> call, @NonNull final Throwable t) {
|
Log.e(TAG, "onFailure: ", t)
|
||||||
Log.e(TAG, "onFailure: ", t);
|
data.postValue(error(t.message, null))
|
||||||
data.postValue(Resource.error(t.getMessage(), null));
|
callback?.invoke()
|
||||||
if (callback != null) {
|
|
||||||
callback.apply(null);
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return data;
|
init {
|
||||||
|
val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
|
||||||
|
viewerId = getUserIdFromCookie(cookie)
|
||||||
|
deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
|
||||||
|
val csrfToken = getCsrfTokenFromCookie(cookie)
|
||||||
|
require(!csrfToken.isNullOrBlank() && viewerId != 0L && deviceUuid.isNotBlank()) { "User is not logged in!" }
|
||||||
|
this.csrfToken = csrfToken
|
||||||
|
service = getInstance(csrfToken, viewerId, deviceUuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,382 +1,349 @@
|
|||||||
package awais.instagrabber.managers;
|
package awais.instagrabber.managers
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.Transformations
|
||||||
|
import awais.instagrabber.R
|
||||||
|
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.repositories.responses.User
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.*
|
||||||
|
import awais.instagrabber.utils.Constants
|
||||||
|
import awais.instagrabber.utils.Utils
|
||||||
|
import awais.instagrabber.utils.getCsrfTokenFromCookie
|
||||||
|
import awais.instagrabber.utils.getUserIdFromCookie
|
||||||
|
import awais.instagrabber.webservices.DirectMessagesService
|
||||||
|
import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance
|
||||||
|
import com.google.common.cache.CacheBuilder
|
||||||
|
import com.google.common.cache.CacheLoader
|
||||||
|
import com.google.common.collect.ImmutableList
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
class InboxManager private constructor(private val pending: Boolean) {
|
||||||
import androidx.lifecycle.LiveData;
|
private val inbox = MutableLiveData<Resource<DirectInbox?>>()
|
||||||
import androidx.lifecycle.MutableLiveData;
|
private val unseenCount = MutableLiveData<Resource<Int?>>()
|
||||||
import androidx.lifecycle.Transformations;
|
private val pendingRequestsTotal = MutableLiveData(0)
|
||||||
|
val threads: LiveData<List<DirectThread>>
|
||||||
|
private val service: DirectMessagesService
|
||||||
|
private var inboxRequest: Call<DirectInboxResponse?>? = null
|
||||||
|
private var unseenCountRequest: Call<DirectBadgeCount?>? = null
|
||||||
|
private var seqId: Long = 0
|
||||||
|
private var cursor: String? = null
|
||||||
|
private var hasOlder = true
|
||||||
|
var viewer: User? = null
|
||||||
|
private set
|
||||||
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
fun getInbox(): LiveData<Resource<DirectInbox?>> {
|
||||||
import com.google.common.cache.CacheLoader;
|
return Transformations.distinctUntilChanged(inbox)
|
||||||
import com.google.common.cache.LoadingCache;
|
}
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
fun getUnseenCount(): LiveData<Resource<Int?>> {
|
||||||
import java.util.Collections;
|
return Transformations.distinctUntilChanged(unseenCount)
|
||||||
import java.util.Comparator;
|
}
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
fun getPendingRequestsTotal(): LiveData<Int> {
|
||||||
import awais.instagrabber.models.Resource;
|
return Transformations.distinctUntilChanged(pendingRequestsTotal)
|
||||||
import awais.instagrabber.repositories.responses.User;
|
}
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectBadgeCount;
|
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectInbox;
|
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectInboxResponse;
|
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
|
||||||
import awais.instagrabber.utils.Constants;
|
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
|
||||||
import awais.instagrabber.utils.TextUtils;
|
|
||||||
import awais.instagrabber.webservices.DirectMessagesService;
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
import static androidx.lifecycle.Transformations.distinctUntilChanged;
|
fun fetchInbox() {
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
val inboxResource = inbox.value
|
||||||
|
if (inboxResource != null && inboxResource.status === Resource.Status.LOADING || !hasOlder) return
|
||||||
|
stopCurrentInboxRequest()
|
||||||
|
inbox.postValue(loading(currentDirectInbox))
|
||||||
|
inboxRequest = if (pending) service.fetchPendingInbox(cursor, seqId) else service.fetchInbox(cursor, seqId)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
parseInboxResponse(body)
|
||||||
|
}
|
||||||
|
|
||||||
public final class InboxManager {
|
override fun onFailure(call: Call<DirectInboxResponse?>, t: Throwable) {
|
||||||
private static final String TAG = InboxManager.class.getSimpleName();
|
Log.e(TAG, "Failed fetching dm inbox", t)
|
||||||
private static final LoadingCache<String, Object> THREAD_LOCKS = CacheBuilder
|
inbox.postValue(error(t.message, currentDirectInbox))
|
||||||
|
hasOlder = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchUnseenCount() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
unseenCount.postValue(success(directBadgeCount.badgeCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<DirectBadgeCount?>, t: Throwable) {
|
||||||
|
Log.e(TAG, "Failed fetching unseen count", t)
|
||||||
|
unseenCount.postValue(error(t.message, currentUnseenCount))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refresh() {
|
||||||
|
cursor = null
|
||||||
|
seqId = 0
|
||||||
|
hasOlder = true
|
||||||
|
fetchInbox()
|
||||||
|
if (!pending) {
|
||||||
|
fetchUnseenCount()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val currentDirectInbox: DirectInbox?
|
||||||
|
get() {
|
||||||
|
val inboxResource = inbox.value
|
||||||
|
return inboxResource?.data
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseInboxResponse(response: DirectInboxResponse) {
|
||||||
|
if (response.status != "ok") {
|
||||||
|
Log.e(TAG, "DM inbox fetch response: status not ok")
|
||||||
|
inbox.postValue(error(R.string.generic_not_ok_response, currentDirectInbox))
|
||||||
|
hasOlder = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
seqId = response.seqId
|
||||||
|
if (viewer == null) {
|
||||||
|
viewer = response.viewer
|
||||||
|
}
|
||||||
|
val inbox = response.inbox ?: return
|
||||||
|
if (!cursor.isNullOrBlank()) {
|
||||||
|
val currentDirectInbox = currentDirectInbox
|
||||||
|
currentDirectInbox?.let {
|
||||||
|
val threads = it.threads
|
||||||
|
val threadsCopy = if (threads == null) LinkedList() else LinkedList(threads)
|
||||||
|
threadsCopy.addAll(inbox.threads ?: emptyList())
|
||||||
|
inbox.threads = threads
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.inbox.postValue(success(inbox))
|
||||||
|
cursor = inbox.oldestCursor
|
||||||
|
hasOlder = inbox.hasOlder
|
||||||
|
pendingRequestsTotal.postValue(response.pendingRequestsTotal)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setThread(
|
||||||
|
threadId: String,
|
||||||
|
thread: DirectThread,
|
||||||
|
) {
|
||||||
|
val inbox = currentDirectInbox ?: return
|
||||||
|
val index = getThreadIndex(threadId, inbox)
|
||||||
|
setThread(inbox, index, thread)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setThread(
|
||||||
|
inbox: DirectInbox,
|
||||||
|
index: Int,
|
||||||
|
thread: DirectThread,
|
||||||
|
) {
|
||||||
|
if (index < 0) return
|
||||||
|
synchronized(this.inbox) {
|
||||||
|
val threads = inbox.threads
|
||||||
|
val threadsCopy = if (threads == null) LinkedList() else LinkedList(threads)
|
||||||
|
threadsCopy[index] = thread
|
||||||
|
try {
|
||||||
|
val clone = inbox.clone() as DirectInbox
|
||||||
|
clone.threads = threadsCopy
|
||||||
|
this.inbox.postValue(success(clone))
|
||||||
|
} catch (e: CloneNotSupportedException) {
|
||||||
|
Log.e(TAG, "setThread: ", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addItemsToThread(
|
||||||
|
threadId: String,
|
||||||
|
insertIndex: Int,
|
||||||
|
items: Collection<DirectItem>,
|
||||||
|
) {
|
||||||
|
val inbox = currentDirectInbox ?: return
|
||||||
|
synchronized(THREAD_LOCKS.getUnchecked(threadId)) {
|
||||||
|
val index = getThreadIndex(threadId, inbox)
|
||||||
|
if (index < 0) return
|
||||||
|
val threads = inbox.threads ?: return
|
||||||
|
val thread = threads[index]
|
||||||
|
val threadItems = thread.items
|
||||||
|
val list = if (threadItems == null) LinkedList() else LinkedList(threadItems)
|
||||||
|
if (insertIndex >= 0) {
|
||||||
|
list.addAll(insertIndex, items)
|
||||||
|
} else {
|
||||||
|
list.addAll(items)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val threadClone = thread.clone() as DirectThread
|
||||||
|
threadClone.items = list
|
||||||
|
setThread(inbox, index, threadClone)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "addItemsToThread: ", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setItemsToThread(
|
||||||
|
threadId: String,
|
||||||
|
updatedItems: List<DirectItem>,
|
||||||
|
) {
|
||||||
|
val inbox = currentDirectInbox ?: return
|
||||||
|
synchronized(THREAD_LOCKS.getUnchecked(threadId)) {
|
||||||
|
val index = getThreadIndex(threadId, inbox)
|
||||||
|
if (index < 0) return
|
||||||
|
val threads = inbox.threads ?: return
|
||||||
|
val thread = threads[index]
|
||||||
|
try {
|
||||||
|
val threadClone = thread.clone() as DirectThread
|
||||||
|
threadClone.items = updatedItems
|
||||||
|
setThread(inbox, index, threadClone)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "setItemsToThread: ", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getThreadIndex(
|
||||||
|
threadId: String,
|
||||||
|
inbox: DirectInbox,
|
||||||
|
): Int {
|
||||||
|
val threads = inbox.threads
|
||||||
|
return if (threads == null || threads.isEmpty()) {
|
||||||
|
-1
|
||||||
|
} else threads.indexOfFirst { it.threadId == threadId }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val currentUnseenCount: Int?
|
||||||
|
get() {
|
||||||
|
val unseenCountResource = unseenCount.value
|
||||||
|
return unseenCountResource?.data
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopCurrentInboxRequest() {
|
||||||
|
inboxRequest?.let {
|
||||||
|
if (it.isCanceled || it.isExecuted) return
|
||||||
|
it.cancel()
|
||||||
|
}
|
||||||
|
inboxRequest = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopCurrentUnseenCountRequest() {
|
||||||
|
unseenCountRequest?.let {
|
||||||
|
if (it.isCanceled || it.isExecuted) return
|
||||||
|
it.cancel()
|
||||||
|
}
|
||||||
|
unseenCountRequest = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDestroy() {
|
||||||
|
stopCurrentInboxRequest()
|
||||||
|
stopCurrentUnseenCountRequest()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addThread(thread: DirectThread, insertIndex: Int) {
|
||||||
|
if (insertIndex < 0) return
|
||||||
|
synchronized(inbox) {
|
||||||
|
val currentDirectInbox = currentDirectInbox ?: return
|
||||||
|
val threads = currentDirectInbox.threads
|
||||||
|
val threadsCopy = if (threads == null) LinkedList() else LinkedList(threads)
|
||||||
|
threadsCopy.add(insertIndex, thread)
|
||||||
|
try {
|
||||||
|
val clone = currentDirectInbox.clone() as DirectInbox
|
||||||
|
clone.threads = threadsCopy
|
||||||
|
inbox.setValue(success(clone))
|
||||||
|
} catch (e: CloneNotSupportedException) {
|
||||||
|
Log.e(TAG, "setThread: ", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeThread(threadId: String) {
|
||||||
|
synchronized(inbox) {
|
||||||
|
val currentDirectInbox = currentDirectInbox ?: return
|
||||||
|
val threads = currentDirectInbox.threads ?: return
|
||||||
|
val threadsCopy = threads.asSequence().filter { it.threadId != threadId }.toList()
|
||||||
|
try {
|
||||||
|
val clone = currentDirectInbox.clone() as DirectInbox
|
||||||
|
clone.threads = threadsCopy
|
||||||
|
inbox.postValue(success(clone))
|
||||||
|
} catch (e: CloneNotSupportedException) {
|
||||||
|
Log.e(TAG, "setThread: ", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPendingRequestsTotal(total: Int) {
|
||||||
|
pendingRequestsTotal.postValue(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun containsThread(threadId: String?): Boolean {
|
||||||
|
if (threadId == null) return false
|
||||||
|
synchronized(inbox) {
|
||||||
|
val currentDirectInbox = currentDirectInbox ?: return false
|
||||||
|
val threads = currentDirectInbox.threads ?: return false
|
||||||
|
return threads.any { it.threadId == threadId }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = InboxManager::class.java.simpleName
|
||||||
|
private val THREAD_LOCKS = CacheBuilder
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.expireAfterAccess(1, TimeUnit.MINUTES) // max lock time ever expected
|
.expireAfterAccess(1, TimeUnit.MINUTES) // max lock time ever expected
|
||||||
.build(CacheLoader.from(Object::new));
|
.build<String, Any>(CacheLoader.from<Any> { Object() })
|
||||||
private static final Comparator<DirectThread> THREAD_COMPARATOR = (t1, t2) -> {
|
private val THREAD_COMPARATOR = Comparator { t1: DirectThread, t2: DirectThread ->
|
||||||
final DirectItem t1FirstDirectItem = t1.getFirstDirectItem();
|
val t1FirstDirectItem = t1.firstDirectItem
|
||||||
final DirectItem t2FirstDirectItem = t2.getFirstDirectItem();
|
val t2FirstDirectItem = t2.firstDirectItem
|
||||||
if (t1FirstDirectItem == null && t2FirstDirectItem == null) return 0;
|
if (t1FirstDirectItem == null && t2FirstDirectItem == null) return@Comparator 0
|
||||||
if (t1FirstDirectItem == null) return 1;
|
if (t1FirstDirectItem == null) return@Comparator 1
|
||||||
if (t2FirstDirectItem == null) return -1;
|
if (t2FirstDirectItem == null) return@Comparator -1
|
||||||
return Long.compare(t2FirstDirectItem.getTimestamp(), t1FirstDirectItem.getTimestamp());
|
t2FirstDirectItem.getTimestamp().compareTo(t1FirstDirectItem.getTimestamp())
|
||||||
};
|
|
||||||
|
|
||||||
private final MutableLiveData<Resource<DirectInbox>> inbox = new MutableLiveData<>();
|
|
||||||
private final MutableLiveData<Resource<Integer>> unseenCount = new MutableLiveData<>();
|
|
||||||
private final MutableLiveData<Integer> pendingRequestsTotal = new MutableLiveData<>(0);
|
|
||||||
|
|
||||||
private final LiveData<List<DirectThread>> threads;
|
|
||||||
private final DirectMessagesService service;
|
|
||||||
private final boolean pending;
|
|
||||||
|
|
||||||
private Call<DirectInboxResponse> inboxRequest;
|
|
||||||
private Call<DirectBadgeCount> unseenCountRequest;
|
|
||||||
private long seqId;
|
|
||||||
private String cursor;
|
|
||||||
private boolean hasOlder = true;
|
|
||||||
private User viewer;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static InboxManager getInstance(final boolean pending) {
|
|
||||||
return new InboxManager(pending);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private InboxManager(final boolean pending) {
|
fun getInstance(pending: Boolean): InboxManager {
|
||||||
this.pending = pending;
|
return InboxManager(pending)
|
||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
|
||||||
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
|
||||||
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
|
|
||||||
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
|
||||||
if (TextUtils.isEmpty(csrfToken)) {
|
|
||||||
throw new IllegalArgumentException("csrfToken is empty!");
|
|
||||||
} else if (userId == 0) {
|
|
||||||
throw new IllegalArgumentException("user id invalid");
|
|
||||||
} else if (TextUtils.isEmpty(deviceUuid)) {
|
|
||||||
throw new IllegalArgumentException("device uuid is empty!");
|
|
||||||
}
|
}
|
||||||
service = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid);
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
|
||||||
|
val viewerId = getUserIdFromCookie(cookie)
|
||||||
|
val deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
|
||||||
|
val csrfToken = getCsrfTokenFromCookie(cookie)
|
||||||
|
require(!csrfToken.isNullOrBlank() && viewerId != 0L && deviceUuid.isNotBlank()) { "User is not logged in!" }
|
||||||
|
service = getInstance(csrfToken, viewerId, deviceUuid)
|
||||||
|
|
||||||
// Transformations
|
// Transformations
|
||||||
threads = distinctUntilChanged(Transformations.map(inbox, inboxResource -> {
|
threads = Transformations.distinctUntilChanged(Transformations.map(inbox) { inboxResource: Resource<DirectInbox?>? ->
|
||||||
if (inboxResource == null) {
|
if (inboxResource == null) {
|
||||||
return Collections.emptyList();
|
return@map emptyList()
|
||||||
}
|
}
|
||||||
final DirectInbox inbox = inboxResource.data;
|
val inbox = inboxResource.data
|
||||||
if (inbox == null) {
|
val threads = inbox?.threads ?: emptyList()
|
||||||
return Collections.emptyList();
|
ImmutableList.sortedCopyOf(THREAD_COMPARATOR, threads)
|
||||||
}
|
})
|
||||||
return ImmutableList.sortedCopyOf(THREAD_COMPARATOR, inbox.getThreads());
|
fetchInbox()
|
||||||
}));
|
|
||||||
|
|
||||||
fetchInbox();
|
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
fetchUnseenCount();
|
fetchUnseenCount()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Resource<DirectInbox>> getInbox() {
|
|
||||||
return distinctUntilChanged(inbox);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<DirectThread>> getThreads() {
|
|
||||||
return threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Resource<Integer>> getUnseenCount() {
|
|
||||||
return distinctUntilChanged(unseenCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Integer> getPendingRequestsTotal() {
|
|
||||||
return distinctUntilChanged(pendingRequestsTotal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getViewer() {
|
|
||||||
return viewer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fetchInbox() {
|
|
||||||
final Resource<DirectInbox> inboxResource = inbox.getValue();
|
|
||||||
if ((inboxResource != null && inboxResource.status == Resource.Status.LOADING) || !hasOlder) return;
|
|
||||||
stopCurrentInboxRequest();
|
|
||||||
inbox.postValue(Resource.loading(getCurrentDirectInbox()));
|
|
||||||
inboxRequest = pending ? service.fetchPendingInbox(cursor, seqId) : service.fetchInbox(cursor, seqId);
|
|
||||||
inboxRequest.enqueue(new Callback<DirectInboxResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull final Call<DirectInboxResponse> call, @NonNull final Response<DirectInboxResponse> response) {
|
|
||||||
parseInboxResponse(response.body());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull final Call<DirectInboxResponse> call, @NonNull final Throwable t) {
|
|
||||||
Log.e(TAG, "Failed fetching dm inbox", t);
|
|
||||||
inbox.postValue(Resource.error(t.getMessage(), getCurrentDirectInbox()));
|
|
||||||
hasOlder = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fetchUnseenCount() {
|
|
||||||
final Resource<Integer> unseenCountResource = unseenCount.getValue();
|
|
||||||
if ((unseenCountResource != null && unseenCountResource.status == Resource.Status.LOADING)) return;
|
|
||||||
stopCurrentUnseenCountRequest();
|
|
||||||
unseenCount.postValue(Resource.loading(getCurrentUnseenCount()));
|
|
||||||
unseenCountRequest = service.fetchUnseenCount();
|
|
||||||
unseenCountRequest.enqueue(new Callback<DirectBadgeCount>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull final Call<DirectBadgeCount> call, @NonNull final Response<DirectBadgeCount> response) {
|
|
||||||
final DirectBadgeCount directBadgeCount = response.body();
|
|
||||||
if (directBadgeCount == null) {
|
|
||||||
Log.e(TAG, "onResponse: directBadgeCount Response is null");
|
|
||||||
unseenCount.postValue(Resource.error(R.string.dms_inbox_error_null_count, getCurrentUnseenCount()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
unseenCount.postValue(Resource.success(directBadgeCount.getBadgeCount()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull final Call<DirectBadgeCount> call, @NonNull final Throwable t) {
|
|
||||||
Log.e(TAG, "Failed fetching unseen count", t);
|
|
||||||
unseenCount.postValue(Resource.error(t.getMessage(), getCurrentUnseenCount()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refresh() {
|
|
||||||
cursor = null;
|
|
||||||
seqId = 0;
|
|
||||||
hasOlder = true;
|
|
||||||
fetchInbox();
|
|
||||||
if (!pending) {
|
|
||||||
fetchUnseenCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DirectInbox getCurrentDirectInbox() {
|
|
||||||
final Resource<DirectInbox> inboxResource = inbox.getValue();
|
|
||||||
return inboxResource != null ? inboxResource.data : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseInboxResponse(final DirectInboxResponse response) {
|
|
||||||
if (response == null) {
|
|
||||||
Log.e(TAG, "parseInboxResponse: Response is null");
|
|
||||||
inbox.postValue(Resource.error(R.string.generic_null_response, getCurrentDirectInbox()));
|
|
||||||
hasOlder = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!Objects.equals(response.getStatus(), "ok")) {
|
|
||||||
Log.e(TAG, "DM inbox fetch response: status not ok");
|
|
||||||
inbox.postValue(Resource.error(R.string.generic_not_ok_response, getCurrentDirectInbox()));
|
|
||||||
hasOlder = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seqId = response.getSeqId();
|
|
||||||
if (viewer == null) {
|
|
||||||
viewer = response.getViewer();
|
|
||||||
}
|
|
||||||
final DirectInbox inbox = response.getInbox();
|
|
||||||
if (inbox == null) return;
|
|
||||||
if (!TextUtils.isEmpty(cursor)) {
|
|
||||||
final DirectInbox currentDirectInbox = getCurrentDirectInbox();
|
|
||||||
if (currentDirectInbox != null) {
|
|
||||||
List<DirectThread> threads = currentDirectInbox.getThreads();
|
|
||||||
threads = threads == null ? new LinkedList<>() : new LinkedList<>(threads);
|
|
||||||
threads.addAll(inbox.getThreads() == null ? Collections.emptyList() : inbox.getThreads());
|
|
||||||
inbox.setThreads(threads);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.inbox.postValue(Resource.success(inbox));
|
|
||||||
cursor = inbox.getOldestCursor();
|
|
||||||
hasOlder = inbox.getHasOlder();
|
|
||||||
pendingRequestsTotal.postValue(response.getPendingRequestsTotal());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setThread(@NonNull final String threadId,
|
|
||||||
@NonNull final DirectThread thread) {
|
|
||||||
final DirectInbox inbox = getCurrentDirectInbox();
|
|
||||||
if (inbox == null) return;
|
|
||||||
final int index = getThreadIndex(threadId, inbox);
|
|
||||||
setThread(inbox, index, thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setThread(@NonNull final DirectInbox inbox,
|
|
||||||
final int index,
|
|
||||||
@NonNull final DirectThread thread) {
|
|
||||||
if (index < 0) return;
|
|
||||||
synchronized (this.inbox) {
|
|
||||||
final List<DirectThread> threadsCopy = new LinkedList<>(inbox.getThreads());
|
|
||||||
threadsCopy.set(index, thread);
|
|
||||||
try {
|
|
||||||
final DirectInbox clone = (DirectInbox) inbox.clone();
|
|
||||||
clone.setThreads(threadsCopy);
|
|
||||||
this.inbox.postValue(Resource.success(clone));
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
Log.e(TAG, "setThread: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addItemsToThread(@NonNull final String threadId,
|
|
||||||
final int insertIndex,
|
|
||||||
@NonNull final Collection<DirectItem> items) {
|
|
||||||
final DirectInbox inbox = getCurrentDirectInbox();
|
|
||||||
if (inbox == null) return;
|
|
||||||
synchronized (THREAD_LOCKS.getUnchecked(threadId)) {
|
|
||||||
final int index = getThreadIndex(threadId, inbox);
|
|
||||||
if (index < 0) return;
|
|
||||||
final List<DirectThread> threads = inbox.getThreads();
|
|
||||||
final DirectThread thread = threads.get(index);
|
|
||||||
List<DirectItem> list = thread.getItems();
|
|
||||||
list = list == null ? new LinkedList<>() : new LinkedList<>(list);
|
|
||||||
if (insertIndex >= 0) {
|
|
||||||
list.addAll(insertIndex, items);
|
|
||||||
} else {
|
|
||||||
list.addAll(items);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
final DirectThread threadClone = (DirectThread) thread.clone();
|
|
||||||
threadClone.setItems(list);
|
|
||||||
setThread(inbox, index, threadClone);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "addItemsToThread: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setItemsToThread(@NonNull final String threadId,
|
|
||||||
@NonNull final List<DirectItem> updatedItems) {
|
|
||||||
final DirectInbox inbox = getCurrentDirectInbox();
|
|
||||||
if (inbox == null) return;
|
|
||||||
synchronized (THREAD_LOCKS.getUnchecked(threadId)) {
|
|
||||||
final int index = getThreadIndex(threadId, inbox);
|
|
||||||
if (index < 0) return;
|
|
||||||
final List<DirectThread> threads = inbox.getThreads();
|
|
||||||
final DirectThread thread = threads.get(index);
|
|
||||||
try {
|
|
||||||
final DirectThread threadClone = (DirectThread) thread.clone();
|
|
||||||
threadClone.setItems(updatedItems);
|
|
||||||
setThread(inbox, index, threadClone);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "setItemsToThread: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getThreadIndex(@NonNull final String threadId,
|
|
||||||
@NonNull final DirectInbox inbox) {
|
|
||||||
final List<DirectThread> threads = inbox.getThreads();
|
|
||||||
if (threads == null || threads.isEmpty()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return Iterables.indexOf(threads, t -> {
|
|
||||||
if (t == null) return false;
|
|
||||||
return t.getThreadId().equals(threadId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private Integer getCurrentUnseenCount() {
|
|
||||||
final Resource<Integer> unseenCountResource = unseenCount.getValue();
|
|
||||||
return unseenCountResource != null ? unseenCountResource.data : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopCurrentInboxRequest() {
|
|
||||||
if (inboxRequest == null || inboxRequest.isCanceled() || inboxRequest.isExecuted()) return;
|
|
||||||
inboxRequest.cancel();
|
|
||||||
inboxRequest = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopCurrentUnseenCountRequest() {
|
|
||||||
if (unseenCountRequest == null || unseenCountRequest.isCanceled() || unseenCountRequest.isExecuted()) return;
|
|
||||||
unseenCountRequest.cancel();
|
|
||||||
unseenCountRequest = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDestroy() {
|
|
||||||
stopCurrentInboxRequest();
|
|
||||||
stopCurrentUnseenCountRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addThread(@NonNull final DirectThread thread, final int insertIndex) {
|
|
||||||
if (insertIndex < 0) return;
|
|
||||||
synchronized (this.inbox) {
|
|
||||||
final DirectInbox currentDirectInbox = getCurrentDirectInbox();
|
|
||||||
if (currentDirectInbox == null) return;
|
|
||||||
final List<DirectThread> threadsCopy = new LinkedList<>(currentDirectInbox.getThreads());
|
|
||||||
threadsCopy.add(insertIndex, thread);
|
|
||||||
try {
|
|
||||||
final DirectInbox clone = (DirectInbox) currentDirectInbox.clone();
|
|
||||||
clone.setThreads(threadsCopy);
|
|
||||||
this.inbox.setValue(Resource.success(clone));
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
Log.e(TAG, "setThread: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeThread(@NonNull final String threadId) {
|
|
||||||
synchronized (this.inbox) {
|
|
||||||
final DirectInbox currentDirectInbox = getCurrentDirectInbox();
|
|
||||||
if (currentDirectInbox == null) return;
|
|
||||||
final List<DirectThread> threadsCopy = currentDirectInbox.getThreads()
|
|
||||||
.stream()
|
|
||||||
.filter(t -> !t.getThreadId().equals(threadId))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
try {
|
|
||||||
final DirectInbox clone = (DirectInbox) currentDirectInbox.clone();
|
|
||||||
clone.setThreads(threadsCopy);
|
|
||||||
this.inbox.postValue(Resource.success(clone));
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
Log.e(TAG, "setThread: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPendingRequestsTotal(final int total) {
|
|
||||||
pendingRequestsTotal.postValue(total);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsThread(final String threadId) {
|
|
||||||
if (threadId == null) return false;
|
|
||||||
synchronized (this.inbox) {
|
|
||||||
final DirectInbox currentDirectInbox = getCurrentDirectInbox();
|
|
||||||
if (currentDirectInbox == null) return false;
|
|
||||||
final List<DirectThread> threads = currentDirectInbox.getThreads();
|
|
||||||
if (threads == null) return false;
|
|
||||||
return threads.stream().anyMatch(thread -> Objects.equals(thread.getThreadId(), threadId));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
1675
app/src/main/java/awais/instagrabber/managers/ThreadManager.kt
Normal file
1675
app/src/main/java/awais/instagrabber/managers/ThreadManager.kt
Normal file
File diff suppressed because it is too large
Load Diff
@ -59,7 +59,7 @@ public class DMSyncService extends LifecycleService {
|
|||||||
super.onCreate();
|
super.onCreate();
|
||||||
startForeground(Constants.DM_CHECK_NOTIFICATION_ID, buildForegroundNotification());
|
startForeground(Constants.DM_CHECK_NOTIFICATION_ID, buildForegroundNotification());
|
||||||
Log.d(TAG, "onCreate: Service created");
|
Log.d(TAG, "onCreate: Service created");
|
||||||
final DirectMessagesManager directMessagesManager = DirectMessagesManager.getInstance();
|
final DirectMessagesManager directMessagesManager = DirectMessagesManager.INSTANCE;
|
||||||
inboxManager = directMessagesManager.getInboxManager();
|
inboxManager = directMessagesManager.getInboxManager();
|
||||||
dmLastNotifiedRepository = DMLastNotifiedRepository.getInstance(DMLastNotifiedDataSource.getInstance(getApplicationContext()));
|
dmLastNotifiedRepository = DMLastNotifiedRepository.getInstance(DMLastNotifiedDataSource.getInstance(getApplicationContext()));
|
||||||
}
|
}
|
||||||
|
@ -1,193 +0,0 @@
|
|||||||
package awais.instagrabber.utils;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import awais.instagrabber.models.UploadPhotoOptions;
|
|
||||||
import awais.instagrabber.models.UploadVideoOptions;
|
|
||||||
import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor;
|
|
||||||
import okhttp3.Call;
|
|
||||||
import okhttp3.Headers;
|
|
||||||
import okhttp3.MediaType;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.RequestBody;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import okhttp3.ResponseBody;
|
|
||||||
import okio.BufferedSink;
|
|
||||||
import okio.Okio;
|
|
||||||
import okio.Source;
|
|
||||||
|
|
||||||
public final class MediaUploader {
|
|
||||||
private static final String TAG = MediaUploader.class.getSimpleName();
|
|
||||||
private static final String HOST = "https://i.instagram.com";
|
|
||||||
private static final AppExecutors appExecutors = AppExecutors.INSTANCE;
|
|
||||||
|
|
||||||
public static void uploadPhoto(@NonNull final Uri uri,
|
|
||||||
@NonNull final ContentResolver contentResolver,
|
|
||||||
@NonNull final OnMediaUploadCompleteListener listener) {
|
|
||||||
BitmapUtils.loadBitmap(contentResolver, uri, 1000, false, new BitmapUtils.ThumbnailLoadCallback() {
|
|
||||||
@Override
|
|
||||||
public void onLoad(@Nullable final Bitmap bitmap, final int width, final int height) {
|
|
||||||
if (bitmap == null) {
|
|
||||||
listener.onFailure(new RuntimeException("Bitmap result was null"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uploadPhoto(bitmap, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull final Throwable t) {
|
|
||||||
listener.onFailure(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void uploadPhoto(@NonNull final Bitmap bitmap,
|
|
||||||
@NonNull final OnMediaUploadCompleteListener listener) {
|
|
||||||
appExecutors.getTasksThread().submit(() -> {
|
|
||||||
final File file;
|
|
||||||
final long byteLength;
|
|
||||||
try {
|
|
||||||
file = BitmapUtils.convertToJpegAndSaveToFile(bitmap, null);
|
|
||||||
byteLength = file.length();
|
|
||||||
} catch (Exception e) {
|
|
||||||
listener.onFailure(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final UploadPhotoOptions options = MediaUploadHelper.createUploadPhotoOptions(byteLength);
|
|
||||||
final Map<String, String> headers = MediaUploadHelper.getUploadPhotoHeaders(options);
|
|
||||||
final String url = HOST + "/rupload_igphoto/" + options.getName() + "/";
|
|
||||||
appExecutors.getNetworkIO().execute(() -> {
|
|
||||||
try (FileInputStream input = new FileInputStream(file)) {
|
|
||||||
upload(input, url, headers, listener);
|
|
||||||
} catch (IOException e) {
|
|
||||||
listener.onFailure(e);
|
|
||||||
} finally {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void uploadVideo(final Uri uri,
|
|
||||||
final ContentResolver contentResolver,
|
|
||||||
final UploadVideoOptions options,
|
|
||||||
final OnMediaUploadCompleteListener listener) {
|
|
||||||
appExecutors.getTasksThread().submit(() -> {
|
|
||||||
final Map<String, String> headers = MediaUploadHelper.getUploadVideoHeaders(options);
|
|
||||||
final String url = HOST + "/rupload_igvideo/" + options.getName() + "/";
|
|
||||||
appExecutors.getNetworkIO().execute(() -> {
|
|
||||||
try (InputStream input = contentResolver.openInputStream(uri)) {
|
|
||||||
if (input == null) {
|
|
||||||
listener.onFailure(new RuntimeException("InputStream was null"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
upload(input, url, headers, listener);
|
|
||||||
} catch (IOException e) {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void upload(@NonNull final InputStream input,
|
|
||||||
@NonNull final String url,
|
|
||||||
@NonNull final Map<String, String> headers,
|
|
||||||
@NonNull final OnMediaUploadCompleteListener listener) {
|
|
||||||
try {
|
|
||||||
final OkHttpClient client = new OkHttpClient.Builder()
|
|
||||||
// .addInterceptor(new LoggingInterceptor())
|
|
||||||
.addInterceptor(new AddCookiesInterceptor())
|
|
||||||
.followRedirects(false)
|
|
||||||
.followSslRedirects(false)
|
|
||||||
.build();
|
|
||||||
final Request request = new Request.Builder()
|
|
||||||
.headers(Headers.of(headers))
|
|
||||||
.url(url)
|
|
||||||
.post(create(MediaType.parse("application/octet-stream"), input))
|
|
||||||
.build();
|
|
||||||
final Call call = client.newCall(request);
|
|
||||||
final Response response = call.execute();
|
|
||||||
final ResponseBody body = response.body();
|
|
||||||
if (!response.isSuccessful()) {
|
|
||||||
listener.onFailure(new IOException("Unexpected code " + response + (body != null ? ": " + body.string() : "")));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
listener.onUploadComplete(new MediaUploadResponse(response.code(), body != null ? new JSONObject(body.string()) : null));
|
|
||||||
} catch (Exception e) {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnMediaUploadCompleteListener {
|
|
||||||
void onUploadComplete(MediaUploadResponse response);
|
|
||||||
|
|
||||||
void onFailure(Throwable t);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static RequestBody create(final MediaType mediaType, final InputStream inputStream) {
|
|
||||||
return new RequestBody() {
|
|
||||||
@Override
|
|
||||||
public MediaType contentType() {
|
|
||||||
return mediaType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long contentLength() {
|
|
||||||
try {
|
|
||||||
return inputStream.available();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeTo(@NonNull BufferedSink sink) throws IOException {
|
|
||||||
try (Source source = Okio.source(inputStream)) {
|
|
||||||
sink.writeAll(source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MediaUploadResponse {
|
|
||||||
private final int responseCode;
|
|
||||||
private final JSONObject response;
|
|
||||||
|
|
||||||
public MediaUploadResponse(int responseCode, JSONObject response) {
|
|
||||||
this.responseCode = responseCode;
|
|
||||||
this.response = response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getResponseCode() {
|
|
||||||
return responseCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JSONObject getResponse() {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "MediaUploadResponse{" +
|
|
||||||
"responseCode=" + responseCode +
|
|
||||||
", response=" + response +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
155
app/src/main/java/awais/instagrabber/utils/MediaUploader.kt
Normal file
155
app/src/main/java/awais/instagrabber/utils/MediaUploader.kt
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.net.Uri
|
||||||
|
import awais.instagrabber.models.UploadVideoOptions
|
||||||
|
import awais.instagrabber.utils.BitmapUtils.ThumbnailLoadCallback
|
||||||
|
import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor
|
||||||
|
import okhttp3.*
|
||||||
|
import okio.BufferedSink
|
||||||
|
import okio.source
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
object MediaUploader {
|
||||||
|
private const val HOST = "https://i.instagram.com"
|
||||||
|
private val appExecutors = AppExecutors
|
||||||
|
|
||||||
|
fun uploadPhoto(
|
||||||
|
uri: Uri,
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
listener: OnMediaUploadCompleteListener,
|
||||||
|
) {
|
||||||
|
BitmapUtils.loadBitmap(contentResolver, uri, 1000f, false, object : ThumbnailLoadCallback {
|
||||||
|
override fun onLoad(bitmap: Bitmap?, width: Int, height: Int) {
|
||||||
|
if (bitmap == null) {
|
||||||
|
listener.onFailure(RuntimeException("Bitmap result was null"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uploadPhoto(bitmap, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(t: Throwable) {
|
||||||
|
listener.onFailure(t)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun uploadPhoto(
|
||||||
|
bitmap: Bitmap,
|
||||||
|
listener: OnMediaUploadCompleteListener,
|
||||||
|
) {
|
||||||
|
appExecutors.tasksThread.submit {
|
||||||
|
val file: File
|
||||||
|
val byteLength: Long
|
||||||
|
try {
|
||||||
|
file = BitmapUtils.convertToJpegAndSaveToFile(bitmap, null)
|
||||||
|
byteLength = file.length()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
listener.onFailure(e)
|
||||||
|
return@submit
|
||||||
|
}
|
||||||
|
val options = createUploadPhotoOptions(byteLength)
|
||||||
|
val headers = getUploadPhotoHeaders(options)
|
||||||
|
val url = HOST + "/rupload_igphoto/" + options.name + "/"
|
||||||
|
appExecutors.networkIO.execute {
|
||||||
|
try {
|
||||||
|
FileInputStream(file).use { input -> upload(input, url, headers, listener) }
|
||||||
|
} catch (e: IOException) {
|
||||||
|
listener.onFailure(e)
|
||||||
|
} finally {
|
||||||
|
file.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun uploadVideo(
|
||||||
|
uri: Uri,
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
options: UploadVideoOptions,
|
||||||
|
listener: OnMediaUploadCompleteListener,
|
||||||
|
) {
|
||||||
|
appExecutors.tasksThread.submit {
|
||||||
|
val headers = getUploadVideoHeaders(options)
|
||||||
|
val url = HOST + "/rupload_igvideo/" + options.name + "/"
|
||||||
|
appExecutors.networkIO.execute {
|
||||||
|
try {
|
||||||
|
contentResolver.openInputStream(uri).use { input ->
|
||||||
|
if (input == null) {
|
||||||
|
listener.onFailure(RuntimeException("InputStream was null"))
|
||||||
|
return@execute
|
||||||
|
}
|
||||||
|
upload(input, url, headers, listener)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
listener.onFailure(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun upload(
|
||||||
|
input: InputStream,
|
||||||
|
url: String,
|
||||||
|
headers: Map<String, String>,
|
||||||
|
listener: OnMediaUploadCompleteListener,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
val client = OkHttpClient.Builder()
|
||||||
|
// .addInterceptor(new LoggingInterceptor())
|
||||||
|
.addInterceptor(AddCookiesInterceptor())
|
||||||
|
.followRedirects(false)
|
||||||
|
.followSslRedirects(false)
|
||||||
|
.build()
|
||||||
|
val request = Request.Builder()
|
||||||
|
.headers(Headers.of(headers))
|
||||||
|
.url(url)
|
||||||
|
.post(create(MediaType.parse("application/octet-stream"), input))
|
||||||
|
.build()
|
||||||
|
val call = client.newCall(request)
|
||||||
|
val response = call.execute()
|
||||||
|
val body = response.body()
|
||||||
|
if (!response.isSuccessful) {
|
||||||
|
listener.onFailure(IOException("Unexpected code " + response + if (body != null) ": " + body.string() else ""))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
listener.onUploadComplete(MediaUploadResponse(response.code(), if (body != null) JSONObject(body.string()) else null))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
listener.onFailure(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun create(mediaType: MediaType?, inputStream: InputStream): RequestBody {
|
||||||
|
return object : RequestBody() {
|
||||||
|
override fun contentType(): MediaType? {
|
||||||
|
return mediaType
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contentLength(): Long {
|
||||||
|
return try {
|
||||||
|
inputStream.available().toLong()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun writeTo(sink: BufferedSink) {
|
||||||
|
inputStream.source().use { sink.writeAll(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnMediaUploadCompleteListener {
|
||||||
|
fun onUploadComplete(response: MediaUploadResponse)
|
||||||
|
fun onFailure(t: Throwable)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MediaUploadResponse(val responseCode: Int, val response: JSONObject?)
|
||||||
|
}
|
@ -18,7 +18,7 @@ public class DirectInboxViewModel extends ViewModel {
|
|||||||
private final InboxManager inboxManager;
|
private final InboxManager inboxManager;
|
||||||
|
|
||||||
public DirectInboxViewModel() {
|
public DirectInboxViewModel() {
|
||||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
final DirectMessagesManager messagesManager = DirectMessagesManager.INSTANCE;
|
||||||
inboxManager = messagesManager.getInboxManager();
|
inboxManager = messagesManager.getInboxManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public class DirectPendingInboxViewModel extends ViewModel {
|
|||||||
private final InboxManager inboxManager;
|
private final InboxManager inboxManager;
|
||||||
|
|
||||||
public DirectPendingInboxViewModel() {
|
public DirectPendingInboxViewModel() {
|
||||||
inboxManager = DirectMessagesManager.getInstance().getPendingInboxManager();
|
inboxManager = DirectMessagesManager.INSTANCE.getPendingInboxManager();
|
||||||
inboxManager.fetchInbox();
|
inboxManager.fetchInbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
|||||||
}
|
}
|
||||||
final ContentResolver contentResolver = application.getContentResolver();
|
final ContentResolver contentResolver = application.getContentResolver();
|
||||||
resources = getApplication().getResources();
|
resources = getApplication().getResources();
|
||||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
final DirectMessagesManager messagesManager = DirectMessagesManager.INSTANCE;
|
||||||
threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
|
threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +52,8 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
private final long viewerId;
|
private final long viewerId;
|
||||||
private final String threadId;
|
private final String threadId;
|
||||||
private final User currentUser;
|
private final User currentUser;
|
||||||
private final ThreadManager threadManager;
|
|
||||||
|
|
||||||
|
private ThreadManager threadManager;
|
||||||
private VoiceRecorder voiceRecorder;
|
private VoiceRecorder voiceRecorder;
|
||||||
|
|
||||||
public DirectThreadViewModel(@NonNull final Application application,
|
public DirectThreadViewModel(@NonNull final Application application,
|
||||||
@ -73,14 +73,15 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
}
|
}
|
||||||
contentResolver = application.getContentResolver();
|
contentResolver = application.getContentResolver();
|
||||||
recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings");
|
recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings");
|
||||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
final DirectMessagesManager messagesManager = DirectMessagesManager.INSTANCE;
|
||||||
threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
|
threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
|
||||||
threadManager.fetchPendingRequests();
|
threadManager.fetchPendingRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveFromPending() {
|
public void moveFromPending() {
|
||||||
DirectMessagesManager.getInstance().moveThreadFromPending(threadId);
|
final DirectMessagesManager messagesManager = DirectMessagesManager.INSTANCE;
|
||||||
threadManager.moveFromPending();
|
messagesManager.moveThreadFromPending(threadId);
|
||||||
|
threadManager = messagesManager.getThreadManager(threadId, false, currentUser, contentResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeThread() {
|
public void removeThread() {
|
||||||
@ -268,7 +269,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
threadManager.forward(recipient, itemToForward);
|
threadManager.forward(recipient, itemToForward);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReplyToItem(final DirectItem item) {
|
public void setReplyToItem(@Nullable final DirectItem item) {
|
||||||
// Log.d(TAG, "setReplyToItem: " + item);
|
// Log.d(TAG, "setReplyToItem: " + item);
|
||||||
threadManager.setReplyToItem(item);
|
threadManager.setReplyToItem(item);
|
||||||
}
|
}
|
||||||
@ -327,7 +328,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
final DirectThread thread = getThread().getValue();
|
final DirectThread thread = getThread().getValue();
|
||||||
if (thread == null) return;
|
if (thread == null) return;
|
||||||
if (thread.isTemp() && (thread.getItems() == null || thread.getItems().isEmpty())) {
|
if (thread.isTemp() && (thread.getItems() == null || thread.getItems().isEmpty())) {
|
||||||
final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager();
|
final InboxManager inboxManager = DirectMessagesManager.INSTANCE.getInboxManager();
|
||||||
inboxManager.removeThread(threadId);
|
inboxManager.removeThread(threadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,14 +333,14 @@ public class PostViewV2ViewModel extends ViewModel {
|
|||||||
|
|
||||||
public void shareDm(@NonNull final RankedRecipient result) {
|
public void shareDm(@NonNull final RankedRecipient result) {
|
||||||
if (messageManager == null) {
|
if (messageManager == null) {
|
||||||
messageManager = DirectMessagesManager.getInstance();
|
messageManager = DirectMessagesManager.INSTANCE;
|
||||||
}
|
}
|
||||||
messageManager.sendMedia(result, media.getId());
|
messageManager.sendMedia(result, media.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shareDm(@NonNull final Set<RankedRecipient> recipients) {
|
public void shareDm(@NonNull final Set<RankedRecipient> recipients) {
|
||||||
if (messageManager == null) {
|
if (messageManager == null) {
|
||||||
messageManager = DirectMessagesManager.getInstance();
|
messageManager = DirectMessagesManager.INSTANCE;
|
||||||
}
|
}
|
||||||
messageManager.sendMedia(recipients, media.getId());
|
messageManager.sendMedia(recipients, media.getId());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user