diff --git a/.all-contributorsrc b/.all-contributorsrc index 34959778..ac44348d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -42,6 +42,15 @@ "bug" ] }, + { + "login": "MeLlamoPablo", + "name": "Pablo RodrΓ­guez", + "avatar_url": "https://avatars.githubusercontent.com/u/11708035?v=4", + "profile": "https://github.com/MeLlamoPablo", + "contributions": [ + "code" + ] + }, { "login": "AwaisKing", "name": "AWAiS", @@ -55,7 +64,7 @@ "login": "snajdovski", "name": "Stefan Najdovski", "avatar_url": "https://avatars2.githubusercontent.com/u/42580385?v=4", - "profile": "https://stefannajdovski.com/", + "profile": "https://snajdovski.github.io", "contributions": [ "design", "translation" diff --git a/README.md b/README.md index 77e3e1dc..d3671d60 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) [![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE) [![GitHub stars](https://img.shields.io/github/stars/austinhuang0131/instagrabber.svg?style=social&label=Star)](https://GitHub.com/austinhuang0131/barinsta/stargazers/) -[![All Contributors](https://img.shields.io/badge/all_contributors-37-orange.svg)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-38-orange.svg)](#contributors) Instagram client; previously known as InstaGrabber. @@ -57,51 +57,52 @@ Prominent contributors are listed here in the [all-contributors](https://allcont
Austin Huang

πŸ’» πŸ“– πŸ’¬ 🌍 πŸ€”
Ammar Githam

πŸ’» 🎨 πŸ€” 🚧 πŸ’¬
Anderson Mesquita

πŸ’» πŸ› +
Pablo RodrΓ­guez

πŸ’»
AWAiS

πŸ’» -
Stefan Najdovski

🎨 🌍 -
CrazyMarvin

πŸ’΅ +
Stefan Najdovski

🎨 🌍 +
CrazyMarvin

πŸ’΅
Kevin Thomas

πŸ’΅
Shadowspear123

πŸ“ πŸ› πŸ€” πŸ’¬
Ricardo

πŸ› 🌍
Airikr

πŸ€” πŸ’¬
Akrai

πŸ€” 🌍 -
avtkal

🌍 +
avtkal

🌍
CΓ©zar Augusto

🌍
Dimitris T

🌍
farzadx

🌍
Fatih AydΔ±n

🌍
fouze555

🌍 -
Galang23

🌍 +
Galang23

🌍
Initdebugs

🌍
Jakub Janek

🌍
GenosseFlosse

🌍
kernoeb

🌍
MoaufmKlo

🌍 -
nalinalini

🌍 +
nalinalini

🌍
peterge1998

🌍
PierreM0

🌍
RAMAR-RAR

🌍
rohang02

🌍
retiolus

🌍 -
rikishi0071

🌍 +
rikishi0071

🌍
Alexey Peschany

🌍
Still Hsu

🌍
Ten_Lego

🌍
wagnim

🌍
wokija

🌍 -
ysakamoto

🌍 +
ysakamoto

🌍
ZDVokoun

🌍 @@ -131,7 +132,7 @@ This app's predecessor, InstaGrabber, was originally made by [@AwaisKing](https: You should have received a copy of the GNU General Public License along with this program. If not, see . -Logo by [Stefan Najdovski](https://stefannajdovski.com/). Used under license. +Logo by [Stefan Najdovski](https://snajdovski.github.io/). Used under license. [![Snyk Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/austinhuang0131/instagrabber)](https://snyk.io/test/github/austinhuang0131/barinsta) [![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/austinhuang0131/instagrabber)](https://lgtm.com/projects/g/austinhuang0131/barinsta) diff --git a/app/build.gradle b/app/build.gradle index 785b9daf..222f72ba 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { minSdkVersion 21 targetSdkVersion 29 - versionCode 58 - versionName '19.1.0-a1' + versionCode 59 + versionName '19.1.0-a2' multiDexEnabled true diff --git a/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java index e912878f..394c2374 100644 --- a/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java @@ -14,13 +14,11 @@ import java.util.List; import awais.instagrabber.adapters.viewholder.NotificationViewHolder; import awais.instagrabber.databinding.ItemNotificationBinding; -import awais.instagrabber.interfaces.MentionClickListener; import awais.instagrabber.models.NotificationModel; import awais.instagrabber.models.enums.NotificationType; public final class NotificationsAdapter extends ListAdapter { private final OnNotificationClickListener notificationClickListener; - private final MentionClickListener mentionClickListener; private static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { @Override @@ -34,11 +32,9 @@ public final class NotificationsAdapter extends ListAdapter { - if (longClickListener != null) longClickListener.onLongClick(this); - }; - - public RamboTextView(final Context context) { - super(context); - } - - public RamboTextView(final Context context, final AttributeSet attrs) { - super(context, attrs); - } - - public RamboTextView(final Context context, final AttributeSet attrs, final int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public void setMentionClickListener(final MentionClickListener mentionClickListener) { - this.mentionClickListener = mentionClickListener; - } - - // public void setCaptionIsExpandable(final boolean isExpandable) { - // this.isExpandable = isExpandable; - // } - - // public void setCaptionIsExpanded(final boolean isExpanded) { - // this.isExpanded = isExpanded; - // } - - @Override - public void setOnLongClickListener(@Nullable final OnLongClickListener l) { - if (l == null) return; - this.longClickListener = l; - } - - @SuppressLint("ClickableViewAccessibility") - @Override - public boolean onTouchEvent(final MotionEvent event) { - final CharSequence text = getText(); - if (text instanceof SpannableString || text instanceof SpannableStringBuilder) { - final Spannable spanText = (Spannable) text; - final ClickableSpan clickableSpanUnderTouch = findClickableSpanUnderTouch(this, spanText, event); - - final int action = event.getAction(); - - if (action == MotionEvent.ACTION_DOWN) clickableSpanUnderTouchOnActionDown = clickableSpanUnderTouch; - final boolean touchStartedOverAClickableSpan = clickableSpanUnderTouchOnActionDown != null; - final boolean isURLSpan = clickableSpanUnderTouch instanceof URLSpan; - - // feed view caption hacks - // if (isExpandable && !touchStartedOverAClickableSpan) - // return !isExpanded | super.onTouchEvent(event); // short operator, because we want two shits to work - - // final Object tag = getTag(); - // final FeedModel feedModel = tag instanceof FeedModel ? (FeedModel) tag : null; - - switch (action) { - case MotionEvent.ACTION_DOWN: - final int longPressTimeout = ViewConfiguration.getLongPressTimeout(); - handler.postDelayed(longPressRunnable, longPressTimeout); - // if (feedModel != null) feedModel.setMentionClicked(false); - if (clickableSpanUnderTouch != null) { - highlightUrl(clickableSpanUnderTouch, spanText); - } - return super.onTouchEvent(event); - case MotionEvent.ACTION_UP: - handler.removeCallbacks(longPressRunnable); - if (touchStartedOverAClickableSpan && clickableSpanUnderTouch == clickableSpanUnderTouchOnActionDown) { - dispatchUrlClick(spanText, clickableSpanUnderTouch); - // if (feedModel != null) feedModel.setMentionClicked(true); - } - cleanupOnTouchUp(spanText); - return super.onTouchEvent(event); - case MotionEvent.ACTION_MOVE: - // handler.removeCallbacks(longPressRunnable); - // if (feedModel != null) feedModel.setMentionClicked(false); - if (clickableSpanUnderTouch != null) highlightUrl(clickableSpanUnderTouch, spanText); - else removeUrlHighlightColor(spanText); - return super.onTouchEvent(event); - case MotionEvent.ACTION_CANCEL: - handler.removeCallbacks(longPressRunnable); - // if (feedModel != null) feedModel.setMentionClicked(false); - cleanupOnTouchUp(spanText); - return super.onTouchEvent(event); - } - } - - return super.onTouchEvent(event); - } - - protected void dispatchUrlClick(final Spanned s, final ClickableSpan clickableSpan) { - if (mentionClickListener != null) { - final int spanStart = s.getSpanStart(clickableSpan); - final boolean ishHashtag = s.charAt(spanStart) == '#'; - - final int start = ishHashtag || s.charAt(spanStart) != '@' ? spanStart : spanStart + 1; - - CharSequence subSequence = s.subSequence(start, s.getSpanEnd(clickableSpan)); - - // for feed ellipsize - final int indexOfEllipsize = TextUtils.indexOfChar(subSequence, '…', 0); - if (indexOfEllipsize != -1) - subSequence = subSequence.subSequence(0, indexOfEllipsize - 1); - - mentionClickListener.onClick(this, subSequence.toString(), ishHashtag, false); - } - } - - protected void highlightUrl(final ClickableSpan clickableSpan, final Spannable text) { - if (!isUrlHighlighted) { - isUrlHighlighted = true; - - final int spanStart = text.getSpanStart(clickableSpan); - final int spanEnd = text.getSpanEnd(clickableSpan); - final BackgroundColorSpan highlightSpan = new BackgroundColorSpan(getHighlightColor()); - text.setSpan(highlightSpan, spanStart, spanEnd, Spannable.SPAN_INCLUSIVE_INCLUSIVE); - setTag(highlightBackgroundSpanKey, highlightSpan); - Selection.setSelection(text, spanStart, spanEnd); - } - } - - protected void removeUrlHighlightColor(final Spannable text) { - if (isUrlHighlighted) { - isUrlHighlighted = false; - - final BackgroundColorSpan highlightSpan = (BackgroundColorSpan) getTag(highlightBackgroundSpanKey); - text.removeSpan(highlightSpan); - - Selection.removeSelection(text); - } - } - - private void cleanupOnTouchUp(final Spannable text) { - clickableSpanUnderTouchOnActionDown = null; - removeUrlHighlightColor(text); - } - - @Nullable - private static ClickableSpan findClickableSpanUnderTouch(@NonNull final TextView textView, - final Spanned text, - @NonNull final MotionEvent event) { - final int touchX = (int) (event.getX() - textView.getTotalPaddingLeft() + textView.getScrollX()); - final int touchY = (int) (event.getY() - textView.getTotalPaddingTop() + textView.getScrollY()); - - final Layout layout = textView.getLayout(); - final int touchedLine = layout.getLineForVertical(touchY); - final int touchOffset = layout.getOffsetForHorizontal(touchedLine, touchX); - - touchedLineBounds.left = layout.getLineLeft(touchedLine); - touchedLineBounds.top = layout.getLineTop(touchedLine); - touchedLineBounds.right = layout.getLineWidth(touchedLine) + touchedLineBounds.left; - touchedLineBounds.bottom = layout.getLineBottom(touchedLine); - - if (touchedLineBounds.contains(touchX, touchY)) { - final Object[] spans = text.getSpans(touchOffset, touchOffset, ClickableSpan.class); - for (final Object span : spans) - if (span instanceof ClickableSpan) return (ClickableSpan) span; - } - - return null; - } - - public boolean isCaptionExpanded() { - return isExpanded; - } -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java index 34dc5922..e272cb8f 100644 --- a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java @@ -33,7 +33,6 @@ import awais.instagrabber.asyncs.NotificationsFetcher; import awais.instagrabber.databinding.FragmentNotificationsViewerBinding; import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections; import awais.instagrabber.interfaces.FetchListener; -import awais.instagrabber.interfaces.MentionClickListener; import awais.instagrabber.models.NotificationModel; import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.repositories.requests.StoryViewerOptions; @@ -145,33 +144,8 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe } }); return; - } else if (model.getType() == NotificationType.RESPONDED_STORY) { - final NavDirections action = NotificationsViewerFragmentDirections - .actionNotificationsViewerFragmentToStoryViewerFragment(StoryViewerOptions.forStory(model.getPostId(), - model.getUsername())); - NavHostFragment.findNavController(NotificationsViewerFragment.this).navigate(action); - return; } - final AlertDialog alertDialog = new AlertDialog.Builder(context) - .setCancelable(false) - .setView(R.layout.dialog_opening_post) - .create(); - alertDialog.show(); - mediaService.fetch(model.getPostId(), new ServiceCallback() { - @Override - public void onSuccess(final Media feedModel) { - final PostViewV2Fragment fragment = PostViewV2Fragment - .builder(feedModel) - .build(); - fragment.setOnShowListener(dialog1 -> alertDialog.dismiss()); - fragment.show(getChildFragmentManager(), "post_view"); - } - - @Override - public void onFailure(final Throwable t) { - Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - } - }); + clickListener.onPreviewClick(model); break; case 2: friendshipService.ignore(model.getUserId(), new ServiceCallback() { @@ -196,16 +170,6 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe } } }; - private final MentionClickListener mentionClickListener = (view, text, isHashtag, isLocation) -> { - if (getContext() == null) return; - new AlertDialog.Builder(getContext()) - .setTitle(text) - .setMessage(isHashtag ? R.string.comment_view_mention_hash_search - : R.string.comment_view_mention_user_search) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, (dialog, which) -> openProfile(text)) - .show(); - }; @Override public void onCreate(@Nullable final Bundle savedInstanceState) { @@ -250,7 +214,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe CookieUtils.setupCookies(settingsHelper.getString(Constants.COOKIE)); binding.swipeRefreshLayout.setOnRefreshListener(this); notificationViewModel = new ViewModelProvider(this).get(NotificationViewModel.class); - final NotificationsAdapter adapter = new NotificationsAdapter(clickListener, mentionClickListener); + final NotificationsAdapter adapter = new NotificationsAdapter(clickListener); binding.rvComments.setLayoutManager(new LinearLayoutManager(context)); binding.rvComments.setAdapter(adapter); notificationViewModel.getList().observe(getViewLifecycleOwner(), adapter::submitList); diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index 74bee61d..3111584d 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -817,7 +817,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im } private void setupCaption(final Caption caption) { - if (caption == null) { + if (caption == null || TextUtils.isEmpty(caption.getText())) { binding.caption.setVisibility(View.GONE); binding.translate.setVisibility(View.GONE); binding.captionToggle.setVisibility(View.GONE); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 856a2164..f045dcd4 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -709,7 +709,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe .trim())); profileDetailsBinding.mainBiography .addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim())); - profileDetailsBinding.mainBiography.setOnClickListener(v -> { + profileDetailsBinding.mainBiography.setOnLongClickListener(v -> { String[] commentDialogList; if (!TextUtils.isEmpty(cookie)) { commentDialogList = new String[]{ @@ -753,9 +753,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe }) .setNegativeButton(R.string.cancel, null) .show(); - }); - profileDetailsBinding.mainBiography.setOnLongClickListener(v -> { - Utils.copyText(context, biography); return true; }); } diff --git a/app/src/main/java/awais/instagrabber/interfaces/MentionClickListener.java b/app/src/main/java/awais/instagrabber/interfaces/MentionClickListener.java deleted file mode 100755 index c3b7c8b7..00000000 --- a/app/src/main/java/awais/instagrabber/interfaces/MentionClickListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package awais.instagrabber.interfaces; - -import awais.instagrabber.customviews.RamboTextView; - -@Deprecated -public interface MentionClickListener { - void onClick(final RamboTextView view, - final String text, - final boolean isHashtag, - final boolean isLocation); -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/models/enums/NotificationType.java b/app/src/main/java/awais/instagrabber/models/enums/NotificationType.java index 7e39443b..28a95153 100755 --- a/app/src/main/java/awais/instagrabber/models/enums/NotificationType.java +++ b/app/src/main/java/awais/instagrabber/models/enums/NotificationType.java @@ -9,7 +9,7 @@ public enum NotificationType implements Serializable { LIKE("GraphLikeAggregatedStory"), FOLLOW("GraphFollowAggregatedStory"), COMMENT("GraphCommentMediaStory"), - MENTION("GraphMentionStory"), + COMMENT_MENTION("GraphMentionStory"), TAGGED("GraphUserTaggedStory"), // app story_type COMMENT_LIKE("13"), diff --git a/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/StoryReplyBroadcastOptions.java b/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/StoryReplyBroadcastOptions.java index 3ab57d14..7fe3f8d0 100644 --- a/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/StoryReplyBroadcastOptions.java +++ b/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/StoryReplyBroadcastOptions.java @@ -17,7 +17,7 @@ public class StoryReplyBroadcastOptions extends BroadcastOptions { final String reelId) throws UnsupportedEncodingException { super(clientContext, threadIdOrUserIds, BroadcastItemType.REELSHARE); - this.text = TextUtils.encode(text); + this.text = text; this.mediaId = mediaId; this.reelId = reelId; // or user id, usually same } diff --git a/app/src/main/java/awais/instagrabber/utils/TextUtils.java b/app/src/main/java/awais/instagrabber/utils/TextUtils.java index 95e82599..e26bd8cf 100644 --- a/app/src/main/java/awais/instagrabber/utils/TextUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/TextUtils.java @@ -104,18 +104,6 @@ public final class TextUtils { return (int) ((d2 - d1) / DateUtils.DAY_IN_MILLIS); } - @NonNull - public static String encode(final String text) throws UnsupportedEncodingException { - return URLEncoder.encode(text, "UTF-8") - .replaceAll("\\+", "%20") - .replaceAll("%21", "!") - .replaceAll("%27", "'") - .replaceAll("%28", "(") - .replaceAll("%29", ")") - .replaceAll("%7E", "~") - .replaceAll("%0A", "\n"); - } - public static List extractUrls(final String text) { if (isEmpty(text)) return Collections.emptyList(); final Matcher matcher = Patterns.WEB_URL.matcher(text); diff --git a/app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java b/app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java index 63c1f0a1..b2d69683 100644 --- a/app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java @@ -18,8 +18,8 @@ public class UserAgentUtils { "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15" }; // use APKpure, assume x86 - private static final String igVersion = "175.1.0.25.119"; - private static final String igVersionCode = "273907115"; + private static final String igVersion = "177.0.0.30.119"; + private static final String igVersionCode = "276028050"; // only pick the ones that has width 1440 for maximum download quality public static final String[] devices = { // https://github.com/dilame/instagram-private-api/blob/master/src/samples/devices.json diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index d8c83313..2eca1769 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -131,7 +131,7 @@ public class NewsService extends BaseService { user.getLong("id"), user.getString("username"), user.getString("profile_pic_url"), - data.has("media") ? data.getJSONObject("media").getLong("id") : 0, + !data.isNull("media") ? Long.valueOf(data.getJSONObject("media").getString("id").split("_")[0]) : 0, data.has("media") ? data.getJSONObject("media").getString("thumbnail_src") : null, notificationType)); } diff --git a/app/src/main/res/layout/item_notification.xml b/app/src/main/res/layout/item_notification.xml index 1ec1c187..f17f2c6c 100644 --- a/app/src/main/res/layout/item_notification.xml +++ b/app/src/main/res/layout/item_notification.xml @@ -45,11 +45,11 @@ app:layout_constraintTop_toTopOf="parent" tools:text="username" /> - - - + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dd7decc5..664e8045 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,8 +12,7 @@ Error copying text Copied to clipboard! Report - Password (Max 32 chars) - Set a password (max 32 chars) + Protect file with password Password OK Yes @@ -319,9 +318,9 @@ Locations Unknown Removed from Favourites - Backup & Restore User Settings - Back up app settings, account login information, and/or favorites data to a plain text or encrypted backup file for later restoration. - If you\'re backing up login info, treat the file as confidential: Keep them somewhere safe! + Backup & Restore + Backup Barinsta app settings, account login data, and/or favorites to a plain text or encrypted backup file for later restoration. + If you\'re backing up account login data, treat the file as confidential and keep it somewhere safe! Create new backup file Restore from existing backup file File: