1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-11-22 22:57:29 +00:00

Merge remote-tracking branch 'origin/dm-notifications-enhancements' into dm-notifications-enhancements

This commit is contained in:
Ammar Githam 2021-01-08 21:49:48 +09:00
commit 039194d046
55 changed files with 674 additions and 901 deletions

View File

@ -18,8 +18,8 @@ assignees: 'austinhuang0131'
## Answer honestly. Check accordingly to your situation. ## Answer honestly. Check accordingly to your situation.
- [ ] I had prior rule violations on Instagram, specifically: - [ ] I had prior rule violations on Instagram, specifically:
- [ ] I have admitted the use of InstaGrabber on Instagram. - [ ] I have admitted the use of Barinsta on Instagram.
- [ ] I have admitted the use of InstaGrabber to a friend who uses Instagram. - [ ] I have admitted the use of Barinsta to a friend who uses Instagram.
- [ ] I have modified the source code of the app that I use, other than what is present in this repo. Specifically: - [ ] I have modified the source code of the app that I use, other than what is present in this repo. Specifically:
## Describe your case, including your usage pattern, but without private information. ## Describe your case, including your usage pattern, but without private information.

View File

@ -6,10 +6,10 @@ labels: bug
assignees: '' assignees: ''
--- ---
<!-- FOLLOW THIS FORMAT --> <!-- If you choose not to follow this format, you should erase the entire body. -->
- [ ] My app is on the latest version. I understand that any other version is not supported. - [ ] My app is on the latest version. I understand that any other version is not supported.
- [ ] I have read [the FAQ](https://instagrabber.austinhuang.me/faq). - [ ] I have read [the FAQ](https://barinsta.austinhuang.me/en/latest/faq).
<!-- <!--
Describe the bug here. Don't stress too much, but do include the key points. Describe the bug here. Don't stress too much, but do include the key points.
@ -18,11 +18,9 @@ Describe the bug here. Don't stress too much, but do include the key points.
## Steps ## Steps
<!-- <!--
DETAILED Steps to reproduce the behaviour. 1. ...
1. Go to '...' 2. ...
2. Click on '....' 3. See error...
3. Scroll down to '....'
4. See error
--> -->
## Environment ## Environment

View File

@ -7,7 +7,13 @@ assignees: ''
--- ---
<!-- <!--
STOP!!!
General questions & feedback should be submitted to General questions & feedback should be submitted to
* one of our chatrooms (see README.md), or * one of our chatrooms (see README.md), or
* r/barinsta on reddit. * r/barinsta on reddit.
STOP!!!
--> -->

View File

@ -10,8 +10,8 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 56 versionCode 57
versionName '19.0.4' versionName '19.0.5'
multiDexEnabled true multiDexEnabled true
@ -60,11 +60,13 @@ dependencies {
def appcompat_version = "1.2.0" def appcompat_version = "1.2.0"
def nav_version = '2.3.2' def nav_version = '2.3.2'
def exoplayer_version = '2.12.0'
implementation 'com.google.android.material:material:1.3.0-beta01' implementation 'com.google.android.material:material:1.3.0-beta01'
implementation 'com.google.android.exoplayer:exoplayer-core:2.12.0' implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.0' implementation "com.google.android.exoplayer:exoplayer-dash:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"
implementation "androidx.appcompat:appcompat:$appcompat_version" implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation "androidx.appcompat:appcompat-resources:$appcompat_version" implementation "androidx.appcompat:appcompat-resources:$appcompat_version"

View File

@ -10,7 +10,7 @@ import androidx.recyclerview.widget.ListAdapter;
import awais.instagrabber.adapters.viewholder.TopicClusterViewHolder; import awais.instagrabber.adapters.viewholder.TopicClusterViewHolder;
import awais.instagrabber.databinding.ItemDiscoverTopicBinding; import awais.instagrabber.databinding.ItemDiscoverTopicBinding;
import awais.instagrabber.models.TopicCluster; import awais.instagrabber.repositories.responses.discover.TopicCluster;
import awais.instagrabber.utils.ResponseBodyUtils; import awais.instagrabber.utils.ResponseBodyUtils;
public class DiscoverTopicsAdapter extends ListAdapter<TopicCluster, TopicClusterViewHolder> { public class DiscoverTopicsAdapter extends ListAdapter<TopicCluster, TopicClusterViewHolder> {

View File

@ -83,7 +83,7 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
else if (o1.getType() == NotificationType.REQUEST) return -1; else if (o1.getType() == NotificationType.REQUEST) return -1;
else if (o2.getType() == NotificationType.REQUEST) return 1; else if (o2.getType() == NotificationType.REQUEST) return 1;
// timestamp // timestamp
return o1.getTimestamp() > o2.getTimestamp() ? -1 : (o1.getTimestamp() == o2.getTimestamp() ? 0 : 1); return Long.compare(o2.getTimestamp(), o1.getTimestamp());
}); });
return listCopy; return listCopy;
} }

View File

@ -1,57 +0,0 @@
// package awais.instagrabber.adapters;
//
// import android.view.LayoutInflater;
// import android.view.View;
// import android.view.ViewGroup;
//
// import androidx.annotation.NonNull;
// import androidx.recyclerview.widget.RecyclerView;
//
// import awais.instagrabber.R;
// import awais.instagrabber.adapters.viewholder.PostMediaViewHolder;
// import awais.instagrabber.databinding.ItemChildPostBinding;
// import awais.instagrabber.models.BasePostModel;
// import awais.instagrabber.models.ViewerPostModel;
//
// public final class PostsMediaAdapter extends RecyclerView.Adapter<PostMediaViewHolder> {
// private final View.OnClickListener clickListener;
// private ViewerPostModel[] postModels;
//
// public PostsMediaAdapter(final ViewerPostModel[] postModels, final View.OnClickListener clickListener) {
// this.postModels = postModels;
// this.clickListener = clickListener;
// }
//
// @NonNull
// @Override
// public PostMediaViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
// final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
// layoutInflater.inflate(R.layout.item_child_post, parent, false);
// final ItemChildPostBinding binding = ItemChildPostBinding.inflate(layoutInflater, parent, false);
// return new PostMediaViewHolder(binding);
// }
//
// @Override
// public void onBindViewHolder(@NonNull final PostMediaViewHolder holder, final int position) {
// final ViewerPostModel postModel = postModels[position];
// holder.bind(postModel, position, clickListener);
// }
//
// public void setData(final ViewerPostModel[] postModels) {
// this.postModels = postModels;
// notifyDataSetChanged();
// }
//
// public ViewerPostModel getItemAt(final int position) {
// return postModels == null ? null : postModels[position];
// }
//
// @Override
// public int getItemCount() {
// return postModels == null ? 0 : postModels.length;
// }
//
// public BasePostModel[] getPostModels() {
// return postModels;
// }
// }

View File

@ -33,5 +33,9 @@ public final class FeedStoryViewHolder extends RecyclerView.ViewHolder {
binding.title.setAlpha(model.isFullyRead() ? 0.5F : 1.0F); binding.title.setAlpha(model.isFullyRead() ? 0.5F : 1.0F);
binding.icon.setImageURI(profileModel.getProfilePicUrl()); binding.icon.setImageURI(profileModel.getProfilePicUrl());
binding.icon.setAlpha(model.isFullyRead() ? 0.5F : 1.0F); binding.icon.setAlpha(model.isFullyRead() ? 0.5F : 1.0F);
if (model.isLive()) binding.icon.setStoriesBorder(2);
else if (model.isBestie()) binding.icon.setStoriesBorder(1);
else binding.icon.setStoriesBorder(0);
} }
} }

View File

