1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-11-15 19:27:31 +00:00

Convert GraphQLRepository and GraphQLService to kotlin

This commit is contained in:
Ammar Githam 2021-06-06 13:14:29 +09:00
parent dd3562116b
commit 143a0ce259
12 changed files with 449 additions and 600 deletions

View File

@ -49,7 +49,6 @@ import awais.instagrabber.models.IntentModel
import awais.instagrabber.models.Resource import awais.instagrabber.models.Resource
import awais.instagrabber.models.Tab import awais.instagrabber.models.Tab
import awais.instagrabber.models.enums.IntentModelType import awais.instagrabber.models.enums.IntentModelType
import awais.instagrabber.repositories.responses.Media
import awais.instagrabber.services.ActivityCheckerService import awais.instagrabber.services.ActivityCheckerService
import awais.instagrabber.services.DMSyncAlarmReceiver import awais.instagrabber.services.DMSyncAlarmReceiver
import awais.instagrabber.utils.* import awais.instagrabber.utils.*
@ -61,7 +60,6 @@ import awais.instagrabber.viewmodels.AppStateViewModel
import awais.instagrabber.viewmodels.DirectInboxViewModel import awais.instagrabber.viewmodels.DirectInboxViewModel
import awais.instagrabber.webservices.GraphQLService import awais.instagrabber.webservices.GraphQLService
import awais.instagrabber.webservices.MediaService import awais.instagrabber.webservices.MediaService
import awais.instagrabber.webservices.ServiceCallback
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.ScrollingViewBehavior import com.google.android.material.appbar.AppBarLayout.ScrollingViewBehavior
import com.google.android.material.appbar.CollapsingToolbarLayout import com.google.android.material.appbar.CollapsingToolbarLayout
@ -71,6 +69,7 @@ import com.google.common.collect.ImmutableList
import com.google.common.collect.Iterators import com.google.common.collect.Iterators
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.* import java.util.*
import java.util.stream.Collectors import java.util.stream.Collectors
@ -92,7 +91,6 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
var currentTabs: List<Tab> = emptyList() var currentTabs: List<Tab> = emptyList()
private set private set
private var showBottomViewDestinations: List<Int> = emptyList() private var showBottomViewDestinations: List<Int> = emptyList()
private var graphQLService: GraphQLService? = null
private val serviceConnection: ServiceConnection = object : ServiceConnection { private val serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) { override fun onServiceConnected(name: ComponentName, service: IBinder) {
@ -633,39 +631,32 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
.setCancelable(false) .setCancelable(false)
.setView(R.layout.dialog_opening_post) .setView(R.layout.dialog_opening_post)
.create() .create()
if (graphQLService == null) graphQLService = GraphQLService.getInstance() alertDialog.show()
val postCb: ServiceCallback<Media> = object : ServiceCallback<Media> { lifecycleScope.launch(Dispatchers.IO) {
override fun onSuccess(feedModel: Media?) { try {
if (feedModel != null) { val media = if (isLoggedIn) MediaService.fetch(shortcodeToId(shortCode)) else GraphQLService.fetchPost(shortCode)
val currentNavControllerLiveData = currentNavControllerLiveData ?: return withContext(Dispatchers.Main) {
if (media == null) {
Toast.makeText(applicationContext, R.string.post_not_found, Toast.LENGTH_SHORT).show()
return@withContext
}
val currentNavControllerLiveData = currentNavControllerLiveData ?: return@withContext
val navController = currentNavControllerLiveData.value val navController = currentNavControllerLiveData.value
val bundle = Bundle() val bundle = Bundle()
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel) bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media)
try { try {
navController?.navigate(R.id.action_global_post_view, bundle) navController?.navigate(R.id.action_global_post_view, bundle)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "showPostView: ", e) Log.e(TAG, "showPostView: ", e)
} }
} else Toast.makeText(applicationContext, R.string.post_not_found, Toast.LENGTH_SHORT).show() }
alertDialog.dismiss() } catch (e: Exception) {
} Log.e(TAG, "showPostView: ", e)
} finally {
override fun onFailure(t: Throwable) { withContext(Dispatchers.Main) {
alertDialog.dismiss() alertDialog.dismiss()
}
}
alertDialog.show()
if (isLoggedIn) {
lifecycleScope.launch(Dispatchers.IO) {
try {
val media = MediaService.fetch(shortcodeToId(shortCode))
postCb.onSuccess(media)
} catch (e: Exception) {
postCb.onFailure(e)
} }
} }
} else {
graphQLService?.fetchPost(shortCode, postCb)
} }
} }

View File

@ -7,9 +7,11 @@ import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.repositories.responses.Hashtag; import awais.instagrabber.repositories.responses.Hashtag;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.repositories.responses.PostsFetchResponse;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.ServiceCallback;
import awais.instagrabber.webservices.TagsService; import awais.instagrabber.webservices.TagsService;
import kotlinx.coroutines.Dispatchers;
public class HashtagPostFetchService implements PostFetcher.PostFetchService { public class HashtagPostFetchService implements PostFetcher.PostFetchService {
private final TagsService tagsService; private final TagsService tagsService;
@ -23,7 +25,7 @@ public class HashtagPostFetchService implements PostFetcher.PostFetchService {
this.hashtagModel = hashtagModel; this.hashtagModel = hashtagModel;
this.isLoggedIn = isLoggedIn; this.isLoggedIn = isLoggedIn;
tagsService = isLoggedIn ? TagsService.getInstance() : null; tagsService = isLoggedIn ? TagsService.getInstance() : null;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
} }
@Override @Override
@ -48,7 +50,17 @@ public class HashtagPostFetchService implements PostFetcher.PostFetchService {
} }
}; };
if (isLoggedIn) tagsService.fetchPosts(hashtagModel.getName().toLowerCase(), nextMaxId, cb); if (isLoggedIn) tagsService.fetchPosts(hashtagModel.getName().toLowerCase(), nextMaxId, cb);
else graphQLService.fetchHashtagPosts(hashtagModel.getName().toLowerCase(), nextMaxId, cb); else graphQLService.fetchHashtagPosts(
hashtagModel.getName().toLowerCase(),
nextMaxId,
CoroutineUtilsKt.getContinuation((postsFetchResponse, throwable) -> {
if (throwable != null) {
cb.onFailure(throwable);
return;
}
cb.onSuccess(postsFetchResponse);
}, Dispatchers.getIO())
);
} }
@Override @Override

