From cf65ed0fc524e23a4e4ad7a8b1569944891bbaa8 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 6 Jun 2021 14:18:27 +0900 Subject: [PATCH] Convert FriendshipRepository and FriendshipService to kotlin --- .../fragments/FollowViewerFragment.java | 138 ++++-- .../NotificationsViewerFragment.java | 58 +-- .../fragments/main/ProfileFragment.java | 129 +++++- .../instagrabber/managers/ThreadManager.kt | 65 ++- .../repositories/FriendshipRepository.kt | 49 +-- .../webservices/FriendshipService.kt | 411 +++++++----------- 6 files changed, 450 insertions(+), 400 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java index 969a1e87..19fcf309 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java @@ -30,9 +30,12 @@ import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; import awais.instagrabber.databinding.FragmentFollowersViewerBinding; import awais.instagrabber.models.FollowModel; import awais.instagrabber.repositories.responses.FriendshipListFetchResponse; +import awais.instagrabber.utils.AppExecutors; +import awais.instagrabber.utils.CoroutineUtilsKt; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.webservices.FriendshipService; import awais.instagrabber.webservices.ServiceCallback; +import kotlinx.coroutines.Dispatchers; import thoughtbot.expandableadapter.ExpandableGroup; public final class FollowViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { @@ -68,10 +71,32 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh if (!isFollowersList) followModels.addAll(result.getItems()); if (result.isMoreAvailable()) { endCursor = result.getNextMaxId(); - friendshipService.getList(false, profileId, endCursor, this); + friendshipService.getList( + false, + profileId, + endCursor, + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + onFailure(throwable); + return; + } + onSuccess(response); + }), Dispatchers.getIO()) + ); } else if (followersModels.size() == 0) { if (!isFollowersList) moreAvailable = false; - friendshipService.getList(true, profileId, null, followingFetchCb); + friendshipService.getList( + true, + profileId, + null, + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + followingFetchCb.onFailure(throwable); + return; + } + followingFetchCb.onSuccess(response); + }), Dispatchers.getIO()) + ); } else { if (!isFollowersList) moreAvailable = false; showCompare(); @@ -84,8 +109,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh try { binding.swipeRefreshLayout.setRefreshing(false); Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(Throwable e) {} + } catch (Throwable ignored) {} Log.e(TAG, "Error fetching list (double, following)", t); } }; @@ -97,10 +121,32 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh if (isFollowersList) followModels.addAll(result.getItems()); if (result.isMoreAvailable()) { endCursor = result.getNextMaxId(); - friendshipService.getList(true, profileId, endCursor, this); + friendshipService.getList( + true, + profileId, + endCursor, + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + onFailure(throwable); + return; + } + onSuccess(response); + }), Dispatchers.getIO()) + ); } else if (followingModels.size() == 0) { if (isFollowersList) moreAvailable = false; - friendshipService.getList(false, profileId, null, followingFetchCb); + friendshipService.getList( + false, + profileId, + null, + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + followingFetchCb.onFailure(throwable); + return; + } + followingFetchCb.onSuccess(response); + }), Dispatchers.getIO()) + ); } else { if (isFollowersList) moreAvailable = false; showCompare(); @@ -113,8 +159,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh try { binding.swipeRefreshLayout.setRefreshing(false); Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(Throwable e) {} + } catch (Throwable ignored) {} Log.e(TAG, "Error fetching list (double, follower)", t); } }; @@ -122,7 +167,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - friendshipService = FriendshipService.getInstance(null, null, 0); + friendshipService = FriendshipService.INSTANCE; fragmentActivity = (AppCompatActivity) getActivity(); setHasOptionsMenu(true); } @@ -235,8 +280,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh try { binding.swipeRefreshLayout.setRefreshing(false); Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(Throwable e) {} + } catch (Throwable ignored) {} Log.e(TAG, "Error fetching list (single)", t); } }; @@ -245,7 +289,18 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh if (!TextUtils.isEmpty(endCursor) && !searching) { binding.swipeRefreshLayout.setRefreshing(true); layoutManager.setStackFromEnd(true); - friendshipService.getList(isFollowersList, profileId, endCursor, cb); + friendshipService.getList( + isFollowersList, + profileId, + endCursor, + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + cb.onFailure(throwable); + return; + } + cb.onSuccess(response); + }), Dispatchers.getIO()) + ); endCursor = null; } }); @@ -253,7 +308,18 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh binding.rvFollow.setLayoutManager(layoutManager); if (moreAvailable) { binding.swipeRefreshLayout.setRefreshing(true); - friendshipService.getList(isFollowersList, profileId, endCursor, cb); + friendshipService.getList( + isFollowersList, + profileId, + endCursor, + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + cb.onFailure(throwable); + return; + } + cb.onSuccess(response); + }), Dispatchers.getIO()) + ); } else { refreshAdapter(followModels, null, null, null); layoutManager.scrollToPosition(0); @@ -269,17 +335,34 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh if (moreAvailable) { binding.swipeRefreshLayout.setRefreshing(true); Toast.makeText(getContext(), R.string.follower_start_compare, Toast.LENGTH_LONG).show(); - friendshipService.getList(isFollowersList, - profileId, - endCursor, - isFollowersList ? followersFetchCb : followingFetchCb); + friendshipService.getList( + isFollowersList, + profileId, + endCursor, + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + final ServiceCallback callback = isFollowersList ? followersFetchCb : followingFetchCb; + if (throwable != null) { + callback.onFailure(throwable); + return; + } + callback.onSuccess(response); + }), Dispatchers.getIO()) + ); } else if (followersModels.size() == 0 || followingModels.size() == 0) { binding.swipeRefreshLayout.setRefreshing(true); Toast.makeText(getContext(), R.string.follower_start_compare, Toast.LENGTH_LONG).show(); - friendshipService.getList(!isFollowersList, - profileId, - null, - isFollowersList ? followingFetchCb : followersFetchCb); + friendshipService.getList( + !isFollowersList, + profileId, + null, + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + final ServiceCallback callback = isFollowersList ? followingFetchCb : followersFetchCb; + if (throwable != null) { + callback.onFailure(throwable); + return; + } + callback.onSuccess(response); + }), Dispatchers.getIO())); } else showCompare(); } @@ -337,10 +420,10 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh final Context context = getContext(); if (loading) Toast.makeText(context, R.string.follower_wait_to_load, Toast.LENGTH_LONG).show(); else if (isCompare) { - isCompare = !isCompare; + isCompare = false; listFollows(); } else { - isCompare = !isCompare; + isCompare = true; listCompare(); } return true; @@ -354,16 +437,15 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh final ArrayList groups = new ArrayList<>(1); if (isCompare && followingModels != null && followersModels != null && allFollowing != null) { - if (followingModels != null && followingModels.size() > 0) + if (followingModels.size() > 0) groups.add(new ExpandableGroup(resources.getString(R.string.followers_not_following, username), followingModels)); - if (followersModels != null && followersModels.size() > 0) + if (followersModels.size() > 0) groups.add(new ExpandableGroup(resources.getString(R.string.followers_not_follower, namePost), followersModels)); - if (allFollowing != null && allFollowing.size() > 0) + if (allFollowing.size() > 0) groups.add(new ExpandableGroup(resources.getString(R.string.followers_both_following), allFollowing)); } else if (followModels != null) { groups.add(new ExpandableGroup(type, followModels)); - } - else return; + } else return; adapter = new FollowAdapter(clickListener, groups); adapter.toggleGroup(0); binding.rvFollow.setAdapter(adapter); diff --git a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java index f0a8f30f..52570afe 100644 --- a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java @@ -34,7 +34,6 @@ import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListe import awais.instagrabber.databinding.FragmentNotificationsViewerBinding; import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.repositories.requests.StoryViewerOptions; -import awais.instagrabber.repositories.responses.FriendshipChangeResponse; import awais.instagrabber.repositories.responses.notification.Notification; import awais.instagrabber.repositories.responses.notification.NotificationArgs; import awais.instagrabber.repositories.responses.notification.NotificationImage; @@ -68,6 +67,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe private String type; private long targetId; private Context context; + private long userId; private final ServiceCallback> cb = new ServiceCallback>() { @Override @@ -168,34 +168,40 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe break; case 1: if (model.getType() == NotificationType.REQUEST) { - friendshipService.approve(args.getUserId(), new ServiceCallback() { - @Override - public void onSuccess(final FriendshipChangeResponse result) { - onRefresh(); - Log.e(TAG, "approve: status was not ok!"); - } - - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "approve: onFailure: ", t); - } - }); + friendshipService.approve( + csrfToken, + userId, + deviceUuid, + args.getUserId(), + CoroutineUtilsKt.getContinuation( + (response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + Log.e(TAG, "approve: onFailure: ", throwable); + return; + } + onRefresh(); + }), + Dispatchers.getIO() + ) + ); return; } clickListener.onPreviewClick(model); break; case 2: - friendshipService.ignore(args.getUserId(), new ServiceCallback() { - @Override - public void onSuccess(final FriendshipChangeResponse result) { - onRefresh(); - } - - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "ignore: onFailure: ", t); - } - }); + friendshipService.ignore( + csrfToken, + userId, + deviceUuid, + args.getUserId(), + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + Log.e(TAG, "approve: onFailure: ", throwable); + return; + } + onRefresh(); + }), Dispatchers.getIO()) + ); break; } }; @@ -219,10 +225,10 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe if (TextUtils.isEmpty(cookie)) { Toast.makeText(context, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show(); } - final long userId = CookieUtils.getUserIdFromCookie(cookie); + userId = CookieUtils.getUserIdFromCookie(cookie); deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID); csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); - friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId); + friendshipService = FriendshipService.INSTANCE; mediaService = MediaService.INSTANCE; newsService = NewsService.getInstance(); } diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 43beb577..099cbabb 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -79,7 +79,6 @@ import awais.instagrabber.models.enums.FavoriteType; import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.repositories.requests.StoryViewerOptions; import awais.instagrabber.repositories.responses.FriendshipChangeResponse; -import awais.instagrabber.repositories.responses.FriendshipRestrictResponse; import awais.instagrabber.repositories.responses.FriendshipStatus; import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.User; @@ -146,6 +145,8 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe private AppStateViewModel appStateViewModel; private boolean disableDm = false; private ProfileFragmentViewModel viewModel; + private String csrfToken; + private String deviceUuid; private final ServiceCallback changeCb = new ServiceCallback() { @Override @@ -331,10 +332,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe cookie = Utils.settingsHelper.getString(Constants.COOKIE); isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; myId = CookieUtils.getUserIdFromCookie(cookie); - final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID); - final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); + deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID); + csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); fragmentActivity = (MainActivity) requireActivity(); - friendshipService = isLoggedIn ? FriendshipService.getInstance(deviceUuid, csrfToken, myId) : null; + friendshipService = isLoggedIn ? FriendshipService.INSTANCE : null; directMessagesService = isLoggedIn ? DirectMessagesService.getInstance(csrfToken, myId, deviceUuid) : null; storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null; mediaService = isLoggedIn ? MediaService.INSTANCE : null; @@ -451,25 +452,38 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe if (!isLoggedIn) return false; final String action = profileModel.getFriendshipStatus().isRestricted() ? "Unrestrict" : "Restrict"; friendshipService.toggleRestrict( + csrfToken, + deviceUuid, profileModel.getPk(), !profileModel.getFriendshipStatus().isRestricted(), - new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRestrictResponse result) { - Log.d(TAG, action + " success: " + result); - fetchProfileDetails(); - } - - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "Error while performing " + action, t); + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + Log.e(TAG, "Error while performing " + action, throwable); + return; } - }); + // Log.d(TAG, action + " success: " + response); + fetchProfileDetails(); + }), Dispatchers.getIO()) + ); return true; } if (item.getItemId() == R.id.block) { if (!isLoggedIn) return false; - friendshipService.changeBlock(profileModel.getFriendshipStatus().getBlocking(), profileModel.getPk(), changeCb); + // changeCb + friendshipService.changeBlock( + csrfToken, + myId, + deviceUuid, + profileModel.getFriendshipStatus().getBlocking(), + profileModel.getPk(), + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + changeCb.onFailure(throwable); + return; + } + changeCb.onSuccess(response); + }), Dispatchers.getIO()) + ); return true; } if (item.getItemId() == R.id.chaining) { @@ -484,25 +498,57 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe if (!isLoggedIn) return false; final String action = profileModel.getFriendshipStatus().isMutingReel() ? "Unmute stories" : "Mute stories"; friendshipService.changeMute( + csrfToken, + myId, + deviceUuid, profileModel.getFriendshipStatus().isMutingReel(), profileModel.getPk(), true, - changeCb); + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + changeCb.onFailure(throwable); + return; + } + changeCb.onSuccess(response); + }), Dispatchers.getIO()) + ); return true; } if (item.getItemId() == R.id.mute_posts) { if (!isLoggedIn) return false; final String action = profileModel.getFriendshipStatus().getMuting() ? "Unmute stories" : "Mute stories"; friendshipService.changeMute( + csrfToken, + myId, + deviceUuid, profileModel.getFriendshipStatus().getMuting(), profileModel.getPk(), false, - changeCb); + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + changeCb.onFailure(throwable); + return; + } + changeCb.onSuccess(response); + }), Dispatchers.getIO()) + ); return true; } if (item.getItemId() == R.id.remove_follower) { if (!isLoggedIn) return false; - friendshipService.removeFollower(profileModel.getPk(), changeCb); + friendshipService.removeFollower( + csrfToken, + myId, + deviceUuid, + profileModel.getPk(), + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + changeCb.onFailure(throwable); + return; + } + changeCb.onSuccess(response); + }), Dispatchers.getIO()) + ); return true; } return super.onOptionsItemSelected(item); @@ -1032,19 +1078,55 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe private void setupCommonListeners() { final Context context = getContext(); + if (context == null) return; profileDetailsBinding.btnFollow.setOnClickListener(v -> { if (profileModel.getFriendshipStatus().getFollowing() && profileModel.isPrivate()) { new AlertDialog.Builder(context) .setTitle(R.string.priv_acc) .setMessage(R.string.priv_acc_confirm) - .setPositiveButton(R.string.confirm, (d, w) -> - friendshipService.unfollow(profileModel.getPk(), changeCb)) + .setPositiveButton(R.string.confirm, (d, w) -> friendshipService.unfollow( + csrfToken, + myId, + deviceUuid, + profileModel.getPk(), + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + changeCb.onFailure(throwable); + return; + } + changeCb.onSuccess(response); + }), Dispatchers.getIO()) + )) .setNegativeButton(R.string.cancel, null) .show(); } else if (profileModel.getFriendshipStatus().getFollowing() || profileModel.getFriendshipStatus().getOutgoingRequest()) { - friendshipService.unfollow(profileModel.getPk(), changeCb); + friendshipService.unfollow( + csrfToken, + myId, + deviceUuid, + profileModel.getPk(), + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + changeCb.onFailure(throwable); + return; + } + changeCb.onSuccess(response); + }), Dispatchers.getIO()) + ); } else { - friendshipService.follow(profileModel.getPk(), changeCb); + friendshipService.follow( + csrfToken, + myId, + deviceUuid, + profileModel.getPk(), + CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { + if (throwable != null) { + changeCb.onFailure(throwable); + return; + } + changeCb.onSuccess(response); + }), Dispatchers.getIO()) + ); } }); profileDetailsBinding.btnSaved.setOnClickListener(v -> { @@ -1109,7 +1191,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } showProfilePicDialog(); }; - if (context == null) return; new AlertDialog.Builder(context) .setItems(options, profileDialogListener) .setNegativeButton(R.string.cancel, null) diff --git a/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt b/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt index 647fb243..0a3ce95d 100644 --- a/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt +++ b/app/src/main/java/awais/instagrabber/managers/ThreadManager.kt @@ -19,8 +19,6 @@ import awais.instagrabber.repositories.requests.UploadFinishOptions import awais.instagrabber.repositories.requests.VideoOptions import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds.Companion.of -import awais.instagrabber.repositories.responses.FriendshipChangeResponse -import awais.instagrabber.repositories.responses.FriendshipRestrictResponse import awais.instagrabber.repositories.responses.User import awais.instagrabber.repositories.responses.directmessages.* import awais.instagrabber.repositories.responses.giphy.GiphyGif @@ -34,7 +32,6 @@ import awais.instagrabber.utils.TextUtils.isEmpty import awais.instagrabber.webservices.DirectMessagesService import awais.instagrabber.webservices.FriendshipService import awais.instagrabber.webservices.MediaService -import awais.instagrabber.webservices.ServiceCallback import com.google.common.collect.ImmutableList import com.google.common.collect.Iterables import kotlinx.coroutines.CoroutineScope @@ -69,7 +66,6 @@ class ThreadManager private constructor( private val currentUser: User? private val contentResolver: ContentResolver private val service: DirectMessagesService - private val friendshipService: FriendshipService val thread: LiveData by lazy { distinctUntilChanged(map(inboxManager.getInbox()) { inboxResource: Resource? -> @@ -1132,61 +1128,57 @@ class ThreadManager private constructor( fun blockUser(user: User, scope: CoroutineScope): LiveData> { val data = MutableLiveData>() - friendshipService.changeBlock(false, user.pk, object : ServiceCallback { - override fun onSuccess(result: FriendshipChangeResponse?) { + scope.launch(Dispatchers.IO) { + try { + FriendshipService.changeBlock(csrfToken, viewerId, deviceUuid, false, user.pk) refreshChats(scope) + } catch (e: Exception) { + Log.e(TAG, "onFailure: ", e) + data.postValue(error(e.message, null)) } - - override fun onFailure(t: Throwable) { - Log.e(TAG, "onFailure: ", t) - data.postValue(error(t.message, null)) - } - }) + } return data } fun unblockUser(user: User, scope: CoroutineScope): LiveData> { val data = MutableLiveData>() - friendshipService.changeBlock(true, user.pk, object : ServiceCallback { - override fun onSuccess(result: FriendshipChangeResponse?) { + scope.launch(Dispatchers.IO) { + try { + FriendshipService.changeBlock(csrfToken, viewerId, deviceUuid, true, user.pk) refreshChats(scope) + } catch (e: Exception) { + Log.e(TAG, "onFailure: ", e) + data.postValue(error(e.message, null)) } - - override fun onFailure(t: Throwable) { - Log.e(TAG, "onFailure: ", t) - data.postValue(error(t.message, null)) - } - }) + } return data } fun restrictUser(user: User, scope: CoroutineScope): LiveData> { val data = MutableLiveData>() - friendshipService.toggleRestrict(user.pk, true, object : ServiceCallback { - override fun onSuccess(result: FriendshipRestrictResponse?) { + scope.launch(Dispatchers.IO) { + try { + FriendshipService.toggleRestrict(csrfToken, deviceUuid, user.pk, true) refreshChats(scope) + } catch (e: Exception) { + Log.e(TAG, "onFailure: ", e) + data.postValue(error(e.message, null)) } - - override fun onFailure(t: Throwable) { - Log.e(TAG, "onFailure: ", t) - data.postValue(error(t.message, null)) - } - }) + } return data } fun unRestrictUser(user: User, scope: CoroutineScope): LiveData> { val data = MutableLiveData>() - friendshipService.toggleRestrict(user.pk, false, object : ServiceCallback { - override fun onSuccess(result: FriendshipRestrictResponse?) { + scope.launch(Dispatchers.IO) { + try { + FriendshipService.toggleRestrict(csrfToken, deviceUuid, user.pk, false) refreshChats(scope) + } catch (e: Exception) { + Log.e(TAG, "onFailure: ", e) + data.postValue(error(e.message, null)) } - - override fun onFailure(t: Throwable) { - Log.e(TAG, "onFailure: ", t) - data.postValue(error(t.message, null)) - } - }) + } return data } @@ -1415,7 +1407,6 @@ class ThreadManager private constructor( this.contentResolver = contentResolver this.viewerId = viewerId service = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid) - friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, viewerId) // fetchChats(); } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.kt b/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.kt index b3da4772..73cd81b0 100644 --- a/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.kt +++ b/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.kt @@ -1,37 +1,36 @@ -package awais.instagrabber.repositories; +package awais.instagrabber.repositories -import java.util.Map; - -import awais.instagrabber.repositories.responses.FriendshipChangeResponse; -import awais.instagrabber.repositories.responses.FriendshipRestrictResponse; -import retrofit2.Call; -import retrofit2.http.FieldMap; -import retrofit2.http.FormUrlEncoded; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; -import retrofit2.http.QueryMap; - -public interface FriendshipRepository { +import awais.instagrabber.repositories.responses.FriendshipChangeResponse +import awais.instagrabber.repositories.responses.FriendshipRestrictResponse +import retrofit2.http.* +interface FriendshipRepository { @FormUrlEncoded @POST("/api/v1/friendships/{action}/{id}/") - Call change(@Path("action") String action, - @Path("id") long id, - @FieldMap Map form); + suspend fun change( + @Path("action") action: String, + @Path("id") id: Long, + @FieldMap form: Map, + ): FriendshipChangeResponse @FormUrlEncoded @POST("/api/v1/restrict_action/{action}/") - Call toggleRestrict(@Path("action") String action, - @FieldMap Map form); + suspend fun toggleRestrict( + @Path("action") action: String, + @FieldMap form: Map, + ): FriendshipRestrictResponse @GET("/api/v1/friendships/{userId}/{type}/") - Call getList(@Path("userId") long userId, - @Path("type") String type, // following or followers - @QueryMap(encoded = true) Map queryParams); + suspend fun getList( + @Path("userId") userId: Long, + @Path("type") type: String, // following or followers + @QueryMap(encoded = true) queryParams: Map, + ): String @FormUrlEncoded @POST("/api/v1/friendships/{action}/") - Call changeMute(@Path("action") String action, - @FieldMap Map form); -} + suspend fun changeMute( + @Path("action") action: String, + @FieldMap form: Map, + ): FriendshipChangeResponse +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.kt b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.kt index ce20dd29..4982cd15 100644 --- a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.kt +++ b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.kt @@ -1,264 +1,155 @@ -package awais.instagrabber.webservices; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import awais.instagrabber.models.FollowModel; -import awais.instagrabber.repositories.FriendshipRepository; -import awais.instagrabber.repositories.responses.FriendshipChangeResponse; -import awais.instagrabber.repositories.responses.FriendshipListFetchResponse; -import awais.instagrabber.repositories.responses.FriendshipRestrictResponse; -import awais.instagrabber.utils.TextUtils; -import awais.instagrabber.utils.Utils; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class FriendshipService extends BaseService { - private static final String TAG = "FriendshipService"; - - private final FriendshipRepository repository; - private final String deviceUuid, csrfToken; - private final long userId; - - private static FriendshipService instance; - - private FriendshipService(final String deviceUuid, - final String csrfToken, - final long userId) { - this.deviceUuid = deviceUuid; - this.csrfToken = csrfToken; - this.userId = userId; - repository = RetrofitFactory.INSTANCE - .getRetrofit() - .create(FriendshipRepository.class); - } - - public String getCsrfToken() { - return csrfToken; - } - - public String getDeviceUuid() { - return deviceUuid; - } - - public long getUserId() { - return userId; - } - - public static FriendshipService getInstance(final String deviceUuid, final String csrfToken, final long userId) { - if (instance == null - || !Objects.equals(instance.getCsrfToken(), csrfToken) - || !Objects.equals(instance.getDeviceUuid(), deviceUuid) - || !Objects.equals(instance.getUserId(), userId)) { - instance = new FriendshipService(deviceUuid, csrfToken, userId); - } - return instance; - } - - public void follow(final long targetUserId, - final ServiceCallback callback) { - change("create", targetUserId, callback); - } - - public void unfollow(final long targetUserId, - final ServiceCallback callback) { - change("destroy", targetUserId, callback); - } - - public void changeBlock(final boolean unblock, - final long targetUserId, - final ServiceCallback callback) { - change(unblock ? "unblock" : "block", targetUserId, callback); - } - - public void toggleRestrict(final long targetUserId, - final boolean restrict, - final ServiceCallback callback) { - final Map form = new HashMap<>(3); - form.put("_csrftoken", csrfToken); - form.put("_uuid", deviceUuid); - form.put("target_user_id", String.valueOf(targetUserId)); - final String action = restrict ? "restrict" : "unrestrict"; - final Call request = repository.toggleRestrict(action, form); - request.enqueue(new Callback() { - @Override - public void onResponse(@NonNull final Call call, - @NonNull final Response response) { - if (callback != null) { - callback.onSuccess(response.body()); - } - } - - @Override - public void onFailure(@NonNull final Call call, - @NonNull final Throwable t) { - if (callback != null) { - callback.onFailure(t); - } - } - }); - } - - public void approve(final long targetUserId, - final ServiceCallback callback) { - change("approve", targetUserId, callback); - } - - public void ignore(final long targetUserId, - final ServiceCallback callback) { - change("ignore", targetUserId, callback); - } - - public void removeFollower(final long targetUserId, - final ServiceCallback callback) { - change("remove_follower", targetUserId, callback); - } - - private void change(final String action, - final long targetUserId, - final ServiceCallback callback) { - final Map form = new HashMap<>(5); - form.put("_csrftoken", csrfToken); - form.put("_uid", userId); - form.put("_uuid", deviceUuid); - form.put("radio_type", "wifi-none"); - form.put("user_id", targetUserId); - final Map signedForm = Utils.sign(form); - final Call request = repository.change(action, targetUserId, signedForm); - request.enqueue(new Callback() { - @Override - public void onResponse(@NonNull final Call call, - @NonNull final Response response) { - if (callback != null) { - callback.onSuccess(response.body()); - } - } - - @Override - public void onFailure(@NonNull final Call call, - @NonNull final Throwable t) { - if (callback != null) { - callback.onFailure(t); - } - } - }); - } - - public void changeMute(final boolean unmute, - final long targetUserId, - final boolean story, // true for story, false for posts - final ServiceCallback callback) { - final Map form = new HashMap<>(4); - form.put("_csrftoken", csrfToken); - form.put("_uid", String.valueOf(userId)); - form.put("_uuid", deviceUuid); - form.put(story ? "target_reel_author_id" : "target_posts_author_id", String.valueOf(targetUserId)); - final Call request = repository.changeMute(unmute ? - "unmute_posts_or_story_from_follow" : - "mute_posts_or_story_from_follow", - form); - request.enqueue(new Callback() { - @Override - public void onResponse(@NonNull final Call call, - @NonNull final Response response) { - if (callback != null) { - callback.onSuccess(response.body()); - } - } - - @Override - public void onFailure(@NonNull final Call call, - @NonNull final Throwable t) { - if (callback != null) { - callback.onFailure(t); - } - } - }); - } - - public void getList(final boolean follower, - final long targetUserId, - final String maxId, - final ServiceCallback callback) { - final Map queryMap = new HashMap<>(); - if (maxId != null) queryMap.put("max_id", maxId); - final Call request = repository.getList( - targetUserId, - follower ? "followers" : "following", - queryMap); - request.enqueue(new Callback() { - @Override - public void onResponse(@NonNull final Call call, @NonNull final Response response) { - try { - if (callback == null) { - return; - } - final String body = response.body(); - if (TextUtils.isEmpty(body)) { - callback.onSuccess(null); - return; - } - final FriendshipListFetchResponse friendshipListFetchResponse = parseListResponse(body); - callback.onSuccess(friendshipListFetchResponse); - } catch (JSONException e) { - Log.e(TAG, "onResponse", e); - callback.onFailure(e); - } - } - - @Override - public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { - if (callback != null) { - callback.onFailure(t); - } - } - }); - } - - private FriendshipListFetchResponse parseListResponse(@NonNull final String body) throws JSONException { - final JSONObject root = new JSONObject(body); - final String nextMaxId = root.optString("next_max_id"); - final String status = root.optString("status"); - final JSONArray itemsJson = root.optJSONArray("users"); - final List items = parseItems(itemsJson); - return new FriendshipListFetchResponse( - nextMaxId, - status, - items - ); - } - - private List parseItems(final JSONArray items) throws JSONException { +package awais.instagrabber.webservices + +import awais.instagrabber.models.FollowModel +import awais.instagrabber.repositories.FriendshipRepository +import awais.instagrabber.repositories.responses.FriendshipChangeResponse +import awais.instagrabber.repositories.responses.FriendshipListFetchResponse +import awais.instagrabber.repositories.responses.FriendshipRestrictResponse +import awais.instagrabber.utils.Utils +import awais.instagrabber.webservices.RetrofitFactory.retrofit +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject + +object FriendshipService : BaseService() { + private val repository: FriendshipRepository = retrofit.create(FriendshipRepository::class.java) + + suspend fun follow( + csrfToken: String, + userId: Long, + deviceUuid: String, + targetUserId: Long, + ): FriendshipChangeResponse = change(csrfToken, userId, deviceUuid, "create", targetUserId) + + suspend fun unfollow( + csrfToken: String, + userId: Long, + deviceUuid: String, + targetUserId: Long, + ): FriendshipChangeResponse = change(csrfToken, userId, deviceUuid, "destroy", targetUserId) + + suspend fun changeBlock( + csrfToken: String, + userId: Long, + deviceUuid: String, + unblock: Boolean, + targetUserId: Long, + ): FriendshipChangeResponse { + return change(csrfToken, userId, deviceUuid, if (unblock) "unblock" else "block", targetUserId) + } + + suspend fun toggleRestrict( + csrfToken: String, + deviceUuid: String, + targetUserId: Long, + restrict: Boolean, + ): FriendshipRestrictResponse { + val form = mapOf( + "_csrftoken" to csrfToken, + "_uuid" to deviceUuid, + "target_user_id" to targetUserId.toString(), + ) + val action = if (restrict) "restrict" else "unrestrict" + return repository.toggleRestrict(action, form) + } + + suspend fun approve( + csrfToken: String, + userId: Long, + deviceUuid: String, + targetUserId: Long, + ): FriendshipChangeResponse = change(csrfToken, userId, deviceUuid, "approve", targetUserId) + + suspend fun ignore( + csrfToken: String, + userId: Long, + deviceUuid: String, + targetUserId: Long, + ): FriendshipChangeResponse = change(csrfToken, userId, deviceUuid, "ignore", targetUserId) + + suspend fun removeFollower( + csrfToken: String, + userId: Long, + deviceUuid: String, + targetUserId: Long, + ): FriendshipChangeResponse = change(csrfToken, userId, deviceUuid, "remove_follower", targetUserId) + + private suspend fun change( + csrfToken: String, + userId: Long, + deviceUuid: String, + action: String, + targetUserId: Long, + ): FriendshipChangeResponse { + val form = mapOf( + "_csrftoken" to csrfToken, + "_uid" to userId, + "_uuid" to deviceUuid, + "radio_type" to "wifi-none", + "user_id" to targetUserId, + ) + val signedForm = Utils.sign(form) + return repository.change(action, targetUserId, signedForm) + } + + suspend fun changeMute( + csrfToken: String, + userId: Long, + deviceUuid: String, + unmute: Boolean, + targetUserId: Long, + story: Boolean, // true for story, false for posts + ): FriendshipChangeResponse { + val form = mapOf( + "_csrftoken" to csrfToken, + "_uid" to userId.toString(), + "_uuid" to deviceUuid, + (if (story) "target_reel_author_id" else "target_posts_author_id") to targetUserId.toString(), + ) + return repository.changeMute( + if (unmute) "unmute_posts_or_story_from_follow" else "mute_posts_or_story_from_follow", + form + ) + } + + suspend fun getList( + follower: Boolean, + targetUserId: Long, + maxId: String?, + ): FriendshipListFetchResponse { + val queryMap = if (maxId != null) mapOf("max_id" to maxId) else emptyMap() + val response = repository.getList(targetUserId, if (follower) "followers" else "following", queryMap) + return parseListResponse(response) + } + + @Throws(JSONException::class) + private fun parseListResponse(body: String): FriendshipListFetchResponse { + val root = JSONObject(body) + val nextMaxId = root.optString("next_max_id") + val status = root.optString("status") + val itemsJson = root.optJSONArray("users") + val items = parseItems(itemsJson) + return FriendshipListFetchResponse( + nextMaxId, + status, + items + ) + } + + @Throws(JSONException::class) + private fun parseItems(items: JSONArray?): List { if (items == null) { - return Collections.emptyList(); + return emptyList() } - final List followModels = new ArrayList<>(); - for (int i = 0; i < items.length(); i++) { - final JSONObject itemJson = items.optJSONObject(i); - if (itemJson == null) { - continue; - } - final FollowModel followModel = new FollowModel(itemJson.getString("pk"), - itemJson.getString("username"), - itemJson.optString("full_name"), - itemJson.getString("profile_pic_url")); - if (followModel != null) { - followModels.add(followModel); - } + val followModels = mutableListOf() + for (i in 0 until items.length()) { + val itemJson = items.optJSONObject(i) ?: continue + val followModel = FollowModel(itemJson.getString("pk"), + itemJson.getString("username"), + itemJson.optString("full_name"), + itemJson.getString("profile_pic_url")) + followModels.add(followModel) } - return followModels; + return followModels } -} +} \ No newline at end of file