Convert to kotlin, suspend funs, and viewModelScope

This commit is contained in:
Ammar Githam 2021-05-31 20:55:22 +09:00
parent 68bc9a7543
commit 87e6e4440f
17 changed files with 662 additions and 806 deletions

View File

@ -182,8 +182,13 @@ dependencies {
def core_version = "1.6.0-beta01" def core_version = "1.6.0-beta01"
implementation "androidx.core:core:$core_version" implementation "androidx.core:core:$core_version"
// Fragment
implementation "androidx.fragment:fragment-ktx:1.3.4" implementation "androidx.fragment:fragment-ktx:1.3.4"
// Lifecycle
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
// Room // Room
def room_version = "2.3.0" def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"

View File

@ -185,7 +185,7 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
private fun initDmUnreadCount() { private fun initDmUnreadCount() {
if (!isLoggedIn) return if (!isLoggedIn) return
val directInboxViewModel = ViewModelProvider(this).get(DirectInboxViewModel::class.java) val directInboxViewModel = ViewModelProvider(this).get(DirectInboxViewModel::class.java)
directInboxViewModel.unseenCount.observe(this, { unseenCountResource: Resource<Int>? -> directInboxViewModel.unseenCount.observe(this, { unseenCountResource: Resource<Int?>? ->
if (unseenCountResource == null) return@observe if (unseenCountResource == null) return@observe
val unseenCount = unseenCountResource.data val unseenCount = unseenCountResource.data
setNavBarDMUnreadCountBadge(unseenCount ?: 0) setNavBarDMUnreadCountBadge(unseenCount ?: 0)

View File

@ -217,7 +217,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
// wasPaused = true; // wasPaused = true;
if (settingsHelper.getBoolean(PreferenceKeys.PLAY_IN_BACKGROUND)) return; if (settingsHelper.getBoolean(PreferenceKeys.PLAY_IN_BACKGROUND)) return;
final Media media = viewModel.getMedia(); final Media media = viewModel.getMedia();
if (media == null || media.getMediaType() == null) return; if (media.getMediaType() == null) return;
switch (media.getMediaType()) { switch (media.getMediaType()) {
case MEDIA_TYPE_VIDEO: case MEDIA_TYPE_VIDEO:
if (videoPlayerViewHelper != null) { if (videoPlayerViewHelper != null) {
@ -250,7 +250,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
super.onDestroyView(); super.onDestroyView();
showSystemUI(); showSystemUI();
final Media media = viewModel.getMedia(); final Media media = viewModel.getMedia();
if (media == null || media.getMediaType() == null) return; if (media.getMediaType() == null) return;
switch (media.getMediaType()) { switch (media.getMediaType()) {
case MEDIA_TYPE_VIDEO: case MEDIA_TYPE_VIDEO:
if (videoPlayerViewHelper != null) { if (videoPlayerViewHelper != null) {
@ -269,7 +269,6 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
public void onSaveInstanceState(@NonNull final Bundle outState) { public void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
final Media media = viewModel.getMedia(); final Media media = viewModel.getMedia();
if (media == null) return;
if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) { if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) {
outState.putInt(ARG_SLIDER_POSITION, sliderPosition); outState.putInt(ARG_SLIDER_POSITION, sliderPosition);
} }
@ -1440,9 +1439,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
actionBar.hide(); actionBar.hide();
} }
final CollapsingToolbarLayout appbarLayout = activity.getCollapsingToolbarView(); final CollapsingToolbarLayout appbarLayout = activity.getCollapsingToolbarView();
if (appbarLayout != null) {
appbarLayout.setVisibility(View.GONE); appbarLayout.setVisibility(View.GONE);
}
final Toolbar toolbar = activity.getToolbar(); final Toolbar toolbar = activity.getToolbar();
if (toolbar != null) { if (toolbar != null) {
toolbar.setVisibility(View.GONE); toolbar.setVisibility(View.GONE);
@ -1467,9 +1464,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme
actionBar.show(); actionBar.show();
} }
final CollapsingToolbarLayout appbarLayout = activity.getCollapsingToolbarView(); final CollapsingToolbarLayout appbarLayout = activity.getCollapsingToolbarView();
if (appbarLayout != null) {
appbarLayout.setVisibility(View.VISIBLE); appbarLayout.setVisibility(View.VISIBLE);
}
final Toolbar toolbar = activity.getToolbar(); final Toolbar toolbar = activity.getToolbar();
if (toolbar != null) { if (toolbar != null) {
toolbar.setVisibility(View.VISIBLE); toolbar.setVisibility(View.VISIBLE);

View File

@ -20,6 +20,7 @@ import awais.instagrabber.utils.getCsrfTokenFromCookie
import awais.instagrabber.utils.getUserIdFromCookie import awais.instagrabber.utils.getUserIdFromCookie
import awais.instagrabber.webservices.DirectMessagesService import awais.instagrabber.webservices.DirectMessagesService
import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance
import kotlinx.coroutines.CoroutineScope
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
@ -108,21 +109,21 @@ object DirectMessagesManager {
}) })
} }
fun sendMedia(recipients: Set<RankedRecipient>, mediaId: String) { fun sendMedia(recipients: Set<RankedRecipient>, mediaId: String, scope: CoroutineScope) {
val resultsCount = intArrayOf(0) val resultsCount = intArrayOf(0)
val callback: () -> Unit = { val callback: () -> Unit = {
resultsCount[0]++ resultsCount[0]++
if (resultsCount[0] == recipients.size) { if (resultsCount[0] == recipients.size) {
inboxManager.refresh() inboxManager.refresh(scope)
} }
} }
for (recipient in recipients) { for (recipient in recipients) {
sendMedia(recipient, mediaId, false, callback) sendMedia(recipient, mediaId, false, callback, scope)
} }
} }
fun sendMedia(recipient: RankedRecipient, mediaId: String) { fun sendMedia(recipient: RankedRecipient, mediaId: String, scope: CoroutineScope) {
sendMedia(recipient, mediaId, true, null) sendMedia(recipient, mediaId, true, null, scope)
} }
private fun sendMedia( private fun sendMedia(
@ -130,6 +131,7 @@ object DirectMessagesManager {
mediaId: String, mediaId: String,
refreshInbox: Boolean, refreshInbox: Boolean,
callback: (() -> Unit)?, callback: (() -> Unit)?,
scope: CoroutineScope,
) { ) {
if (recipient.thread == null && recipient.user != null) { if (recipient.thread == null && recipient.user != null) {
// create thread and forward // create thread and forward
@ -137,7 +139,7 @@ object DirectMessagesManager {
val threadIdTemp = threadId ?: return@createThread val threadIdTemp = threadId ?: return@createThread
sendMedia(threadIdTemp, mediaId) { sendMedia(threadIdTemp, mediaId) {
if (refreshInbox) { if (refreshInbox) {
inboxManager.refresh() inboxManager.refresh(scope)
} }
callback?.invoke() callback?.invoke()
} }
@ -149,7 +151,7 @@ object DirectMessagesManager {
val threadId = thread.threadId ?: return val threadId = thread.threadId ?: return
sendMedia(threadId, mediaId) { sendMedia(threadId, mediaId) {
if (refreshInbox) { if (refreshInbox) {
inboxManager.refresh() inboxManager.refresh(scope)
} }
callback?.invoke() callback?.invoke()
} }

View File

@ -11,15 +11,15 @@ import awais.instagrabber.models.Resource.Companion.loading
import awais.instagrabber.models.Resource.Companion.success import awais.instagrabber.models.Resource.Companion.success
import awais.instagrabber.repositories.responses.User import awais.instagrabber.repositories.responses.User
import awais.instagrabber.repositories.responses.directmessages.* import awais.instagrabber.repositories.responses.directmessages.*
import awais.instagrabber.utils.Constants import awais.instagrabber.utils.*
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
import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance import awais.instagrabber.webservices.DirectMessagesService.Companion.getInstance
import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader import com.google.common.cache.CacheLoader
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
@ -27,7 +27,9 @@ import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class InboxManager private constructor(private val pending: Boolean) { class InboxManager private constructor(private val pending: Boolean) {
private val inbox = MutableLiveData<Resource<DirectInbox?>>() // private val fetchInboxControlledRunner: ControlledRunner<Resource<DirectInbox>> = ControlledRunner()
// private val fetchPendingInboxControlledRunner: ControlledRunner<Resource<DirectInbox>> = ControlledRunner()
private val inbox = MutableLiveData<Resource<DirectInbox?>>(success(null))
private val unseenCount = MutableLiveData<Resource<Int?>>() private val unseenCount = MutableLiveData<Resource<Int?>>()
private val pendingRequestsTotal = MutableLiveData(0) private val pendingRequestsTotal = MutableLiveData(0)
val threads: LiveData<List<DirectThread>> val threads: LiveData<List<DirectThread>>
@ -52,30 +54,37 @@ class InboxManager private constructor(private val pending: Boolean) {
return Transformations.distinctUntilChanged(pendingRequestsTotal) return Transformations.distinctUntilChanged(pendingRequestsTotal)
} }
fun fetchInbox() { fun fetchInbox(scope: CoroutineScope) {
val inboxResource = inbox.value val inboxResource = inbox.value
if (inboxResource != null && inboxResource.status === Resource.Status.LOADING || !hasOlder) return if (inboxResource != null && inboxResource.status === Resource.Status.LOADING || !hasOlder) return
stopCurrentInboxRequest()
inbox.postValue(loading(currentDirectInbox)) inbox.postValue(loading(currentDirectInbox))
inboxRequest = if (pending) service.fetchPendingInbox(cursor, seqId) else service.fetchInbox(cursor, seqId) scope.launch(Dispatchers.IO) {
inboxRequest?.enqueue(object : Callback<DirectInboxResponse?> { try {
override fun onResponse(call: Call<DirectInboxResponse?>, response: Response<DirectInboxResponse?>) { val inboxValue = if (pending) service.fetchPendingInbox(cursor, seqId) else service.fetchInbox(cursor, seqId)
val body = response.body() parseInboxResponse(inboxValue)
if (body == null) { } catch (e: Exception) {
Log.e(TAG, "parseInboxResponse: Response is null") inbox.postValue(error(e.message, currentDirectInbox))
inbox.postValue(error(R.string.generic_null_response, currentDirectInbox))
hasOlder = false
return
}
parseInboxResponse(body)
}
override fun onFailure(call: Call<DirectInboxResponse?>, t: Throwable) {
Log.e(TAG, "Failed fetching dm inbox", t)
inbox.postValue(error(t.message, currentDirectInbox))
hasOlder = false 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() {
@ -102,11 +111,11 @@ class InboxManager private constructor(private val pending: Boolean) {
}) })
} }
fun refresh() { fun refresh(scope: CoroutineScope) {
cursor = null cursor = null
seqId = 0 seqId = 0
hasOlder = true hasOlder = true
fetchInbox() fetchInbox(scope)
if (!pending) { if (!pending) {
fetchUnseenCount() fetchUnseenCount()
} }
@ -333,15 +342,15 @@ class InboxManager private constructor(private val pending: Boolean) {
service = getInstance(csrfToken, viewerId, deviceUuid) service = getInstance(csrfToken, viewerId, deviceUuid)
// Transformations // Transformations
threads = Transformations.distinctUntilChanged(Transformations.map(inbox) { inboxResource: Resource<DirectInbox?>? -> threads = Transformations.distinctUntilChanged(Transformations.map(inbox) { inboxResource: Resource<DirectInbox?> ->
if (inboxResource == null) { // if (inboxResource == null) {
return@map emptyList() // return@map emptyList()
} // }
val inbox = inboxResource.data val inbox = inboxResource.data
val threads = inbox?.threads ?: emptyList() val threads = inbox?.threads ?: emptyList()
ImmutableList.sortedCopyOf(THREAD_COMPARATOR, threads) ImmutableList.sortedCopyOf(THREAD_COMPARATOR, threads)
}) })
fetchInbox() // fetchInbox()
if (!pending) { if (!pending) {
fetchUnseenCount() fetchUnseenCount()
} }

View File

@ -37,6 +37,9 @@ import awais.instagrabber.webservices.MediaService
import awais.instagrabber.webservices.ServiceCallback import awais.instagrabber.webservices.ServiceCallback
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.google.common.collect.Iterables import com.google.common.collect.Iterables
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
@ -56,9 +59,12 @@ class ThreadManager private constructor(
csrfToken: String, csrfToken: String,
deviceUuid: String, deviceUuid: String,
) { ) {
private val fetching = MutableLiveData<Resource<Any?>>() private val _fetching = MutableLiveData<Resource<Any?>>()
private val replyToItem = MutableLiveData<DirectItem?>() val fetching: LiveData<Resource<Any?>> = _fetching
private val pendingRequests = MutableLiveData<DirectThreadParticipantRequestsResponse?>(null) private val _replyToItem = MutableLiveData<DirectItem?>()
val replyToItem: LiveData<DirectItem?> = _replyToItem
private val _pendingRequests = MutableLiveData<DirectThreadParticipantRequestsResponse?>(null)
val pendingRequests: LiveData<DirectThreadParticipantRequestsResponse?> = _pendingRequests
private val inboxManager: InboxManager = if (pending) DirectMessagesManager.pendingInboxManager else DirectMessagesManager.inboxManager private val inboxManager: InboxManager = if (pending) DirectMessagesManager.pendingInboxManager else DirectMessagesManager.inboxManager
private val viewerId: Long private val viewerId: Long
private val threadIdOrUserIds: ThreadIdOrUserIds = of(threadId) private val threadIdOrUserIds: ThreadIdOrUserIds = of(threadId)
@ -106,7 +112,7 @@ class ThreadManager private constructor(
val isMuted: LiveData<Boolean> by lazy { distinctUntilChanged(map(thread) { it?.muted ?: false }) } val isMuted: LiveData<Boolean> by lazy { distinctUntilChanged(map(thread) { it?.muted ?: false }) }
val isApprovalRequiredToJoin: LiveData<Boolean> by lazy { distinctUntilChanged(map(thread) { it?.approvalRequiredForNewMembers ?: false }) } val isApprovalRequiredToJoin: LiveData<Boolean> by lazy { distinctUntilChanged(map(thread) { it?.approvalRequiredForNewMembers ?: false }) }
val isMentionsMuted: LiveData<Boolean> by lazy { distinctUntilChanged(map(thread) { it?.mentionsMuted ?: false }) } val isMentionsMuted: LiveData<Boolean> by lazy { distinctUntilChanged(map(thread) { it?.mentionsMuted ?: false }) }
val pendingRequestsCount: LiveData<Int> by lazy { distinctUntilChanged(map(pendingRequests) { it?.totalParticipantRequests ?: 0 }) } val pendingRequestsCount: LiveData<Int> by lazy { distinctUntilChanged(map(_pendingRequests) { it?.totalParticipantRequests ?: 0 }) }
val inviter: LiveData<User?> by lazy { distinctUntilChanged(map(thread) { it?.inviter }) } val inviter: LiveData<User?> by lazy { distinctUntilChanged(map(thread) { it?.inviter }) }
private var hasOlder = true private var hasOlder = true
@ -125,50 +131,58 @@ class ThreadManager private constructor(
return builder.build() return builder.build()
} }
fun isFetching(): LiveData<Resource<Any?>> { fun fetchChats(scope: CoroutineScope) {
return fetching val fetchingValue = _fetching.value
}
fun getReplyToItem(): LiveData<DirectItem?> {
return replyToItem
}
fun getPendingRequests(): LiveData<DirectThreadParticipantRequestsResponse?> {
return pendingRequests
}
fun fetchChats() {
val fetchingValue = fetching.value
if (fetchingValue != null && fetchingValue.status === Resource.Status.LOADING || !hasOlder) return if (fetchingValue != null && fetchingValue.status === Resource.Status.LOADING || !hasOlder) return
fetching.postValue(loading(null)) _fetching.postValue(loading(null))
chatsRequest = service.fetchThread(threadId, cursor) scope.launch(Dispatchers.IO) {
chatsRequest?.enqueue(object : Callback<DirectThreadFeedResponse?> { try {
override fun onResponse(call: Call<DirectThreadFeedResponse?>, response: Response<DirectThreadFeedResponse?>) { val threadFeedResponse = service.fetchThread(threadId, cursor)
val feedResponse = response.body() if (threadFeedResponse.status != null && threadFeedResponse.status != "ok") {
if (feedResponse == null) { _fetching.postValue(error(R.string.generic_not_ok_response, null))
fetching.postValue(error(R.string.generic_null_response, null)) return@launch
Log.e(TAG, "onResponse: response was null!")
return
} }
if (feedResponse.status != null && feedResponse.status != "ok") { val thread = threadFeedResponse.thread
fetching.postValue(error(R.string.generic_not_ok_response, null))
return
}
val thread = feedResponse.thread
if (thread == null) { if (thread == null) {
fetching.postValue(error("thread is null!", null)) _fetching.postValue(error("thread is null!", null))
return return@launch
} }
setThread(thread) setThread(thread)
fetching.postValue(success(Any())) _fetching.postValue(success(Any()))
} } catch (e: Exception) {
Log.e(TAG, "Failed fetching dm chats", e)
override fun onFailure(call: Call<DirectThreadFeedResponse?>, t: Throwable) { _fetching.postValue(error(e.message, null))
Log.e(TAG, "Failed fetching dm chats", t)
fetching.postValue(error(t.message, null))
hasOlder = false hasOlder = false
} }
})
// chatsRequest?.enqueue(object : Callback<DirectThreadFeedResponse?> {
// override fun onResponse(call: Call<DirectThreadFeedResponse?>, response: Response<DirectThreadFeedResponse?>) {
// val feedResponse = response.body()
// if (feedResponse == null) {
// fetching.postValue(error(R.string.generic_null_response, null))
// Log.e(TAG, "onResponse: response was null!")
// return
// }
// if (feedResponse.status != null && feedResponse.status != "ok") {
// fetching.postValue(error(R.string.generic_not_ok_response, null))
// return
// }
// val thread = feedResponse.thread
// if (thread == null) {
// fetching.postValue(error("thread is null!", null))
// return
// }
// setThread(thread)
// fetching.postValue(success(Any()))
// }
//
// override fun onFailure(call: Call<DirectThreadFeedResponse?>, t: Throwable) {
// Log.e(TAG, "Failed fetching dm chats", t)
// fetching.postValue(error(t.message, null))
// hasOlder = false
// }
// })
}
if (cursor == null) { if (cursor == null) {
fetchPendingRequests() fetchPendingRequests()
} }
@ -206,7 +220,7 @@ class ThreadManager private constructor(
Log.e(TAG, "onResponse: response body was null") Log.e(TAG, "onResponse: response body was null")
return return
} }
pendingRequests.postValue(body) _pendingRequests.postValue(body)
} }
override fun onFailure(call: Call<DirectThreadParticipantRequestsResponse?>, t: Throwable) { override fun onFailure(call: Call<DirectThreadParticipantRequestsResponse?>, t: Throwable) {
@ -389,7 +403,7 @@ class ThreadManager private constructor(
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val userId = getCurrentUserId(data) ?: return data val userId = getCurrentUserId(data) ?: return data
val clientContext = UUID.randomUUID().toString() val clientContext = UUID.randomUUID().toString()
val replyToItemValue = replyToItem.value val replyToItemValue = _replyToItem.value
val directItem = createText(userId, clientContext, text, replyToItemValue) val directItem = createText(userId, clientContext, text, replyToItemValue)
// Log.d(TAG, "sendText: sending: itemId: " + directItem.getItemId()); // Log.d(TAG, "sendText: sending: itemId: " + directItem.getItemId());
directItem.isPending = true directItem.isPending = true
@ -630,7 +644,7 @@ class ThreadManager private constructor(
fun setReplyToItem(item: DirectItem?) { fun setReplyToItem(item: DirectItem?) {
// Log.d(TAG, "setReplyToItem: " + item); // Log.d(TAG, "setReplyToItem: " + item);
replyToItem.postValue(item) _replyToItem.postValue(item)
} }
private fun forward(thread: DirectThread, itemToForward: DirectItem): LiveData<Resource<Any?>> { private fun forward(thread: DirectThread, itemToForward: DirectItem): LiveData<Resource<Any?>> {
@ -770,14 +784,14 @@ class ThreadManager private constructor(
return data return data
} }
fun refreshChats() { fun refreshChats(scope: CoroutineScope) {
val isFetching = fetching.value val isFetching = _fetching.value
if (isFetching != null && isFetching.status === Resource.Status.LOADING) { if (isFetching != null && isFetching.status === Resource.Status.LOADING) {
stopCurrentRequest() stopCurrentRequest()
} }
cursor = null cursor = null
hasOlder = true hasOlder = true
fetchChats() fetchChats(scope)
} }
private fun sendPhoto( private fun sendPhoto(
@ -1076,7 +1090,7 @@ class ThreadManager private constructor(
if (it.isExecuted || it.isCanceled) return if (it.isExecuted || it.isCanceled) return
it.cancel() it.cancel()
} }
fetching.postValue(success(Any())) _fetching.postValue(success(Any()))
} }
private fun getCurrentUserId(data: MutableLiveData<Resource<Any?>>): Long? { private fun getCurrentUserId(data: MutableLiveData<Resource<Any?>>): Long? {
@ -1108,10 +1122,7 @@ class ThreadManager private constructor(
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
val addUsersRequest = service.addUsers( val addUsersRequest = service.addUsers(
threadId, threadId,
users.stream() users.map { obj: User -> obj.pk }
.filter { obj: User? -> Objects.nonNull(obj) }
.map { obj: User -> obj.pk }
.collect(Collectors.toList())
) )
handleDetailsChangeRequest(data, addUsersRequest) handleDetailsChangeRequest(data, addUsersRequest)
return data return data
@ -1135,10 +1146,7 @@ class ThreadManager private constructor(
if (leftUsersValue == null) { if (leftUsersValue == null) {
leftUsersValue = emptyList() leftUsersValue = emptyList()
} }
val updatedActiveUsers = activeUsers.stream() val updatedActiveUsers = activeUsers.filter { u: User -> u.pk != user.pk }
.filter { obj: User? -> Objects.nonNull(obj) }
.filter { u: User -> u.pk != user.pk }
.collect(Collectors.toList())
val updatedLeftUsersBuilder = ImmutableList.builder<User>().addAll(leftUsersValue) val updatedLeftUsersBuilder = ImmutableList.builder<User>().addAll(leftUsersValue)
if (!leftUsersValue.contains(user)) { if (!leftUsersValue.contains(user)) {
updatedLeftUsersBuilder.add(user) updatedLeftUsersBuilder.add(user)
@ -1204,10 +1212,7 @@ class ThreadManager private constructor(
return return
} }
val currentAdmins = adminUserIds.value ?: return val currentAdmins = adminUserIds.value ?: return
val updatedAdminUserIds = currentAdmins.stream() val updatedAdminUserIds = currentAdmins.filter { userId1: Long -> userId1 != user.pk }
.filter { obj: Long? -> Objects.nonNull(obj) }
.filter { userId1: Long -> userId1 != user.pk }
.collect(Collectors.toList())
val currentThread = thread.value ?: return val currentThread = thread.value ?: return
try { try {
val thread = currentThread.clone() as DirectThread val thread = currentThread.clone() as DirectThread
@ -1362,11 +1367,11 @@ class ThreadManager private constructor(
return data return data
} }
fun blockUser(user: User): LiveData<Resource<Any?>> { fun blockUser(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
friendshipService.changeBlock(false, user.pk, object : ServiceCallback<FriendshipChangeResponse?> { friendshipService.changeBlock(false, user.pk, object : ServiceCallback<FriendshipChangeResponse?> {
override fun onSuccess(result: FriendshipChangeResponse?) { override fun onSuccess(result: FriendshipChangeResponse?) {
refreshChats() refreshChats(scope)
} }
override fun onFailure(t: Throwable) { override fun onFailure(t: Throwable) {
@ -1377,11 +1382,11 @@ class ThreadManager private constructor(
return data return data
} }
fun unblockUser(user: User): LiveData<Resource<Any?>> { fun unblockUser(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
friendshipService.changeBlock(true, user.pk, object : ServiceCallback<FriendshipChangeResponse?> { friendshipService.changeBlock(true, user.pk, object : ServiceCallback<FriendshipChangeResponse?> {
override fun onSuccess(result: FriendshipChangeResponse?) { override fun onSuccess(result: FriendshipChangeResponse?) {
refreshChats() refreshChats(scope)
} }
override fun onFailure(t: Throwable) { override fun onFailure(t: Throwable) {
@ -1392,11 +1397,11 @@ class ThreadManager private constructor(
return data return data
} }
fun restrictUser(user: User): LiveData<Resource<Any?>> { fun restrictUser(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
friendshipService.toggleRestrict(user.pk, true, object : ServiceCallback<FriendshipRestrictResponse?> { friendshipService.toggleRestrict(user.pk, true, object : ServiceCallback<FriendshipRestrictResponse?> {
override fun onSuccess(result: FriendshipRestrictResponse?) { override fun onSuccess(result: FriendshipRestrictResponse?) {
refreshChats() refreshChats(scope)
} }
override fun onFailure(t: Throwable) { override fun onFailure(t: Throwable) {
@ -1407,11 +1412,11 @@ class ThreadManager private constructor(
return data return data
} }
fun unRestrictUser(user: User): LiveData<Resource<Any?>> { fun unRestrictUser(user: User, scope: CoroutineScope): LiveData<Resource<Any?>> {
val data = MutableLiveData<Resource<Any?>>() val data = MutableLiveData<Resource<Any?>>()
friendshipService.toggleRestrict(user.pk, false, object : ServiceCallback<FriendshipRestrictResponse?> { friendshipService.toggleRestrict(user.pk, false, object : ServiceCallback<FriendshipRestrictResponse?> {
override fun onSuccess(result: FriendshipRestrictResponse?) { override fun onSuccess(result: FriendshipRestrictResponse?) {
refreshChats() refreshChats(scope)
} }
override fun onFailure(t: Throwable) { override fun onFailure(t: Throwable) {
@ -1427,10 +1432,7 @@ class ThreadManager private constructor(
data.postValue(loading(null)) data.postValue(loading(null))
val approveUsersRequest = service.approveParticipantRequests( val approveUsersRequest = service.approveParticipantRequests(
threadId, threadId,
users.stream() users.map { obj: User -> obj.pk }
.filter { obj: User? -> Objects.nonNull(obj) }
.map { obj: User -> obj.pk }
.collect(Collectors.toList())
) )
handleDetailsChangeRequest(data, approveUsersRequest, object : OnSuccessAction { handleDetailsChangeRequest(data, approveUsersRequest, object : OnSuccessAction {
override fun onSuccess() { override fun onSuccess() {
@ -1445,9 +1447,7 @@ class ThreadManager private constructor(
data.postValue(loading(null)) data.postValue(loading(null))
val approveUsersRequest = service.declineParticipantRequests( val approveUsersRequest = service.declineParticipantRequests(
threadId, threadId,
users.stream() users.map { obj: User -> obj.pk }
.map { obj: User -> obj.pk }
.collect(Collectors.toList())
) )
handleDetailsChangeRequest(data, approveUsersRequest, object : OnSuccessAction { handleDetailsChangeRequest(data, approveUsersRequest, object : OnSuccessAction {
override fun onSuccess() { override fun onSuccess() {
@ -1458,18 +1458,16 @@ class ThreadManager private constructor(
} }
private fun pendingUserApproveDenySuccessAction(users: List<User>) { private fun pendingUserApproveDenySuccessAction(users: List<User>) {
val pendingRequestsValue = pendingRequests.value ?: return val pendingRequestsValue = _pendingRequests.value ?: return
val pendingUsers = pendingRequestsValue.users val pendingUsers = pendingRequestsValue.users
if (pendingUsers == null || pendingUsers.isEmpty()) return if (pendingUsers == null || pendingUsers.isEmpty()) return
val filtered = pendingUsers.stream() val filtered = pendingUsers.filter { o: User -> !users.contains(o) }
.filter { o: User -> !users.contains(o) }
.collect(Collectors.toList())
try { try {
val clone = pendingRequestsValue.clone() as DirectThreadParticipantRequestsResponse val clone = pendingRequestsValue.clone() as DirectThreadParticipantRequestsResponse
clone.users = filtered clone.users = filtered
val totalParticipantRequests = clone.totalParticipantRequests val totalParticipantRequests = clone.totalParticipantRequests
clone.totalParticipantRequests = if (totalParticipantRequests > 0) totalParticipantRequests - 1 else 0 clone.totalParticipantRequests = if (totalParticipantRequests > 0) totalParticipantRequests - 1 else 0
pendingRequests.postValue(clone) _pendingRequests.postValue(clone)
} catch (e: CloneNotSupportedException) { } catch (e: CloneNotSupportedException) {
Log.e(TAG, "pendingUserApproveDenySuccessAction: ", e) Log.e(TAG, "pendingUserApproveDenySuccessAction: ", e)
} }

View File

@ -6,16 +6,16 @@ import retrofit2.http.*
interface DirectMessagesRepository { interface DirectMessagesRepository {
@GET("/api/v1/direct_v2/inbox/") @GET("/api/v1/direct_v2/inbox/")
fun fetchInbox(@QueryMap queryMap: Map<String, String>): Call<DirectInboxResponse?> suspend fun fetchInbox(@QueryMap queryMap: Map<String, String>): DirectInboxResponse
@GET("/api/v1/direct_v2/pending_inbox/") @GET("/api/v1/direct_v2/pending_inbox/")
fun fetchPendingInbox(@QueryMap queryMap: Map<String, String>): Call<DirectInboxResponse?> suspend fun fetchPendingInbox(@QueryMap queryMap: Map<String, String>): DirectInboxResponse
@GET("/api/v1/direct_v2/threads/{threadId}/") @GET("/api/v1/direct_v2/threads/{threadId}/")
fun fetchThread( suspend fun fetchThread(
@Path("threadId") threadId: String, @Path("threadId") threadId: String,
@QueryMap queryMap: Map<String, String>, @QueryMap queryMap: Map<String, String>,
): Call<DirectThreadFeedResponse?> ): DirectThreadFeedResponse
@GET("/api/v1/direct_v2/get_badge_count/?no_raven=1") @GET("/api/v1/direct_v2/get_badge_count/?no_raven=1")
fun fetchUnseenCount(): Call<DirectBadgeCount?> fun fetchUnseenCount(): Call<DirectBadgeCount?>

View File

@ -234,7 +234,7 @@ public class DMSyncService extends LifecycleService {
parseUnread(directInbox); parseUnread(directInbox);
}); });
Log.d(TAG, "onStartCommand: refreshing inbox"); Log.d(TAG, "onStartCommand: refreshing inbox");
inboxManager.refresh(); // inboxManager.refresh();
return START_NOT_STICKY; return START_NOT_STICKY;
} }

View File

@ -1,56 +0,0 @@
package awais.instagrabber.viewmodels;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import java.util.List;
import awais.instagrabber.managers.DirectMessagesManager;
import awais.instagrabber.managers.InboxManager;
import awais.instagrabber.models.Resource;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectInbox;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
public class DirectInboxViewModel extends ViewModel {
private static final String TAG = DirectInboxViewModel.class.getSimpleName();
private final InboxManager inboxManager;
public DirectInboxViewModel() {
final DirectMessagesManager messagesManager = DirectMessagesManager.INSTANCE;
inboxManager = messagesManager.getInboxManager();
}
public LiveData<Resource<DirectInbox>> getInbox() {
return inboxManager.getInbox();
}
public LiveData<List<DirectThread>> getThreads() {
return inboxManager.getThreads();
}
public LiveData<Resource<Integer>> getUnseenCount() {
return inboxManager.getUnseenCount();
}
public LiveData<Integer> getPendingRequestsTotal() {
return inboxManager.getPendingRequestsTotal();
}
public User getViewer() {
return inboxManager.getViewer();
}
public void fetchInbox() {
inboxManager.fetchInbox();
}
public void refresh() {
inboxManager.refresh();
}
public void onDestroy() {
inboxManager.onDestroy();
}
}

View File

@ -0,0 +1,36 @@
package awais.instagrabber.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import awais.instagrabber.managers.DirectMessagesManager
import awais.instagrabber.managers.InboxManager
import awais.instagrabber.models.Resource
import awais.instagrabber.repositories.responses.User
import awais.instagrabber.repositories.responses.directmessages.DirectInbox
import awais.instagrabber.repositories.responses.directmessages.DirectThread
class DirectInboxViewModel : ViewModel() {
private val inboxManager: InboxManager = DirectMessagesManager.inboxManager
val inbox: LiveData<Resource<DirectInbox?>> = inboxManager.getInbox()
val threads: LiveData<List<DirectThread>> = inboxManager.threads
val unseenCount: LiveData<Resource<Int?>> = inboxManager.getUnseenCount()
val pendingRequestsTotal: LiveData<Int> = inboxManager.getPendingRequestsTotal()
val viewer: User? = inboxManager.viewer
fun fetchInbox() {
inboxManager.fetchInbox(viewModelScope)
}
fun refresh() {
inboxManager.refresh(viewModelScope)
}
fun onDestroy() {
inboxManager.onDestroy()
}
init {
inboxManager.fetchInbox(viewModelScope)
}
}

View File

@ -1,48 +0,0 @@
package awais.instagrabber.viewmodels;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import java.util.List;
import awais.instagrabber.managers.DirectMessagesManager;
import awais.instagrabber.managers.InboxManager;
import awais.instagrabber.models.Resource;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectInbox;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
public class DirectPendingInboxViewModel extends ViewModel {
private static final String TAG = DirectPendingInboxViewModel.class.getSimpleName();
private final InboxManager inboxManager;
public DirectPendingInboxViewModel() {
inboxManager = DirectMessagesManager.INSTANCE.getPendingInboxManager();
inboxManager.fetchInbox();
}
public LiveData<List<DirectThread>> getThreads() {
return inboxManager.getThreads();
}
public LiveData<Resource<DirectInbox>> getInbox() {
return inboxManager.getInbox();
}
public User getViewer() {
return inboxManager.getViewer();
}
public void fetchInbox() {
inboxManager.fetchInbox();
}
public void refresh() {
inboxManager.refresh();
}
public void onDestroy() {
inboxManager.onDestroy();
}
}

View File

@ -0,0 +1,34 @@
package awais.instagrabber.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import awais.instagrabber.managers.DirectMessagesManager.pendingInboxManager
import awais.instagrabber.managers.InboxManager
import awais.instagrabber.models.Resource
import awais.instagrabber.repositories.responses.User
import awais.instagrabber.repositories.responses.directmessages.DirectInbox
import awais.instagrabber.repositories.responses.directmessages.DirectThread
class DirectPendingInboxViewModel : ViewModel() {
private val inboxManager: InboxManager = pendingInboxManager
val threads: LiveData<List<DirectThread>> = inboxManager.threads
val inbox: LiveData<Resource<DirectInbox?>> = inboxManager.getInbox()
val viewer: User? = inboxManager.viewer
fun fetchInbox() {
inboxManager.fetchInbox(viewModelScope)
}
fun refresh() {
inboxManager.refresh(viewModelScope)
}
fun onDestroy() {
inboxManager.onDestroy()
}
init {
inboxManager.fetchInbox(viewModelScope)
}
}

View File

@ -1,299 +0,0 @@
package awais.instagrabber.viewmodels;
import android.app.Application;
import android.content.ContentResolver;
import android.content.res.Resources;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.core.util.Pair;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import awais.instagrabber.R;
import awais.instagrabber.dialogs.MultiOptionDialogFragment.Option;
import awais.instagrabber.managers.DirectMessagesManager;
import awais.instagrabber.managers.ThreadManager;
import awais.instagrabber.models.Resource;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.TextUtils;
import static awais.instagrabber.utils.Utils.settingsHelper;
public class DirectSettingsViewModel extends AndroidViewModel {
private static final String TAG = DirectSettingsViewModel.class.getSimpleName();
private static final String ACTION_KICK = "kick";
private static final String ACTION_MAKE_ADMIN = "make_admin";
private static final String ACTION_REMOVE_ADMIN = "remove_admin";
private static final String ACTION_BLOCK = "block";
private static final String ACTION_UNBLOCK = "unblock";
// private static final String ACTION_REPORT = "report";
private static final String ACTION_RESTRICT = "restrict";
private static final String ACTION_UNRESTRICT = "unrestrict";
private final long viewerId;
private final Resources resources;
private final ThreadManager threadManager;
public DirectSettingsViewModel(final Application application,
@NonNull final String threadId,
final boolean pending,
@NonNull final User currentUser) {
super(application);
final String cookie = settingsHelper.getString(Constants.COOKIE);
viewerId = CookieUtils.getUserIdFromCookie(cookie);
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
if (TextUtils.isEmpty(csrfToken) || viewerId <= 0 || TextUtils.isEmpty(deviceUuid)) {
throw new IllegalArgumentException("User is not logged in!");
}
final ContentResolver contentResolver = application.getContentResolver();
resources = getApplication().getResources();
final DirectMessagesManager messagesManager = DirectMessagesManager.INSTANCE;
threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
}
@NonNull
public LiveData<DirectThread> getThread() {
return threadManager.getThread();
}
// public void setThread(@NonNull final DirectThread thread) {
// this.thread = thread;
// inputMode.postValue(thread.getInputMode());
// List<User> users = thread.getUsers();
// final ImmutableList.Builder<User> builder = ImmutableList.<User>builder().add(currentUser);
// if (users != null) {
// builder.addAll(users);
// }
// users = builder.build();
// this.users.postValue(new Pair<>(users, thread.getLeftUsers()));
// // setTitle(thread.getThreadTitle());
// final List<Long> adminUserIds = thread.getAdminUserIds();
// this.adminUserIds.postValue(adminUserIds);
// viewerIsAdmin = adminUserIds.contains(viewerId);
// muted.postValue(thread.getMuted());
// mentionsMuted.postValue(thread.isMentionsMuted());
// approvalRequiredToJoin.postValue(thread.isApprovalRequiredForNewMembers());
// isPending.postValue(thread.isPending());
// if (thread.getInputMode() != 1 && thread.isGroup() && viewerIsAdmin) {
// fetchPendingRequests();
// }
// }
public LiveData<Integer> getInputMode() {
return threadManager.getInputMode();
}
public LiveData<Boolean> isGroup() {
return threadManager.isGroup();
}
public LiveData<List<User>> getUsers() {
return threadManager.getUsersWithCurrent();
}
public LiveData<List<User>> getLeftUsers() {
return threadManager.getLeftUsers();
}
public LiveData<Pair<List<User>, List<User>>> getUsersAndLeftUsers() {
return threadManager.getUsersAndLeftUsers();
}
public LiveData<String> getTitle() {
return threadManager.getThreadTitle();
}
// public void setTitle(final String title) {
// if (title == null) {
// this.title.postValue("");
// return;
// }
// this.title.postValue(title.trim());
// }
public LiveData<List<Long>> getAdminUserIds() {
return threadManager.getAdminUserIds();
}
public LiveData<Boolean> isMuted() {
return threadManager.isMuted();
}
public LiveData<Boolean> getApprovalRequiredToJoin() {
return threadManager.isApprovalRequiredToJoin();
}
public LiveData<DirectThreadParticipantRequestsResponse> getPendingRequests() {
return threadManager.getPendingRequests();
}
public LiveData<Boolean> isPending() {
return threadManager.isPending();
}
public LiveData<Boolean> isViewerAdmin() {
return threadManager.isViewerAdmin();
}
public LiveData<Resource<Object>> updateTitle(final String newTitle) {
return threadManager.updateTitle(newTitle);
}
public LiveData<Resource<Object>> addMembers(final Set<User> users) {
return threadManager.addMembers(users);
}
public LiveData<Resource<Object>> removeMember(final User user) {
return threadManager.removeMember(user);
}
private LiveData<Resource<Object>> makeAdmin(final User user) {
return threadManager.makeAdmin(user);
}
private LiveData<Resource<Object>> removeAdmin(final User user) {
return threadManager.removeAdmin(user);
}
public LiveData<Resource<Object>> mute() {
return threadManager.mute();
}
public LiveData<Resource<Object>> unmute() {
return threadManager.unmute();
}
public LiveData<Resource<Object>> muteMentions() {
return threadManager.muteMentions();
}
public LiveData<Resource<Object>> unmuteMentions() {
return threadManager.unmuteMentions();
}
private LiveData<Resource<Object>> blockUser(final User user) {
return threadManager.blockUser(user);
}
private LiveData<Resource<Object>> unblockUser(final User user) {
return threadManager.unblockUser(user);
}
private LiveData<Resource<Object>> restrictUser(final User user) {
return threadManager.restrictUser(user);
}
private LiveData<Resource<Object>> unRestrictUser(final User user) {
return threadManager.unRestrictUser(user);
}
public LiveData<Resource<Object>> approveUsers(final List<User> users) {
return threadManager.approveUsers(users);
}
public LiveData<Resource<Object>> denyUsers(final List<User> users) {
return threadManager.denyUsers(users);
}
public LiveData<Resource<Object>> approvalRequired() {
return threadManager.approvalRequired();
}
public LiveData<Resource<Object>> approvalNotRequired() {
return threadManager.approvalNotRequired();
}
public LiveData<Resource<Object>> leave() {
return threadManager.leave();
}
public LiveData<Resource<Object>> end() {
return threadManager.end();
}
public ArrayList<Option<String>> createUserOptions(final User user) {
final ArrayList<Option<String>> options = new ArrayList<>();
if (user == null || isSelf(user) || hasLeft(user)) {
return options;
}
final Boolean viewerIsAdmin = threadManager.isViewerAdmin().getValue();
if (viewerIsAdmin != null && viewerIsAdmin) {
options.add(new Option<>(getString(R.string.dms_action_kick), ACTION_KICK));
final boolean isAdmin = threadManager.isAdmin(user);
options.add(new Option<>(
isAdmin ? getString(R.string.dms_action_remove_admin) : getString(R.string.dms_action_make_admin),
isAdmin ? ACTION_REMOVE_ADMIN : ACTION_MAKE_ADMIN
));
}
final boolean blocking = user.getFriendshipStatus().getBlocking();
options.add(new Option<>(
blocking ? getString(R.string.unblock) : getString(R.string.block),
blocking ? ACTION_UNBLOCK : ACTION_BLOCK
));
// options.add(new Option<>(getString(R.string.report), ACTION_REPORT));
final Boolean isGroup = threadManager.isGroup().getValue();
if (isGroup != null && isGroup) {
final boolean restricted = user.getFriendshipStatus().isRestricted();
options.add(new Option<>(
restricted ? getString(R.string.unrestrict) : getString(R.string.restrict),
restricted ? ACTION_UNRESTRICT : ACTION_RESTRICT
));
}
return options;
}
private boolean hasLeft(final User user) {
final List<User> leftUsers = getLeftUsers().getValue();
if (leftUsers == null) return false;
return leftUsers.contains(user);
}
private boolean isSelf(final User user) {
return user.getPk() == viewerId;
}
private String getString(@StringRes final int resId) {
return resources.getString(resId);
}
public LiveData<Resource<Object>> doAction(final User user, final String action) {
if (user == null || action == null) return null;
switch (action) {
case ACTION_KICK:
return removeMember(user);
case ACTION_MAKE_ADMIN:
return makeAdmin(user);
case ACTION_REMOVE_ADMIN:
return removeAdmin(user);
case ACTION_BLOCK:
return blockUser(user);
case ACTION_UNBLOCK:
return unblockUser(user);
// case ACTION_REPORT:
// break;
case ACTION_RESTRICT:
return restrictUser(user);
case ACTION_UNRESTRICT:
return unRestrictUser(user);
default:
return null;
}
}
public LiveData<User> getInviter() {
return threadManager.getInviter();
}
}

View File

@ -0,0 +1,201 @@
package awais.instagrabber.viewmodels
import android.app.Application
import androidx.annotation.StringRes
import androidx.core.util.Pair
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import awais.instagrabber.R
import awais.instagrabber.dialogs.MultiOptionDialogFragment.Option
import awais.instagrabber.managers.DirectMessagesManager
import awais.instagrabber.models.Resource
import awais.instagrabber.repositories.responses.User
import awais.instagrabber.repositories.responses.directmessages.DirectThread
import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse
import awais.instagrabber.utils.Constants
import awais.instagrabber.utils.Utils
import awais.instagrabber.utils.getCsrfTokenFromCookie
import awais.instagrabber.utils.getUserIdFromCookie
class DirectSettingsViewModel(
application: Application,
threadId: String,
pending: Boolean,
currentUser: User,
) : AndroidViewModel(application) {
private val viewerId: Long
private val resources = application.resources
private val threadManager = DirectMessagesManager.getThreadManager(threadId, pending, currentUser, application.contentResolver)
val thread: LiveData<DirectThread?> = threadManager.thread
// public void setThread(@NonNull final DirectThread thread) {
// this.thread = thread;
// inputMode.postValue(thread.getInputMode());
// List<User> users = thread.getUsers();
// final ImmutableList.Builder<User> builder = ImmutableList.<User>builder().add(currentUser);
// if (users != null) {
// builder.addAll(users);
// }
// users = builder.build();
// this.users.postValue(new Pair<>(users, thread.getLeftUsers()));
// // setTitle(thread.getThreadTitle());
// final List<Long> adminUserIds = thread.getAdminUserIds();
// this.adminUserIds.postValue(adminUserIds);
// viewerIsAdmin = adminUserIds.contains(viewerId);
// muted.postValue(thread.getMuted());
// mentionsMuted.postValue(thread.isMentionsMuted());
// approvalRequiredToJoin.postValue(thread.isApprovalRequiredForNewMembers());
// isPending.postValue(thread.isPending());
// if (thread.getInputMode() != 1 && thread.isGroup() && viewerIsAdmin) {
// fetchPendingRequests();
// }
// }
val inputMode: LiveData<Int> = threadManager.inputMode
fun isGroup(): LiveData<Boolean> = threadManager.isGroup
fun getUsers(): LiveData<List<User>> = threadManager.usersWithCurrent
fun getLeftUsers(): LiveData<List<User>> = threadManager.leftUsers
fun getUsersAndLeftUsers(): LiveData<Pair<List<User>, List<User>>> = threadManager.usersAndLeftUsers
fun getTitle(): LiveData<String?> = threadManager.threadTitle
// public void setTitle(final String title) {
// if (title == null) {
// this.title.postValue("");
// return;
// }
// this.title.postValue(title.trim());
// }
fun getAdminUserIds(): LiveData<List<Long>> = threadManager.adminUserIds
fun isMuted(): LiveData<Boolean> = threadManager.isMuted
fun getApprovalRequiredToJoin(): LiveData<Boolean> = threadManager.isApprovalRequiredToJoin
fun getPendingRequests(): LiveData<DirectThreadParticipantRequestsResponse?> = threadManager.pendingRequests
fun isPending(): LiveData<Boolean> = threadManager.isPending
fun isViewerAdmin(): LiveData<Boolean> = threadManager.isViewerAdmin
fun updateTitle(newTitle: String): LiveData<Resource<Any?>> = threadManager.updateTitle(newTitle)
fun addMembers(users: Set<User>): LiveData<Resource<Any?>> = threadManager.addMembers(users)
fun removeMember(user: User): LiveData<Resource<Any?>> = threadManager.removeMember(user)
private fun makeAdmin(user: User): LiveData<Resource<Any?>> = threadManager.makeAdmin(user)
private fun removeAdmin(user: User): LiveData<Resource<Any?>> = threadManager.removeAdmin(user)
fun mute(): LiveData<Resource<Any?>> = threadManager.mute()
fun unmute(): LiveData<Resource<Any?>> = threadManager.unmute()
fun muteMentions(): LiveData<Resource<Any?>> = threadManager.muteMentions()
fun unmuteMentions(): LiveData<Resource<Any?>> = threadManager.unmuteMentions()
private fun blockUser(user: User): LiveData<Resource<Any?>> = threadManager.blockUser(user, viewModelScope)
private fun unblockUser(user: User): LiveData<Resource<Any?>> = threadManager.unblockUser(user, viewModelScope)
private fun restrictUser(user: User): LiveData<Resource<Any?>> = threadManager.restrictUser(user, viewModelScope)
private fun unRestrictUser(user: User): LiveData<Resource<Any?>> = threadManager.unRestrictUser(user, viewModelScope)
fun approveUsers(users: List<User>): LiveData<Resource<Any?>> = threadManager.approveUsers(users)
fun denyUsers(users: List<User>): LiveData<Resource<Any?>> = threadManager.denyUsers(users)
fun approvalRequired(): LiveData<Resource<Any?>> = threadManager.approvalRequired()
fun approvalNotRequired(): LiveData<Resource<Any?>> = threadManager.approvalNotRequired()
fun leave(): LiveData<Resource<Any?>> = threadManager.leave()
fun end(): LiveData<Resource<Any?>> = threadManager.end()
fun createUserOptions(user: User?): ArrayList<Option<String>> {
val options: ArrayList<Option<String>> = ArrayList()
if (user == null || isSelf(user) || hasLeft(user)) {
return options
}
val viewerIsAdmin: Boolean? = threadManager.isViewerAdmin.value
if (viewerIsAdmin != null && viewerIsAdmin) {
options.add(Option(getString(R.string.dms_action_kick), ACTION_KICK))
val isAdmin: Boolean = threadManager.isAdmin(user)
options.add(Option(
if (isAdmin) getString(R.string.dms_action_remove_admin) else getString(R.string.dms_action_make_admin),
if (isAdmin) ACTION_REMOVE_ADMIN else ACTION_MAKE_ADMIN
))
}
val blocking: Boolean = user.friendshipStatus.blocking
options.add(Option(
if (blocking) getString(R.string.unblock) else getString(R.string.block),
if (blocking) ACTION_UNBLOCK else ACTION_BLOCK
))
// options.add(new Option<>(getString(R.string.report), ACTION_REPORT));
val isGroup: Boolean? = threadManager.isGroup.value
if (isGroup != null && isGroup) {
val restricted: Boolean = user.friendshipStatus.isRestricted
options.add(Option(
if (restricted) getString(R.string.unrestrict) else getString(R.string.restrict),
if (restricted) ACTION_UNRESTRICT else ACTION_RESTRICT
))
}
return options
}
private fun hasLeft(user: User): Boolean {
val leftUsers: List<User> = getLeftUsers().value ?: return false
return leftUsers.contains(user)
}
private fun isSelf(user: User): Boolean = user.pk == viewerId
private fun getString(@StringRes resId: Int): String {
return resources.getString(resId)
}
fun doAction(user: User?, action: String?): LiveData<Resource<Any?>>? {
return if (user == null || action == null) null else when (action) {
ACTION_KICK -> removeMember(user)
ACTION_MAKE_ADMIN -> makeAdmin(user)
ACTION_REMOVE_ADMIN -> removeAdmin(user)
ACTION_BLOCK -> blockUser(user)
ACTION_UNBLOCK -> unblockUser(user)
ACTION_RESTRICT -> restrictUser(user)
ACTION_UNRESTRICT -> unRestrictUser(user)
else -> null
}
}
fun getInviter(): LiveData<User?> = threadManager.inviter
companion object {
private const val ACTION_KICK = "kick"
private const val ACTION_MAKE_ADMIN = "make_admin"
private const val ACTION_REMOVE_ADMIN = "remove_admin"
private const val ACTION_BLOCK = "block"
private const val ACTION_UNBLOCK = "unblock"
// private static final String ACTION_REPORT = "report";
private const val ACTION_RESTRICT = "restrict"
private const val ACTION_UNRESTRICT = "unrestrict"
}
init {
val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
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!" }
}
}

View File

@ -5,10 +5,7 @@ import android.content.ContentResolver
import android.media.MediaScannerConnection import android.media.MediaScannerConnection
import android.net.Uri import android.net.Uri
import android.util.Log import android.util.Log
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.*
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import awais.instagrabber.customviews.emoji.Emoji import awais.instagrabber.customviews.emoji.Emoji
import awais.instagrabber.managers.DirectMessagesManager import awais.instagrabber.managers.DirectMessagesManager
import awais.instagrabber.managers.DirectMessagesManager.inboxManager import awais.instagrabber.managers.DirectMessagesManager.inboxManager
@ -50,13 +47,13 @@ class DirectThreadViewModel(
val items: LiveData<List<DirectItem>> by lazy { val items: LiveData<List<DirectItem>> by lazy {
Transformations.map(threadManager.items) { it.filter { thread -> thread.hideInThread == 0 } } Transformations.map(threadManager.items) { it.filter { thread -> thread.hideInThread == 0 } }
} }
val isFetching: LiveData<Resource<Any?>> by lazy { threadManager.isFetching() } val isFetching: LiveData<Resource<Any?>> by lazy { threadManager.fetching }
val users: LiveData<List<User>> by lazy { threadManager.users } val users: LiveData<List<User>> by lazy { threadManager.users }
val leftUsers: LiveData<List<User>> by lazy { threadManager.leftUsers } val leftUsers: LiveData<List<User>> by lazy { threadManager.leftUsers }
val pendingRequestsCount: LiveData<Int> by lazy { threadManager.pendingRequestsCount } val pendingRequestsCount: LiveData<Int> by lazy { threadManager.pendingRequestsCount }
val inputMode: LiveData<Int> by lazy { threadManager.inputMode } val inputMode: LiveData<Int> by lazy { threadManager.inputMode }
val isPending: LiveData<Boolean> by lazy { threadManager.isPending } val isPending: LiveData<Boolean> by lazy { threadManager.isPending }
val replyToItem: LiveData<DirectItem?> by lazy { threadManager.getReplyToItem() } val replyToItem: LiveData<DirectItem?> by lazy { threadManager.replyToItem }
fun moveFromPending() { fun moveFromPending() {
val messagesManager = DirectMessagesManager val messagesManager = DirectMessagesManager
@ -69,11 +66,11 @@ class DirectThreadViewModel(
} }
fun fetchChats() { fun fetchChats() {
threadManager.fetchChats() threadManager.fetchChats(viewModelScope)
} }
fun refreshChats() { fun refreshChats() {
threadManager.refreshChats() threadManager.refreshChats(viewModelScope)
} }
fun sendText(text: String): LiveData<Resource<Any?>> { fun sendText(text: String): LiveData<Resource<Any?>> {

View File

@ -1,347 +1,329 @@
package awais.instagrabber.viewmodels; package awais.instagrabber.viewmodels
import android.util.Log; import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import awais.instagrabber.R
import awais.instagrabber.managers.DirectMessagesManager
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.MediaItemType
import awais.instagrabber.repositories.responses.Caption
import awais.instagrabber.repositories.responses.Location
import awais.instagrabber.repositories.responses.Media
import awais.instagrabber.repositories.responses.User
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient
import awais.instagrabber.utils.Constants
import awais.instagrabber.utils.Utils
import awais.instagrabber.utils.extensions.TAG
import awais.instagrabber.utils.getCsrfTokenFromCookie
import awais.instagrabber.utils.getUserIdFromCookie
import awais.instagrabber.webservices.MediaService
import awais.instagrabber.webservices.ServiceCallback
import com.google.common.collect.ImmutableList
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.util.*
import androidx.annotation.NonNull; class PostViewV2ViewModel : ViewModel() {
import androidx.lifecycle.LiveData; private val user = MutableLiveData<User?>()
import androidx.lifecycle.MutableLiveData; private val caption = MutableLiveData<Caption?>()
import androidx.lifecycle.ViewModel; private val location = MutableLiveData<Location?>()
private val date = MutableLiveData<String>()
private val likeCount = MutableLiveData(0L)
private val commentCount = MutableLiveData(0L)
private val viewCount = MutableLiveData(0L)
private val type = MutableLiveData<MediaItemType?>()
private val liked = MutableLiveData(false)
private val saved = MutableLiveData(false)
private val options = MutableLiveData<List<Int>>(ArrayList())
private val viewerId: Long
val isLoggedIn: Boolean
lateinit var media: Media
private set
private var mediaService: MediaService? = null
private var messageManager: DirectMessagesManager? = null
import com.google.common.collect.ImmutableList; fun setMedia(media: Media) {
this.media = media
import java.util.ArrayList; user.postValue(media.user)
import java.util.List; caption.postValue(media.caption)
import java.util.Set; location.postValue(media.location)
date.postValue(media.date)
import awais.instagrabber.R; likeCount.postValue(media.likeCount)
import awais.instagrabber.managers.DirectMessagesManager; commentCount.postValue(media.commentCount)
import awais.instagrabber.models.Resource; viewCount.postValue(if (media.mediaType == MediaItemType.MEDIA_TYPE_VIDEO) media.viewCount else null)
import awais.instagrabber.models.enums.MediaItemType; type.postValue(media.mediaType)
import awais.instagrabber.repositories.responses.Caption; liked.postValue(media.hasLiked)
import awais.instagrabber.repositories.responses.Location; saved.postValue(media.hasViewerSaved)
import awais.instagrabber.repositories.responses.Media; initOptions()
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.webservices.MediaService;
import awais.instagrabber.webservices.ServiceCallback;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static awais.instagrabber.utils.Utils.settingsHelper;
public class PostViewV2ViewModel extends ViewModel {
private static final String TAG = PostViewV2ViewModel.class.getSimpleName();
private final MutableLiveData<User> user = new MutableLiveData<>();
private final MutableLiveData<Caption> caption = new MutableLiveData<>();
private final MutableLiveData<Location> location = new MutableLiveData<>();
private final MutableLiveData<String> date = new MutableLiveData<>();
private final MutableLiveData<Long> likeCount = new MutableLiveData<>(0L);
private final MutableLiveData<Long> commentCount = new MutableLiveData<>(0L);
private final MutableLiveData<Long> viewCount = new MutableLiveData<>(0L);
private final MutableLiveData<MediaItemType> type = new MutableLiveData<>();
private final MutableLiveData<Boolean> liked = new MutableLiveData<>(false);
private final MutableLiveData<Boolean> saved = new MutableLiveData<>(false);
private final MutableLiveData<List<Integer>> options = new MutableLiveData<>(new ArrayList<>());
private final MediaService mediaService;
private final long viewerId;
private final boolean isLoggedIn;
private Media media;
private DirectMessagesManager messageManager;
public PostViewV2ViewModel() {
final String cookie = settingsHelper.getString(Constants.COOKIE);
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
viewerId = CookieUtils.getUserIdFromCookie(cookie);
mediaService = MediaService.getInstance(deviceUuid, csrfToken, viewerId);
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
} }
public void setMedia(final Media media) { private fun initOptions() {
this.media = media; val builder = ImmutableList.builder<Int>()
user.postValue(media.getUser()); val user1 = media.user
caption.postValue(media.getCaption()); if (isLoggedIn && user1 != null && user1.pk == viewerId) {
location.postValue(media.getLocation()); builder.add(R.id.edit_caption)
date.postValue(media.getDate()); builder.add(R.id.delete)
likeCount.postValue(media.getLikeCount()); }
commentCount.postValue(media.getCommentCount()); options.postValue(builder.build())
viewCount.postValue(media.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO ? media.getViewCount() : null);
type.postValue(media.getMediaType());
liked.postValue(media.getHasLiked());
saved.postValue(media.getHasViewerSaved());
initOptions();
} }
private void initOptions() { fun getUser(): LiveData<User?> {
final ImmutableList.Builder<Integer> builder = ImmutableList.builder(); return user
if (isLoggedIn && media.getUser() != null && media.getUser().getPk() == viewerId) {
builder.add(R.id.edit_caption);
builder.add(R.id.delete);
}
options.postValue(builder.build());
} }
public Media getMedia() { fun getCaption(): LiveData<Caption?> {
return media; return caption
} }
public boolean isLoggedIn() { fun getLocation(): LiveData<Location?> {
return isLoggedIn; return location
} }
public LiveData<User> getUser() { fun getDate(): LiveData<String> {
return user; return date
} }
public LiveData<Caption> getCaption() { fun getLikeCount(): LiveData<Long> {
return caption; return likeCount
} }
public LiveData<Location> getLocation() { fun getCommentCount(): LiveData<Long> {
return location; return commentCount
} }
public LiveData<String> getDate() { fun getViewCount(): LiveData<Long?> {
return date; return viewCount
} }
public LiveData<Long> getLikeCount() { fun getType(): LiveData<MediaItemType?> {
return likeCount; return type
} }
public LiveData<Long> getCommentCount() { fun getLiked(): LiveData<Boolean> {
return commentCount; return liked
} }
public LiveData<Long> getViewCount() { fun getSaved(): LiveData<Boolean> {
return viewCount; return saved
} }
public LiveData<MediaItemType> getType() { fun getOptions(): LiveData<List<Int>> {
return type; return options
} }
public LiveData<Boolean> getLiked() { fun toggleLike(): LiveData<Resource<Any?>> {
return liked; return if (media.hasLiked) {
unlike()
} else like()
} }
public LiveData<Boolean> getSaved() { fun like(): LiveData<Resource<Any?>> {
return saved; val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null))
mediaService?.like(media.pk, getLikeUnlikeCallback(data))
return data
} }
public LiveData<List<Integer>> getOptions() { fun unlike(): LiveData<Resource<Any?>> {
return options; val data = MutableLiveData<Resource<Any?>>()
data.postValue(loading(null))
mediaService?.unlike(media.pk, getLikeUnlikeCallback(data))
return data
} }
@NonNull private fun getLikeUnlikeCallback(data: MutableLiveData<Resource<Any?>>): ServiceCallback<Boolean?> {
public LiveData<Resource<Object>> toggleLike() { return object : ServiceCallback<Boolean?> {
if (media.getHasLiked()) { override fun onSuccess(result: Boolean?) {
return unlike(); if (result != null && !result) {
data.postValue(error("", null))
return
} }
return like(); data.postValue(success(true))
} val currentLikesCount = media.likeCount
val updatedCount: Long
public LiveData<Resource<Object>> like() { if (!media.hasLiked) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); updatedCount = currentLikesCount + 1
data.postValue(Resource.loading(null)); media.hasLiked = true
mediaService.like(media.getPk(), getLikeUnlikeCallback(data));
return data;
}
public LiveData<Resource<Object>> unlike() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null));
mediaService.unlike(media.getPk(), getLikeUnlikeCallback(data));
return data;
}
@NonNull
private ServiceCallback<Boolean> getLikeUnlikeCallback(final MutableLiveData<Resource<Object>> data) {
return new ServiceCallback<Boolean>() {
@Override
public void onSuccess(final Boolean result) {
if (!result) {
data.postValue(Resource.error("", null));
return;
}
data.postValue(Resource.success(true));
final long currentLikesCount = media.getLikeCount();
final long updatedCount;
if (!media.getHasLiked()) {
updatedCount = currentLikesCount + 1;
media.setHasLiked(true);
} else { } else {
updatedCount = currentLikesCount - 1; updatedCount = currentLikesCount - 1
media.setHasLiked(false); media.hasLiked = false
} }
media.setLikeCount(updatedCount); media.likeCount = updatedCount
likeCount.postValue(updatedCount); likeCount.postValue(updatedCount)
liked.postValue(media.getHasLiked()); liked.postValue(media.hasLiked)
} }
@Override override fun onFailure(t: Throwable) {
public void onFailure(final Throwable t) { data.postValue(error(t.message, null))
data.postValue(Resource.error(t.getMessage(), null)); Log.e(TAG, "Error during like/unlike", t)
Log.e(TAG, "Error during like/unlike", t); }
} }
};
} }
@NonNull fun toggleSave(): LiveData<Resource<Any?>> {
public LiveData<Resource<Object>> toggleSave() { return if (!media.hasViewerSaved) {
if (!media.getHasViewerSaved()) { save(null, false)
return save(null, false); } else unsave()
}
return unsave();
} }
@NonNull fun toggleSave(collection: String?, ignoreSaveState: Boolean): LiveData<Resource<Any?>> {
public LiveData<Resource<Object>> toggleSave(final String collection, final boolean ignoreSaveState) { return save(collection, ignoreSaveState)
return save(collection, ignoreSaveState);
} }
public LiveData<Resource<Object>> save(final String collection, final boolean ignoreSaveState) { fun save(collection: String?, ignoreSaveState: Boolean): LiveData<Resource<Any?>> {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); val data = MutableLiveData<Resource<Any?>>()
data.postValue(Resource.loading(null)); data.postValue(loading(null))
mediaService.save(media.getPk(), collection, getSaveUnsaveCallback(data, ignoreSaveState)); mediaService?.save(media.pk, collection, getSaveUnsaveCallback(data, ignoreSaveState))
return data; return data
} }
public LiveData<Resource<Object>> unsave() { fun unsave(): LiveData<Resource<Any?>> {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); val data = MutableLiveData<Resource<Any?>>()
data.postValue(Resource.loading(null)); data.postValue(loading(null))
mediaService.unsave(media.getPk(), getSaveUnsaveCallback(data, false)); mediaService?.unsave(media.pk, getSaveUnsaveCallback(data, false))
return data; return data
} }
@NonNull private fun getSaveUnsaveCallback(
private ServiceCallback<Boolean> getSaveUnsaveCallback(final MutableLiveData<Resource<Object>> data, data: MutableLiveData<Resource<Any?>>,
final boolean ignoreSaveState) { ignoreSaveState: Boolean,
return new ServiceCallback<Boolean>() { ): ServiceCallback<Boolean?> {
@Override return object : ServiceCallback<Boolean?> {
public void onSuccess(final Boolean result) { override fun onSuccess(result: Boolean?) {
if (!result) { if (result != null && !result) {
data.postValue(Resource.error("", null)); data.postValue(error("", null))
return; return
} }
data.postValue(Resource.success(true)); data.postValue(success(true))
if (!ignoreSaveState) media.setHasViewerSaved(!media.getHasViewerSaved()); if (!ignoreSaveState) media.hasViewerSaved = !media.hasViewerSaved
saved.postValue(media.getHasViewerSaved()); saved.postValue(media.hasViewerSaved)
} }
@Override override fun onFailure(t: Throwable) {
public void onFailure(final Throwable t) { data.postValue(error(t.message, null))
data.postValue(Resource.error(t.getMessage(), null)); Log.e(TAG, "Error during save/unsave", t)
Log.e(TAG, "Error during save/unsave", t); }
} }
};
} }
public LiveData<Resource<Object>> updateCaption(final String caption) { fun updateCaption(caption: String): LiveData<Resource<Any?>> {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); val data = MutableLiveData<Resource<Any?>>()
data.postValue(Resource.loading(null)); data.postValue(loading(null))
mediaService.editCaption(media.getPk(), caption, new ServiceCallback<Boolean>() { mediaService?.editCaption(media.pk, caption, object : ServiceCallback<Boolean?> {
@Override override fun onSuccess(result: Boolean?) {
public void onSuccess(final Boolean result) { if (result != null && result) {
if (result) { data.postValue(success(""))
data.postValue(Resource.success("")); media.setPostCaption(caption)
media.setPostCaption(caption); this@PostViewV2ViewModel.caption.postValue(media.caption)
PostViewV2ViewModel.this.caption.postValue(media.getCaption()); return
return;
} }
data.postValue(Resource.error("", null)); data.postValue(error("", null))
} }
@Override override fun onFailure(t: Throwable) {
public void onFailure(final Throwable t) { Log.e(TAG, "Error editing caption", t)
Log.e(TAG, "Error editing caption", t); data.postValue(error(t.message, null))
data.postValue(Resource.error(t.getMessage(), null));
} }
}); })
return data; return data
} }
public LiveData<Resource<String>> translateCaption() { fun translateCaption(): LiveData<Resource<String?>> {
final MutableLiveData<Resource<String>> data = new MutableLiveData<>(); val data = MutableLiveData<Resource<String?>>()
data.postValue(Resource.loading(null)); data.postValue(loading(null))
final Caption value = caption.getValue(); val value = caption.value ?: return data
if (value == null) return data; mediaService?.translate(value.pk, "1", object : ServiceCallback<String?> {
mediaService.translate(value.getPk(), "1", new ServiceCallback<String>() { override fun onSuccess(result: String?) {
@Override if (result.isNullOrBlank()) {
public void onSuccess(final String result) { data.postValue(error("", null))
if (TextUtils.isEmpty(result)) { return
data.postValue(Resource.error("", null));
return;
} }
data.postValue(Resource.success(result)); data.postValue(success(result))
} }
@Override override fun onFailure(t: Throwable) {
public void onFailure(final Throwable t) { Log.e(TAG, "Error translating comment", t)
Log.e(TAG, "Error translating comment", t); data.postValue(error(t.message, null))
data.postValue(Resource.error(t.getMessage(), null));
} }
}); })
return data; return data
} }
public boolean hasPk() { fun hasPk(): Boolean {
return media.getPk() != null; return media.pk != null
} }
public void setViewCount(final Long viewCount) { fun setViewCount(viewCount: Long?) {
this.viewCount.postValue(viewCount); this.viewCount.postValue(viewCount)
} }
public LiveData<Resource<Object>> delete() { fun delete(): LiveData<Resource<Any?>> {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); val data = MutableLiveData<Resource<Any?>>()
data.postValue(Resource.loading(null)); data.postValue(loading(null))
final Call<String> request = mediaService.delete(media.getId(), media.getMediaType()); val mediaId = media.id
val mediaType = media.mediaType
if (mediaId == null || mediaType == null) {
data.postValue(error("media id or type is null", null))
return data
}
val request = mediaService?.delete(mediaId, mediaType)
if (request == null) { if (request == null) {
data.postValue(Resource.success(new Object())); data.postValue(success(Any()))
return data; return data
} }
request.enqueue(new Callback<String>() { request.enqueue(object : Callback<String?> {
@Override override fun onResponse(call: Call<String?>, response: Response<String?>) {
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { if (!response.isSuccessful) {
if (!response.isSuccessful()) { data.postValue(error(R.string.generic_null_response, null))
data.postValue(Resource.error(R.string.generic_null_response, null)); return
return;
} }
final String body = response.body(); val body = response.body()
if (body == null) { if (body == null) {
data.postValue(Resource.error(R.string.generic_null_response, null)); data.postValue(error(R.string.generic_null_response, null))
return; return
} }
data.postValue(Resource.success(new Object())); data.postValue(success(Any()))
} }
@Override override fun onFailure(call: Call<String?>, t: Throwable) {
public void onFailure(@NonNull final Call<String> 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));
} }
}); })
return data; return data
} }
public void shareDm(@NonNull final RankedRecipient result) { fun shareDm(result: RankedRecipient) {
if (messageManager == null) { if (messageManager == null) {
messageManager = DirectMessagesManager.INSTANCE; messageManager = DirectMessagesManager
} }
messageManager.sendMedia(result, media.getId()); val mediaId = media.id ?: return
messageManager?.sendMedia(result, mediaId, viewModelScope)
} }
public void shareDm(@NonNull final Set<RankedRecipient> recipients) { fun shareDm(recipients: Set<RankedRecipient>) {
if (messageManager == null) { if (messageManager == null) {
messageManager = DirectMessagesManager.INSTANCE; messageManager = DirectMessagesManager
}
val mediaId = media.id ?: return
messageManager?.sendMedia(recipients, mediaId, viewModelScope)
}
init {
val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
val deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
val csrfToken: String? = getCsrfTokenFromCookie(cookie)
viewerId = getUserIdFromCookie(cookie)
isLoggedIn = cookie.isNotBlank() && viewerId != 0L
if (!csrfToken.isNullOrBlank()) {
mediaService = MediaService.getInstance(deviceUuid, csrfToken, viewerId)
} }
messageManager.sendMedia(recipients, media.getId());
} }
} }

View File

@ -18,10 +18,10 @@ class DirectMessagesService private constructor(
) : BaseService() { ) : BaseService() {
private val repository: DirectMessagesRepository = RetrofitFactory.retrofit.create(DirectMessagesRepository::class.java) private val repository: DirectMessagesRepository = RetrofitFactory.retrofit.create(DirectMessagesRepository::class.java)
fun fetchInbox( suspend fun fetchInbox(
cursor: String?, cursor: String?,
seqId: Long, seqId: Long,
): Call<DirectInboxResponse?> { ): DirectInboxResponse {
val queryMap = mutableMapOf( val queryMap = mutableMapOf(
"visual_message_return_type" to "unseen", "visual_message_return_type" to "unseen",
"thread_message_limit" to 10.toString(), "thread_message_limit" to 10.toString(),
@ -38,10 +38,10 @@ class DirectMessagesService private constructor(
return repository.fetchInbox(queryMap) return repository.fetchInbox(queryMap)
} }
fun fetchThread( suspend fun fetchThread(
threadId: String, threadId: String,
cursor: String?, cursor: String?,
): Call<DirectThreadFeedResponse?> { ): DirectThreadFeedResponse {
val queryMap = mutableMapOf( val queryMap = mutableMapOf(
"visual_message_return_type" to "unseen", "visual_message_return_type" to "unseen",
"limit" to 20.toString(), "limit" to 20.toString(),
@ -409,7 +409,7 @@ class DirectMessagesService private constructor(
return repository.end(threadId, form) return repository.end(threadId, form)
} }
fun fetchPendingInbox(cursor: String?, seqId: Long): Call<DirectInboxResponse?> { suspend fun fetchPendingInbox(cursor: String?, seqId: Long): DirectInboxResponse {
val queryMap = mutableMapOf( val queryMap = mutableMapOf(
"visual_message_return_type" to "unseen", "visual_message_return_type" to "unseen",
"thread_message_limit" to 20.toString(), "thread_message_limit" to 20.toString(),