@ -1,9 +1,7 @@
package awais.instagrabber.adapters.viewholder; package awais.instagrabber.adapters.viewholder;
import android.text.Spannable;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -54,7 +52,7 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
subtext = model.getText(); subtext = model.getText();
break; break;
case AYML: case AYML:
subtext = model.getPostId(); subtext = model.getPreviewPic();
break; break;
} }
binding.tvSubComment.setText(model.getType() == NotificationType.AYML ? model.getText() : subtext); binding.tvSubComment.setText(model.getType() == NotificationType.AYML ? model.getText() : subtext);
@ -62,8 +60,7 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
binding.tvComment.setText(subtext); binding.tvComment.setText(subtext);
binding.tvComment.setVisibility(TextUtils.isEmpty(subtext) ? View.GONE : View.VISIBLE); binding.tvComment.setVisibility(TextUtils.isEmpty(subtext) ? View.GONE : View.VISIBLE);
binding.tvSubComment.setVisibility(model.getType() == NotificationType.AYML ? View.VISIBLE : View.GONE); binding.tvSubComment.setVisibility(model.getType() == NotificationType.AYML ? View.VISIBLE : View.GONE);
} } else if (text != -1) {
else if (text != -1) {
binding.tvComment.setText(text); binding.tvComment.setText(text);
binding.tvSubComment.setVisibility(subtext == null ? View.GONE : View.VISIBLE); binding.tvSubComment.setVisibility(subtext == null ? View.GONE : View.VISIBLE);
} }
@ -81,8 +78,7 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
if (model.getType() == NotificationType.AYML) { if (model.getType() == NotificationType.AYML) {
binding.ivPreviewPic.setVisibility(View.GONE); binding.ivPreviewPic.setVisibility(View.GONE);
} } else if (TextUtils.isEmpty(model.getPreviewPic())) {
else if (TextUtils.isEmpty(model.getPreviewPic())) {
binding.ivPreviewPic.setVisibility(View.INVISIBLE); binding.ivPreviewPic.setVisibility(View.INVISIBLE);
} else { } else {
binding.ivPreviewPic.setVisibility(View.VISIBLE); binding.ivPreviewPic.setVisibility(View.VISIBLE);

View File

@ -1,29 +0,0 @@
// package awais.instagrabber.adapters.viewholder;
//
// import android.view.View;
//
// import androidx.annotation.NonNull;
// import androidx.recyclerview.widget.RecyclerView;
//
// import awais.instagrabber.databinding.ItemChildPostBinding;
// import awais.instagrabber.models.ViewerPostModel;
//
// public final class PostMediaViewHolder extends RecyclerView.ViewHolder {
//
// private final ItemChildPostBinding binding;
//
// public PostMediaViewHolder(@NonNull final ItemChildPostBinding binding) {
// super(binding.getRoot());
// this.binding = binding;
// }
//
// public void bind(final ViewerPostModel model, final int position, final View.OnClickListener clickListener) {
// if (model == null) return;
// // model.setPosition(position);
// itemView.setTag(model);
// itemView.setOnClickListener(clickListener);
// binding.selectedView.setVisibility(model.isCurrentSlide() ? View.VISIBLE : View.GONE);
// binding.isDownloaded.setVisibility(model.isDownloaded() ? View.VISIBLE : View.GONE);
// binding.icon.setImageURI(model.getDisplayUrl());
// }
// }

View File

@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import awais.instagrabber.R; import awais.instagrabber.R;
import awais.instagrabber.adapters.DiscoverTopicsAdapter; import awais.instagrabber.adapters.DiscoverTopicsAdapter;
import awais.instagrabber.databinding.ItemDiscoverTopicBinding; import awais.instagrabber.databinding.ItemDiscoverTopicBinding;
import awais.instagrabber.models.TopicCluster; import awais.instagrabber.repositories.responses.discover.TopicCluster;
import awais.instagrabber.utils.ResponseBodyUtils; import awais.instagrabber.utils.ResponseBodyUtils;
public class TopicClusterViewHolder extends RecyclerView.ViewHolder { public class TopicClusterViewHolder extends RecyclerView.ViewHolder {

View File

@ -1,4 +1,4 @@
package awais.instagrabber.asyncs.direct_messages; package awais.instagrabber.asyncs;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;

View File

@ -52,8 +52,7 @@ public final class LocationFetcher extends AsyncTask<Void, Void, LocationModel>
// final JSONArray edges = timelineMedia.getJSONArray("edges"); // final JSONArray edges = timelineMedia.getJSONArray("edges");
// } // }
result = new LocationModel( result = new LocationModel(
location.getString(Constants.EXTRAS_ID), location.getLong(Constants.EXTRAS_ID),
location.getString("slug"),
location.getString("name"), location.getString("name"),
location.getString("blurb"), location.getString("blurb"),
location.getString("website"), location.getString("website"),

View File

@ -1,252 +0,0 @@
// package awais.instagrabber.asyncs.direct_messages;
//
// import android.os.AsyncTask;
// import android.util.Log;
//
// import org.json.JSONObject;
//
// import java.io.BufferedReader;
// import java.io.DataOutputStream;
// import java.io.IOException;
// import java.io.InputStreamReader;
// import java.net.HttpURLConnection;
// import java.net.URL;
// import java.util.HashMap;
// import java.util.Map;
// import java.util.UUID;
//
// import awais.instagrabber.repositories.requests.directmessages.BroadcastOptions;
// import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse;
// import awais.instagrabber.utils.Constants;
// import awais.instagrabber.utils.CookieUtils;
// import awais.instagrabber.utils.Utils;
//
// import static awais.instagrabber.utils.Utils.settingsHelper;
//
// public class DirectThreadBroadcaster extends AsyncTask<BroadcastOptions, Void, DirectThreadBroadcastResponse> {
// private static final String TAG = "DirectThreadBroadcaster";
//
// private final String threadId;
//
// private OnBroadcastCompleteListener listener;
//
// public DirectThreadBroadcaster(String threadId) {
// this.threadId = threadId;
// }
//
// @Override
// protected DirectThreadBroadcastResponse doInBackground(final BroadcastOptions... broadcastOptionsArray) {
// if (broadcastOptionsArray == null || broadcastOptionsArray.length == 0 || broadcastOptionsArray[0] == null) {
// return null;
// }
// final BroadcastOptions broadcastOptions = broadcastOptionsArray[0];
// final String cookie = settingsHelper.getString(Constants.COOKIE);
// final String cc = UUID.randomUUID().toString();
// final Map<String, String> form = new HashMap<>();
// form.put("_csrftoken", CookieUtils.getCsrfTokenFromCookie(cookie));
// form.put("_uid", CookieUtils.getUserIdFromCookie(cookie));
// form.put("__uuid", settingsHelper.getString(Constants.DEVICE_UUID));
// form.put("client_context", cc);
// form.put("mutation_token", cc);
// form.putAll(broadcastOptions.getFormMap());
// form.put("thread_id", threadId);
// form.put("action", "send_item");
// final String message = new JSONObject(form).toString();
// final String content = Utils.sign(message);
// final String url = "https://i.instagram.com/api/v1/direct_v2/threads/broadcast/" + broadcastOptions.getItemType().getValue() + "/";
// HttpURLConnection connection = null;
// DataOutputStream outputStream = null;
// BufferedReader r = null;
// try {
// connection = (HttpURLConnection) new URL(url).openConnection();
// connection.setRequestMethod("POST");
// connection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
// connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// if (content != null) {
// connection.setRequestProperty("Content-Length", "" + content.getBytes().length);
// }
// connection.setUseCaches(false);
// connection.setDoOutput(true);
// outputStream = new DataOutputStream(connection.getOutputStream());
// outputStream.writeBytes(content);
// outputStream.flush();
// final int responseCode = connection.getResponseCode();
// if (responseCode != HttpURLConnection.HTTP_OK) {
// Log.d(TAG, responseCode + ": " + content + ": " + cookie);
// return new DirectThreadBroadcastResponse(responseCode, null);
// }
// r = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// final StringBuilder builder = new StringBuilder();
// for (String line = r.readLine(); line != null; line = r.readLine()) {
// if (builder.length() != 0) {
// builder.append("\n");
// }
// builder.append(line);
// }
// return new DirectThreadBroadcastResponse(responseCode, new JSONObject(builder.toString()));
// } catch (Exception e) {
// Log.e(TAG, "Error", e);
// } finally {
// if (r != null) {
// try {
// r.close();
// } catch (IOException ignored) {
// }
// }
// if (outputStream != null) {
// try {
// outputStream.close();
// } catch (IOException ignored) {
// }
// }
// if (connection != null) {
// connection.disconnect();
// }
// }
// return null;
// }
//
// @Override
// protected void onPostExecute(final DirectThreadBroadcastResponse result) {
// if (listener != null) {
// listener.onTaskComplete(result);
// }
// }
//
// public void setOnTaskCompleteListener(final OnBroadcastCompleteListener listener) {
// if (listener != null) {
// this.listener = listener;
// }
// }
//
// public interface OnBroadcastCompleteListener {
// void onTaskComplete(DirectThreadBroadcastResponse response);
// }
//
// public enum ItemType {
// TEXT("text"),
// REACTION("reaction"),
// REELSHARE("reel_share"),
// IMAGE("configure_photo");
//
// private final String value;
//
// ItemType(final String value) {
// this.value = value;
// }
//
// public String getValue() {
// return value;
// }
// }
//
// public static abstract class BroadcastOptions {
// private final ItemType itemType;
//
// public BroadcastOptions(final ItemType itemType) {
// this.itemType = itemType;
// }
//
// public ItemType getItemType() {
// return itemType;
// }
//
// abstract Map<String, String> getFormMap();
// }
//
// public static class TextBroadcastOptions extends BroadcastOptions {
// private final String text;
//
// public TextBroadcastOptions(String text) throws UnsupportedEncodingException {
// super(ItemType.TEXT);
// this.text = URLEncoder.encode(text, "UTF-8")
// .replaceAll("\\+", "%20").replaceAll("%21", "!").replaceAll("%27", "'").replaceAll("%22", "\\\"")
// .replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("%7E", "~").replaceAll("%0A", "\n");
// }
//
// @Override
// Map<String, String> getFormMap() {
// return Collections.singletonMap("text", text);
// }
// }
//
// public static class ReactionBroadcastOptions extends BroadcastOptions {
// private final String itemId;
// private final boolean delete;
//
// public ReactionBroadcastOptions(String itemId, boolean delete) {
// super(ItemType.REACTION);
// this.itemId = itemId;
// this.delete = delete;
// }
//
// @Override
// Map<String, String> getFormMap() {
// final Map<String, String> form = new HashMap<>();
// form.put("item_id", itemId);
// form.put("reaction_status", delete ? "deleted" : "created");
// form.put("reaction_type", "like");
// return form;
// }
// }
//
// public static class StoryReplyBroadcastOptions extends BroadcastOptions {
// private final String text, mediaId, reelId;
//
// public StoryReplyBroadcastOptions(String text, String mediaId, String reelId) throws UnsupportedEncodingException {
// super(ItemType.REELSHARE);
// this.text = URLEncoder.encode(text, "UTF-8")
// .replaceAll("\\+", "%20").replaceAll("%21", "!").replaceAll("%27", "'")
// .replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("%7E", "~").replaceAll("%0A", "\n");
// this.mediaId = mediaId;
// this.reelId = reelId; // or user id, usually same
// }
//
// @Override
// Map<String, String> getFormMap() {
// final Map<String, String> form = new HashMap<>();
// form.put("text", text);
// form.put("media_id", mediaId);
// form.put("reel_id", reelId);
// form.put("entry", "reel");
// return form;
// }
// }
//
// public static class ImageBroadcastOptions extends BroadcastOptions {
// final boolean allowFullAspectRatio;
// final String uploadId;
//
// public ImageBroadcastOptions(final boolean allowFullAspectRatio, final String uploadId) {
// super(ItemType.IMAGE);
// this.allowFullAspectRatio = allowFullAspectRatio;
// this.uploadId = uploadId;
// }
//
// @Override
// Map<String, String> getFormMap() {
// final Map<String, String> form = new HashMap<>();
// form.put("allow_full_aspect_ratio", String.valueOf(allowFullAspectRatio));
// form.put("upload_id", uploadId);
// return form;
// }
// }
//
// public static class DirectThreadBroadcastResponse {
// private final int responseCode;
// private final JSONObject response;
//
// public DirectThreadBroadcastResponse(int responseCode, JSONObject response) {
// this.responseCode = responseCode;
// this.response = response;
// }
//
// public int getResponseCode() {
// return responseCode;
// }
//
// public JSONObject getResponse() {
// return response;
// }
// }
// }

View File

@ -49,14 +49,15 @@ public class CircularImageView extends SimpleDraweeView {
setBackgroundResource(R.drawable.shape_oval_light); setBackgroundResource(R.drawable.shape_oval_light);
} }
public void setStoriesBorder() { /* types: 0 clear, 1 green (feed bestie / has story), 2 red (live) */
public void setStoriesBorder(final int type) {
// private final int borderSize = 8; // private final int borderSize = 8;
final int color = Color.GREEN; final int color = type == 2 ? Color.RED : Color.GREEN;
RoundingParams roundingParams = getHierarchy().getRoundingParams(); RoundingParams roundingParams = getHierarchy().getRoundingParams();
if (roundingParams == null) { if (roundingParams == null) {
roundingParams = RoundingParams.asCircle().setRoundingMethod(RoundingParams.RoundingMethod.BITMAP_ONLY); roundingParams = RoundingParams.asCircle().setRoundingMethod(RoundingParams.RoundingMethod.BITMAP_ONLY);
} }
roundingParams.setBorder(color, 5.0f); roundingParams.setBorder(color, type == 0 ? 0f : 5.0f);
getHierarchy().setRoundingParams(roundingParams); getHierarchy().setRoundingParams(roundingParams);
} }
} }

View File

@ -59,6 +59,7 @@ import awais.instagrabber.models.HashtagModel;
import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.PostsLayoutPreferences;
import awais.instagrabber.models.StoryModel; 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.responses.Location; import awais.instagrabber.repositories.responses.Location;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
@ -559,7 +560,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
if (!hasStories) return; if (!hasStories) return;
// show stories // show stories
final NavDirections action = HashTagFragmentDirections final NavDirections action = HashTagFragmentDirections
.actionHashtagFragmentToStoryViewerFragment(-1, null, true, false, hashtagModel.getName(), hashtagModel.getName(), false, false); .actionHashtagFragmentToStoryViewerFragment(StoryViewerOptions.forHashtag(hashtagModel.getName()));
NavHostFragment.findNavController(this).navigate(action); NavHostFragment.findNavController(this).navigate(action);
}); });
} }
@ -576,16 +577,12 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
if (!isLoggedIn) return; if (!isLoggedIn) return;
storiesFetching = true; storiesFetching = true;
storiesService.getUserStory( storiesService.getUserStory(
hashtagModel.getName(), StoryViewerOptions.forHashtag(hashtagModel.getName()),
null,
false,
true,
false,
new ServiceCallback<List<StoryModel>>() { new ServiceCallback<List<StoryModel>>() {
@Override @Override
public void onSuccess(final List<StoryModel> storyModels) { public void onSuccess(final List<StoryModel> storyModels) {
if (storyModels != null && !storyModels.isEmpty()) { if (storyModels != null && !storyModels.isEmpty()) {
hashtagDetailsBinding.mainHashtagImage.setStoriesBorder(); hashtagDetailsBinding.mainHashtagImage.setStoriesBorder(1);
hasStories = true; hasStories = true;
} else { } else {
hasStories = false; hasStories = false;

View File

@ -19,7 +19,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedCallback;
@ -61,6 +60,7 @@ import awais.instagrabber.models.LocationModel;
import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.PostsLayoutPreferences;
import awais.instagrabber.models.StoryModel; 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.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.CookieUtils;
@ -72,6 +72,7 @@ import awais.instagrabber.webservices.StoriesService;
import awaisomereport.LogCollector; import awaisomereport.LogCollector;
import static androidx.core.content.PermissionChecker.checkSelfPermission; import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG;
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
import static awais.instagrabber.utils.Utils.logCollector; import static awais.instagrabber.utils.Utils.logCollector;
import static awais.instagrabber.utils.Utils.settingsHelper; import static awais.instagrabber.utils.Utils.settingsHelper;
@ -396,7 +397,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
} }
private void setupLocationDetails() { private void setupLocationDetails() {
final String locationId = locationModel.getId(); final long locationId = locationModel.getId();
// binding.swipeRefreshLayout.setRefreshing(true); // binding.swipeRefreshLayout.setRefreshing(true);
locationDetailsBinding.mainLocationImage.setImageURI(locationModel.getSdProfilePic()); locationDetailsBinding.mainLocationImage.setImageURI(locationModel.getSdProfilePic());
final String postCount = String.valueOf(locationModel.getPostCount()); final String postCount = String.valueOf(locationModel.getPostCount());
@ -416,15 +417,29 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
if (TextUtils.isEmpty(biography)) { if (TextUtils.isEmpty(biography)) {
locationDetailsBinding.locationBiography.setVisibility(View.GONE); locationDetailsBinding.locationBiography.setVisibility(View.GONE);
} else if (TextUtils.hasMentions(biography)) {
locationDetailsBinding.locationBiography.setVisibility(View.VISIBLE);
biography = TextUtils.getMentionText(biography);
locationDetailsBinding.locationBiography.setText(biography, TextView.BufferType.SPANNABLE);
// binding.locationBiography.setMentionClickListener(mentionClickListener);
} else { } else {
locationDetailsBinding.locationBiography.setVisibility(View.VISIBLE); locationDetailsBinding.locationBiography.setVisibility(View.VISIBLE);
locationDetailsBinding.locationBiography.setText(biography); locationDetailsBinding.locationBiography.setText(biography);
locationDetailsBinding.locationBiography.setMentionClickListener(null); locationDetailsBinding.locationBiography.addOnHashtagListener(autoLinkItem -> {
final NavController navController = NavHostFragment.findNavController(this);
final Bundle bundle = new Bundle();
final String originalText = autoLinkItem.getOriginalText().trim();
bundle.putString(ARG_HASHTAG, originalText);
navController.navigate(R.id.action_global_hashTagFragment, bundle);
});
locationDetailsBinding.locationBiography.addOnMentionClickListener(autoLinkItem -> {
final String originalText = autoLinkItem.getOriginalText().trim();
navigateToProfile(originalText);
});
locationDetailsBinding.locationBiography.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(getContext(),
autoLinkItem.getOriginalText()
.trim()));
locationDetailsBinding.locationBiography
.addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim()));
locationDetailsBinding.locationBiography.setOnLongClickListener(v -> {
Utils.copyText(getContext(), biography);
return true;
});
} }
if (!locationModel.getGeo().startsWith("geo:0.0,0.0?z=17")) { if (!locationModel.getGeo().startsWith("geo:0.0,0.0?z=17")) {
@ -452,7 +467,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
final FavoriteDataSource dataSource = FavoriteDataSource.getInstance(getContext()); final FavoriteDataSource dataSource = FavoriteDataSource.getInstance(getContext());
final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(dataSource); final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(dataSource);
locationDetailsBinding.favChip.setVisibility(View.VISIBLE); locationDetailsBinding.favChip.setVisibility(View.VISIBLE);
favoriteRepository.getFavorite(locationId, FavoriteType.LOCATION, new RepositoryCallback<Favorite>() { favoriteRepository.getFavorite(String.valueOf(locationId), FavoriteType.LOCATION, new RepositoryCallback<Favorite>() {
@Override @Override
public void onSuccess(final Favorite result) { public void onSuccess(final Favorite result) {
locationDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); locationDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24);
@ -460,7 +475,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
locationDetailsBinding.favChip.setText(R.string.favorite_short); locationDetailsBinding.favChip.setText(R.string.favorite_short);
favoriteRepository.insertOrUpdateFavorite(new Favorite( favoriteRepository.insertOrUpdateFavorite(new Favorite(
result.getId(), result.getId(),
locationId, String.valueOf(locationId),
FavoriteType.LOCATION, FavoriteType.LOCATION,
locationModel.getName(), locationModel.getName(),
locationModel.getSdProfilePic(), locationModel.getSdProfilePic(),
@ -482,10 +497,10 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
} }
}); });
locationDetailsBinding.favChip.setOnClickListener(v -> { locationDetailsBinding.favChip.setOnClickListener(v -> {
favoriteRepository.getFavorite(locationId, FavoriteType.LOCATION, new RepositoryCallback<Favorite>() { favoriteRepository.getFavorite(String.valueOf(locationId), FavoriteType.LOCATION, new RepositoryCallback<Favorite>() {
@Override @Override
public void onSuccess(final Favorite result) { public void onSuccess(final Favorite result) {
favoriteRepository.deleteFavorite(locationId, FavoriteType.LOCATION, new RepositoryCallback<Void>() { favoriteRepository.deleteFavorite(String.valueOf(locationId), FavoriteType.LOCATION, new RepositoryCallback<Void>() {
@Override @Override
public void onSuccess(final Void result) { public void onSuccess(final Void result) {
locationDetailsBinding.favChip.setText(R.string.add_to_favorites); locationDetailsBinding.favChip.setText(R.string.add_to_favorites);
@ -502,7 +517,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
public void onDataNotAvailable() { public void onDataNotAvailable() {
favoriteRepository.insertOrUpdateFavorite(new Favorite( favoriteRepository.insertOrUpdateFavorite(new Favorite(
0, 0,
locationId, String.valueOf(locationId),
FavoriteType.LOCATION, FavoriteType.LOCATION,
locationModel.getName(), locationModel.getName(),
locationModel.getSdProfilePic(), locationModel.getSdProfilePic(),
@ -525,7 +540,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
if (hasStories) { if (hasStories) {
// show stories // show stories
final NavDirections action = LocationFragmentDirections final NavDirections action = LocationFragmentDirections
.actionLocationFragmentToStoryViewerFragment(-1, null, false, true, locationId, locationModel.getName(), false, false); .actionLocationFragmentToStoryViewerFragment(StoryViewerOptions.forLocation(locationId, locationModel.getName()));
NavHostFragment.findNavController(this).navigate(action); NavHostFragment.findNavController(this).navigate(action);
} }
}); });
@ -542,27 +557,24 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
private void fetchStories() { private void fetchStories() {
if (isLoggedIn) { if (isLoggedIn) {
storiesFetching = true; storiesFetching = true;
storiesService.getUserStory(String.valueOf(locationId), storiesService.getUserStory(
null, StoryViewerOptions.forLocation(locationId, locationModel.getName()),
true, new ServiceCallback<List<StoryModel>>() {
false, @Override
false, public void onSuccess(final List<StoryModel> storyModels) {
new ServiceCallback<List<StoryModel>>() { if (storyModels != null && !storyModels.isEmpty()) {
@Override locationDetailsBinding.mainLocationImage.setStoriesBorder(1);
public void onSuccess(final List<StoryModel> storyModels) { hasStories = true;
if (storyModels != null && !storyModels.isEmpty()) { }
locationDetailsBinding.mainLocationImage.setStoriesBorder(); storiesFetching = false;
hasStories = true; }
}
storiesFetching = false;
}
@Override @Override
public void onFailure(final Throwable t) { public void onFailure(final Throwable t) {
Log.e(TAG, "Error", t); Log.e(TAG, "Error", t);
storiesFetching = false; storiesFetching = false;
} }
}); });
} }
} }

View File

@ -36,6 +36,7 @@ import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.interfaces.MentionClickListener; import awais.instagrabber.interfaces.MentionClickListener;
import awais.instagrabber.models.NotificationModel; import awais.instagrabber.models.NotificationModel;
import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.models.enums.NotificationType;
import awais.instagrabber.repositories.requests.StoryViewerOptions;
import awais.instagrabber.repositories.responses.FriendshipChangeResponse; import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
@ -73,8 +74,9 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
@Override @Override
public void onPreviewClick(final NotificationModel model) { public void onPreviewClick(final NotificationModel model) {
if (model.getType() == NotificationType.RESPONDED_STORY) { if (model.getType() == NotificationType.RESPONDED_STORY) {
final NavDirections action = NotificationsViewerFragmentDirections.actionNotificationsViewerFragmentToStoryViewerFragment( final NavDirections action = NotificationsViewerFragmentDirections
-1, null, false, false, model.getPostId(), model.getUsername(), false, true); .actionNotificationsViewerFragmentToStoryViewerFragment(StoryViewerOptions.forStory(model.getPostId(),
model.getUsername()));
NavHostFragment.findNavController(NotificationsViewerFragment.this).navigate(action); NavHostFragment.findNavController(NotificationsViewerFragment.this).navigate(action);
} else { } else {
mediaService.fetch(model.getPostId(), new ServiceCallback<Media>() { mediaService.fetch(model.getPostId(), new ServiceCallback<Media>() {
@ -110,7 +112,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
getString(R.string.open_profile), getString(R.string.open_profile),
getString(R.string.view_story) getString(R.string.view_story)
}; };
} else if (model.getPostId() != null) { } else if (model.getPostId() > 0) {
commentDialogList = new String[]{ commentDialogList = new String[]{
getString(R.string.open_profile), getString(R.string.open_profile),
getString(R.string.view_post) getString(R.string.view_post)
@ -146,8 +148,8 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
return; return;
} else if (model.getType() == NotificationType.RESPONDED_STORY) { } else if (model.getType() == NotificationType.RESPONDED_STORY) {
final NavDirections action = NotificationsViewerFragmentDirections final NavDirections action = NotificationsViewerFragmentDirections
.actionNotificationsViewerFragmentToStoryViewerFragment( .actionNotificationsViewerFragmentToStoryViewerFragment(StoryViewerOptions.forStory(model.getPostId(),
-1, null, false, false, model.getPostId(), model.getUsername(), false, true); model.getUsername()));
NavHostFragment.findNavController(NotificationsViewerFragment.this).navigate(action); NavHostFragment.findNavController(NotificationsViewerFragment.this).navigate(action);
return; return;
} }

View File

@ -32,6 +32,7 @@ import awais.instagrabber.databinding.FragmentStoryListViewerBinding;
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections; 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.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;
@ -58,7 +59,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
public void onFeedStoryClick(final FeedStoryModel model, final int position) { public void onFeedStoryClick(final FeedStoryModel model, final int position) {
if (model == null) return; if (model == null) return;
final NavDirections action = StoryListViewerFragmentDirections final NavDirections action = StoryListViewerFragmentDirections
.actionStoryListFragmentToStoryViewerFragment(position, null, false, false, null, null, false, false); .actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forFeedStoryPosition(position));
NavHostFragment.findNavController(StoryListViewerFragment.this).navigate(action); NavHostFragment.findNavController(StoryListViewerFragment.this).navigate(action);
} }
@ -72,8 +73,8 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
@Override @Override
public void onHighlightClick(final HighlightModel model, final int position) { public void onHighlightClick(final HighlightModel model, final int position) {
if (model == null) return; if (model == null) return;
final NavDirections action = StoryListViewerFragmentDirections.actionStoryListFragmentToStoryViewerFragment( final NavDirections action = StoryListViewerFragmentDirections
position, getString(R.string.action_archive), false, false, null, null, true, false); .actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forStoryArchive(position));
NavHostFragment.findNavController(StoryListViewerFragment.this).navigate(action); NavHostFragment.findNavController(StoryListViewerFragment.this).navigate(action);
} }
@ -188,6 +189,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
@Override @Override
public void onSuccess(final List<FeedStoryModel> result) { public void onSuccess(final List<FeedStoryModel> result) {
feedStoriesViewModel.getList().postValue(result); feedStoriesViewModel.getList().postValue(result);
adapter.submitList(result);
binding.swipeRefreshLayout.setRefreshing(false); binding.swipeRefreshLayout.setRefreshing(false);
} }

View File

@ -55,6 +55,7 @@ import com.google.android.exoplayer2.source.MediaLoadData;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceEventListener; import com.google.android.exoplayer2.source.MediaSourceEventListener;
import com.google.android.exoplayer2.source.ProgressiveMediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import java.io.IOException; import java.io.IOException;
@ -68,9 +69,9 @@ import java.util.List;
import awais.instagrabber.BuildConfig; import awais.instagrabber.BuildConfig;
import awais.instagrabber.R; import awais.instagrabber.R;
import awais.instagrabber.adapters.StoriesAdapter; import awais.instagrabber.adapters.StoriesAdapter;
import awais.instagrabber.asyncs.CreateThreadAction;
import awais.instagrabber.asyncs.PostFetcher; import awais.instagrabber.asyncs.PostFetcher;
import awais.instagrabber.asyncs.SeenAction; import awais.instagrabber.asyncs.SeenAction;
import awais.instagrabber.asyncs.direct_messages.CreateThreadAction;
import awais.instagrabber.customviews.helpers.SwipeGestureListener; import awais.instagrabber.customviews.helpers.SwipeGestureListener;
import awais.instagrabber.databinding.FragmentStoryViewerBinding; import awais.instagrabber.databinding.FragmentStoryViewerBinding;
import awais.instagrabber.fragments.main.ProfileFragmentDirections; import awais.instagrabber.fragments.main.ProfileFragmentDirections;
@ -84,6 +85,8 @@ import awais.instagrabber.models.stickers.QuestionModel;
import awais.instagrabber.models.stickers.QuizModel; import awais.instagrabber.models.stickers.QuizModel;
import awais.instagrabber.models.stickers.SliderModel; import awais.instagrabber.models.stickers.SliderModel;
import awais.instagrabber.models.stickers.SwipeUpModel; import awais.instagrabber.models.stickers.SwipeUpModel;
import awais.instagrabber.repositories.requests.StoryViewerOptions;
import awais.instagrabber.repositories.requests.StoryViewerOptions.Type;
import awais.instagrabber.repositories.requests.directmessages.BroadcastOptions; import awais.instagrabber.repositories.requests.directmessages.BroadcastOptions;
import awais.instagrabber.repositories.responses.StoryStickerResponse; import awais.instagrabber.repositories.responses.StoryStickerResponse;
import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse; import awais.instagrabber.repositories.responses.directmessages.DirectThreadBroadcastResponse;
@ -133,27 +136,32 @@ public class StoryViewerFragment extends Fragment {
private MenuItem menuDownload; private MenuItem menuDownload;
private MenuItem menuDm; private MenuItem menuDm;
private SimpleExoPlayer player; private SimpleExoPlayer player;
private boolean isHashtag, isLoc; // private boolean isHashtag;
private String highlight; // private boolean isLoc;
// private String highlight;
private String actionBarTitle;
private boolean fetching = false, sticking = false, shouldRefresh = true; private boolean fetching = false, sticking = false, shouldRefresh = true;
private int currentFeedStoryIndex; private int currentFeedStoryIndex;
private double sliderValue; private double sliderValue;
private StoriesViewModel storiesViewModel; private StoriesViewModel storiesViewModel;
private StoryViewerFragmentArgs fragmentArgs;
private ViewModel viewModel; private ViewModel viewModel;
private boolean isHighlight, isArchive, isNotification; // private boolean isHighlight;
// private boolean isArchive;
// private boolean isNotification;
private DirectMessagesService directMessagesService; private DirectMessagesService directMessagesService;
private final String cookie = settingsHelper.getString(Constants.COOKIE); private final String cookie = settingsHelper.getString(Constants.COOKIE);
private final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); private final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
private final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); private final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
private final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID); private final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
private StoryViewerOptions options;
@Override @Override
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
fragmentActivity = (AppCompatActivity) requireActivity(); fragmentActivity = (AppCompatActivity) requireActivity();
storiesService = StoriesService.getInstance(); storiesService = StoriesService.getInstance();
if (csrfToken == null) return;
directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId); directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId);
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@ -256,6 +264,15 @@ public class StoryViewerFragment extends Fragment {
releasePlayer(); releasePlayer();
} }
@Override
public void onResume() {
super.onResume();
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(actionBarTitle);
}
}
@Override @Override
public void onDestroy() { public void onDestroy() {
releasePlayer(); releasePlayer();
@ -269,21 +286,21 @@ public class StoryViewerFragment extends Fragment {
private void init() { private void init() {
if (getArguments() == null) return; if (getArguments() == null) return;
fragmentArgs = StoryViewerFragmentArgs.fromBundle(getArguments()); final StoryViewerFragmentArgs fragmentArgs = StoryViewerFragmentArgs.fromBundle(getArguments());
currentFeedStoryIndex = fragmentArgs.getFeedStoryIndex(); options = fragmentArgs.getOptions();
highlight = fragmentArgs.getHighlight(); currentFeedStoryIndex = options.getCurrentFeedStoryIndex();
isHighlight = !TextUtils.isEmpty(highlight); // highlight = fragmentArgs.getHighlight();
isArchive = fragmentArgs.getIsArchive(); // isHighlight = !TextUtils.isEmpty(highlight);
isNotification = fragmentArgs.getIsNotification(); // isArchive = fragmentArgs.getIsArchive();
// isNotification = fragmentArgs.getIsNotification();
final Type type = options.getType();
if (currentFeedStoryIndex >= 0) { if (currentFeedStoryIndex >= 0) {
viewModel = isHighlight viewModel = type == Type.HIGHLIGHT
? isArchive ? type == Type.STORY_ARCHIVE
? new ViewModelProvider(fragmentActivity).get(ArchivesViewModel.class) ? new ViewModelProvider(fragmentActivity).get(ArchivesViewModel.class)
: new ViewModelProvider(fragmentActivity).get(HighlightsViewModel.class) : new ViewModelProvider(fragmentActivity).get(HighlightsViewModel.class)
: new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class); : new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class);
} }
// feedStoryModels = feedStoriesViewModel.getList().getValue();
// feedStoryModels == null || feedStoryModels.isEmpty() ||
setupStories(); setupStories();
} }
@ -308,21 +325,20 @@ public class StoryViewerFragment extends Fragment {
final boolean hasFeedStories; final boolean hasFeedStories;
List<?> models = null; List<?> models = null;
if (currentFeedStoryIndex >= 0) { if (currentFeedStoryIndex >= 0) {
if (isArchive) { final Type type = options.getType();
final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel; switch (type) {
models = archivesViewModel.getList().getValue(); case HIGHLIGHT:
} else if (isHighlight) { final HighlightsViewModel highlightsViewModel = (HighlightsViewModel) viewModel;
final HighlightsViewModel highlightsViewModel = (HighlightsViewModel) viewModel; models = highlightsViewModel.getList().getValue();
models = highlightsViewModel.getList().getValue(); break;
// final HighlightModel model = models.get(currentFeedStoryIndex); case FEED_STORY_POSITION:
// currentStoryMediaId = model.getId(); final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel;
// currentStoryUsername = model.getTitle(); models = feedStoriesViewModel.getList().getValue();
} else { break;
final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel; case STORY_ARCHIVE:
models = feedStoriesViewModel.getList().getValue(); final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel;
// final FeedStoryModel model = models.get(currentFeedStoryIndex); models = archivesViewModel.getList().getValue();
// currentStoryMediaId = model.getStoryMediaId(); break;
// currentStoryUsername = model.getProfileModel().getUsername();
} }
} }
hasFeedStories = models != null && !models.isEmpty(); hasFeedStories = models != null && !models.isEmpty();
@ -646,6 +662,7 @@ public class StoryViewerFragment extends Fragment {
private void resetView() { private void resetView() {
final Context context = getContext(); final Context context = getContext();
StoryModel live = null;
slidePos = 0; slidePos = 0;
lastSlidePos = 0; lastSlidePos = 0;
if (menuDownload != null) menuDownload.setVisible(false); if (menuDownload != null) menuDownload.setVisible(false);
@ -653,58 +670,60 @@ public class StoryViewerFragment extends Fragment {
binding.imageViewer.setController(null); binding.imageViewer.setController(null);
releasePlayer(); releasePlayer();
String currentStoryMediaId = null; String currentStoryMediaId = null;
final Type type = options.getType();
StoryViewerOptions fetchOptions = null;
if (currentFeedStoryIndex >= 0) { if (currentFeedStoryIndex >= 0) {
if (isArchive) { switch (type) {
final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel; case HIGHLIGHT: {
final List<HighlightModel> models = archivesViewModel.getList().getValue(); final HighlightsViewModel highlightsViewModel = (HighlightsViewModel) viewModel;
if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size()) { final List<HighlightModel> models = highlightsViewModel.getList().getValue();
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size()) {
return; Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
return;
}
final HighlightModel model = models.get(currentFeedStoryIndex);
currentStoryMediaId = model.getId();
fetchOptions = StoryViewerOptions.forHighlight(model.getId());
currentStoryUsername = model.getTitle();
break;
} }
final HighlightModel model = models.get(currentFeedStoryIndex); case FEED_STORY_POSITION: {
currentStoryMediaId = model.getId(); final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel;
currentStoryUsername = model.getTitle(); final List<FeedStoryModel> models = feedStoriesViewModel.getList().getValue();
} else if (isHighlight) { if (models == null) return;
final HighlightsViewModel highlightsViewModel = (HighlightsViewModel) viewModel; final FeedStoryModel model = models.get(currentFeedStoryIndex);
final List<HighlightModel> models = highlightsViewModel.getList().getValue(); currentStoryMediaId = model.getStoryMediaId();
if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size()) { currentStoryUsername = model.getProfileModel().getUsername();
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); fetchOptions = StoryViewerOptions.forUser(Long.parseLong(currentStoryMediaId), currentStoryUsername);
return; if (model.isLive()) {
live = model.getFirstStoryModel();
}
break;
}
case STORY_ARCHIVE: {
final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel;
final List<HighlightModel> models = archivesViewModel.getList().getValue();
if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size()) {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
return;
}
final HighlightModel model = models.get(currentFeedStoryIndex);
currentStoryMediaId = model.getId();
currentStoryUsername = model.getTitle();
fetchOptions = StoryViewerOptions.forUser(Long.parseLong(currentStoryMediaId), currentStoryUsername);
break;
} }
final HighlightModel model = models.get(currentFeedStoryIndex);
currentStoryMediaId = model.getId();
currentStoryUsername = model.getTitle();
} else {
final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel;
final List<FeedStoryModel> models = feedStoriesViewModel.getList().getValue();
if (models == null) return;
final FeedStoryModel model = models.get(currentFeedStoryIndex);
currentStoryMediaId = model.getStoryMediaId();
currentStoryUsername = model.getProfileModel().getUsername();
}
} else if (fragmentArgs.getProfileId() > 0 && !TextUtils.isEmpty(fragmentArgs.getUsername())) {
currentStoryMediaId = String.valueOf(fragmentArgs.getProfileId());
currentStoryUsername = fragmentArgs.getUsername();
}
isHashtag = fragmentArgs.getIsHashtag();
isLoc = fragmentArgs.getIsLoc();
final boolean hasUsername = !TextUtils.isEmpty(currentStoryUsername);
if (isHighlight) {
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(highlight);
}
} else if (hasUsername) {
currentStoryUsername = currentStoryUsername.replace("@", "");
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(currentStoryUsername);
} }
} }
if (type == Type.USER) {
currentStoryMediaId = String.valueOf(options.getId());
currentStoryUsername = options.getName();
fetchOptions = StoryViewerOptions.forUser(options.getId(), currentStoryUsername);
}
setTitle(type);
storiesViewModel.getList().setValue(Collections.emptyList()); storiesViewModel.getList().setValue(Collections.emptyList());
if (currentStoryMediaId == null) return; if (type == Type.STORY) {
if (isNotification) { storiesService.fetch(options.getId(), new ServiceCallback<StoryModel>() {
storiesService.fetch(currentStoryMediaId, new ServiceCallback<StoryModel>() {
@Override @Override
public void onSuccess(final StoryModel storyModel) { public void onSuccess(final StoryModel storyModel) {
fetching = false; fetching = false;
@ -728,6 +747,7 @@ public class StoryViewerFragment extends Fragment {
}); });
return; return;
} }
if (currentStoryMediaId == null) return;
final ServiceCallback<List<StoryModel>> storyCallback = new ServiceCallback<List<StoryModel>>() { final ServiceCallback<List<StoryModel>> storyCallback = new ServiceCallback<List<StoryModel>>() {
@Override @Override
public void onSuccess(final List<StoryModel> storyModels) { public void onSuccess(final List<StoryModel> storyModels) {
@ -739,8 +759,10 @@ public class StoryViewerFragment extends Fragment {
return; return;
} }
binding.storiesList.setVisibility((storyModels.size() == 1 && currentFeedStoryIndex == -1) ? View.GONE : View.VISIBLE); binding.storiesList.setVisibility((storyModels.size() == 1 && currentFeedStoryIndex == -1) ? View.GONE : View.VISIBLE);
binding.btnBackward.setVisibility(currentFeedStoryIndex == -1 ? View.GONE : View.VISIBLE); if (currentFeedStoryIndex == -1) {
binding.btnForward.setVisibility(currentFeedStoryIndex == -1 ? View.GONE : View.VISIBLE); binding.btnBackward.setVisibility(View.GONE);
binding.btnForward.setVisibility(View.GONE);
}
storiesViewModel.getList().setValue(storyModels); storiesViewModel.getList().setValue(storyModels);
currentStory = storyModels.get(0); currentStory = storyModels.get(0);
refreshStory(); refreshStory();
@ -753,12 +775,29 @@ public class StoryViewerFragment extends Fragment {
Log.e(TAG, "Error", t); Log.e(TAG, "Error", t);
} }
}; };
storiesService.getUserStory(currentStoryMediaId, if (live != null) {
currentStoryUsername, storyCallback.onSuccess(Collections.singletonList(live));
isLoc, return;
isHashtag, }
isHighlight, storiesService.getUserStory(fetchOptions, storyCallback);
storyCallback); }
private void setTitle(final Type type) {
final boolean hasUsername = !TextUtils.isEmpty(currentStoryUsername);
if (type == Type.HIGHLIGHT) {
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
if (actionBar != null) {
actionBarTitle = options.getName();
actionBar.setTitle(options.getName());
}
} else if (hasUsername) {
currentStoryUsername = currentStoryUsername.replace("@", "");
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
if (actionBar != null) {
actionBarTitle = currentStoryUsername;
actionBar.setTitle(currentStoryUsername);
}
}
} }
private void refreshStory() { private void refreshStory() {
@ -782,51 +821,56 @@ public class StoryViewerFragment extends Fragment {
final MediaItemType itemType = currentStory.getItemType(); final MediaItemType itemType = currentStory.getItemType();
if (menuDownload != null) menuDownload.setVisible(false); if (menuDownload != null) menuDownload.setVisible(false);
url = itemType == MediaItemType.MEDIA_TYPE_VIDEO ? currentStory.getVideoUrl() : currentStory.getStoryUrl(); url = itemType == MediaItemType.MEDIA_TYPE_IMAGE ? currentStory.getStoryUrl() : currentStory.getVideoUrl();
final String shortCode = currentStory.getTappableShortCode(); if (itemType != MediaItemType.MEDIA_TYPE_LIVE) {
binding.viewStoryPost.setVisibility(shortCode != null ? View.VISIBLE : View.GONE); final String shortCode = currentStory.getTappableShortCode();
binding.viewStoryPost.setTag(shortCode); binding.viewStoryPost.setVisibility(shortCode != null ? View.VISIBLE : View.GONE);
binding.viewStoryPost.setTag(shortCode);
final String spotify = currentStory.getSpotify(); final String spotify = currentStory.getSpotify();
binding.spotify.setVisibility(spotify != null ? View.VISIBLE : View.GONE); binding.spotify.setVisibility(spotify != null ? View.VISIBLE : View.GONE);
binding.spotify.setTag(spotify); binding.spotify.setTag(spotify);
poll = currentStory.getPoll(); poll = currentStory.getPoll();
binding.poll.setVisibility(poll != null ? View.VISIBLE : View.GONE); binding.poll.setVisibility(poll != null ? View.VISIBLE : View.GONE);
binding.poll.setTag(poll); binding.poll.setTag(poll);
question = currentStory.getQuestion(); question = currentStory.getQuestion();
binding.answer.setVisibility((question != null && !TextUtils.isEmpty(cookie)) ? View.VISIBLE : View.GONE); binding.answer.setVisibility((question != null && !TextUtils.isEmpty(cookie)) ? View.VISIBLE : View.GONE);
binding.answer.setTag(question); binding.answer.setTag(question);
mentions = currentStory.getMentions(); mentions = currentStory.getMentions();
binding.mention.setVisibility((mentions != null && mentions.length > 0) ? View.VISIBLE : View.GONE); binding.mention.setVisibility((mentions != null && mentions.length > 0) ? View.VISIBLE : View.GONE);
binding.mention.setTag(mentions); binding.mention.setTag(mentions);
quiz = currentStory.getQuiz(); quiz = currentStory.getQuiz();
binding.quiz.setVisibility(quiz != null ? View.VISIBLE : View.GONE); binding.quiz.setVisibility(quiz != null ? View.VISIBLE : View.GONE);
binding.quiz.setTag(quiz); binding.quiz.setTag(quiz);
slider = currentStory.getSlider(); slider = currentStory.getSlider();
binding.slider.setVisibility(slider != null ? View.VISIBLE : View.GONE); binding.slider.setVisibility(slider != null ? View.VISIBLE : View.GONE);
binding.slider.setTag(slider); binding.slider.setTag(slider);
final SwipeUpModel swipeUp = currentStory.getSwipeUp(); final SwipeUpModel swipeUp = currentStory.getSwipeUp();
if (swipeUp != null) { if (swipeUp != null) {
binding.swipeUp.setVisibility(View.VISIBLE); binding.swipeUp.setVisibility(View.VISIBLE);
binding.swipeUp.setText(swipeUp.getText()); binding.swipeUp.setText(swipeUp.getText());
binding.swipeUp.setTag(swipeUp.getUrl()); binding.swipeUp.setTag(swipeUp.getUrl());
} else binding.swipeUp.setVisibility(View.GONE);
} }
releasePlayer(); releasePlayer();
if (isHashtag || isLoc) { final Type type = options.getType();
if (type == Type.HASHTAG || type == Type.LOCATION) {
final ActionBar actionBar = fragmentActivity.getSupportActionBar(); final ActionBar actionBar = fragmentActivity.getSupportActionBar();
if (actionBar != null) { if (actionBar != null) {
actionBarTitle = currentStory.getUsername();
actionBar.setTitle(currentStory.getUsername()); actionBar.setTitle(currentStory.getUsername());
} }
} }
if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo(); if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo();
else if (itemType == MediaItemType.MEDIA_TYPE_LIVE) setupLive();
else setupImage(); else setupImage();
final ActionBar actionBar = fragmentActivity.getSupportActionBar(); final ActionBar actionBar = fragmentActivity.getSupportActionBar();
@ -952,6 +996,72 @@ public class StoryViewerFragment extends Fragment {
}); });
} }
private void setupLive() {
binding.playerView.setVisibility(View.VISIBLE);
binding.progressView.setVisibility(View.GONE);
binding.imageViewer.setVisibility(View.GONE);
binding.imageViewer.setController(null);
if (menuDownload != null) menuDownload.setVisible(false);
if (menuDm != null) menuDm.setVisible(false);
final Context context = getContext();
if (context == null) return;
player = new SimpleExoPlayer.Builder(context).build();
binding.playerView.setPlayer(player);
player.setPlayWhenReady(settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
final Uri uri = Uri.parse(url);
final MediaItem mediaItem = MediaItem.fromUri(uri);
final DashMediaSource mediaSource = new DashMediaSource.Factory(new DefaultDataSourceFactory(context, "instagram"))
.createMediaSource(mediaItem);
mediaSource.addEventListener(new Handler(), new MediaSourceEventListener() {
@Override
public void onLoadCompleted(final int windowIndex,
@Nullable final MediaSource.MediaPeriodId mediaPeriodId,
@NonNull final LoadEventInfo loadEventInfo,
@NonNull final MediaLoadData mediaLoadData) {
binding.progressView.setVisibility(View.GONE);
}
@Override
public void onLoadStarted(final int windowIndex,
@Nullable final MediaSource.MediaPeriodId mediaPeriodId,
@NonNull final LoadEventInfo loadEventInfo,
@NonNull final MediaLoadData mediaLoadData) {
binding.progressView.setVisibility(View.VISIBLE);
}
@Override
public void onLoadCanceled(final int windowIndex,
@Nullable final MediaSource.MediaPeriodId mediaPeriodId,
@NonNull final LoadEventInfo loadEventInfo,
@NonNull final MediaLoadData mediaLoadData) {
binding.progressView.setVisibility(View.GONE);
}
@Override
public void onLoadError(final int windowIndex,
@Nullable final MediaSource.MediaPeriodId mediaPeriodId,
@NonNull final LoadEventInfo loadEventInfo,
@NonNull final MediaLoadData mediaLoadData,
@NonNull final IOException error,
final boolean wasCanceled) {
binding.progressView.setVisibility(View.GONE);
}
});
player.setMediaSource(mediaSource);
player.prepare();
binding.playerView.setOnClickListener(v -> {
if (player != null) {
if (player.getPlaybackState() == Player.STATE_ENDED) player.seekTo(0);
player.setPlayWhenReady(player.getPlaybackState() == Player.STATE_ENDED || !player.isPlaying());
}
});
}
private void openProfile(final String username) { private void openProfile(final String username) {
final ActionBar actionBar = fragmentActivity.getSupportActionBar(); final ActionBar actionBar = fragmentActivity.getSupportActionBar();
if (actionBar != null) { if (actionBar != null) {

View File

@ -51,7 +51,7 @@ import awais.instagrabber.databinding.FragmentTopicPostsBinding;
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment; import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
import awais.instagrabber.fragments.main.DiscoverFragmentDirections; import awais.instagrabber.fragments.main.DiscoverFragmentDirections;
import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.PostsLayoutPreferences;
import awais.instagrabber.models.TopicCluster; import awais.instagrabber.repositories.responses.discover.TopicCluster;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.DownloadUtils;

View File

@ -253,7 +253,7 @@ public class DirectMessageThreadFragment extends Fragment {
public boolean onOptionsItemSelected(@NonNull final MenuItem item) { public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
final int itemId = item.getItemId(); final int itemId = item.getItemId();
if (itemId == R.id.info) { if (itemId == R.id.info) {
final NavDirections action = DirectMessageThreadFragmentDirections.actionDMThreadFragmentToDMSettingsFragment(viewModel.getThreadId()); final NavDirections action = DirectMessageThreadFragmentDirections.actionDMThreadFragmentToDMSettingsFragment(viewModel.getThreadId(), null);
NavHostFragment.findNavController(this).navigate(action); NavHostFragment.findNavController(this).navigate(action);
return true; return true;
} }

View File

@ -78,6 +78,21 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
private RecyclerView storiesRecyclerView; private RecyclerView storiesRecyclerView;
private MenuItem storyListMenu; private MenuItem storyListMenu;
private final FeedStoriesAdapter feedStoriesAdapter = new FeedStoriesAdapter(
new FeedStoriesAdapter.OnFeedStoryClickListener() {
@Override
public void onFeedStoryClick(FeedStoryModel model, int position) {
final NavDirections action = FeedFragmentDirections.actionFeedFragmentToStoryViewerFragment(position, null, false, false, null, null, false, false);
NavHostFragment.findNavController(FeedFragment.this).navigate(action);
}
@Override
public void onFeedStoryLongClick(FeedStoryModel model, int position) {
navigateToProfile("@" + model.getProfileModel().getUsername());
}
}
);
private final FeedAdapterV2.FeedItemCallback feedItemCallback = new FeedAdapterV2.FeedItemCallback() { private final FeedAdapterV2.FeedItemCallback feedItemCallback = new FeedAdapterV2.FeedItemCallback() {
@Override @Override
public void onPostClick(final Media feedModel, final View profilePicView, final View mainPostImage) { public void onPostClick(final Media feedModel, final View profilePicView, final View mainPostImage) {
@ -351,21 +366,6 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
private void setupFeedStories() { private void setupFeedStories() {
if (storyListMenu != null) storyListMenu.setVisible(false); if (storyListMenu != null) storyListMenu.setVisible(false);
feedStoriesViewModel = new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class); feedStoriesViewModel = new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class);
final FeedStoriesAdapter feedStoriesAdapter = new FeedStoriesAdapter(
new FeedStoriesAdapter.OnFeedStoryClickListener() {
@Override
public void onFeedStoryClick(FeedStoryModel model, int position) {
final NavDirections action = FeedFragmentDirections
.actionFeedFragmentToStoryViewerFragment(position, null, false, false, null, null, false, false);
NavHostFragment.findNavController(FeedFragment.this).navigate(action);
}
@Override
public void onFeedStoryLongClick(FeedStoryModel model, int position) {
navigateToProfile("@" + model.getProfileModel().getUsername());
}
}
);
final Context context = getContext(); final Context context = getContext();
if (context == null) return; if (context == null) return;
storiesRecyclerView = new RecyclerView(context); storiesRecyclerView = new RecyclerView(context);
@ -389,6 +389,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
@Override @Override
public void onSuccess(final List<FeedStoryModel> result) { public void onSuccess(final List<FeedStoryModel> result) {
feedStoriesViewModel.getList().postValue(result); feedStoriesViewModel.getList().postValue(result);
feedStoriesAdapter.submitList(result);
storiesFetching = false; storiesFetching = false;
if (storyListMenu != null) storyListMenu.setVisible(true); if (storyListMenu != null) storyListMenu.setVisible(true);
updateSwipeRefreshState(); updateSwipeRefreshState();

View File

@ -874,7 +874,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
@Override @Override
public void onSuccess(final List<StoryModel> storyModels) { public void onSuccess(final List<StoryModel> storyModels) {
if (storyModels != null && !storyModels.isEmpty()) { if (storyModels != null && !storyModels.isEmpty()) {
profileDetailsBinding.mainProfileImage.setStoriesBorder(); profileDetailsBinding.mainProfileImage.setStoriesBorder(1);
hasStories = true; hasStories = true;
} }
} }

View File

@ -13,17 +13,21 @@ public final class FeedStoryModel implements Serializable {
private final User profileModel; private final User profileModel;
private final StoryModel firstStoryModel; private final StoryModel firstStoryModel;
private Boolean fullyRead; private Boolean fullyRead;
private final boolean isLive, isBestie;
private final long timestamp; private final long timestamp;
private final int mediaCount; private final int mediaCount;
public FeedStoryModel(final String storyMediaId, final User profileModel, final boolean fullyRead, public FeedStoryModel(final String storyMediaId, final User profileModel, final boolean fullyRead,
final long timestamp, final StoryModel firstStoryModel, final int mediaCount) { final long timestamp, final StoryModel firstStoryModel, final int mediaCount,
final boolean isLive, final boolean isBestie) {
this.storyMediaId = storyMediaId; this.storyMediaId = storyMediaId;
this.profileModel = profileModel; this.profileModel = profileModel;
this.fullyRead = fullyRead; this.fullyRead = fullyRead;
this.timestamp = timestamp; this.timestamp = timestamp;
this.firstStoryModel = firstStoryModel; this.firstStoryModel = firstStoryModel;
this.mediaCount = mediaCount; this.mediaCount = mediaCount;
this.isLive = isLive;
this.isBestie = isBestie;
} }
public String getStoryMediaId() { public String getStoryMediaId() {
@ -62,4 +66,12 @@ public final class FeedStoryModel implements Serializable {
public void setFullyRead(final boolean fullyRead) { public void setFullyRead(final boolean fullyRead) {
this.fullyRead = fullyRead; this.fullyRead = fullyRead;
} }
public boolean isLive() {
return isLive;
}
public boolean isBestie() {
return isBestie;
}
} }

View File

@ -4,8 +4,7 @@ import java.io.Serializable;
public final class LocationModel implements Serializable { public final class LocationModel implements Serializable {
private final long postCount; private final long postCount;
private final String id; private final long id;
private final String slug;
private final String name; private final String name;
private final String bio; private final String bio;
private final String url; private final String url;
@ -13,8 +12,7 @@ public final class LocationModel implements Serializable {
private final String lat; private final String lat;
private final String lng; private final String lng;
public LocationModel(final String id, public LocationModel(final long id,
final String slug,
final String name, final String name,
final String bio, final String bio,
final String url, final String url,
@ -23,7 +21,6 @@ public final class LocationModel implements Serializable {
final String lat, final String lat,
final String lng) { final String lng) {
this.id = id; this.id = id;
this.slug = slug;
this.name = name; this.name = name;
this.bio = bio; this.bio = bio;
this.url = url; this.url = url;
@ -33,14 +30,10 @@ public final class LocationModel implements Serializable {
this.lng = lng; this.lng = lng;
} }
public String getId() { public long getId() {
return id; return id;
} }
public String getSlug() {
return slug;
}
public String getName() { public String getName() {
return name; return name;
} }

View File

@ -5,7 +5,6 @@ import androidx.annotation.NonNull;
import java.util.Date; import java.util.Date;
import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.models.enums.NotificationType;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
public final class NotificationModel { public final class NotificationModel {
@ -13,7 +12,7 @@ public final class NotificationModel {
private final long userId; private final long userId;
private final String username; private final String username;
private final String profilePicUrl; private final String profilePicUrl;
private final String postId; private final long postId;
private final String previewUrl; private final String previewUrl;
private final NotificationType type; private final NotificationType type;
private final CharSequence text; private final CharSequence text;
@ -25,11 +24,11 @@ public final class NotificationModel {
final long userId, final long userId,
final String username, final String username,
final String profilePicUrl, final String profilePicUrl,
final String postId, final long postId,
final String previewUrl, final String previewUrl,
final NotificationType type) { final NotificationType type) {
this.id = id; this.id = id;
this.text = TextUtils.hasMentions(text) ? TextUtils.getMentionText(text) : text; this.text = text;
this.timestamp = timestamp; this.timestamp = timestamp;
this.userId = userId; this.userId = userId;
this.username = username; this.username = username;
@ -68,7 +67,7 @@ public final class NotificationModel {
return profilePicUrl; return profilePicUrl;
} }
public String getPostId() { public long getPostId() {
return postId; return postId;
} }

View File

@ -14,7 +14,10 @@ public enum MediaItemType implements Serializable {
@SerializedName("8") @SerializedName("8")
MEDIA_TYPE_SLIDER(8), MEDIA_TYPE_SLIDER(8),
@SerializedName("11") @SerializedName("11")
MEDIA_TYPE_VOICE(11); MEDIA_TYPE_VOICE(11),
// 5 is arbitrary
@SerializedName("5")
MEDIA_TYPE_LIVE(5);
private final int id; private final int id;
private static final Map<Integer, MediaItemType> map = new HashMap<>(); private static final Map<Integer, MediaItemType> map = new HashMap<>();

View File

@ -11,6 +11,6 @@ import retrofit2.http.QueryMap;
public interface LocationRepository { public interface LocationRepository {
@GET("/api/v1/feed/location/{location}/") @GET("/api/v1/feed/location/{location}/")
Call<LocationFeedResponse> fetchPosts(@Path("location") final String locationId, Call<LocationFeedResponse> fetchPosts(@Path("location") final long locationId,
@QueryMap Map<String, String> queryParams); @QueryMap Map<String, String> queryParams);
} }

View File

@ -15,7 +15,7 @@ import retrofit2.http.QueryMap;
public interface MediaRepository { public interface MediaRepository {
@GET("/api/v1/media/{mediaId}/info/") @GET("/api/v1/media/{mediaId}/info/")
Call<MediaInfoResponse> fetch(@Path("mediaId") final String mediaId); Call<MediaInfoResponse> fetch(@Path("mediaId") final long mediaId);
@GET("/api/v1/media/{mediaId}/{action}/") @GET("/api/v1/media/{mediaId}/{action}/")
Call<LikersResponse> fetchLikes(@Path("mediaId") final String mediaId, Call<LikersResponse> fetchLikes(@Path("mediaId") final String mediaId,

View File

@ -15,7 +15,7 @@ import retrofit2.http.Url;
public interface StoriesRepository { public interface StoriesRepository {
@GET("/api/v1/media/{mediaId}/info/") @GET("/api/v1/media/{mediaId}/info/")
Call<String> fetch(@Path("mediaId") final String mediaId); 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/feed/reels_tray/") @GET("/api/v1/feed/reels_tray/")

View File

@ -0,0 +1,93 @@
package awais.instagrabber.repositories.requests;
import java.io.Serializable;
public class StoryViewerOptions implements Serializable {
private final long id;
private final String name;
private final Type type;
private int currentFeedStoryIndex;
private StoryViewerOptions(final int position, final Type type) {
id = 0;
name = null;
this.currentFeedStoryIndex = position;
this.type = type;
}
private StoryViewerOptions(final String name, final Type type) {
this.name = name;
this.id = 0;
this.type = type;
}
private StoryViewerOptions(final long id, final Type type) {
this.name = null;
this.id = id;
this.type = type;
}
private StoryViewerOptions(final long id, final String name, final Type type) {
this.id = id;
this.name = name;
this.type = type;
}
public static StoryViewerOptions forHashtag(final String name) {
return new StoryViewerOptions(name, Type.HASHTAG);
}
public static StoryViewerOptions forLocation(final long id, final String name) {
return new StoryViewerOptions(id, name, Type.LOCATION);
}
public static StoryViewerOptions forUser(final long id, final String name) {
return new StoryViewerOptions(id, name,Type.USER);
}
public static StoryViewerOptions forHighlight(final String highlight) {
return new StoryViewerOptions(highlight, Type.HIGHLIGHT);
}
public static StoryViewerOptions forStory(final long mediaId, final String username) {
return new StoryViewerOptions(mediaId, username, Type.STORY);
}
public static StoryViewerOptions forFeedStoryPosition(final int position) {
return new StoryViewerOptions(position, Type.FEED_STORY_POSITION);
}
public static StoryViewerOptions forStoryArchive(final int position) {
return new StoryViewerOptions(position, Type.STORY_ARCHIVE);
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public Type getType() {
return type;
}
public int getCurrentFeedStoryIndex() {
return currentFeedStoryIndex;
}
public void setCurrentFeedStoryIndex(final int index) {
this.currentFeedStoryIndex = index;
}
public enum Type {
HASHTAG,
LOCATION,
USER,
HIGHLIGHT,
STORY,
FEED_STORY_POSITION,
STORY_ARCHIVE
}
}

View File

@ -1,4 +1,4 @@
package awais.instagrabber.models; package awais.instagrabber.repositories.responses.discover;
import java.io.Serializable; import java.io.Serializable;

View File

@ -2,8 +2,6 @@ package awais.instagrabber.repositories.responses.discover;
import java.util.List; import java.util.List;
import awais.instagrabber.models.TopicCluster;
public class TopicalExploreFeedResponse { public class TopicalExploreFeedResponse {
private final boolean moreAvailable; private final boolean moreAvailable;
private final String nextMaxId; private final String nextMaxId;

View File

@ -1,5 +1,6 @@
package awais.instagrabber.utils; package awais.instagrabber.utils;
import android.net.Uri;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@ -964,7 +965,7 @@ public final class ResponseBodyUtils {
public static StoryModel parseStoryItem(final JSONObject data, public static StoryModel parseStoryItem(final JSONObject data,
final boolean isLoc, final boolean isLoc,
final boolean isHashtag, final boolean isHashtag,
final String localUsername) throws JSONException { final String username) throws JSONException {
final boolean isVideo = data.has("video_duration"); final boolean isVideo = data.has("video_duration");
final StoryModel model = new StoryModel(data.getString("id"), final StoryModel model = new StoryModel(data.getString("id"),
data.getJSONObject("image_versions2").getJSONArray("candidates").getJSONObject(0) data.getJSONObject("image_versions2").getJSONArray("candidates").getJSONObject(0)
@ -973,7 +974,7 @@ public final class ResponseBodyUtils {
data.optLong("taken_at", 0), data.optLong("taken_at", 0),
(isLoc || isHashtag) (isLoc || isHashtag)
? data.getJSONObject("user").getString("username") ? data.getJSONObject("user").getString("username")
: localUsername, : username,
data.getJSONObject("user").getLong("pk"), data.getJSONObject("user").getLong("pk"),
data.optBoolean("can_reply")); data.optBoolean("can_reply"));
@ -1041,10 +1042,15 @@ public final class ResponseBodyUtils {
} }
if (data.has("story_cta") && data.has("link_text")) { if (data.has("story_cta") && data.has("link_text")) {
JSONObject tappableObject = data.getJSONArray("story_cta").getJSONObject(0).getJSONArray("links").getJSONObject(0); JSONObject tappableObject = data.getJSONArray("story_cta").getJSONObject(0).getJSONArray("links").getJSONObject(0);
String swipeUpUrl = tappableObject.getString("webUri"); String swipeUpUrl = tappableObject.optString("webUri");
if (swipeUpUrl.startsWith("http")) { final String backupSwipeUpUrl = swipeUpUrl;
model.setSwipeUp(new SwipeUpModel(swipeUpUrl, data.getString("link_text"))); if (swipeUpUrl != null && swipeUpUrl.startsWith("https://l.instagram.com/")) {
swipeUpUrl = Uri.parse(swipeUpUrl).getQueryParameter("u");
} }
if (swipeUpUrl != null && swipeUpUrl.startsWith("http"))
model.setSwipeUp(new SwipeUpModel(swipeUpUrl, data.getString("link_text")));
else if (backupSwipeUpUrl != null && backupSwipeUpUrl.startsWith("http"))
model.setSwipeUp(new SwipeUpModel(backupSwipeUpUrl, data.getString("link_text")));
} }
if (data.has("story_sliders")) { if (data.has("story_sliders")) {
final JSONObject tappableObject = data.getJSONArray("story_sliders").getJSONObject(0) final JSONObject tappableObject = data.getJSONArray("story_sliders").getJSONObject(0)
@ -1137,4 +1143,17 @@ public final class ResponseBodyUtils {
} }
return read; return read;
} }
public static StoryModel parseBroadcastItem(final JSONObject data) throws JSONException {
final StoryModel model = new StoryModel(data.getString("id"),
data.getString("cover_frame_url"),
data.getString("cover_frame_url"),
MediaItemType.MEDIA_TYPE_LIVE,
data.optLong("published_time", 0),
data.getJSONObject("user").getString("username"),
data.getJSONObject("user").getLong("pk"),
false);
model.setVideoUrl(data.getString("dash_playback_url"));
return model;
}
} }

View File

@ -24,56 +24,6 @@ import java.util.regex.Pattern;
import awais.instagrabber.customviews.CommentMentionClickSpan; import awais.instagrabber.customviews.CommentMentionClickSpan;
public final class TextUtils { public final class TextUtils {
private static final Pattern URL_PATTERN = Pattern.compile(
"(^|[\\s.:;?\\-\\]<\\(])((https?://|www\\.|pic\\.)[-\\w;/?:@&=+$\\|\\_.!~*\\|'()\\[\\]%#,☺]+[\\w/#](\\(\\))?)(?=$|[\\s',\\|\\(\\).:;?\\-\\[\\]>\\)])");
@NonNull
public static CharSequence getMentionText(@NonNull final CharSequence text) {
final int commentLength = text.length();
final SpannableStringBuilder stringBuilder = new SpannableStringBuilder(text, 0, commentLength);
for (int i = 0; i < commentLength; ++i) {
char currChar = text.charAt(i);
if (currChar == '@' || currChar == '#') {
final int startLen = i;
do {
if (++i == commentLength) break;
currChar = text.charAt(i);
if (currChar == '.' && i + 1 < commentLength) {
final char nextChar = text.charAt(i + 1);
if (nextChar == '.' || nextChar == ' ' || nextChar == '#' || nextChar == '@' || nextChar == '/'
|| nextChar == '\r' || nextChar == '\n') {
break;
}
} else if (currChar == '.')
break;
// for merged hashtags
if (currChar == '#') {
--i;
break;
}
} while (currChar != ' ' && currChar != '\r' && currChar != '\n' && currChar != '>' && currChar != '<'
&& currChar != ':' && currChar != ';' && currChar != '\'' && currChar != '"' && currChar != '['
&& currChar != ']' && currChar != '\\' && currChar != '=' && currChar != '-' && currChar != '!'
&& currChar != '$' && currChar != '%' && currChar != '^' && currChar != '&' && currChar != '*'
&& currChar != '(' && currChar != ')' && currChar != '{' && currChar != '}' && currChar != '/'
&& currChar != '|' && currChar != '?' && currChar != '`' && currChar != '~'
);
final int endLen = currChar != '#' ? i : i + 1; // for merged hashtags
stringBuilder.setSpan(new CommentMentionClickSpan(), startLen,
Math.min(commentLength, endLen), // fixed - crash when end index is greater than comment length ( @kernoeb )
Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
}
}
return stringBuilder;
}
// extracted from String class // extracted from String class
public static int indexOfChar(@NonNull final CharSequence sequence, final int ch, final int startIndex) { public static int indexOfChar(@NonNull final CharSequence sequence, final int ch, final int startIndex) {
final int max = sequence.length(); final int max = sequence.length();
@ -90,11 +40,6 @@ public final class TextUtils {
return -1; return -1;
} }
public static boolean hasMentions(final CharSequence text) {
if (isEmpty(text)) return false;
return indexOfChar(text, '@', 0) != -1 || indexOfChar(text, '#', 0) != -1;
}
public static CharSequence getSpannableUrl(final String url) { public static CharSequence getSpannableUrl(final String url) {
if (isEmpty(url)) return url; if (isEmpty(url)) return url;
final int httpIndex = url.indexOf("http:"); final int httpIndex = url.indexOf("http:");

View File

@ -140,11 +140,6 @@ public final class Utils {
return mimeType.toLowerCase(); return mimeType.toLowerCase();
} }
public static void errorFinish(@NonNull final Activity activity) {
Toast.makeText(activity, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
activity.finish();
}
public static SimpleCache getSimpleCacheInstance(final Context context) { public static SimpleCache getSimpleCacheInstance(final Context context) {
if (context == null) { if (context == null) {
return null; return null;

View File

@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModel;
import java.util.List; import java.util.List;
import awais.instagrabber.models.TopicCluster; import awais.instagrabber.repositories.responses.discover.TopicCluster;
public class TopicClusterViewModel extends ViewModel { public class TopicClusterViewModel extends ViewModel {
private MutableLiveData<List<TopicCluster>> list; private MutableLiveData<List<TopicCluster>> list;

View File

@ -85,7 +85,7 @@ public class GraphQLService extends BaseService {
}); });
} }
public void fetchLocationPosts(@NonNull final String locationId, public void fetchLocationPosts(final long locationId,
final String maxId, final String maxId,
final ServiceCallback<PostsFetchResponse> callback) { final ServiceCallback<PostsFetchResponse> callback) {
fetch("36bd0f2bf5911908de389b8ceaa3be6d", fetch("36bd0f2bf5911908de389b8ceaa3be6d",

View File

@ -34,7 +34,7 @@ public class LocationService extends BaseService {
return instance; return instance;
} }
public void fetchPosts(@NonNull final String locationId, public void fetchPosts(final long locationId,
final String maxId, final String maxId,
final ServiceCallback<PostsFetchResponse> callback) { final ServiceCallback<PostsFetchResponse> callback) {
final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder(); final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();

View File

@ -51,7 +51,7 @@ public class MediaService extends BaseService {
return instance; return instance;
} }
public void fetch(final String mediaId, public void fetch(final long mediaId,
final ServiceCallback<Media> callback) { final ServiceCallback<Media> callback) {
final Call<MediaInfoResponse> request = repository.fetch(mediaId); final Call<MediaInfoResponse> request = repository.fetch(mediaId);
request.enqueue(new Callback<MediaInfoResponse>() { request.enqueue(new Callback<MediaInfoResponse>() {

View File

@ -62,7 +62,7 @@ public class NewsService extends BaseService {
try { try {
final JSONObject jsonObject = new JSONObject(body); final JSONObject jsonObject = new JSONObject(body);
final JSONArray oldStories = jsonObject.getJSONArray("old_stories"), final JSONArray oldStories = jsonObject.getJSONArray("old_stories"),
newStories = jsonObject.getJSONArray("new_stories"); newStories = jsonObject.getJSONArray("new_stories");
for (int j = 0; j < newStories.length(); ++j) { for (int j = 0; j < newStories.length(); ++j) {
final NotificationModel newsItem = parseNewsItem(newStories.getJSONObject(j)); final NotificationModel newsItem = parseNewsItem(newStories.getJSONObject(j));
@ -105,7 +105,7 @@ public class NewsService extends BaseService {
.getJSONObject("graphql") .getJSONObject("graphql")
.getJSONObject("user"); .getJSONObject("user");
final JSONObject ewaf = page.getJSONObject("activity_feed") final JSONObject ewaf = page.getJSONObject("activity_feed")
.optJSONObject("edge_web_activity_feed"); .optJSONObject("edge_web_activity_feed");
final JSONObject efr = page.optJSONObject("edge_follow_requests"); final JSONObject efr = page.optJSONObject("edge_follow_requests");
JSONObject data; JSONObject data;
JSONArray media; JSONArray media;
@ -127,8 +127,9 @@ public class NewsService extends BaseService {
user.getLong("id"), user.getLong("id"),
user.getString("username"), user.getString("username"),
user.getString("profile_pic_url"), user.getString("profile_pic_url"),
!data.isNull("media") ? data.getJSONObject("media").getString("id") : null, data.has("media") ? data.getJSONObject("media").getLong("id") : 0,
!data.isNull("media") ? data.getJSONObject("media").getString("thumbnail_src") : null, notificationType)); data.has("media") ? data.getJSONObject("media").getString("thumbnail_src") : null,
notificationType));
} }
} }
@ -146,7 +147,7 @@ public class NewsService extends BaseService {
data.getLong(Constants.EXTRAS_ID), data.getLong(Constants.EXTRAS_ID),
data.getString("username"), data.getString("username"),
data.getString("profile_pic_url"), data.getString("profile_pic_url"),
null, 0,
null, NotificationType.REQUEST)); null, NotificationType.REQUEST));
} }
} }
@ -169,7 +170,7 @@ public class NewsService extends BaseService {
final String type = itemJson.getString("story_type"); final String type = itemJson.getString("story_type");
final NotificationType notificationType = NotificationType.valueOfType(type); final NotificationType notificationType = NotificationType.valueOfType(type);
if (notificationType == null) { if (notificationType == null) {
if (BuildConfig.DEBUG) Log.d("austin_debug", "unhandled news type: "+itemJson); if (BuildConfig.DEBUG) Log.d("austin_debug", "unhandled news type: " + itemJson);
return null; return null;
} }
final JSONObject data = itemJson.getJSONObject("args"); final JSONObject data = itemJson.getJSONObject("args");
@ -180,7 +181,7 @@ public class NewsService extends BaseService {
data.getLong("profile_id"), data.getLong("profile_id"),
data.getString("profile_name"), data.getString("profile_name"),
data.getString("profile_image"), data.getString("profile_image"),
!data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getString("id") : null, !data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getLong("id") : 0,
!data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getString("image") : null, !data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getString("image") : null,
notificationType); notificationType);
} }
@ -254,8 +255,8 @@ public class NewsService extends BaseService {
data.getLong("pk"), data.getLong("pk"),
data.getString("username"), data.getString("username"),
data.getString("profile_pic_url"), data.getString("profile_pic_url"),
0,
data.getString("full_name"), // just borrowing this field data.getString("full_name"), // just borrowing this field
null,
NotificationType.AYML); NotificationType.AYML);
} }
} }

View File

@ -3,6 +3,7 @@ package awais.instagrabber.webservices;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -20,6 +21,7 @@ import awais.instagrabber.models.FeedStoryModel;
import awais.instagrabber.models.HighlightModel; import awais.instagrabber.models.HighlightModel;
import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.StoryModel;
import awais.instagrabber.repositories.StoriesRepository; import awais.instagrabber.repositories.StoriesRepository;
import awais.instagrabber.repositories.requests.StoryViewerOptions;
import awais.instagrabber.repositories.responses.FriendshipStatus; import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.StoryStickerResponse; import awais.instagrabber.repositories.responses.StoryStickerResponse;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
@ -34,7 +36,6 @@ import retrofit2.Retrofit;
public class StoriesService extends BaseService { public class StoriesService extends BaseService {
private static final String TAG = "StoriesService"; private static final String TAG = "StoriesService";
private static final boolean loadFromMock = false;
private final StoriesRepository repository; private final StoriesRepository repository;
@ -54,7 +55,7 @@ public class StoriesService extends BaseService {
return instance; return instance;
} }
public void fetch(final String mediaId, public void fetch(final long mediaId,
final ServiceCallback<StoryModel> callback) { final ServiceCallback<StoryModel> callback) {
final Call<String> request = repository.fetch(mediaId); final Call<String> request = repository.fetch(mediaId);
request.enqueue(new Callback<String>() { request.enqueue(new Callback<String>() {
@ -156,12 +157,66 @@ public class StoriesService extends BaseService {
final long timestamp = node.getLong("latest_reel_media"); final long timestamp = node.getLong("latest_reel_media");
final int mediaCount = node.getInt("media_count"); final int mediaCount = node.getInt("media_count");
final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp; final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp;
final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").getJSONObject(0) : null; final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").optJSONObject(0) : null;
final boolean isBestie = node.optBoolean("has_besties_media", false);
StoryModel firstStoryModel = null; StoryModel firstStoryModel = null;
if (itemJson != null) { if (itemJson != null) {
firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, false, null); firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, false, null);
} }
feedStoryModels.add(new FeedStoryModel(id, user, fullyRead, timestamp, firstStoryModel, mediaCount)); feedStoryModels.add(new FeedStoryModel(id, user, fullyRead, timestamp, firstStoryModel, mediaCount, false, isBestie));
}
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"),
null,
new FriendshipStatus(
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
),
userJson.optBoolean("is_verified"),
false,
false,
false,
false,
null,
null,
0,
0,
0,
0,
null,
null,
0,
null
);
final String id = node.getString("id");
final long timestamp = node.getLong("published_time");
final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").getJSONObject(0) : null;
StoryModel firstStoryModel = null;
if (itemJson != null) {
firstStoryModel = ResponseBodyUtils.parseBroadcastItem(itemJson);
}
feedStoryModels.add(new FeedStoryModel(id, user, false, timestamp, firstStoryModel, 1, true, false));
} }
callback.onSuccess(sort(feedStoryModels)); callback.onSuccess(sort(feedStoryModels));
} catch (JSONException e) { } catch (JSONException e) {
@ -274,20 +329,17 @@ public class StoriesService extends BaseService {
}); });
} }
public void getUserStory(final String id, public void getUserStory(final StoryViewerOptions options,
final String username,
final boolean isLoc,
final boolean isHashtag,
final boolean highlight,
final ServiceCallback<List<StoryModel>> callback) { final ServiceCallback<List<StoryModel>> callback) {
final String url = buildUrl(id, isLoc, isHashtag, highlight); final String url = buildUrl(options);
Log.d("austin_debug", url);
final Call<String> userStoryCall = repository.getUserStory(Constants.I_USER_AGENT, url); final Call<String> userStoryCall = repository.getUserStory(Constants.I_USER_AGENT, url);
final boolean isLoc = options.getType() == StoryViewerOptions.Type.LOCATION;
final boolean isHashtag = options.getType() == StoryViewerOptions.Type.HASHTAG;
final boolean isHighlight = options.getType() == StoryViewerOptions.Type.HIGHLIGHT;
userStoryCall.enqueue(new Callback<String>() { userStoryCall.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
JSONObject data; JSONObject data;
String localUsername = username;
try { try {
final String body = response.body(); final String body = response.body();
if (body == null) { if (body == null) {
@ -296,15 +348,19 @@ public class StoriesService extends BaseService {
} }
data = new JSONObject(body); data = new JSONObject(body);
if (!highlight) if (!isHighlight) {
data = data.optJSONObject((isLoc || isHashtag) ? "story" : "reel"); data = data.optJSONObject((isLoc || isHashtag) ? "story" : "reel");
else if (highlight) data = data.getJSONObject("reels").optJSONObject(id); } else if (isHighlight) {
data = data.getJSONObject("reels").optJSONObject(options.getName());
}
String username = null;
if (data != null if (data != null
&& localUsername == null // && localUsername == null
&& !isLoc && !isLoc
&& !isHashtag) && !isHashtag) {
localUsername = data.getJSONObject("user").getString("username"); username = data.getJSONObject("user").getString("username");
}
JSONArray media; JSONArray media;
if (data != null if (data != null
@ -315,7 +371,7 @@ public class StoriesService extends BaseService {
final List<StoryModel> models = new ArrayList<>(); final List<StoryModel> models = new ArrayList<>();
for (int i = 0; i < mediaLen; ++i) { for (int i = 0; i < mediaLen; ++i) {
data = media.getJSONObject(i); data = media.getJSONObject(i);
models.add(ResponseBodyUtils.parseStoryItem(data, isLoc, isHashtag, localUsername)); models.add(ResponseBodyUtils.parseStoryItem(data, isLoc, isHashtag, username));
} }
callback.onSuccess(models); callback.onSuccess(models);
} else { } else {
@ -410,21 +466,42 @@ public class StoriesService extends BaseService {
respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), userId, csrfToken, callback); respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), userId, csrfToken, callback);
} }
private String buildUrl(final String id, final boolean isLoc, final boolean isHashtag, final boolean highlight) { @Nullable
final String userId = id.replace(":", "%3A"); private String buildUrl(@NonNull final StoryViewerOptions options) {
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
builder.append("https://i.instagram.com/api/v1/"); builder.append("https://i.instagram.com/api/v1/");
if (isLoc) { final StoryViewerOptions.Type type = options.getType();
builder.append("locations/"); String id = null;
} else if (isHashtag) { switch (type) {
builder.append("tags/"); case HASHTAG:
} else if (highlight) { builder.append("tags/");
builder.append("feed/reels_media/?user_ids="); id = options.getName();
} else { break;
builder.append("feed/user/"); 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:
builder.append("feed/reels_media/?user_ids=");
id = options.getName();
break;
case STORY:
break;
// case FEED_STORY_POSITION:
// break;
// case STORY_ARCHIVE:
// break;
} }
if (id == null) {
return null;
}
final String userId = id.replace(":", "%3A");
builder.append(userId); builder.append(userId);
if (!highlight) { if (type != StoryViewerOptions.Type.HIGHLIGHT) {
builder.append("/story/"); builder.append("/story/");
} }
return builder.toString(); return builder.toString();

View File

@ -83,24 +83,18 @@
app:layout_constraintTop_toBottomOf="@id/mainLocationImage" app:layout_constraintTop_toBottomOf="@id/mainLocationImage"
tools:text="OUR HOUSE" /> tools:text="OUR HOUSE" />
<awais.instagrabber.customviews.RamboTextView <awais.instagrabber.customviews.RamboTextViewV2
android:id="@+id/locationBiography" android:id="@+id/locationBiography"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/locationFullName" android:padding="8dp"
android:background="?android:selectableItemBackground" android:background="?android:selectableItemBackground"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingEnd="8dp"
android:paddingRight="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/locationUrl" app:layout_constraintBottom_toTopOf="@id/locationUrl"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/locationFullName" app:layout_constraintTop_toBottomOf="@id/locationFullName"
tools:text="IN THE MIDDLE OF OUR STREET" tools:text="IN THE MIDDLE OF OUR STREET" />
tools:visibility="visible" />
<awais.instagrabber.customviews.RamboTextView <awais.instagrabber.customviews.RamboTextView
android:id="@+id/locationUrl" android:id="@+id/locationUrl"

View File

@ -141,6 +141,10 @@
app:argType="string" app:argType="string"
app:nullable="false" /> app:nullable="false" />
<argument
android:name="title"
app:argType="string" />
<action <action
android:id="@+id/action_settings_to_inbox" android:id="@+id/action_settings_to_inbox"
app:destination="@id/directMessagesInboxFragment" app:destination="@id/directMessagesInboxFragment"

View File

@ -96,7 +96,7 @@
tools:layout="@layout/fragment_topic_posts"> tools:layout="@layout/fragment_topic_posts">
<argument <argument
android:name="topicCluster" android:name="topicCluster"
app:argType="awais.instagrabber.models.TopicCluster" /> app:argType="awais.instagrabber.repositories.responses.discover.TopicCluster" />
<argument <argument
android:name="titleColor" android:name="titleColor"

View File

@ -107,34 +107,7 @@
android:label="StoryViewerFragment" android:label="StoryViewerFragment"
tools:layout="@layout/fragment_story_viewer"> tools:layout="@layout/fragment_story_viewer">
<argument <argument
android:name="feedStoryIndex" android:name="options"
app:argType="integer" app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
app:nullable="false" />
<argument
android:name="highlight"
app:argType="string"
app:nullable="true" />
<argument
android:name="isHashtag"
app:argType="boolean" />
<argument
android:name="isLoc"
app:argType="boolean" />
<argument
android:name="profileId"
app:argType="string"
app:nullable="true" />
<argument
android:name="username"
app:argType="string"
app:nullable="true" />
<argument
android:name="isArchive"
app:argType="boolean"
app:nullable="false" />
<argument
android:name="isNotification"
app:argType="boolean"
app:nullable="false" />
</fragment> </fragment>
</navigation> </navigation>

View File

@ -74,35 +74,8 @@
android:label="StoryViewerFragment" android:label="StoryViewerFragment"
tools:layout="@layout/fragment_story_viewer"> tools:layout="@layout/fragment_story_viewer">
<argument <argument
android:name="feedStoryIndex" android:name="options"
app:argType="integer" app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
app:nullable="false" />
<argument
android:name="highlight"
app:argType="string"
app:nullable="true" />
<argument
android:name="isHashtag"
app:argType="boolean" />
<argument
android:name="isLoc"
app:argType="boolean" />
<argument
android:name="profileId"
app:argType="string"
app:nullable="true" />
<argument
android:name="username"
app:argType="string"
app:nullable="true" />
<argument
android:name="isArchive"
app:argType="boolean"
app:nullable="false" />
<argument
android:name="isNotification"
app:argType="boolean"
app:nullable="false" />
</fragment> </fragment>
<action <action
android:id="@+id/action_global_hashTagFragment" android:id="@+id/action_global_hashTagFragment"

View File

@ -81,34 +81,7 @@
android:label="StoryViewerFragment" android:label="StoryViewerFragment"
tools:layout="@layout/fragment_story_viewer"> tools:layout="@layout/fragment_story_viewer">
<argument <argument
android:name="feedStoryIndex" android:name="options"
app:argType="integer" app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
app:nullable="false" />
<argument
android:name="highlight"
app:argType="string"
app:nullable="true" />
<argument
android:name="isHashtag"
app:argType="boolean" />
<argument
android:name="isLoc"
app:argType="boolean" />
<argument
android:name="profileId"
app:argType="string"
app:nullable="true" />
<argument
android:name="username"
app:argType="string"
app:nullable="true" />
<argument
android:name="isArchive"
app:argType="boolean"
app:nullable="false" />
<argument
android:name="isNotification"
app:argType="boolean"
app:nullable="false" />
</fragment> </fragment>
</navigation> </navigation>

View File

@ -67,34 +67,7 @@
android:label="StoryViewerFragment" android:label="StoryViewerFragment"
tools:layout="@layout/fragment_story_viewer"> tools:layout="@layout/fragment_story_viewer">
<argument <argument
android:name="feedStoryIndex" android:name="options"
app:argType="integer" app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
app:nullable="false" />
<argument
android:name="highlight"
app:argType="string"
app:nullable="true" />
<argument
android:name="isHashtag"
app:argType="boolean" />
<argument
android:name="isLoc"
app:argType="boolean" />
<argument
android:name="profileId"
app:argType="string"
app:nullable="true" />
<argument
android:name="username"
app:argType="string"
app:nullable="true" />
<argument
android:name="isArchive"
app:argType="boolean"
app:nullable="false" />
<argument
android:name="isNotification"
app:argType="boolean"
app:nullable="false" />
</fragment> </fragment>
</navigation> </navigation>

View File

@ -153,61 +153,37 @@
android:name="awais.instagrabber.fragments.StoryViewerFragment" android:name="awais.instagrabber.fragments.StoryViewerFragment"
android:label="StoryViewerFragment" android:label="StoryViewerFragment"
tools:layout="@layout/fragment_story_viewer"> tools:layout="@layout/fragment_story_viewer">
<argument <argument
android:name="feedStoryIndex" android:name="options"
app:argType="integer" app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
app:nullable="false" />
<argument
android:name="highlight"
app:argType="string"
app:nullable="true" />
<argument
android:name="isHashtag"
app:argType="boolean" />
<argument
android:name="isLoc"
app:argType="boolean" />
<argument
android:name="profileId"
app:argType="long" />
<argument
android:name="username"
app:argType="string"
app:nullable="true" />
<argument
android:name="isArchive"
app:argType="boolean"
app:nullable="false" />
<argument
android:name="isNotification"
app:argType="boolean"
app:nullable="false" />
</fragment>
<fragment
android:id="@+id/directMessagesThreadFragment"
android:name="awais.instagrabber.fragments.directmessages.DirectMessageThreadFragment"
android:label="DirectMessagesThreadFragment"
tools:layout="@layout/fragment_direct_messages_thread">
<argument
android:name="threadId"
app:argType="string" />
<argument
android:name="title"
app:argType="string" />
<action
android:id="@+id/action_dMThreadFragment_to_dMSettingsFragment"
app:destination="@id/directMessagesSettingsFragment" />
</fragment>
<fragment
android:id="@+id/directMessagesSettingsFragment"
android:name="awais.instagrabber.fragments.directmessages.DirectMessageSettingsFragment"
android:label="DirectMessagesSettingsFragment"
tools:layout="@layout/fragment_direct_messages_settings">
<argument
android:name="threadId"
app:argType="string" />
<argument
android:name="title"
app:argType="string" />
</fragment> </fragment>
<!--<fragment-->
<!-- android:id="@+id/directMessagesThreadFragment"-->
<!-- android:name="awais.instagrabber.fragments.directmessages.DirectMessageThreadFragment"-->
<!-- android:label="DirectMessagesThreadFragment"-->
<!-- tools:layout="@layout/fragment_direct_messages_thread">-->
<!-- <argument-->
<!-- android:name="threadId"-->
<!-- app:argType="string" />-->
<!-- <argument-->
<!-- android:name="title"-->
<!-- app:argType="string" />-->
<!-- <action-->
<!-- android:id="@+id/action_dMThreadFragment_to_dMSettingsFragment"-->
<!-- app:destination="@id/directMessagesSettingsFragment" />-->
<!--</fragment>-->
<!--<fragment-->
<!-- android:id="@+id/directMessagesSettingsFragment"-->
<!-- android:name="awais.instagrabber.fragments.directmessages.DirectMessageSettingsFragment"-->
<!-- android:label="@string/details"-->
<!-- tools:layout="@layout/fragment_direct_messages_settings">-->
<!-- <argument-->
<!-- android:name="threadId"-->
<!-- app:argType="string"-->
<!-- app:nullable="false"/>-->
<!-- <argument-->
<!-- android:name="title"-->
<!-- app:argType="string" />-->
<!--</fragment>-->
</navigation> </navigation>

View File

@ -43,34 +43,7 @@
android:label="StoryViewerFragment" android:label="StoryViewerFragment"
tools:layout="@layout/fragment_story_viewer"> tools:layout="@layout/fragment_story_viewer">
<argument <argument
android:name="feedStoryIndex" android:name="options"
app:argType="integer" app:argType="awais.instagrabber.repositories.requests.StoryViewerOptions" />
app:nullable="false" />
<argument
android:name="highlight"
app:argType="string"
app:nullable="true" />
<argument
android:name="isHashtag"
app:argType="boolean" />
<argument
android:name="isLoc"
app:argType="boolean" />
<argument
android:name="profileId"
app:argType="string"
app:nullable="true" />
<argument
android:name="username"
app:argType="string"
app:nullable="true" />
<argument
android:name="isArchive"
app:argType="boolean"
app:nullable="false" />
<argument
android:name="isNotification"
app:argType="boolean"
app:nullable="false" />
</fragment> </fragment>
</navigation> </navigation>

View File

@ -28,21 +28,25 @@
</fragment> </fragment>
<!--<action <!--<action-->
android:id="@+id/action_global_user_search" <!-- android:id="@+id/action_global_user_search"-->
app:destination="@id/user_search"> <!-- app:destination="@id/user_search_nav_graph">-->
<argument <!-- <argument-->
android:name="multiple" <!-- android:name="multiple"-->
app:argType="boolean" /> <!-- app:argType="boolean" />-->
<argument <!-- <argument-->
android:name="title" <!-- android:name="title"-->
app:argType="string" <!-- app:argType="string"-->
app:nullable="true" /> <!-- app:nullable="true" />-->
<argument <!-- <argument-->
android:name="action_label" <!-- android:name="action_label"-->
app:argType="string" <!-- app:argType="string"-->
app:nullable="true" /> <!-- app:nullable="true" />-->
</action>-->
<!-- <argument-->
<!-- android:name="hideUserIds"-->
<!-- app:argType="long[]" />-->
<!--</action>-->
</navigation> </navigation>

View File

@ -319,7 +319,7 @@
<string name="save_unsuccessful">Save unsuccessful</string> <string name="save_unsuccessful">Save unsuccessful</string>
<string name="save_remove_unsuccessful">Remove unsuccessful</string> <string name="save_remove_unsuccessful">Remove unsuccessful</string>
<string name="downloading">Downloading…</string> <string name="downloading">Downloading…</string>
<string name="downloader_downloading_child">Download item %d of %d</string> <string name="downloader_downloading_child">Download item %1$d of %2$d</string>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="comment">Comment</string> <string name="comment">Comment</string>
<string name="layout">Layout</string> <string name="layout">Layout</string>

View File

@ -0,0 +1,3 @@
Preliminary support for live videos, as well as bug fixes.
For details see https://github.com/austinhuang0131/barinsta/releases/tag/v19.0.5