View File

@ -7,9 +7,11 @@ import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Location;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.repositories.responses.PostsFetchResponse;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.LocationService; import awais.instagrabber.webservices.LocationService;
import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.ServiceCallback;
import kotlinx.coroutines.Dispatchers;
public class LocationPostFetchService implements PostFetcher.PostFetchService { public class LocationPostFetchService implements PostFetcher.PostFetchService {
private final LocationService locationService; private final LocationService locationService;
@ -23,7 +25,7 @@ public class LocationPostFetchService implements PostFetcher.PostFetchService {
this.locationModel = locationModel; this.locationModel = locationModel;
this.isLoggedIn = isLoggedIn; this.isLoggedIn = isLoggedIn;
locationService = isLoggedIn ? LocationService.getInstance() : null; locationService = isLoggedIn ? LocationService.getInstance() : null;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
} }
@Override @Override
@ -48,7 +50,17 @@ public class LocationPostFetchService implements PostFetcher.PostFetchService {
} }
}; };
if (isLoggedIn) locationService.fetchPosts(locationModel.getPk(), nextMaxId, cb); if (isLoggedIn) locationService.fetchPosts(locationModel.getPk(), nextMaxId, cb);
else graphQLService.fetchLocationPosts(locationModel.getPk(), nextMaxId, cb); else graphQLService.fetchLocationPosts(
locationModel.getPk(),
nextMaxId,
CoroutineUtilsKt.getContinuation((postsFetchResponse, throwable) -> {
if (throwable != null) {
cb.onFailure(throwable);
return;
}
cb.onSuccess(postsFetchResponse);
}, Dispatchers.getIO())
);
} }
@Override @Override

View File

@ -7,9 +7,11 @@ import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.repositories.responses.PostsFetchResponse;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.ProfileService; import awais.instagrabber.webservices.ProfileService;
import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.ServiceCallback;
import kotlinx.coroutines.Dispatchers;
public class ProfilePostFetchService implements PostFetcher.PostFetchService { public class ProfilePostFetchService implements PostFetcher.PostFetchService {
private static final String TAG = "ProfilePostFetchService"; private static final String TAG = "ProfilePostFetchService";
@ -23,7 +25,7 @@ public class ProfilePostFetchService implements PostFetcher.PostFetchService {
public ProfilePostFetchService(final User profileModel, final boolean isLoggedIn) { public ProfilePostFetchService(final User profileModel, final boolean isLoggedIn) {
this.profileModel = profileModel; this.profileModel = profileModel;
this.isLoggedIn = isLoggedIn; this.isLoggedIn = isLoggedIn;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
profileService = isLoggedIn ? ProfileService.getInstance() : null; profileService = isLoggedIn ? ProfileService.getInstance() : null;
} }
@ -49,7 +51,19 @@ public class ProfilePostFetchService implements PostFetcher.PostFetchService {
} }
}; };
if (isLoggedIn) profileService.fetchPosts(profileModel.getPk(), nextMaxId, cb); if (isLoggedIn) profileService.fetchPosts(profileModel.getPk(), nextMaxId, cb);
else graphQLService.fetchProfilePosts(profileModel.getPk(), 30, nextMaxId, profileModel, cb); else graphQLService.fetchProfilePosts(
profileModel.getPk(),
30,
nextMaxId,
profileModel,
CoroutineUtilsKt.getContinuation((postsFetchResponse, throwable) -> {
if (throwable != null) {
cb.onFailure(throwable);
return;
}
cb.onSuccess(postsFetchResponse);
}, Dispatchers.getIO())
);
} }
@Override @Override

View File

@ -7,9 +7,11 @@ import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.models.enums.PostItemType;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.repositories.responses.PostsFetchResponse;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.ProfileService; import awais.instagrabber.webservices.ProfileService;
import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.ServiceCallback;
import kotlinx.coroutines.Dispatchers;
public class SavedPostFetchService implements PostFetcher.PostFetchService { public class SavedPostFetchService implements PostFetcher.PostFetchService {
private final ProfileService profileService; private final ProfileService profileService;
@ -27,7 +29,7 @@ public class SavedPostFetchService implements PostFetcher.PostFetchService {
this.type = type; this.type = type;
this.isLoggedIn = isLoggedIn; this.isLoggedIn = isLoggedIn;
this.collectionId = collectionId; this.collectionId = collectionId;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
profileService = isLoggedIn ? ProfileService.getInstance() : null; profileService = isLoggedIn ? ProfileService.getInstance() : null;
} }
@ -58,7 +60,18 @@ public class SavedPostFetchService implements PostFetcher.PostFetchService {
break; break;
case TAGGED: case TAGGED:
if (isLoggedIn) profileService.fetchTagged(profileId, nextMaxId, callback); if (isLoggedIn) profileService.fetchTagged(profileId, nextMaxId, callback);
else graphQLService.fetchTaggedPosts(profileId, 30, nextMaxId, callback); else graphQLService.fetchTaggedPosts(
profileId,
30,
nextMaxId,
CoroutineUtilsKt.getContinuation((postsFetchResponse, throwable) -> {
if (throwable != null) {
callback.onFailure(throwable);
return;
}
callback.onSuccess(postsFetchResponse);
}, Dispatchers.getIO())
);
break; break;
case COLLECTION: case COLLECTION:
case SAVED: case SAVED:

View File

@ -63,8 +63,10 @@ import awais.instagrabber.repositories.responses.Hashtag;
import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Location;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.utils.AppExecutors;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
@ -72,6 +74,7 @@ import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.ServiceCallback;
import awais.instagrabber.webservices.StoriesService; import awais.instagrabber.webservices.StoriesService;
import awais.instagrabber.webservices.TagsService; import awais.instagrabber.webservices.TagsService;
import kotlinx.coroutines.Dispatchers;
import static androidx.core.content.PermissionChecker.checkSelfPermission; import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
@ -218,20 +221,15 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
if (TextUtils.isEmpty(user.getUsername())) { if (TextUtils.isEmpty(user.getUsername())) {
// this only happens for anons // this only happens for anons
opening = true; opening = true;
graphQLService.fetchPost(feedModel.getCode(), new ServiceCallback<Media>() { graphQLService.fetchPost(feedModel.getCode(), CoroutineUtilsKt.getContinuation((media, throwable) -> {
@Override opening = false;
public void onSuccess(final Media newFeedModel) { if (throwable != null) {
opening = false; Log.e(TAG, "Error", throwable);
if (newFeedModel == null) return; return;
openPostDialog(newFeedModel, profilePicView, mainPostImage, position);
} }
if (media == null) return;
@Override AppExecutors.INSTANCE.getMainThread().execute(() -> openPostDialog(media, profilePicView, mainPostImage, position));
public void onFailure(final Throwable t) { }, Dispatchers.getIO()));
opening = false;
Log.e(TAG, "Error", t);
}
});
return; return;
} }
opening = true; opening = true;
@ -304,7 +302,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
tagsService = isLoggedIn ? TagsService.getInstance() : null; tagsService = isLoggedIn ? TagsService.getInstance() : null;
storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null; storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@ -385,7 +383,13 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
private void fetchHashtagModel() { private void fetchHashtagModel() {
binding.swipeRefreshLayout.setRefreshing(true); binding.swipeRefreshLayout.setRefreshing(true);
if (isLoggedIn) tagsService.fetch(hashtag, cb); if (isLoggedIn) tagsService.fetch(hashtag, cb);
else graphQLService.fetchTag(hashtag, cb); else graphQLService.fetchTag(hashtag, CoroutineUtilsKt.getContinuation((hashtag1, throwable) -> {
if (throwable != null) {
cb.onFailure(throwable);
return;
}
AppExecutors.INSTANCE.getMainThread().execute(() -> cb.onSuccess(hashtag1));
}, Dispatchers.getIO()));
} }
private void setupPosts() { private void setupPosts() {

View File

@ -113,7 +113,7 @@ public final class LikesViewerFragment extends BottomSheetDialogFragment impleme
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
if (csrfToken == null) return; if (csrfToken == null) return;
mediaService = isLoggedIn ? MediaService.INSTANCE : null; mediaService = isLoggedIn ? MediaService.INSTANCE : null;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
// setHasOptionsMenu(true); // setHasOptionsMenu(true);
} }
@ -135,7 +135,17 @@ public final class LikesViewerFragment extends BottomSheetDialogFragment impleme
public void onRefresh() { public void onRefresh() {
if (isComment && !isLoggedIn) { if (isComment && !isLoggedIn) {
lazyLoader.resetState(); lazyLoader.resetState();
graphQLService.fetchCommentLikers(postId, null, anonCb); graphQLService.fetchCommentLikers(
postId,
null,
CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
if (throwable != null) {
anonCb.onFailure(throwable);
return;
}
anonCb.onSuccess(response);
}), Dispatchers.getIO())
);
} else { } else {
mediaService.fetchLikes( mediaService.fetchLikes(
postId, postId,
@ -164,8 +174,19 @@ public final class LikesViewerFragment extends BottomSheetDialogFragment impleme
binding.rvLikes.setLayoutManager(layoutManager); binding.rvLikes.setLayoutManager(layoutManager);
binding.rvLikes.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.HORIZONTAL)); binding.rvLikes.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.HORIZONTAL));
lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> {
if (!TextUtils.isEmpty(endCursor)) if (!TextUtils.isEmpty(endCursor)) {
graphQLService.fetchCommentLikers(postId, endCursor, anonCb); graphQLService.fetchCommentLikers(
postId,
endCursor,
CoroutineUtilsKt.getContinuation((response, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
if (throwable != null) {
anonCb.onFailure(throwable);
return;
}
anonCb.onSuccess(response);
}), Dispatchers.getIO())
);
}
endCursor = null; endCursor = null;
}); });
binding.rvLikes.addOnScrollListener(lazyLoader); binding.rvLikes.addOnScrollListener(lazyLoader);

View File

