Browse Source

Convert to kotlin, suspend funs, and viewModelScope

renovate/org.robolectric-robolectric-4.x
Ammar Githam 4 years ago
parent
commit
87e6e4440f
  1. 5
      app/build.gradle
  2. 2
      app/src/main/java/awais/instagrabber/activities/MainActivity.kt
  3. 13
      app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java
  4. 16
      app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt
  5. 71
      app/src/main/java/awais/instagrabber/managers/InboxManager.kt
  6. 158
      app/src/main/java/awais/instagrabber/managers/ThreadManager.kt
  7. 8
      app/src/main/java/awais/instagrabber/repositories/DirectMessagesRepository.kt
  8. 2
      app/src/main/java/awais/instagrabber/services/DMSyncService.java
  9. 56
      app/src/main/java/awais/instagrabber/viewmodels/DirectInboxViewModel.java
  10. 36
      app/src/main/java/awais/instagrabber/viewmodels/DirectInboxViewModel.kt
  11. 48
      app/src/main/java/awais/instagrabber/viewmodels/DirectPendingInboxViewModel.java
  12. 34
      app/src/main/java/awais/instagrabber/viewmodels/DirectPendingInboxViewModel.kt
  13. 299
      app/src/main/java/awais/instagrabber/viewmodels/DirectSettingsViewModel.java
  14. 201
      app/src/main/java/awais/instagrabber/viewmodels/DirectSettingsViewModel.kt
  15. 13
      app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.kt
  16. 508
      app/src/main/java/awais/instagrabber/viewmodels/PostViewV2ViewModel.kt
  17. 10
      app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.kt

5
app/build.gradle

@ -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"

2
app/src/main/java/awais/instagrabber/activities/MainActivity.kt

@ -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)

13
app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java

@ -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);

16
app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt

@ -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) {
sendMedia(recipient, mediaId, true, null)
fun sendMedia(recipient: RankedRecipient, mediaId: String, scope: CoroutineScope) {
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()
} }

71
app/src/main/java/awais/instagrabber/managers/InboxManager.kt

@ -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.Utils
import awais.instagrabber.utils.getCsrfTokenFromCookie
import awais.instagrabber.utils.getUserIdFromCookie
import awais.instagrabber.utils.*
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)
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)
}
override fun onFailure(call: Call<DirectInboxResponse?>, t: Throwable) {
Log.e(TAG, "Failed fetching dm inbox", t)
inbox.postValue(error(t.message, currentDirectInbox))
scope.launch(Dispatchers.IO) {
try {
val inboxValue = if (pending) service.fetchPendingInbox(cursor, seqId) else service.fetchInbox(cursor, seqId)
parseInboxResponse(inboxValue)
} catch (e: Exception) {
inbox.postValue(error(e.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?>? ->
if (inboxResource == null) {
return@map emptyList()
}
threads = Transformations.distinctUntilChanged(Transformations.map(inbox) { inboxResource: Resource<DirectInbox?> ->
// if (inboxResource == null) {
// 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()
} }

158
app/src/main/java/awais/instagrabber/managers/ThreadManager.kt

@ -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 replyToItem = MutableLiveData<DirectItem?>()
private val pendingRequests = MutableLiveData<DirectThreadParticipantRequestsResponse?>(null)
private val _fetching = MutableLiveData<Resource<Any?>>()
val fetching: LiveData<Resource<Any?>> = _fetching
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?>> {
return fetching
}
fun getReplyToItem(): LiveData<DirectItem?> {
return replyToItem
}
fun getPendingRequests(): LiveData<DirectThreadParticipantRequestsResponse?> {
return pendingRequests
}
fun fetchChats() {
val fetchingValue = fetching.value
fun fetchChats(scope: CoroutineScope) {
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))
chatsRequest = service.fetchThread(threadId, cursor)
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
_fetching.postValue(loading(null))
scope.launch(Dispatchers.IO) {
try {
val threadFeedResponse = service.fetchThread(threadId, cursor)
if (threadFeedResponse.status != null && threadFeedResponse.status != "ok") {
_fetching.postValue(error(R.string.generic_not_ok_response, null))
return@launch
} }
val thread = feedResponse.thread
val thread = threadFeedResponse.thread
if (thread == null) { if (thread == null) {
fetching.postValue(error("thread is null!", null))
return
_fetching.postValue(error("thread is null!", null))
return@launch
} }
setThread(thread) 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))
_fetching.postValue(success(Any()))
} catch (e: Exception) {
Log.e(TAG, "Failed fetching dm chats", e)
_fetching.postValue(error(e.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() {
val isFetching = fetching.value
fun refreshChats(scope: CoroutineScope) {
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()
.filter { obj: User? -> Objects.nonNull(obj) }
.map { obj: User -> obj.pk }
.collect(Collectors.toList())
users.map { obj: User -> obj.pk }
) )
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()
.filter { obj: User? -> Objects.nonNull(obj) }
.filter { u: User -> u.pk != user.pk }
.collect(Collectors.toList())
val updatedActiveUsers = activeUsers.filter { u: User -> u.pk != user.pk }
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()
.filter { obj: Long? -> Objects.nonNull(obj) }
.filter { userId1: Long -> userId1 != user.pk }
.collect(Collectors.toList())
val updatedAdminUserIds = currentAdmins.filter { userId1: Long -> userId1 != user.pk }
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()
.filter { obj: User? -> Objects.nonNull(obj) }
.map { obj: User -> obj.pk }
.collect(Collectors.toList())
users.map { obj: User -> obj.pk }
) )
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()
.map { obj: User -> obj.pk }
.collect(Collectors.toList())
users.map { obj: User -> obj.pk }
) )
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()
.filter { o: User -> !users.contains(o) }
.collect(Collectors.toList())
val filtered = pendingUsers.filter { o: User -> !users.contains(o) }
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)
} }

8
app/src/main/java/awais/instagrabber/repositories/DirectMessagesRepository.kt

@ -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?>

2
app/src/main/java/awais/instagrabber/services/DMSyncService.java

@ -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;
} }

56
app/src/main/java/awais/instagrabber/viewmodels/DirectInboxViewModel.java

@ -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();
}
}

36
app/src/main/java/awais/instagrabber/viewmodels/DirectInboxViewModel.kt

@ -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)
}
}

48
app/src/main/java/awais/instagrabber/viewmodels/DirectPendingInboxViewModel.java

@ -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();
}
}

34
app/src/main/java/awais/instagrabber/viewmodels/DirectPendingInboxViewModel.kt

@ -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)
}
}

299
app/src/main/java/awais/instagrabber/viewmodels/DirectSettingsViewModel.java

@ -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();
}
}

201
app/src/main/java/awais/instagrabber/viewmodels/DirectSettingsViewModel.kt

@ -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!" }
}
}

13
app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.kt

@ -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.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.*
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?>> {

508
app/src/main/java/awais/instagrabber/viewmodels/PostViewV2ViewModel.kt

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

10
app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.kt

@ -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(),

Loading…
Cancel
Save