mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 06:37:30 +00:00
Convert StoriesRepository and StoriesService to kotlin
This commit is contained in:
parent
a2cc4573e1
commit
cae457aa9a
@ -39,7 +39,6 @@ import com.google.android.material.snackbar.Snackbar;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
@ -55,7 +54,6 @@ import awais.instagrabber.db.repositories.FavoriteRepository;
|
|||||||
import awais.instagrabber.db.repositories.RepositoryCallback;
|
import awais.instagrabber.db.repositories.RepositoryCallback;
|
||||||
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
||||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||||
import awais.instagrabber.models.StoryModel;
|
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
import awais.instagrabber.models.enums.FavoriteType;
|
||||||
import awais.instagrabber.models.enums.FollowingType;
|
import awais.instagrabber.models.enums.FollowingType;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
@ -301,7 +299,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
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.INSTANCE : null;
|
||||||
graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
|
graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
@ -582,24 +580,21 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
storiesFetching = true;
|
storiesFetching = true;
|
||||||
storiesService.getUserStory(
|
storiesService.getUserStory(
|
||||||
StoryViewerOptions.forHashtag(hashtagModel.getName()),
|
StoryViewerOptions.forHashtag(hashtagModel.getName()),
|
||||||
new ServiceCallback<List<StoryModel>>() {
|
CoroutineUtilsKt.getContinuation((storyModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
@Override
|
if (throwable != null) {
|
||||||
public void onSuccess(final List<StoryModel> storyModels) {
|
Log.e(TAG, "Error", throwable);
|
||||||
if (storyModels != null && !storyModels.isEmpty()) {
|
|
||||||
hashtagDetailsBinding.mainHashtagImage.setStoriesBorder(1);
|
|
||||||
hasStories = true;
|
|
||||||
} else {
|
|
||||||
hasStories = false;
|
|
||||||
}
|
|
||||||
storiesFetching = false;
|
storiesFetching = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (storyModels != null && !storyModels.isEmpty()) {
|
||||||
@Override
|
hashtagDetailsBinding.mainHashtagImage.setStoriesBorder(1);
|
||||||
public void onFailure(final Throwable t) {
|
hasStories = true;
|
||||||
Log.e(TAG, "Error", t);
|
} else {
|
||||||
storiesFetching = false;
|
hasStories = false;
|
||||||
}
|
}
|
||||||
});
|
storiesFetching = false;
|
||||||
|
}), Dispatchers.getIO())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTitle() {
|
private void setTitle() {
|
||||||
|
@ -37,7 +37,6 @@ import com.google.android.material.snackbar.Snackbar;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
@ -53,7 +52,6 @@ import awais.instagrabber.db.repositories.FavoriteRepository;
|
|||||||
import awais.instagrabber.db.repositories.RepositoryCallback;
|
import awais.instagrabber.db.repositories.RepositoryCallback;
|
||||||
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
||||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||||
import awais.instagrabber.models.StoryModel;
|
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
import awais.instagrabber.models.enums.FavoriteType;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
import awais.instagrabber.repositories.responses.Location;
|
import awais.instagrabber.repositories.responses.Location;
|
||||||
@ -70,6 +68,7 @@ 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 awais.instagrabber.webservices.StoriesService;
|
import awais.instagrabber.webservices.StoriesService;
|
||||||
|
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;
|
||||||
@ -293,7 +292,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
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.INSTANCE;
|
||||||
graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
|
graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
@ -586,22 +585,19 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
storiesFetching = true;
|
storiesFetching = true;
|
||||||
storiesService.getUserStory(
|
storiesService.getUserStory(
|
||||||
StoryViewerOptions.forLocation(locationId, locationModel.getName()),
|
StoryViewerOptions.forLocation(locationId, locationModel.getName()),
|
||||||
new ServiceCallback<List<StoryModel>>() {
|
CoroutineUtilsKt.getContinuation((storyModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
@Override
|
if (throwable != null) {
|
||||||
public void onSuccess(final List<StoryModel> storyModels) {
|
Log.e(TAG, "Error", throwable);
|
||||||
if (storyModels != null && !storyModels.isEmpty()) {
|
|
||||||
locationDetailsBinding.mainLocationImage.setStoriesBorder(1);
|
|
||||||
hasStories = true;
|
|
||||||
}
|
|
||||||
storiesFetching = false;
|
storiesFetching = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (storyModels != null && !storyModels.isEmpty()) {
|
||||||
@Override
|
locationDetailsBinding.mainLocationImage.setStoriesBorder(1);
|
||||||
public void onFailure(final Throwable t) {
|
hasStories = true;
|
||||||
Log.e(TAG, "Error", t);
|
|
||||||
storiesFetching = false;
|
|
||||||
}
|
}
|
||||||
});
|
storiesFetching = false;
|
||||||
|
}), Dispatchers.getIO())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,12 +41,15 @@ import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
|
|||||||
import awais.instagrabber.models.FeedStoryModel;
|
import awais.instagrabber.models.FeedStoryModel;
|
||||||
import awais.instagrabber.models.HighlightModel;
|
import awais.instagrabber.models.HighlightModel;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
|
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.viewmodels.ArchivesViewModel;
|
import awais.instagrabber.viewmodels.ArchivesViewModel;
|
||||||
import awais.instagrabber.viewmodels.FeedStoriesViewModel;
|
import awais.instagrabber.viewmodels.FeedStoriesViewModel;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
import awais.instagrabber.webservices.StoriesService;
|
import awais.instagrabber.webservices.StoriesService;
|
||||||
import awais.instagrabber.webservices.StoriesService.ArchiveFetchResponse;
|
import awais.instagrabber.webservices.StoriesService.ArchiveFetchResponse;
|
||||||
|
import kotlinx.coroutines.Dispatchers;
|
||||||
|
|
||||||
public final class StoryListViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
public final class StoryListViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
||||||
private static final String TAG = "StoryListViewerFragment";
|
private static final String TAG = "StoryListViewerFragment";
|
||||||
@ -133,7 +136,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
|
|||||||
context = getContext();
|
context = getContext();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
storiesService = StoriesService.getInstance(null, 0L, null);
|
storiesService = StoriesService.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -239,22 +242,31 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
|
|||||||
}
|
}
|
||||||
firstRefresh = false;
|
firstRefresh = false;
|
||||||
} else if (type.equals("feed")) {
|
} else if (type.equals("feed")) {
|
||||||
storiesService.getFeedStories(new ServiceCallback<List<FeedStoryModel>>() {
|
storiesService.getFeedStories(
|
||||||
@Override
|
CoroutineUtilsKt.getContinuation((feedStoryModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
public void onSuccess(final List<FeedStoryModel> result) {
|
if (throwable != null) {
|
||||||
feedStoriesViewModel.getList().postValue(result);
|
Log.e(TAG, "failed", throwable);
|
||||||
adapter.submitList(result);
|
Toast.makeText(context, throwable.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
binding.swipeRefreshLayout.setRefreshing(false);
|
return;
|
||||||
}
|
}
|
||||||
|
//noinspection unchecked
|
||||||
@Override
|
feedStoriesViewModel.getList().postValue((List<FeedStoryModel>) feedStoryModels);
|
||||||
public void onFailure(final Throwable t) {
|
//noinspection unchecked
|
||||||
Log.e(TAG, "failed", t);
|
adapter.submitList((List<FeedStoryModel>) feedStoryModels);
|
||||||
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
|
binding.swipeRefreshLayout.setRefreshing(false);
|
||||||
}
|
}), Dispatchers.getIO())
|
||||||
});
|
);
|
||||||
} else if (type.equals("archive")) {
|
} else if (type.equals("archive")) {
|
||||||
storiesService.fetchArchive(endCursor, cb);
|
storiesService.fetchArchive(
|
||||||
|
endCursor,
|
||||||
|
CoroutineUtilsKt.getContinuation((archiveFetchResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
cb.onFailure(throwable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cb.onSuccess(archiveFetchResponse);
|
||||||
|
}), Dispatchers.getIO())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,6 @@ import awais.instagrabber.models.stickers.SwipeUpModel;
|
|||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions.Type;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions.Type;
|
||||||
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds;
|
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds;
|
||||||
import awais.instagrabber.repositories.responses.StoryStickerResponse;
|
|
||||||
import awais.instagrabber.utils.AppExecutors;
|
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;
|
||||||
@ -113,6 +112,8 @@ import static awais.instagrabber.utils.Utils.settingsHelper;
|
|||||||
public class StoryViewerFragment extends Fragment {
|
public class StoryViewerFragment extends Fragment {
|
||||||
private static final String TAG = "StoryViewerFragment";
|
private static final String TAG = "StoryViewerFragment";
|
||||||
|
|
||||||
|
private final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
|
|
||||||
private AppCompatActivity fragmentActivity;
|
private AppCompatActivity fragmentActivity;
|
||||||
private View root;
|
private View root;
|
||||||
private FragmentStoryViewerBinding binding;
|
private FragmentStoryViewerBinding binding;
|
||||||
@ -148,21 +149,22 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
// private boolean isArchive;
|
// private boolean isArchive;
|
||||||
// private boolean isNotification;
|
// private boolean isNotification;
|
||||||
private DirectMessagesService directMessagesService;
|
private DirectMessagesService directMessagesService;
|
||||||
|
|
||||||
private final String cookie = settingsHelper.getString(Constants.COOKIE);
|
|
||||||
private StoryViewerOptions options;
|
private StoryViewerOptions options;
|
||||||
|
private String csrfToken;
|
||||||
|
private String deviceId;
|
||||||
|
private long userId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||||
if (csrfToken == null) return;
|
if (csrfToken == null) return;
|
||||||
final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
|
userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||||
final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
|
deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
|
||||||
fragmentActivity = (AppCompatActivity) requireActivity();
|
fragmentActivity = (AppCompatActivity) requireActivity();
|
||||||
storiesService = StoriesService.getInstance(csrfToken, userIdFromCookie, deviceId);
|
storiesService = StoriesService.INSTANCE;
|
||||||
mediaService = MediaService.INSTANCE;
|
mediaService = MediaService.INSTANCE;
|
||||||
directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId);
|
directMessagesService = DirectMessagesService.getInstance(csrfToken, userId, deviceId);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,28 +516,31 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
}), (d, w) -> {
|
}), (d, w) -> {
|
||||||
sticking = true;
|
sticking = true;
|
||||||
storiesService.respondToPoll(
|
storiesService.respondToPoll(
|
||||||
|
csrfToken,
|
||||||
|
userId,
|
||||||
|
deviceId,
|
||||||
currentStory.getStoryMediaId().split("_")[0],
|
currentStory.getStoryMediaId().split("_")[0],
|
||||||
poll.getId(),
|
poll.getId(),
|
||||||
w,
|
w,
|
||||||
new ServiceCallback<StoryStickerResponse>() {
|
CoroutineUtilsKt.getContinuation(
|
||||||
@Override
|
(storyStickerResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
public void onSuccess(final StoryStickerResponse result) {
|
if (throwable != null) {
|
||||||
sticking = false;
|
sticking = false;
|
||||||
try {
|
Log.e(TAG, "Error responding", throwable);
|
||||||
poll.setMyChoice(w);
|
try {
|
||||||
Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
@Override
|
sticking = false;
|
||||||
public void onFailure(final Throwable t) {
|
try {
|
||||||
sticking = false;
|
poll.setMyChoice(w);
|
||||||
Log.e(TAG, "Error responding", t);
|
Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
|
||||||
try {
|
} catch (Exception ignored) {}
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
}),
|
||||||
} catch (Exception ignored) {}
|
Dispatchers.getIO()
|
||||||
}
|
)
|
||||||
});
|
);
|
||||||
})
|
})
|
||||||
.setPositiveButton(R.string.cancel, null)
|
.setPositiveButton(R.string.cancel, null)
|
||||||
.show();
|
.show();
|
||||||
@ -550,27 +555,30 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
.setPositiveButton(R.string.confirm, (d, w) -> {
|
.setPositiveButton(R.string.confirm, (d, w) -> {
|
||||||
sticking = true;
|
sticking = true;
|
||||||
storiesService.respondToQuestion(
|
storiesService.respondToQuestion(
|
||||||
|
csrfToken,
|
||||||
|
userId,
|
||||||
|
deviceId,
|
||||||
currentStory.getStoryMediaId().split("_")[0],
|
currentStory.getStoryMediaId().split("_")[0],
|
||||||
question.getId(),
|
question.getId(),
|
||||||
input.getText().toString(),
|
input.getText().toString(),
|
||||||
new ServiceCallback<StoryStickerResponse>() {
|
CoroutineUtilsKt.getContinuation(
|
||||||
@Override
|
(storyStickerResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
public void onSuccess(final StoryStickerResponse result) {
|
if (throwable != null) {
|
||||||
sticking = false;
|
sticking = false;
|
||||||
try {
|
Log.e(TAG, "Error responding", throwable);
|
||||||
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
try {
|
||||||
} catch (Exception ignored) {}
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
}
|
} catch (Exception ignored) {}
|
||||||
|
return;
|
||||||
@Override
|
}
|
||||||
public void onFailure(final Throwable t) {
|
sticking = false;
|
||||||
sticking = false;
|
try {
|
||||||
Log.e(TAG, "Error responding", t);
|
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||||
try {
|
} catch (Exception ignored) {}
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
}),
|
||||||
} catch (Exception ignored) {}
|
Dispatchers.getIO()
|
||||||
}
|
)
|
||||||
});
|
);
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.show();
|
.show();
|
||||||
@ -605,28 +613,31 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
if (quiz.getMyChoice() == -1) {
|
if (quiz.getMyChoice() == -1) {
|
||||||
sticking = true;
|
sticking = true;
|
||||||
storiesService.respondToQuiz(
|
storiesService.respondToQuiz(
|
||||||
|
csrfToken,
|
||||||
|
userId,
|
||||||
|
deviceId,
|
||||||
currentStory.getStoryMediaId().split("_")[0],
|
currentStory.getStoryMediaId().split("_")[0],
|
||||||
quiz.getId(),
|
quiz.getId(),
|
||||||
w,
|
w,
|
||||||
new ServiceCallback<StoryStickerResponse>() {
|
CoroutineUtilsKt.getContinuation(
|
||||||
@Override
|
(storyStickerResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
public void onSuccess(final StoryStickerResponse result) {
|
if (throwable != null) {
|
||||||
sticking = false;
|
sticking = false;
|
||||||
try {
|
Log.e(TAG, "Error responding", throwable);
|
||||||
quiz.setMyChoice(w);
|
try {
|
||||||
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
@Override
|
sticking = false;
|
||||||
public void onFailure(final Throwable t) {
|
try {
|
||||||
sticking = false;
|
quiz.setMyChoice(w);
|
||||||
Log.e(TAG, "Error responding", t);
|
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||||
try {
|
} catch (Exception ignored) {}
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
}),
|
||||||
} catch (Exception ignored) {}
|
Dispatchers.getIO()
|
||||||
}
|
)
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setPositiveButton(R.string.cancel, null)
|
.setPositiveButton(R.string.cancel, null)
|
||||||
@ -673,28 +684,30 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
.setPositiveButton(R.string.confirm, (d, w) -> {
|
.setPositiveButton(R.string.confirm, (d, w) -> {
|
||||||
sticking = true;
|
sticking = true;
|
||||||
storiesService.respondToSlider(
|
storiesService.respondToSlider(
|
||||||
|
csrfToken,
|
||||||
|
userId,
|
||||||
|
deviceId,
|
||||||
currentStory.getStoryMediaId().split("_")[0],
|
currentStory.getStoryMediaId().split("_")[0],
|
||||||
slider.getId(),
|
slider.getId(),
|
||||||
sliderValue,
|
sliderValue,
|
||||||
new ServiceCallback<StoryStickerResponse>() {
|
CoroutineUtilsKt.getContinuation(
|
||||||
@Override
|
(storyStickerResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
public void onSuccess(final StoryStickerResponse result) {
|
if (throwable != null) {
|
||||||
sticking = false;
|
sticking = false;
|
||||||
try {
|
Log.e(TAG, "Error responding", throwable);
|
||||||
slider.setMyChoice(sliderValue);
|
try {
|
||||||
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
@Override
|
sticking = false;
|
||||||
public void onFailure(final Throwable t) {
|
try {
|
||||||
sticking = false;
|
slider.setMyChoice(sliderValue);
|
||||||
Log.e(TAG, "Error responding", t);
|
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||||
try {
|
} catch (Exception ignored) {}
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
}), Dispatchers.getIO()
|
||||||
} catch (Exception ignored) {}
|
)
|
||||||
}
|
);
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.show();
|
.show();
|
||||||
@ -786,27 +799,26 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
setTitle(type);
|
setTitle(type);
|
||||||
storiesViewModel.getList().setValue(Collections.emptyList());
|
storiesViewModel.getList().setValue(Collections.emptyList());
|
||||||
if (type == Type.STORY) {
|
if (type == Type.STORY) {
|
||||||
storiesService.fetch(options.getId(), new ServiceCallback<StoryModel>() {
|
storiesService.fetch(
|
||||||
@Override
|
options.getId(),
|
||||||
public void onSuccess(final StoryModel storyModel) {
|
CoroutineUtilsKt.getContinuation((storyModel, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
fetching = false;
|
if (throwable != null) {
|
||||||
binding.storiesList.setVisibility(View.GONE);
|
Toast.makeText(context, throwable.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
if (storyModel == null) {
|
Log.e(TAG, "Error", throwable);
|
||||||
storiesViewModel.getList().setValue(Collections.emptyList());
|
return;
|
||||||
currentStory = null;
|
}
|
||||||
return;
|
fetching = false;
|
||||||
}
|
binding.storiesList.setVisibility(View.GONE);
|
||||||
storiesViewModel.getList().setValue(Collections.singletonList(storyModel));
|
if (storyModel == null) {
|
||||||
currentStory = storyModel;
|
storiesViewModel.getList().setValue(Collections.emptyList());
|
||||||
refreshStory();
|
currentStory = null;
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
@Override
|
storiesViewModel.getList().setValue(Collections.singletonList(storyModel));
|
||||||
public void onFailure(final Throwable t) {
|
currentStory = storyModel;
|
||||||
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
|
refreshStory();
|
||||||
Log.e(TAG, "Error", t);
|
}), Dispatchers.getIO())
|
||||||
}
|
);
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentStoryMediaId == null) return;
|
if (currentStoryMediaId == null) return;
|
||||||
@ -840,7 +852,17 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
storyCallback.onSuccess(Collections.singletonList(live));
|
storyCallback.onSuccess(Collections.singletonList(live));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
storiesService.getUserStory(fetchOptions, storyCallback);
|
storiesService.getUserStory(
|
||||||
|
fetchOptions,
|
||||||
|
CoroutineUtilsKt.getContinuation((storyModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
storyCallback.onFailure(throwable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//noinspection unchecked
|
||||||
|
storyCallback.onSuccess((List<StoryModel>) storyModels);
|
||||||
|
}), Dispatchers.getIO())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTitle(final Type type) {
|
private void setTitle(final Type type) {
|
||||||
@ -944,10 +966,15 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (settingsHelper.getBoolean(MARK_AS_SEEN))
|
if (settingsHelper.getBoolean(MARK_AS_SEEN))
|
||||||
storiesService.seen(currentStory.getStoryMediaId(),
|
storiesService.seen(
|
||||||
currentStory.getTimestamp(),
|
csrfToken,
|
||||||
System.currentTimeMillis() / 1000,
|
userId,
|
||||||
null);
|
deviceId,
|
||||||
|
currentStory.getStoryMediaId(),
|
||||||
|
currentStory.getTimestamp(),
|
||||||
|
System.currentTimeMillis() / 1000,
|
||||||
|
CoroutineUtilsKt.getContinuation((s, throwable) -> {}, Dispatchers.getIO())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void downloadStory() {
|
private void downloadStory() {
|
||||||
|
@ -48,12 +48,14 @@ import awais.instagrabber.models.FeedStoryModel;
|
|||||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
import awais.instagrabber.repositories.responses.Media;
|
import awais.instagrabber.repositories.responses.Media;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||||
import awais.instagrabber.utils.DownloadUtils;
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.viewmodels.FeedStoriesViewModel;
|
import awais.instagrabber.viewmodels.FeedStoriesViewModel;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
|
||||||
import awais.instagrabber.webservices.StoriesService;
|
import awais.instagrabber.webservices.StoriesService;
|
||||||
|
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;
|
||||||
@ -274,7 +276,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
fragmentActivity = (MainActivity) requireActivity();
|
fragmentActivity = (MainActivity) requireActivity();
|
||||||
storiesService = StoriesService.getInstance(null, 0L, null);
|
storiesService = StoriesService.INSTANCE;
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,23 +430,23 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||||||
// final String cookie = settingsHelper.getString(Constants.COOKIE);
|
// final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
storiesFetching = true;
|
storiesFetching = true;
|
||||||
updateSwipeRefreshState();
|
updateSwipeRefreshState();
|
||||||
storiesService.getFeedStories(new ServiceCallback<List<FeedStoryModel>>() {
|
storiesService.getFeedStories(
|
||||||
@Override
|
CoroutineUtilsKt.getContinuation((feedStoryModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
public void onSuccess(final List<FeedStoryModel> result) {
|
if (throwable != null) {
|
||||||
storiesFetching = false;
|
Log.e(TAG, "failed", throwable);
|
||||||
feedStoriesViewModel.getList().postValue(result);
|
storiesFetching = false;
|
||||||
feedStoriesAdapter.submitList(result);
|
updateSwipeRefreshState();
|
||||||
if (storyListMenu != null) storyListMenu.setVisible(true);
|
return;
|
||||||
updateSwipeRefreshState();
|
}
|
||||||
}
|
storiesFetching = false;
|
||||||
|
//noinspection unchecked
|
||||||
@Override
|
feedStoriesViewModel.getList().postValue((List<FeedStoryModel>) feedStoryModels);
|
||||||
public void onFailure(final Throwable t) {
|
//noinspection unchecked
|
||||||
Log.e(TAG, "failed", t);
|
feedStoriesAdapter.submitList((List<FeedStoryModel>) feedStoryModels);
|
||||||
storiesFetching = false;
|
if (storyListMenu != null) storyListMenu.setVisible(true);
|
||||||
updateSwipeRefreshState();
|
updateSwipeRefreshState();
|
||||||
}
|
}), Dispatchers.getIO())
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPostsLayoutPreferences() {
|
private void showPostsLayoutPreferences() {
|
||||||
|
@ -74,7 +74,6 @@ import awais.instagrabber.managers.DirectMessagesManager;
|
|||||||
import awais.instagrabber.managers.InboxManager;
|
import awais.instagrabber.managers.InboxManager;
|
||||||
import awais.instagrabber.models.HighlightModel;
|
import awais.instagrabber.models.HighlightModel;
|
||||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||||
import awais.instagrabber.models.StoryModel;
|
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
import awais.instagrabber.models.enums.FavoriteType;
|
||||||
import awais.instagrabber.models.enums.PostItemType;
|
import awais.instagrabber.models.enums.PostItemType;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
@ -337,7 +336,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
fragmentActivity = (MainActivity) requireActivity();
|
fragmentActivity = (MainActivity) requireActivity();
|
||||||
friendshipService = isLoggedIn ? FriendshipService.INSTANCE : null;
|
friendshipService = isLoggedIn ? FriendshipService.INSTANCE : null;
|
||||||
directMessagesService = isLoggedIn ? DirectMessagesService.getInstance(csrfToken, myId, deviceUuid) : null;
|
directMessagesService = isLoggedIn ? DirectMessagesService.getInstance(csrfToken, myId, deviceUuid) : null;
|
||||||
storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null;
|
storiesService = isLoggedIn ? StoriesService.INSTANCE : 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.INSTANCE;
|
graphQLService = isLoggedIn ? null : GraphQLService.INSTANCE;
|
||||||
@ -1044,36 +1043,34 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
private void fetchStoryAndHighlights(final long profileId) {
|
private void fetchStoryAndHighlights(final long profileId) {
|
||||||
storiesService.getUserStory(
|
storiesService.getUserStory(
|
||||||
StoryViewerOptions.forUser(profileId, profileModel.getFullName()),
|
StoryViewerOptions.forUser(profileId, profileModel.getFullName()),
|
||||||
new ServiceCallback<List<StoryModel>>() {
|
CoroutineUtilsKt.getContinuation((storyModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
@Override
|
if (throwable != null) {
|
||||||
public void onSuccess(final List<StoryModel> storyModels) {
|
Log.e(TAG, "Error", throwable);
|
||||||
if (storyModels != null && !storyModels.isEmpty()) {
|
return;
|
||||||
profileDetailsBinding.mainProfileImage.setStoriesBorder(1);
|
|
||||||
hasStories = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (storyModels != null && !storyModels.isEmpty()) {
|
||||||
@Override
|
profileDetailsBinding.mainProfileImage.setStoriesBorder(1);
|
||||||
public void onFailure(final Throwable t) {
|
hasStories = true;
|
||||||
Log.e(TAG, "Error", t);
|
|
||||||
}
|
}
|
||||||
});
|
}), Dispatchers.getIO())
|
||||||
storiesService.fetchHighlights(profileId,
|
);
|
||||||
new ServiceCallback<List<HighlightModel>>() {
|
storiesService.fetchHighlights(
|
||||||
@Override
|
profileId,
|
||||||
public void onSuccess(final List<HighlightModel> result) {
|
CoroutineUtilsKt.getContinuation((highlightModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
if (result != null) {
|
if (throwable != null) {
|
||||||
profileDetailsBinding.highlightsList.setVisibility(View.VISIBLE);
|
profileDetailsBinding.highlightsList.setVisibility(View.GONE);
|
||||||
highlightsViewModel.getList().postValue(result);
|
Log.e(TAG, "Error", throwable);
|
||||||
} else profileDetailsBinding.highlightsList.setVisibility(View.GONE);
|
return;
|
||||||
}
|
}
|
||||||
|
if (highlightModels != null) {
|
||||||
@Override
|
profileDetailsBinding.highlightsList.setVisibility(View.VISIBLE);
|
||||||
public void onFailure(final Throwable t) {
|
//noinspection unchecked
|
||||||
profileDetailsBinding.highlightsList.setVisibility(View.GONE);
|
highlightsViewModel.getList().postValue((List<HighlightModel>) highlightModels);
|
||||||
Log.e(TAG, "Error", t);
|
} else {
|
||||||
}
|
profileDetailsBinding.highlightsList.setVisibility(View.GONE);
|
||||||
});
|
}
|
||||||
|
}), Dispatchers.getIO())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupCommonListeners() {
|
private void setupCommonListeners() {
|
||||||
|
@ -1,43 +1,38 @@
|
|||||||
package awais.instagrabber.repositories;
|
package awais.instagrabber.repositories
|
||||||
|
|
||||||
import java.util.Map;
|
import awais.instagrabber.repositories.responses.StoryStickerResponse
|
||||||
|
import retrofit2.http.*
|
||||||
|
|
||||||
import awais.instagrabber.repositories.responses.StoryStickerResponse;
|
interface StoriesRepository {
|
||||||
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;
|
|
||||||
import retrofit2.http.Url;
|
|
||||||
|
|
||||||
public interface StoriesRepository {
|
|
||||||
@GET("/api/v1/media/{mediaId}/info/")
|
|
||||||
Call<String> fetch(@Path("mediaId") final long mediaId);
|
|
||||||
// this one is the same as MediaRepository.fetch BUT you need to make sure it's a story
|
// this one is the same as MediaRepository.fetch BUT you need to make sure it's a story
|
||||||
|
@GET("/api/v1/media/{mediaId}/info/")
|
||||||
|
suspend fun fetch(@Path("mediaId") mediaId: Long): String
|
||||||
|
|
||||||
@GET("/api/v1/feed/reels_tray/")
|
@GET("/api/v1/feed/reels_tray/")
|
||||||
Call<String> getFeedStories();
|
suspend fun getFeedStories(): String
|
||||||
|
|
||||||
@GET("/api/v1/highlights/{uid}/highlights_tray/")
|
@GET("/api/v1/highlights/{uid}/highlights_tray/")
|
||||||
Call<String> fetchHighlights(@Path("uid") final long uid);
|
suspend fun fetchHighlights(@Path("uid") uid: Long): String
|
||||||
|
|
||||||
@GET("/api/v1/archive/reel/day_shells/")
|
@GET("/api/v1/archive/reel/day_shells/")
|
||||||
Call<String> fetchArchive(@QueryMap Map<String, String> queryParams);
|
suspend fun fetchArchive(@QueryMap queryParams: Map<String, String>): String
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
Call<String> getUserStory(@Url String url);
|
suspend fun getUserStory(@Url url: String): String
|
||||||
|
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("/api/v1/media/{storyId}/{stickerId}/{action}/")
|
@POST("/api/v1/media/{storyId}/{stickerId}/{action}/")
|
||||||
Call<StoryStickerResponse> respondToSticker(@Path("storyId") String storyId,
|
suspend fun respondToSticker(
|
||||||
@Path("stickerId") String stickerId,
|
@Path("storyId") storyId: String,
|
||||||
@Path("action") String action,
|
@Path("stickerId") stickerId: String,
|
||||||
// story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer
|
@Path("action") action: String, // story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer
|
||||||
@FieldMap Map<String, String> form);
|
@FieldMap form: Map<String, String>,
|
||||||
|
): StoryStickerResponse
|
||||||
|
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("/api/v2/media/seen/")
|
@POST("/api/v2/media/seen/")
|
||||||
Call<String> seen(@QueryMap Map<String, String> queryParams, @FieldMap Map<String, String> form);
|
suspend fun seen(
|
||||||
}
|
@QueryMap queryParams: Map<String, String>,
|
||||||
|
@FieldMap form: Map<String, String>,
|
||||||
|
): String
|
||||||
|
}
|
@ -1,548 +1,309 @@
|
|||||||
package awais.instagrabber.webservices;
|
package awais.instagrabber.webservices
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log
|
||||||
|
import awais.instagrabber.fragments.settings.PreferenceKeys
|
||||||
|
import awais.instagrabber.models.FeedStoryModel
|
||||||
|
import awais.instagrabber.models.HighlightModel
|
||||||
|
import awais.instagrabber.models.StoryModel
|
||||||
|
import awais.instagrabber.repositories.StoriesRepository
|
||||||
|
import awais.instagrabber.repositories.requests.StoryViewerOptions
|
||||||
|
import awais.instagrabber.repositories.responses.StoryStickerResponse
|
||||||
|
import awais.instagrabber.repositories.responses.User
|
||||||
|
import awais.instagrabber.utils.Constants
|
||||||
|
import awais.instagrabber.utils.ResponseBodyUtils
|
||||||
|
import awais.instagrabber.utils.TextUtils.isEmpty
|
||||||
|
import awais.instagrabber.utils.Utils
|
||||||
|
import awais.instagrabber.utils.extensions.TAG
|
||||||
|
import awais.instagrabber.webservices.RetrofitFactory.retrofit
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
object StoriesService : BaseService() {
|
||||||
import androidx.annotation.Nullable;
|
private val repository: StoriesRepository = retrofit.create(StoriesRepository::class.java)
|
||||||
|
|
||||||
import org.json.JSONArray;
|
suspend fun fetch(mediaId: Long): StoryModel {
|
||||||
import org.json.JSONException;
|
val response = repository.fetch(mediaId)
|
||||||
import org.json.JSONObject;
|
val itemJson = JSONObject(response).getJSONArray("items").getJSONObject(0)
|
||||||
|
return ResponseBodyUtils.parseStoryItem(itemJson, false, null)
|
||||||
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 java.util.UUID;
|
|
||||||
|
|
||||||
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
|
||||||
import awais.instagrabber.models.FeedStoryModel;
|
|
||||||
import awais.instagrabber.models.HighlightModel;
|
|
||||||
import awais.instagrabber.models.StoryModel;
|
|
||||||
import awais.instagrabber.repositories.StoriesRepository;
|
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
|
||||||
import awais.instagrabber.repositories.responses.StoryStickerResponse;
|
|
||||||
import awais.instagrabber.repositories.responses.User;
|
|
||||||
import awais.instagrabber.utils.Constants;
|
|
||||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
|
||||||
import awais.instagrabber.utils.TextUtils;
|
|
||||||
import awais.instagrabber.utils.Utils;
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
public class StoriesService extends BaseService {
|
|
||||||
private static final String TAG = "StoriesService";
|
|
||||||
|
|
||||||
private static StoriesService instance;
|
|
||||||
|
|
||||||
private final StoriesRepository repository;
|
|
||||||
private final String csrfToken;
|
|
||||||
private final long userId;
|
|
||||||
private final String deviceUuid;
|
|
||||||
|
|
||||||
private StoriesService(@NonNull final String csrfToken,
|
|
||||||
final long userId,
|
|
||||||
@NonNull final String deviceUuid) {
|
|
||||||
this.csrfToken = csrfToken;
|
|
||||||
this.userId = userId;
|
|
||||||
this.deviceUuid = deviceUuid;
|
|
||||||
repository = RetrofitFactory.INSTANCE
|
|
||||||
.getRetrofit()
|
|
||||||
.create(StoriesRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCsrfToken() {
|
suspend fun getFeedStories(): List<FeedStoryModel> {
|
||||||
return csrfToken;
|
val response = repository.getFeedStories()
|
||||||
|
return parseStoriesBody(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getUserId() {
|
private fun parseStoriesBody(body: String): List<FeedStoryModel> {
|
||||||
return userId;
|
val feedStoryModels: MutableList<FeedStoryModel> = ArrayList()
|
||||||
}
|
val feedStoriesReel = JSONObject(body).getJSONArray("tray")
|
||||||
|
for (i in 0 until feedStoriesReel.length()) {
|
||||||
public String getDeviceUuid() {
|
val node = feedStoriesReel.getJSONObject(i)
|
||||||
return deviceUuid;
|
if (node.optBoolean("hide_from_feed_unit") && Utils.settingsHelper.getBoolean(PreferenceKeys.HIDE_MUTED_REELS)) continue
|
||||||
}
|
val userJson = node.getJSONObject(if (node.has("user")) "user" else "owner")
|
||||||
|
try {
|
||||||
public static StoriesService getInstance(final String csrfToken,
|
val user = User(userJson.getLong("pk"),
|
||||||
final long userId,
|
userJson.getString("username"),
|
||||||
final String deviceUuid) {
|
userJson.optString("full_name"),
|
||||||
if (instance == null
|
userJson.optBoolean("is_private"),
|
||||||
|| !Objects.equals(instance.getCsrfToken(), csrfToken)
|
userJson.getString("profile_pic_url"),
|
||||||
|| !Objects.equals(instance.getUserId(), userId)
|
userJson.optBoolean("is_verified")
|
||||||
|| !Objects.equals(instance.getDeviceUuid(), deviceUuid)) {
|
)
|
||||||
instance = new StoriesService(csrfToken, userId, deviceUuid);
|
val timestamp = node.getLong("latest_reel_media")
|
||||||
|
val fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp
|
||||||
|
val itemJson = if (node.has("items")) node.getJSONArray("items").optJSONObject(0) else null
|
||||||
|
var firstStoryModel: StoryModel? = null
|
||||||
|
if (itemJson != null) {
|
||||||
|
firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, null)
|
||||||
|
}
|
||||||
|
feedStoryModels.add(FeedStoryModel(
|
||||||
|
node.getString("id"),
|
||||||
|
user,
|
||||||
|
fullyRead,
|
||||||
|
timestamp,
|
||||||
|
firstStoryModel,
|
||||||
|
node.getInt("media_count"),
|
||||||
|
false,
|
||||||
|
node.optBoolean("has_besties_media")))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "parseStoriesBody: ", e)
|
||||||
|
} // to cover promotional reels with non-long user pk's
|
||||||
}
|
}
|
||||||
return instance;
|
val broadcasts = JSONObject(body).getJSONArray("broadcasts")
|
||||||
}
|
for (i in 0 until broadcasts.length()) {
|
||||||
|
val node = broadcasts.getJSONObject(i)
|
||||||
public void fetch(final long mediaId,
|
val userJson = node.getJSONObject("broadcast_owner")
|
||||||
final ServiceCallback<StoryModel> callback) {
|
val user = User(userJson.getLong("pk"),
|
||||||
final Call<String> request = repository.fetch(mediaId);
|
userJson.getString("username"),
|
||||||
request.enqueue(new Callback<String>() {
|
userJson.optString("full_name"),
|
||||||
@Override
|
userJson.optBoolean("is_private"),
|
||||||
public void onResponse(@NonNull final Call<String> call,
|
userJson.getString("profile_pic_url"),
|
||||||
@NonNull final Response<String> response) {
|
userJson.optBoolean("is_verified")
|
||||||
if (callback == null) return;
|
)
|
||||||
final String body = response.body();
|
feedStoryModels.add(FeedStoryModel(
|
||||||
if (body == null) {
|
node.getString("id"),
|
||||||
callback.onSuccess(null);
|
user,
|
||||||
return;
|
false,
|
||||||
}
|
node.getLong("published_time"),
|
||||||
try {
|
ResponseBodyUtils.parseBroadcastItem(node),
|
||||||
final JSONObject itemJson = new JSONObject(body).getJSONArray("items").getJSONObject(0);
|
1,
|
||||||
callback.onSuccess(ResponseBodyUtils.parseStoryItem(itemJson, false, null));
|
isLive = true,
|
||||||
} catch (JSONException e) {
|
isBestie = false
|
||||||
callback.onFailure(e);
|
))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull final Call<String> call,
|
|
||||||
@NonNull final Throwable t) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFailure(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getFeedStories(final ServiceCallback<List<FeedStoryModel>> callback) {
|
|
||||||
final Call<String> response = repository.getFeedStories();
|
|
||||||
response.enqueue(new Callback<String>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
|
||||||
final String body = response.body();
|
|
||||||
if (body == null) {
|
|
||||||
Log.e(TAG, "getFeedStories: body is empty");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parseStoriesBody(body, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
|
||||||
callback.onFailure(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseStoriesBody(final String body, final ServiceCallback<List<FeedStoryModel>> callback) {
|
|
||||||
try {
|
|
||||||
final List<FeedStoryModel> feedStoryModels = new ArrayList<>();
|
|
||||||
final JSONArray feedStoriesReel = new JSONObject(body).getJSONArray("tray");
|
|
||||||
for (int i = 0; i < feedStoriesReel.length(); ++i) {
|
|
||||||
final JSONObject node = feedStoriesReel.getJSONObject(i);
|
|
||||||
if (node.optBoolean("hide_from_feed_unit") && Utils.settingsHelper.getBoolean(PreferenceKeys.HIDE_MUTED_REELS)) continue;
|
|
||||||
final JSONObject userJson = node.getJSONObject(node.has("user") ? "user" : "owner");
|
|
||||||
try {
|
|
||||||
final User user = new User(userJson.getLong("pk"),
|
|
||||||
userJson.getString("username"),
|
|
||||||
userJson.optString("full_name"),
|
|
||||||
userJson.optBoolean("is_private"),
|
|
||||||
userJson.getString("profile_pic_url"),
|
|
||||||
userJson.optBoolean("is_verified")
|
|
||||||
);
|
|
||||||
final long timestamp = node.getLong("latest_reel_media");
|
|
||||||
final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp;
|
|
||||||
final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").optJSONObject(0) : null;
|
|
||||||
StoryModel firstStoryModel = null;
|
|
||||||
if (itemJson != null) {
|
|
||||||
firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, null);
|
|
||||||
}
|
|
||||||
feedStoryModels.add(new FeedStoryModel(
|
|
||||||
node.getString("id"),
|
|
||||||
user,
|
|
||||||
fullyRead,
|
|
||||||
timestamp,
|
|
||||||
firstStoryModel,
|
|
||||||
node.getInt("media_count"),
|
|
||||||
false,
|
|
||||||
node.optBoolean("has_besties_media")));
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "parseStoriesBody: ", e);
|
|
||||||
} // to cover promotional reels with non-long user pk's
|
|
||||||
}
|
|
||||||
final JSONArray broadcasts = new JSONObject(body).getJSONArray("broadcasts");
|
|
||||||
for (int i = 0; i < broadcasts.length(); ++i) {
|
|
||||||
final JSONObject node = broadcasts.getJSONObject(i);
|
|
||||||
final JSONObject userJson = node.getJSONObject("broadcast_owner");
|
|
||||||
// final ProfileModel profileModel = new ProfileModel(false, false, false,
|
|
||||||
// userJson.getString("pk"),
|
|
||||||
// userJson.getString("username"),
|
|
||||||
// null, null, null,
|
|
||||||
// userJson.getString("profile_pic_url"),
|
|
||||||
// null, 0, 0, 0, false, false, false, false, false);
|
|
||||||
final User user = new User(userJson.getLong("pk"),
|
|
||||||
userJson.getString("username"),
|
|
||||||
userJson.optString("full_name"),
|
|
||||||
userJson.optBoolean("is_private"),
|
|
||||||
userJson.getString("profile_pic_url"),
|
|
||||||
userJson.optBoolean("is_verified")
|
|
||||||
);
|
|
||||||
feedStoryModels.add(new FeedStoryModel(
|
|
||||||
node.getString("id"),
|
|
||||||
user,
|
|
||||||
false,
|
|
||||||
node.getLong("published_time"),
|
|
||||||
ResponseBodyUtils.parseBroadcastItem(node),
|
|
||||||
1,
|
|
||||||
true,
|
|
||||||
false
|
|
||||||
));
|
|
||||||
}
|
|
||||||
callback.onSuccess(sort(feedStoryModels));
|
|
||||||
} catch (JSONException e) {
|
|
||||||
Log.e(TAG, "Error parsing json", e);
|
|
||||||
}
|
}
|
||||||
|
return sort(feedStoryModels)
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fetchHighlights(final long profileId,
|
suspend fun fetchHighlights(profileId: Long): List<HighlightModel> {
|
||||||
final ServiceCallback<List<HighlightModel>> callback) {
|
val response = repository.fetchHighlights(profileId)
|
||||||
final Call<String> request = repository.fetchHighlights(profileId);
|
val highlightsReel = JSONObject(response).getJSONArray("tray")
|
||||||
request.enqueue(new Callback<String>() {
|
val length = highlightsReel.length()
|
||||||
@Override
|
val highlightModels: MutableList<HighlightModel> = ArrayList()
|
||||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
for (i in 0 until length) {
|
||||||
try {
|
val highlightNode = highlightsReel.getJSONObject(i)
|
||||||
if (callback == null) {
|
highlightModels.add(HighlightModel(
|
||||||
return;
|
highlightNode.getString("title"),
|
||||||
}
|
highlightNode.getString(Constants.EXTRAS_ID),
|
||||||
final String body = response.body();
|
highlightNode.getJSONObject("cover_media")
|
||||||
if (TextUtils.isEmpty(body)) {
|
.getJSONObject("cropped_image_version")
|
||||||
callback.onSuccess(null);
|
.getString("url"),
|
||||||
return;
|
highlightNode.getLong("latest_reel_media"),
|
||||||
}
|
highlightNode.getInt("media_count")
|
||||||
final JSONArray highlightsReel = new JSONObject(body).getJSONArray("tray");
|
))
|
||||||
|
|
||||||
final int length = highlightsReel.length();
|
|
||||||
final List<HighlightModel> highlightModels = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int i = 0; i < length; ++i) {
|
|
||||||
final JSONObject highlightNode = highlightsReel.getJSONObject(i);
|
|
||||||
highlightModels.add(new HighlightModel(
|
|
||||||
highlightNode.getString("title"),
|
|
||||||
highlightNode.getString(Constants.EXTRAS_ID),
|
|
||||||
highlightNode.getJSONObject("cover_media")
|
|
||||||
.getJSONObject("cropped_image_version")
|
|
||||||
.getString("url"),
|
|
||||||
highlightNode.getLong("latest_reel_media"),
|
|
||||||
highlightNode.getInt("media_count")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
callback.onSuccess(highlightModels);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
Log.e(TAG, "onResponse", e);
|
|
||||||
callback.onFailure(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFailure(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fetchArchive(final String maxId,
|
|
||||||
final ServiceCallback<ArchiveFetchResponse> callback) {
|
|
||||||
final Map<String, String> form = new HashMap<>();
|
|
||||||
form.put("include_suggested_highlights", "false");
|
|
||||||
form.put("is_in_archive_home", "true");
|
|
||||||
form.put("include_cover", "1");
|
|
||||||
if (!TextUtils.isEmpty(maxId)) {
|
|
||||||
form.put("max_id", maxId); // NOT TESTED
|
|
||||||
}
|
}
|
||||||
final Call<String> request = repository.fetchArchive(form);
|
return highlightModels
|
||||||
request.enqueue(new Callback<String>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
|
||||||
try {
|
|
||||||
if (callback == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final String body = response.body();
|
|
||||||
if (TextUtils.isEmpty(body)) {
|
|
||||||
callback.onSuccess(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final JSONObject data = new JSONObject(body);
|
|
||||||
final JSONArray highlightsReel = data.getJSONArray("items");
|
|
||||||
|
|
||||||
final int length = highlightsReel.length();
|
|
||||||
final List<HighlightModel> highlightModels = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int i = 0; i < length; ++i) {
|
|
||||||
final JSONObject highlightNode = highlightsReel.getJSONObject(i);
|
|
||||||
highlightModels.add(new HighlightModel(
|
|
||||||
null,
|
|
||||||
highlightNode.getString(Constants.EXTRAS_ID),
|
|
||||||
highlightNode.getJSONObject("cover_image_version").getString("url"),
|
|
||||||
highlightNode.getLong("latest_reel_media"),
|
|
||||||
highlightNode.getInt("media_count")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
callback.onSuccess(new ArchiveFetchResponse(highlightModels,
|
|
||||||
data.getBoolean("more_available"),
|
|
||||||
data.getString("max_id")));
|
|
||||||
} catch (JSONException e) {
|
|
||||||
Log.e(TAG, "onResponse", e);
|
|
||||||
callback.onFailure(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFailure(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getUserStory(final StoryViewerOptions options,
|
suspend fun fetchArchive(maxId: String): ArchiveFetchResponse {
|
||||||
final ServiceCallback<List<StoryModel>> callback) {
|
val form = mutableMapOf(
|
||||||
final String url = buildUrl(options);
|
"include_suggested_highlights" to "false",
|
||||||
final Call<String> userStoryCall = repository.getUserStory(url);
|
"is_in_archive_home" to "true",
|
||||||
final boolean isLocOrHashtag = options.getType() == StoryViewerOptions.Type.LOCATION || options.getType() == StoryViewerOptions.Type.HASHTAG;
|
"include_cover" to "1",
|
||||||
final boolean isHighlight = options.getType() == StoryViewerOptions.Type.HIGHLIGHT || options
|
)
|
||||||
.getType() == StoryViewerOptions.Type.STORY_ARCHIVE;
|
if (!isEmpty(maxId)) {
|
||||||
userStoryCall.enqueue(new Callback<String>() {
|
form["max_id"] = maxId // NOT TESTED
|
||||||
@Override
|
}
|
||||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
val response = repository.fetchArchive(form)
|
||||||
JSONObject data;
|
val data = JSONObject(response)
|
||||||
try {
|
val highlightsReel = data.getJSONArray("items")
|
||||||
final String body = response.body();
|
val length = highlightsReel.length()
|
||||||
if (body == null) {
|
val highlightModels: MutableList<HighlightModel> = ArrayList()
|
||||||
Log.e(TAG, "body is null");
|
for (i in 0 until length) {
|
||||||
return;
|
val highlightNode = highlightsReel.getJSONObject(i)
|
||||||
}
|
highlightModels.add(HighlightModel(
|
||||||
data = new JSONObject(body);
|
null,
|
||||||
|
highlightNode.getString(Constants.EXTRAS_ID),
|
||||||
|
highlightNode.getJSONObject("cover_image_version").getString("url"),
|
||||||
|
highlightNode.getLong("latest_reel_media"),
|
||||||
|
highlightNode.getInt("media_count")
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return ArchiveFetchResponse(highlightModels, data.getBoolean("more_available"), data.getString("max_id"))
|
||||||
|
}
|
||||||
|
|
||||||
if (!isHighlight) {
|
suspend fun getUserStory(options: StoryViewerOptions): List<StoryModel> {
|
||||||
data = data.optJSONObject((isLocOrHashtag) ? "story" : "reel");
|
val url = buildUrl(options) ?: return emptyList()
|
||||||
} else {
|
val response = repository.getUserStory(url)
|
||||||
data = data.getJSONObject("reels").optJSONObject(options.getName());
|
val isLocOrHashtag = options.type == StoryViewerOptions.Type.LOCATION || options.type == StoryViewerOptions.Type.HASHTAG
|
||||||
}
|
val isHighlight = options.type == StoryViewerOptions.Type.HIGHLIGHT || options.type == StoryViewerOptions.Type.STORY_ARCHIVE
|
||||||
|
var data: JSONObject? = JSONObject(response)
|
||||||
String username = null;
|
data = if (!isHighlight) {
|
||||||
if (data != null
|
data?.optJSONObject(if (isLocOrHashtag) "story" else "reel")
|
||||||
// && localUsername == null
|
} else {
|
||||||
&& !isLocOrHashtag) {
|
data?.getJSONObject("reels")?.optJSONObject(options.name)
|
||||||
username = data.getJSONObject("user").getString("username");
|
}
|
||||||
}
|
var username: String? = null
|
||||||
|
if (data != null && !isLocOrHashtag) {
|
||||||
JSONArray media;
|
username = data.getJSONObject("user").getString("username")
|
||||||
if (data != null
|
}
|
||||||
&& (media = data.optJSONArray("items")) != null
|
val media: JSONArray? = data?.optJSONArray("items")
|
||||||
&& media.length() > 0 && media.optJSONObject(0) != null) {
|
return if (media?.length() ?: 0 > 0 && media?.optJSONObject(0) != null) {
|
||||||
final int mediaLen = media.length();
|
val mediaLen = media.length()
|
||||||
final List<StoryModel> models = new ArrayList<>();
|
val models: MutableList<StoryModel> = ArrayList()
|
||||||
for (int i = 0; i < mediaLen; ++i) {
|
for (i in 0 until mediaLen) {
|
||||||
data = media.getJSONObject(i);
|
data = media.getJSONObject(i)
|
||||||
models.add(ResponseBodyUtils.parseStoryItem(data, isLocOrHashtag, username));
|
models.add(ResponseBodyUtils.parseStoryItem(data, isLocOrHashtag, username))
|
||||||
}
|
|
||||||
callback.onSuccess(models);
|
|
||||||
} else {
|
|
||||||
callback.onSuccess(null);
|
|
||||||
}
|
|
||||||
} catch (JSONException e) {
|
|
||||||
Log.e(TAG, "Error parsing string", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
models
|
||||||
|
} else emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private suspend fun respondToSticker(
|
||||||
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
csrfToken: String,
|
||||||
callback.onFailure(t);
|
userId: Long,
|
||||||
|
deviceUuid: String,
|
||||||
|
storyId: String,
|
||||||
|
stickerId: String,
|
||||||
|
action: String,
|
||||||
|
arg1: String,
|
||||||
|
arg2: String,
|
||||||
|
): StoryStickerResponse {
|
||||||
|
val form = mapOf(
|
||||||
|
"_csrftoken" to csrfToken,
|
||||||
|
"_uid" to userId,
|
||||||
|
"_uuid" to deviceUuid,
|
||||||
|
"mutation_token" to UUID.randomUUID().toString(),
|
||||||
|
"client_context" to UUID.randomUUID().toString(),
|
||||||
|
"radio_type" to "wifi-none",
|
||||||
|
arg1 to arg2,
|
||||||
|
)
|
||||||
|
val signedForm = Utils.sign(form)
|
||||||
|
return repository.respondToSticker(storyId, stickerId, action, signedForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun respondToQuestion(
|
||||||
|
csrfToken: String,
|
||||||
|
userId: Long,
|
||||||
|
deviceUuid: String,
|
||||||
|
storyId: String,
|
||||||
|
stickerId: String,
|
||||||
|
answer: String,
|
||||||
|
): StoryStickerResponse = respondToSticker(csrfToken, userId, deviceUuid, storyId, stickerId, "story_question_response", "response", answer)
|
||||||
|
|
||||||
|
suspend fun respondToQuiz(
|
||||||
|
csrfToken: String,
|
||||||
|
userId: Long,
|
||||||
|
deviceUuid: String,
|
||||||
|
storyId: String,
|
||||||
|
stickerId: String,
|
||||||
|
answer: Int,
|
||||||
|
): StoryStickerResponse {
|
||||||
|
return respondToSticker(csrfToken, userId, deviceUuid, storyId, stickerId, "story_quiz_answer", "answer", answer.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun respondToPoll(
|
||||||
|
csrfToken: String,
|
||||||
|
userId: Long,
|
||||||
|
deviceUuid: String,
|
||||||
|
storyId: String,
|
||||||
|
stickerId: String,
|
||||||
|
answer: Int,
|
||||||
|
): StoryStickerResponse = respondToSticker(csrfToken, userId, deviceUuid, storyId, stickerId, "story_poll_vote", "vote", answer.toString())
|
||||||
|
|
||||||
|
suspend fun respondToSlider(
|
||||||
|
csrfToken: String,
|
||||||
|
userId: Long,
|
||||||
|
deviceUuid: String,
|
||||||
|
storyId: String,
|
||||||
|
stickerId: String,
|
||||||
|
answer: Double,
|
||||||
|
): StoryStickerResponse = respondToSticker(csrfToken, userId, deviceUuid, storyId, stickerId, "story_slider_vote", "vote", answer.toString())
|
||||||
|
|
||||||
|
suspend fun seen(
|
||||||
|
csrfToken: String,
|
||||||
|
userId: Long,
|
||||||
|
deviceUuid: String,
|
||||||
|
storyMediaId: String,
|
||||||
|
takenAt: Long,
|
||||||
|
seenAt: Long,
|
||||||
|
): String {
|
||||||
|
val reelsForm = mapOf(storyMediaId to listOf(takenAt.toString() + "_" + seenAt))
|
||||||
|
val form = mutableMapOf(
|
||||||
|
"_csrftoken" to csrfToken,
|
||||||
|
"_uid" to userId,
|
||||||
|
"_uuid" to deviceUuid,
|
||||||
|
"container_module" to "feed_timeline",
|
||||||
|
"reels" to reelsForm,
|
||||||
|
)
|
||||||
|
val signedForm = Utils.sign(form)
|
||||||
|
val queryMap = mapOf(
|
||||||
|
"reel" to "1",
|
||||||
|
"live_vod" to "0",
|
||||||
|
)
|
||||||
|
return repository.seen(queryMap, signedForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildUrl(options: StoryViewerOptions): String? {
|
||||||
|
val builder = StringBuilder()
|
||||||
|
builder.append("https://i.instagram.com/api/v1/")
|
||||||
|
val type = options.type
|
||||||
|
var id: String? = null
|
||||||
|
when (type) {
|
||||||
|
StoryViewerOptions.Type.HASHTAG -> {
|
||||||
|
builder.append("tags/")
|
||||||
|
id = options.name
|
||||||
}
|
}
|
||||||
});
|
StoryViewerOptions.Type.LOCATION -> {
|
||||||
}
|
builder.append("locations/")
|
||||||
|
id = options.id.toString()
|
||||||
private void respondToSticker(final String storyId,
|
|
||||||
final String stickerId,
|
|
||||||
final String action,
|
|
||||||
final String arg1,
|
|
||||||
final String arg2,
|
|
||||||
final ServiceCallback<StoryStickerResponse> callback) {
|
|
||||||
final Map<String, Object> form = new HashMap<>();
|
|
||||||
form.put("_csrftoken", csrfToken);
|
|
||||||
form.put("_uid", userId);
|
|
||||||
form.put("_uuid", deviceUuid);
|
|
||||||
form.put("mutation_token", UUID.randomUUID().toString());
|
|
||||||
form.put("client_context", UUID.randomUUID().toString());
|
|
||||||
form.put("radio_type", "wifi-none");
|
|
||||||
form.put(arg1, arg2);
|
|
||||||
final Map<String, String> signedForm = Utils.sign(form);
|
|
||||||
final Call<StoryStickerResponse> request =
|
|
||||||
repository.respondToSticker(storyId, stickerId, action, signedForm);
|
|
||||||
request.enqueue(new Callback<StoryStickerResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull final Call<StoryStickerResponse> call,
|
|
||||||
@NonNull final Response<StoryStickerResponse> response) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onSuccess(response.body());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
StoryViewerOptions.Type.USER -> {
|
||||||
@Override
|
builder.append("feed/user/")
|
||||||
public void onFailure(@NonNull final Call<StoryStickerResponse> call,
|
id = options.id.toString()
|
||||||
@NonNull final Throwable t) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFailure(t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
StoryViewerOptions.Type.HIGHLIGHT, StoryViewerOptions.Type.STORY_ARCHIVE -> {
|
||||||
}
|
builder.append("feed/reels_media/?user_ids=")
|
||||||
|
id = options.name
|
||||||
// RespondAction.java
|
|
||||||
public void respondToQuestion(final String storyId,
|
|
||||||
final String stickerId,
|
|
||||||
final String answer,
|
|
||||||
final ServiceCallback<StoryStickerResponse> callback) {
|
|
||||||
respondToSticker(storyId, stickerId, "story_question_response", "response", answer, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// QuizAction.java
|
|
||||||
public void respondToQuiz(final String storyId,
|
|
||||||
final String stickerId,
|
|
||||||
final int answer,
|
|
||||||
final ServiceCallback<StoryStickerResponse> callback) {
|
|
||||||
respondToSticker(storyId, stickerId, "story_quiz_answer", "answer", String.valueOf(answer), callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// VoteAction.java
|
|
||||||
public void respondToPoll(final String storyId,
|
|
||||||
final String stickerId,
|
|
||||||
final int answer,
|
|
||||||
final ServiceCallback<StoryStickerResponse> callback) {
|
|
||||||
respondToSticker(storyId, stickerId, "story_poll_vote", "vote", String.valueOf(answer), callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void respondToSlider(final String storyId,
|
|
||||||
final String stickerId,
|
|
||||||
final double answer,
|
|
||||||
final ServiceCallback<StoryStickerResponse> callback) {
|
|
||||||
respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void seen(final String storyMediaId,
|
|
||||||
final long takenAt,
|
|
||||||
final long seenAt,
|
|
||||||
final ServiceCallback<String> callback) {
|
|
||||||
final Map<String, Object> form = new HashMap<>();
|
|
||||||
form.put("_csrftoken", csrfToken);
|
|
||||||
form.put("_uid", userId);
|
|
||||||
form.put("_uuid", deviceUuid);
|
|
||||||
form.put("container_module", "feed_timeline");
|
|
||||||
final Map<String, Object> reelsForm = new HashMap<>();
|
|
||||||
reelsForm.put(storyMediaId, Collections.singletonList(takenAt + "_" + seenAt));
|
|
||||||
form.put("reels", reelsForm);
|
|
||||||
final Map<String, String> signedForm = Utils.sign(form);
|
|
||||||
final Map<String, String> queryMap = new HashMap<>();
|
|
||||||
queryMap.put("reel", "1");
|
|
||||||
queryMap.put("live_vod", "0");
|
|
||||||
final Call<String> request = repository.seen(queryMap, signedForm);
|
|
||||||
request.enqueue(new Callback<String>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull final Call<String> call,
|
|
||||||
@NonNull final Response<String> response) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onSuccess(response.body());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
StoryViewerOptions.Type.STORY -> {
|
||||||
@Override
|
}
|
||||||
public void onFailure(@NonNull final Call<String> call,
|
else -> {
|
||||||
@NonNull final Throwable t) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFailure(t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String buildUrl(@NonNull final StoryViewerOptions options) {
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append("https://i.instagram.com/api/v1/");
|
|
||||||
final StoryViewerOptions.Type type = options.getType();
|
|
||||||
String id = null;
|
|
||||||
switch (type) {
|
|
||||||
case HASHTAG:
|
|
||||||
builder.append("tags/");
|
|
||||||
id = options.getName();
|
|
||||||
break;
|
|
||||||
case LOCATION:
|
|
||||||
builder.append("locations/");
|
|
||||||
id = String.valueOf(options.getId());
|
|
||||||
break;
|
|
||||||
case USER:
|
|
||||||
builder.append("feed/user/");
|
|
||||||
id = String.valueOf(options.getId());
|
|
||||||
break;
|
|
||||||
case HIGHLIGHT:
|
|
||||||
case STORY_ARCHIVE:
|
|
||||||
builder.append("feed/reels_media/?user_ids=");
|
|
||||||
id = options.getName();
|
|
||||||
break;
|
|
||||||
case STORY:
|
|
||||||
break;
|
|
||||||
// case FEED_STORY_POSITION:
|
|
||||||
// break;
|
|
||||||
}
|
}
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
builder.append(id);
|
builder.append(id)
|
||||||
if (type != StoryViewerOptions.Type.HIGHLIGHT && type != StoryViewerOptions.Type.STORY_ARCHIVE) {
|
if (type != StoryViewerOptions.Type.HIGHLIGHT && type != StoryViewerOptions.Type.STORY_ARCHIVE) {
|
||||||
builder.append("/story/");
|
builder.append("/story/")
|
||||||
}
|
}
|
||||||
return builder.toString();
|
return builder.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<FeedStoryModel> sort(final List<FeedStoryModel> list) {
|
private fun sort(list: List<FeedStoryModel>): List<FeedStoryModel> {
|
||||||
final List<FeedStoryModel> listCopy = new ArrayList<>(list);
|
val listCopy = ArrayList(list)
|
||||||
Collections.sort(listCopy, (o1, o2) -> {
|
listCopy.sortWith { o1, o2 ->
|
||||||
int result;
|
when (Utils.settingsHelper.getString(PreferenceKeys.STORY_SORT)) {
|
||||||
switch (Utils.settingsHelper.getString(PreferenceKeys.STORY_SORT)) {
|
"1" -> return@sortWith o2.timestamp.compareTo(o1.timestamp)
|
||||||
case "1":
|
"2" -> return@sortWith o1.timestamp.compareTo(o2.timestamp)
|
||||||
result = Long.compare(o2.getTimestamp(), o1.getTimestamp());
|
else -> return@sortWith 0
|
||||||
break;
|
|
||||||
case "2":
|
|
||||||
result = Long.compare(o1.getTimestamp(), o2.getTimestamp());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result = 0;
|
|
||||||
}
|
}
|
||||||
return result;
|
}
|
||||||
});
|
return listCopy
|
||||||
return listCopy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ArchiveFetchResponse {
|
class ArchiveFetchResponse(val result: List<HighlightModel>, val hasNextPage: Boolean, val nextCursor: String) {
|
||||||
private final List<HighlightModel> archives;
|
fun hasNextPage(): Boolean {
|
||||||
private final boolean hasNextPage;
|
return hasNextPage
|
||||||
private final String nextCursor;
|
|
||||||
|
|
||||||
public ArchiveFetchResponse(final List<HighlightModel> archives, final boolean hasNextPage, final String nextCursor) {
|
|
||||||
this.archives = archives;
|
|
||||||
this.hasNextPage = hasNextPage;
|
|
||||||
this.nextCursor = nextCursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<HighlightModel> getResult() {
|
|
||||||
return archives;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNextPage() {
|
|
||||||
return hasNextPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNextCursor() {
|
|
||||||
return nextCursor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user