@ -59,8 +59,10 @@ import awais.instagrabber.repositories.requests.StoryViewerOptions;
import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Location;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.utils.AppExecutors;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
@ -208,20 +210,18 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
if (user == null) return; if (user == null) return;
if (TextUtils.isEmpty(user.getUsername())) { if (TextUtils.isEmpty(user.getUsername())) {
opening = true; opening = true;
graphQLService.fetchPost(feedModel.getCode(), new ServiceCallback<Media>() { graphQLService.fetchPost(
@Override feedModel.getCode(),
public void onSuccess(final Media newFeedModel) { CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
opening = false; opening = false;
if (newFeedModel == null) return; if (throwable != null) {
openPostDialog(newFeedModel, profilePicView, mainPostImage, position); Log.e(TAG, "Error", throwable);
} return;
}
@Override if (media == null) return;
public void onFailure(final Throwable t) { openPostDialog(media, profilePicView, mainPostImage, position);
opening = false; }))
Log.e(TAG, "Error", t); );
}
});
return; return;
} }
opening = true; opening = true;
@ -294,7 +294,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
locationService = isLoggedIn ? LocationService.getInstance() : null; locationService = isLoggedIn ? LocationService.getInstance() : null;
storiesService = StoriesService.getInstance(null, 0L, null); storiesService = StoriesService.getInstance(null, 0L, null);
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@ -402,7 +402,16 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
private void fetchLocationModel() { private void fetchLocationModel() {
binding.swipeRefreshLayout.setRefreshing(true); binding.swipeRefreshLayout.setRefreshing(true);
if (isLoggedIn) locationService.fetch(locationId, cb); if (isLoggedIn) locationService.fetch(locationId, cb);
else graphQLService.fetchLocation(locationId, cb); else graphQLService.fetchLocation(
locationId,
CoroutineUtilsKt.getContinuation((location, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
if (throwable != null) {
cb.onFailure(throwable);
return;
}
cb.onSuccess(location);
}))
);
} }
private void setupLocationDetails() { private void setupLocationDetails() {

View File

@ -339,7 +339,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null; storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null;
mediaService = isLoggedIn ? MediaService.INSTANCE : null; mediaService = isLoggedIn ? MediaService.INSTANCE : null;
userService = isLoggedIn ? UserService.INSTANCE : null; userService = isLoggedIn ? UserService.INSTANCE : null;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
final Context context = getContext(); final Context context = getContext();
if (context == null) return; if (context == null) return;
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(context)); accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(context));
@ -618,25 +618,19 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
); );
return; return;
} }
graphQLService.fetchUser(usernameTemp, new ServiceCallback<User>() { graphQLService.fetchUser(
@Override usernameTemp,
public void onSuccess(final User user) { CoroutineUtilsKt.getContinuation((user, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
profileModel = user; if (throwable != null) {
setProfileDetails(); Log.e(TAG, "Error fetching profile", throwable);
} final Context context = getContext();
if (context == null) return;
@Override Toast.makeText(context, throwable.getMessage(), Toast.LENGTH_SHORT).show();
public void onFailure(final Throwable t) { }
Log.e(TAG, "Error fetching profile", t); profileModel = user;
final Context context = getContext(); setProfileDetails();
try { }))
if (t == null) );
Toast.makeText(context, R.string.error_loading_profile, Toast.LENGTH_LONG).show();
else Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
} catch (final Throwable ignored) {
}
}
});
} }
private void setProfileDetails() { private void setProfileDetails() {

View File

@ -1,25 +1,22 @@
package awais.instagrabber.repositories; package awais.instagrabber.repositories
import java.util.Map; import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.QueryMap
import retrofit2.Call; interface GraphQLRepository {
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.QueryMap;
public interface GraphQLRepository {
@GET("/graphql/query/") @GET("/graphql/query/")
Call<String> fetch(@QueryMap(encoded = true) Map<String, String> queryParams); suspend fun fetch(@QueryMap(encoded = true) queryParams: Map<String, String>): String
@GET("/{username}/?__a=1") @GET("/{username}/?__a=1")
Call<String> getUser(@Path("username") String username); suspend fun getUser(@Path("username") username: String): String
@GET("/p/{shortcode}/?__a=1") @GET("/p/{shortcode}/?__a=1")
Call<String> getPost(@Path("shortcode") String shortcode); suspend fun getPost(@Path("shortcode") shortcode: String): String
@GET("/explore/tags/{tag}/?__a=1") @GET("/explore/tags/{tag}/?__a=1")
Call<String> getTag(@Path("tag") String tag); suspend fun getTag(@Path("tag") tag: String): String
@GET("/explore/locations/{locationId}/?__a=1") @GET("/explore/locations/{locationId}/?__a=1")
Call<String> getLocation(@Path("locationId") long locationId); suspend fun getLocation(@Path("locationId") locationId: Long): String
} }

View File

@ -30,13 +30,13 @@ import awais.instagrabber.repositories.responses.CommentsFetchResponse;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.CoroutineUtilsKt;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
import awais.instagrabber.webservices.CommentService; import awais.instagrabber.webservices.CommentService;
import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.ServiceCallback;
import retrofit2.Call; import kotlin.coroutines.Continuation;
import retrofit2.Callback; import kotlinx.coroutines.Dispatchers;
import retrofit2.Response;
import static awais.instagrabber.utils.Utils.settingsHelper; import static awais.instagrabber.utils.Utils.settingsHelper;
@ -113,7 +113,7 @@ public class CommentsViewerViewModel extends ViewModel {
}; };
public CommentsViewerViewModel() { public CommentsViewerViewModel() {
graphQLService = GraphQLService.getInstance(); graphQLService = GraphQLService.INSTANCE;
final String cookie = settingsHelper.getString(Constants.COOKIE); final String cookie = settingsHelper.getString(Constants.COOKIE);
final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID); final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
@ -165,8 +165,12 @@ public class CommentsViewerViewModel extends ViewModel {
commentService.fetchComments(postId, rootCursor, ccb); commentService.fetchComments(postId, rootCursor, ccb);
return; return;
} }
final Call<String> request = graphQLService.fetchComments(shortCode, true, rootCursor); graphQLService.fetchComments(
enqueueRequest(request, true, shortCode, ccb); shortCode,
true,
rootCursor,
enqueueRequest(true, shortCode, ccb)
);
} }
public void fetchReplies() { public void fetchReplies() {
@ -190,54 +194,49 @@ public class CommentsViewerViewModel extends ViewModel {
commentService.fetchChildComments(postId, commentId, repliesCursor, rcb); commentService.fetchChildComments(postId, commentId, repliesCursor, rcb);
return; return;
} }
final Call<String> request = graphQLService.fetchComments(commentId, false, repliesCursor); graphQLService.fetchComments(commentId, false, repliesCursor, enqueueRequest(false, commentId, rcb));
enqueueRequest(request, false, commentId, rcb);
} }
private void enqueueRequest(@NonNull final Call<String> request, private Continuation<String> enqueueRequest(final boolean root,
final boolean root, final String shortCodeOrCommentId,
final String shortCodeOrCommentId, @SuppressWarnings("rawtypes") final ServiceCallback callback) {
final ServiceCallback callback) { return CoroutineUtilsKt.getContinuation((response, throwable) -> {
request.enqueue(new Callback<String>() { if (throwable != null) {
@Override callback.onFailure(throwable);
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { return;
final String rawBody = response.body();
if (rawBody == null) {
Log.e(TAG, "Error occurred while fetching gql comments of " + shortCodeOrCommentId);
callback.onSuccess(null);
return;
}
try {
final JSONObject body = root ? new JSONObject(rawBody).getJSONObject("data")
.getJSONObject("shortcode_media")
.getJSONObject("edge_media_to_parent_comment")
: new JSONObject(rawBody).getJSONObject("data")
.getJSONObject("comment")
.getJSONObject("edge_threaded_comments");
final int count = body.optInt("count");
final JSONObject pageInfo = body.getJSONObject("page_info");
final boolean hasNextPage = pageInfo.getBoolean("has_next_page");
final String endCursor = pageInfo.isNull("end_cursor") || !hasNextPage ? null : pageInfo.optString("end_cursor");
final JSONArray commentsJsonArray = body.getJSONArray("edges");
final ImmutableList.Builder<Comment> builder = ImmutableList.builder();
for (int i = 0; i < commentsJsonArray.length(); i++) {
final Comment commentModel = getComment(commentsJsonArray.getJSONObject(i).getJSONObject("node"), root);
builder.add(commentModel);
}
callback.onSuccess(root ?
new CommentsFetchResponse(count, endCursor, builder.build()) :
new ChildCommentsFetchResponse(count, endCursor, builder.build()));
} catch (Exception e) {
Log.e(TAG, "onResponse", e);
callback.onFailure(e);
}
} }
if (response == null) {
@Override Log.e(TAG, "Error occurred while fetching gql comments of " + shortCodeOrCommentId);
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) { //noinspection unchecked
callback.onFailure(t); callback.onSuccess(null);
return;
} }
}); try {
final JSONObject body = root ? new JSONObject(response).getJSONObject("data")
.getJSONObject("shortcode_media")
.getJSONObject("edge_media_to_parent_comment")
: new JSONObject(response).getJSONObject("data")
.getJSONObject("comment")
.getJSONObject("edge_threaded_comments");
final int count = body.optInt("count");
final JSONObject pageInfo = body.getJSONObject("page_info");
final boolean hasNextPage = pageInfo.getBoolean("has_next_page");
final String endCursor = pageInfo.isNull("end_cursor") || !hasNextPage ? null : pageInfo.optString("end_cursor");
final JSONArray commentsJsonArray = body.getJSONArray("edges");
final ImmutableList.Builder<Comment> builder = ImmutableList.builder();
for (int i = 0; i < commentsJsonArray.length(); i++) {
final Comment commentModel = getComment(commentsJsonArray.getJSONObject(i).getJSONObject("node"), root);
builder.add(commentModel);
}
final Object result = root ? new CommentsFetchResponse(count, endCursor, builder.build())
: new ChildCommentsFetchResponse(count, endCursor, builder.build());
//noinspection unchecked
callback.onSuccess(result);
} catch (Exception e) {
Log.e(TAG, "onResponse", e);
callback.onFailure(e);
}
}, Dispatchers.getIO());
} }
@NonNull @NonNull

View File

@ -1,483 +1,266 @@
package awais.instagrabber.webservices; package awais.instagrabber.webservices
import android.util.Log; import android.util.Log
import awais.instagrabber.models.enums.FollowingType
import awais.instagrabber.repositories.GraphQLRepository
import awais.instagrabber.repositories.responses.*
import awais.instagrabber.utils.Constants
import awais.instagrabber.utils.ResponseBodyUtils
import awais.instagrabber.utils.extensions.TAG
import awais.instagrabber.webservices.RetrofitFactory.retrofitWeb
import org.json.JSONException
import org.json.JSONObject
import java.util.*
import androidx.annotation.NonNull; object GraphQLService : BaseService() {
private val repository: GraphQLRepository = retrofitWeb.create(GraphQLRepository::class.java)
import com.google.common.collect.ImmutableMap;
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 awais.instagrabber.models.enums.FollowingType;
import awais.instagrabber.repositories.GraphQLRepository;
import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.GraphQLUserListFetchResponse;
import awais.instagrabber.repositories.responses.Hashtag;
import awais.instagrabber.repositories.responses.Location;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.PostsFetchResponse;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.ResponseBodyUtils;
import awais.instagrabber.utils.TextUtils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class GraphQLService extends BaseService {
private static final String TAG = "GraphQLService";
private final GraphQLRepository repository;
private static GraphQLService instance;
private GraphQLService() {
repository = RetrofitFactory.INSTANCE
.getRetrofitWeb()
.create(GraphQLRepository.class);
}
public static GraphQLService getInstance() {
if (instance == null) {
instance = new GraphQLService();
}
return instance;
}
// TODO convert string response to a response class // TODO convert string response to a response class
private void fetch(final String queryHash, private suspend fun fetch(
final String variables, queryHash: String,
final String arg1, variables: String,
final String arg2, arg1: String,
final User backup, arg2: String,
final ServiceCallback<PostsFetchResponse> callback) { backup: User?,
final Map<String, String> queryMap = new HashMap<>(); ): PostsFetchResponse {
queryMap.put("query_hash", queryHash); val queryMap = mapOf(
queryMap.put("variables", variables); "query_hash" to queryHash,
final Call<String> request = repository.fetch(queryMap); "variables" to variables,
request.enqueue(new Callback<String>() { )
@Override val response = repository.fetch(queryMap)
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { return parsePostResponse(response, arg1, arg2, backup)
try {
// Log.d(TAG, "onResponse: body: " + response.body());
final PostsFetchResponse postsFetchResponse = parsePostResponse(response, arg1, arg2, backup);
if (callback != null) {
callback.onSuccess(postsFetchResponse);
}
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
if (callback != null) {
callback.onFailure(e);
}
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
} }
public void fetchLocationPosts(final long locationId, suspend fun fetchLocationPosts(
final String maxId, locationId: Long,
final ServiceCallback<PostsFetchResponse> callback) { maxId: String?,
fetch("36bd0f2bf5911908de389b8ceaa3be6d", ): PostsFetchResponse = fetch(
"{\"id\":\"" + locationId + "\"," + "36bd0f2bf5911908de389b8ceaa3be6d",
"\"first\":25," + "{\"id\":\"" + locationId + "\"," + "\"first\":25," + "\"after\":\"" + (maxId ?: "") + "\"}",
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"}", Constants.EXTRAS_LOCATION,
Constants.EXTRAS_LOCATION, "edge_location_to_media",
"edge_location_to_media", null
null, )
callback);
}
public void fetchHashtagPosts(@NonNull final String tag, suspend fun fetchHashtagPosts(
final String maxId, tag: String,
final ServiceCallback<PostsFetchResponse> callback) { maxId: String?,
fetch("9b498c08113f1e09617a1703c22b2f32", ): PostsFetchResponse = fetch(
"{\"tag_name\":\"" + tag + "\"," + "9b498c08113f1e09617a1703c22b2f32",
"\"first\":25," + "{\"tag_name\":\"" + tag + "\"," + "\"first\":25," + "\"after\":\"" + (maxId ?: "") + "\"}",
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"}", Constants.EXTRAS_HASHTAG,
Constants.EXTRAS_HASHTAG, "edge_hashtag_to_media",
"edge_hashtag_to_media", null,
null, )
callback);
}
public void fetchProfilePosts(final long profileId, suspend fun fetchProfilePosts(
final int postsPerPage, profileId: Long,
final String maxId, postsPerPage: Int,
final User backup, maxId: String?,
final ServiceCallback<PostsFetchResponse> callback) { backup: User?,
fetch("02e14f6a7812a876f7d133c9555b1151", ): PostsFetchResponse = fetch(
"{\"id\":\"" + profileId + "\"," + "02e14f6a7812a876f7d133c9555b1151",
"\"first\":" + postsPerPage + "," + "{\"id\":\"" + profileId + "\"," + "\"first\":" + postsPerPage + "," + "\"after\":\"" + (maxId ?: "") + "\"}",
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"}", Constants.EXTRAS_USER,
Constants.EXTRAS_USER, "edge_owner_to_timeline_media",
"edge_owner_to_timeline_media", backup,
backup, )
callback);
}
public void fetchTaggedPosts(final long profileId, suspend fun fetchTaggedPosts(
final int postsPerPage, profileId: Long,
final String maxId, postsPerPage: Int,
final ServiceCallback<PostsFetchResponse> callback) { maxId: String?,
fetch("31fe64d9463cbbe58319dced405c6206", ): PostsFetchResponse = fetch(
"{\"id\":\"" + profileId + "\"," + "31fe64d9463cbbe58319dced405c6206",
"\"first\":" + postsPerPage + "," + "{\"id\":\"" + profileId + "\"," + "\"first\":" + postsPerPage + "," + "\"after\":\"" + (maxId ?: "") + "\"}",
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"}", Constants.EXTRAS_USER,
Constants.EXTRAS_USER, "edge_user_to_photos_of_you",
"edge_user_to_photos_of_you", null,
null, )
callback);
}
@NonNull @Throws(JSONException::class)
private PostsFetchResponse parsePostResponse(@NonNull final Response<String> response, private fun parsePostResponse(
@NonNull final String arg1, response: String,
@NonNull final String arg2, arg1: String,
final User backup) arg2: String,
throws JSONException { backup: User?,
if (TextUtils.isEmpty(response.body())) { ): PostsFetchResponse {
Log.e(TAG, "parseResponse: feed response body is empty with status code: " + response.code()); if (response.isBlank()) {
return new PostsFetchResponse(Collections.emptyList(), false, null); Log.e(TAG, "parseResponse: feed response body is empty")
return PostsFetchResponse(emptyList(), false, null)
} }
return parseResponseBody(response.body(), arg1, arg2, backup); return parseResponseBody(response, arg1, arg2, backup)
} }
@NonNull @Throws(JSONException::class)
private PostsFetchResponse parseResponseBody(@NonNull final String body, private fun parseResponseBody(
@NonNull final String arg1, body: String,
@NonNull final String arg2, arg1: String,
final User backup) arg2: String,
throws JSONException { backup: User?,
final List<Media> items = new ArrayList<>(); ): PostsFetchResponse {
final JSONObject timelineFeed = new JSONObject(body) val items: MutableList<Media> = ArrayList()
.getJSONObject("data") val timelineFeed = JSONObject(body)
.getJSONObject(arg1) .getJSONObject("data")
.getJSONObject(arg2); .getJSONObject(arg1)
final String endCursor; .getJSONObject(arg2)
final boolean hasNextPage; val endCursor: String?
val hasNextPage: Boolean
final JSONObject pageInfo = timelineFeed.getJSONObject("page_info"); val pageInfo = timelineFeed.getJSONObject("page_info")
if (pageInfo.has("has_next_page")) { if (pageInfo.has("has_next_page")) {
hasNextPage = pageInfo.getBoolean("has_next_page"); hasNextPage = pageInfo.getBoolean("has_next_page")
endCursor = hasNextPage ? pageInfo.getString("end_cursor") : null; endCursor = if (hasNextPage) pageInfo.getString("end_cursor") else null
} else { } else {
hasNextPage = false; hasNextPage = false
endCursor = null; endCursor = null
} }
val feedItems = timelineFeed.getJSONArray("edges")
final JSONArray feedItems = timelineFeed.getJSONArray("edges"); for (i in 0 until feedItems.length()) {
val itemJson = feedItems.optJSONObject(i) ?: continue
for (int i = 0; i < feedItems.length(); ++i) { val media = ResponseBodyUtils.parseGraphQLItem(itemJson, backup)
final JSONObject itemJson = feedItems.optJSONObject(i);
if (itemJson == null) {
continue;
}
final Media media = ResponseBodyUtils.parseGraphQLItem(itemJson, backup);
if (media != null) { if (media != null) {
items.add(media); items.add(media)
} }
} }
return new PostsFetchResponse(items, hasNextPage, endCursor); return PostsFetchResponse(items, hasNextPage, endCursor)
} }
// TODO convert string response to a response class // TODO convert string response to a response class
public void fetchCommentLikers(final String commentId, suspend fun fetchCommentLikers(
final String endCursor, commentId: String,
final ServiceCallback<GraphQLUserListFetchResponse> callback) { endCursor: String?,
final Map<String, String> queryMap = new HashMap<>(); ): GraphQLUserListFetchResponse {
queryMap.put("query_hash", "5f0b1f6281e72053cbc07909c8d154ae"); val queryMap = mapOf(
queryMap.put("variables", "{\"comment_id\":\"" + commentId + "\"," + "query_hash" to "5f0b1f6281e72053cbc07909c8d154ae",
"\"first\":30," + "variables" to "{\"comment_id\":\"" + commentId + "\"," + "\"first\":30," + "\"after\":\"" + (endCursor ?: "") + "\"}"
"\"after\":\"" + (endCursor == null ? "" : endCursor) + "\"}"); )
final Call<String> request = repository.fetch(queryMap); val response = repository.fetch(queryMap)
request.enqueue(new Callback<String>() { val body = JSONObject(response)
@Override val status = body.getString("status")
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { val data = body.getJSONObject("data").getJSONObject("comment").getJSONObject("edge_liked_by")
final String rawBody = response.body(); val pageInfo = data.getJSONObject("page_info")
if (rawBody == null) { val newEndCursor = if (pageInfo.getBoolean("has_next_page")) pageInfo.getString("end_cursor") else null
Log.e(TAG, "Error occurred while fetching gql comment likes of " + commentId); val users = data.getJSONArray("edges")
callback.onSuccess(null); val usersLen = users.length()
return; val userModels: MutableList<User> = ArrayList()
} for (j in 0 until usersLen) {
try { val userObject = users.getJSONObject(j).getJSONObject("node")
final JSONObject body = new JSONObject(rawBody); userModels.add(User(
final String status = body.getString("status"); userObject.getLong("id"),
final JSONObject data = body.getJSONObject("data").getJSONObject("comment").getJSONObject("edge_liked_by"); userObject.getString("username"),
final JSONObject pageInfo = data.getJSONObject("page_info"); userObject.optString("full_name"),
final String endCursor = pageInfo.getBoolean("has_next_page") ? pageInfo.getString("end_cursor") : null; userObject.optBoolean("is_private"),
final JSONArray users = data.getJSONArray("edges"); userObject.getString("profile_pic_url"),
final int usersLen = users.length(); userObject.optBoolean("is_verified")
final List<User> userModels = new ArrayList<>(); ))
for (int j = 0; j < usersLen; ++j) { }
final JSONObject userObject = users.getJSONObject(j).getJSONObject("node"); return GraphQLUserListFetchResponse(newEndCursor, status, userModels)
userModels.add(new User(
userObject.getLong("id"),
userObject.getString("username"),
userObject.optString("full_name"),
userObject.optBoolean("is_private"),
userObject.getString("profile_pic_url"),
userObject.optBoolean("is_verified")
));
// userModels.add(new ProfileModel(userObject.optBoolean("is_private"),
// false,
// userObject.optBoolean("is_verified"),
// userObject.getString("id"),
// userObject.getString("username"),
// userObject.optString("full_name"),
// null, null,
// userObject.getString("profile_pic_url"),
// null, 0, 0, 0, false, false, false, false, false));
}
callback.onSuccess(new GraphQLUserListFetchResponse(endCursor, status, userModels));
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
if (callback != null) {
callback.onFailure(e);
}
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
} }
public Call<String> fetchComments(final String shortCodeOrCommentId, suspend fun fetchComments(
final boolean root, shortCodeOrCommentId: String?,
final String cursor) { root: Boolean,
final Map<String, String> queryMap = new HashMap<>(); cursor: String?,
queryMap.put("query_hash", root ? "bc3296d1ce80a24b1b6e40b1e72903f5" : "51fdd02b67508306ad4484ff574a0b62"); ): String {
final Map<String, Object> variables = ImmutableMap.of( val variables = mapOf(
root ? "shortcode" : "comment_id", shortCodeOrCommentId, (if (root) "shortcode" else "comment_id") to shortCodeOrCommentId,
"first", 50, "first" to 50,
"after", cursor == null ? "" : cursor "after" to (cursor ?: "")
); )
queryMap.put("variables", new JSONObject(variables).toString()); val queryMap = mapOf(
return repository.fetch(queryMap); "query_hash" to if (root) "bc3296d1ce80a24b1b6e40b1e72903f5" else "51fdd02b67508306ad4484ff574a0b62",
"variables" to JSONObject(variables).toString()
)
return repository.fetch(queryMap)
} }
// TODO convert string response to a response class // TODO convert string response to a response class
public void fetchUser(final String username, suspend fun fetchUser(
final ServiceCallback<User> callback) { username: String,
final Call<String> request = repository.getUser(username); ): User {
request.enqueue(new Callback<String>() { val response = repository.getUser(username)
@Override val body = JSONObject(response)
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { val userJson = body.getJSONObject("graphql").getJSONObject(Constants.EXTRAS_USER)
final String rawBody = response.body(); val isPrivate = userJson.getBoolean("is_private")
if (rawBody == null) { val id = userJson.optLong(Constants.EXTRAS_ID, 0)
Log.e(TAG, "Error occurred while fetching gql user of " + username); val timelineMedia = userJson.getJSONObject("edge_owner_to_timeline_media")
callback.onSuccess(null); // if (timelineMedia.has("edges")) {
return; // final JSONArray edges = timelineMedia.getJSONArray("edges");
} // }
try { var url: String? = userJson.optString("external_url")
final JSONObject body = new JSONObject(rawBody); if (url.isNullOrBlank()) url = null
final JSONObject userJson = body.getJSONObject("graphql") return User(
.getJSONObject(Constants.EXTRAS_USER); id,
username,
boolean isPrivate = userJson.getBoolean("is_private"); userJson.getString("full_name"),
final long id = userJson.optLong(Constants.EXTRAS_ID, 0); isPrivate,
final JSONObject timelineMedia = userJson.getJSONObject("edge_owner_to_timeline_media"); userJson.getString("profile_pic_url_hd"),
// if (timelineMedia.has("edges")) { userJson.getBoolean("is_verified"),
// final JSONArray edges = timelineMedia.getJSONArray("edges"); friendshipStatus = FriendshipStatus(
// } userJson.optBoolean("followed_by_viewer"),
userJson.optBoolean("follows_viewer"),
String url = userJson.optString("external_url"); userJson.optBoolean("blocked_by_viewer"),
if (TextUtils.isEmpty(url)) url = null; false,
isPrivate,
callback.onSuccess(new User( userJson.optBoolean("has_requested_viewer"),
id, userJson.optBoolean("requested_by_viewer"),
username, false,
userJson.getString("full_name"), userJson.optBoolean("restricted_by_viewer"),
isPrivate, false
userJson.getString("profile_pic_url_hd"), ),
userJson.getBoolean("is_verified"), mediaCount = timelineMedia.getLong("count"),
null, followerCount = userJson.getJSONObject("edge_followed_by").getLong("count"),
new FriendshipStatus( followingCount = userJson.getJSONObject("edge_follow").getLong("count"),
userJson.optBoolean("followed_by_viewer"), biography = userJson.getString("biography"),
userJson.optBoolean("follows_viewer"), externalUrl = url,
userJson.optBoolean("blocked_by_viewer"), )
false,
isPrivate,
userJson.optBoolean("has_requested_viewer"),
userJson.optBoolean("requested_by_viewer"),
false,
userJson.optBoolean("restricted_by_viewer"),
false
),
false,
false,
false,
false,
false,
null,
null,
timelineMedia.getLong("count"),
userJson.getJSONObject("edge_followed_by").getLong("count"),
userJson.getJSONObject("edge_follow").getLong("count"),
0,
userJson.getString("biography"),
url,
0,
null,
null,
null,
null,
null,
null));
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
if (callback != null) {
callback.onFailure(e);
}
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
} }
// TODO convert string response to a response class // TODO convert string response to a response class
public void fetchPost(final String shortcode, suspend fun fetchPost(
final ServiceCallback<Media> callback) { shortcode: String,
final Call<String> request = repository.getPost(shortcode); ): Media {
request.enqueue(new Callback<String>() { val response = repository.getPost(shortcode)
@Override val body = JSONObject(response)
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { val media = body.getJSONObject("graphql").getJSONObject("shortcode_media")
final String rawBody = response.body(); return ResponseBodyUtils.parseGraphQLItem(media, null)
if (rawBody == null) {
Log.e(TAG, "Error occurred while fetching gql post of " + shortcode);
callback.onSuccess(null);
return;
}
try {
final JSONObject body = new JSONObject(rawBody);
final JSONObject media = body.getJSONObject("graphql")
.getJSONObject("shortcode_media");
callback.onSuccess(ResponseBodyUtils.parseGraphQLItem(media, null));
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
if (callback != null) {
callback.onFailure(e);
}
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
} }
// TODO convert string response to a response class // TODO convert string response to a response class
public void fetchTag(final String tag, suspend fun fetchTag(
final ServiceCallback<Hashtag> callback) { tag: String,
final Call<String> request = repository.getTag(tag); ): Hashtag {
request.enqueue(new Callback<String>() { val response = repository.getTag(tag)
@Override val body = JSONObject(response)
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { .getJSONObject("graphql")
final String rawBody = response.body(); .getJSONObject(Constants.EXTRAS_HASHTAG)
if (rawBody == null) { val timelineMedia = body.getJSONObject("edge_hashtag_to_media")
Log.e(TAG, "Error occurred while fetching gql tag of " + tag); return Hashtag(
callback.onSuccess(null); body.getString(Constants.EXTRAS_ID),
return; body.getString("name"),
} timelineMedia.getLong("count"),
try { if (body.optBoolean("is_following")) FollowingType.FOLLOWING else FollowingType.NOT_FOLLOWING,
final JSONObject body = new JSONObject(rawBody) null)
.getJSONObject("graphql")
.getJSONObject(Constants.EXTRAS_HASHTAG);
final JSONObject timelineMedia = body.getJSONObject("edge_hashtag_to_media");
callback.onSuccess(new Hashtag(
body.getString(Constants.EXTRAS_ID),
body.getString("name"),
timelineMedia.getLong("count"),
body.optBoolean("is_following") ? FollowingType.FOLLOWING : FollowingType.NOT_FOLLOWING,
null));
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
if (callback != null) {
callback.onFailure(e);
}
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
} }
// TODO convert string response to a response class // TODO convert string response to a response class
public void fetchLocation(final long locationId, suspend fun fetchLocation(
final ServiceCallback<Location> callback) { locationId: Long,
final Call<String> request = repository.getLocation(locationId); ): Location {
request.enqueue(new Callback<String>() { val response = repository.getLocation(locationId)
@Override val body = JSONObject(response)
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { .getJSONObject("graphql")
final String rawBody = response.body(); .getJSONObject(Constants.EXTRAS_LOCATION)
if (rawBody == null) { // val timelineMedia = body.getJSONObject("edge_location_to_media")
Log.e(TAG, "Error occurred while fetching gql location of " + locationId); val address = JSONObject(body.getString("address_json"))
callback.onSuccess(null); return Location(
return; body.getLong(Constants.EXTRAS_ID),
} body.getString("slug"),
try { body.getString("name"),
final JSONObject body = new JSONObject(rawBody) address.optString("street_address"),
.getJSONObject("graphql") address.optString("city_name"),
.getJSONObject(Constants.EXTRAS_LOCATION); body.optDouble("lng", 0.0),
final JSONObject timelineMedia = body.getJSONObject("edge_location_to_media"); body.optDouble("lat", 0.0)
final JSONObject address = new JSONObject(body.getString("address_json")); )
callback.onSuccess(new Location(
body.getLong(Constants.EXTRAS_ID),
body.getString("slug"),
body.getString("name"),
address.optString("street_address"),
address.optString("city_name"),
body.optDouble("lng", 0d),
body.optDouble("lat", 0d)
));
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
if (callback != null) {
callback.onFailure(e);
}
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
} }
} }