Browse Source

regular maintenance

1. fix notification can't open post + remove duplicate code
2. optimize bio (long)click mechanism
3. remove the old deprecated RamboTextView and its MentionClickListener
renovate/org.robolectric-robolectric-4.x
Austin Huang 4 years ago
parent
commit
de86668caf
No known key found for this signature in database GPG Key ID: 84C23AA04587A91F
  1. 4
      app/build.gradle
  2. 6
      app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java
  3. 2
      app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java
  4. 205
      app/src/main/java/awais/instagrabber/customviews/RamboTextView.java
  5. 40
      app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java
  6. 5
      app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java
  7. 11
      app/src/main/java/awais/instagrabber/interfaces/MentionClickListener.java
  8. 2
      app/src/main/java/awais/instagrabber/models/enums/NotificationType.java
  9. 4
      app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java
  10. 2
      app/src/main/java/awais/instagrabber/webservices/NewsService.java
  11. 8
      app/src/main/res/layout/item_notification.xml
  12. 13
      app/src/main/res/layout/layout_location_details.xml

4
app/build.gradle

@ -10,8 +10,8 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 58
versionName '19.1.0-a1'
versionCode 59
versionName '19.1.0-a2'
multiDexEnabled true multiDexEnabled true

6
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.adapters.viewholder.NotificationViewHolder;
import awais.instagrabber.databinding.ItemNotificationBinding; import awais.instagrabber.databinding.ItemNotificationBinding;
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;
public final class NotificationsAdapter extends ListAdapter<NotificationModel, NotificationViewHolder> { public final class NotificationsAdapter extends ListAdapter<NotificationModel, NotificationViewHolder> {
private final OnNotificationClickListener notificationClickListener; private final OnNotificationClickListener notificationClickListener;
private final MentionClickListener mentionClickListener;
private static final DiffUtil.ItemCallback<NotificationModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<NotificationModel>() { private static final DiffUtil.ItemCallback<NotificationModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<NotificationModel>() {
@Override @Override
@ -34,11 +32,9 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
} }
}; };
public NotificationsAdapter(final OnNotificationClickListener notificationClickListener,
final MentionClickListener mentionClickListener) {
public NotificationsAdapter(final OnNotificationClickListener notificationClickListener) {
super(DIFF_CALLBACK); super(DIFF_CALLBACK);
this.notificationClickListener = notificationClickListener; this.notificationClickListener = notificationClickListener;
this.mentionClickListener = mentionClickListener;
} }
@NonNull @NonNull

2
app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java

@ -32,7 +32,7 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
text = R.string.comment_notif; text = R.string.comment_notif;
subtext = model.getText(); subtext = model.getText();
break; break;
case MENTION:
case COMMENT_MENTION:
text = R.string.mention_notif; text = R.string.mention_notif;
subtext = model.getText(); subtext = model.getText();
break; break;

205
app/src/main/java/awais/instagrabber/customviews/RamboTextView.java

@ -1,205 +0,0 @@
package awais.instagrabber.customviews;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.RectF;
import android.os.Handler;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.BackgroundColorSpan;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
import awais.instagrabber.R;
import awais.instagrabber.interfaces.MentionClickListener;
import awais.instagrabber.utils.TextUtils;
@Deprecated
public final class RamboTextView extends AppCompatTextView {
private static final String TAG = "RamboTextView";
private static final int highlightBackgroundSpanKey = R.id.tvComment;
private static final RectF touchedLineBounds = new RectF();
private ClickableSpan clickableSpanUnderTouchOnActionDown;
private MentionClickListener mentionClickListener;
private boolean isUrlHighlighted;
private boolean isExpanded;
private OnLongClickListener longClickListener;
private final Handler handler = new Handler();
private final Runnable longPressRunnable = () -> {
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;
}
}

40
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.databinding.FragmentNotificationsViewerBinding;
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections; import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.interfaces.FetchListener;
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.requests.StoryViewerOptions;
@ -145,33 +144,8 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
} }
}); });
return; 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<Media>() {
@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; break;
case 2: case 2:
friendshipService.ignore(model.getUserId(), new ServiceCallback<FriendshipChangeResponse>() { friendshipService.ignore(model.getUserId(), new ServiceCallback<FriendshipChangeResponse>() {
@ -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 @Override
public void onCreate(@Nullable final Bundle savedInstanceState) { 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)); CookieUtils.setupCookies(settingsHelper.getString(Constants.COOKIE));
binding.swipeRefreshLayout.setOnRefreshListener(this); binding.swipeRefreshLayout.setOnRefreshListener(this);
notificationViewModel = new ViewModelProvider(this).get(NotificationViewModel.class); 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.setLayoutManager(new LinearLayoutManager(context));
binding.rvComments.setAdapter(adapter); binding.rvComments.setAdapter(adapter);
notificationViewModel.getList().observe(getViewLifecycleOwner(), adapter::submitList); notificationViewModel.getList().observe(getViewLifecycleOwner(), adapter::submitList);

5
app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java

@ -710,7 +710,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
.trim())); .trim()));
profileDetailsBinding.mainBiography profileDetailsBinding.mainBiography
.addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim())); .addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim()));
profileDetailsBinding.mainBiography.setOnClickListener(v -> {
profileDetailsBinding.mainBiography.setOnLongClickListener(v -> {
String[] commentDialogList; String[] commentDialogList;
if (!TextUtils.isEmpty(cookie)) { if (!TextUtils.isEmpty(cookie)) {
commentDialogList = new String[]{ commentDialogList = new String[]{
@ -754,9 +754,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
}) })
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show(); .show();
});
profileDetailsBinding.mainBiography.setOnLongClickListener(v -> {
Utils.copyText(context, biography);
return true; return true;
}); });
} }

11
app/src/main/java/awais/instagrabber/interfaces/MentionClickListener.java

@ -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);
}

2
app/src/main/java/awais/instagrabber/models/enums/NotificationType.java

@ -9,7 +9,7 @@ public enum NotificationType implements Serializable {
LIKE("GraphLikeAggregatedStory"), LIKE("GraphLikeAggregatedStory"),
FOLLOW("GraphFollowAggregatedStory"), FOLLOW("GraphFollowAggregatedStory"),
COMMENT("GraphCommentMediaStory"), COMMENT("GraphCommentMediaStory"),
MENTION("GraphMentionStory"),
COMMENT_MENTION("GraphMentionStory"),
TAGGED("GraphUserTaggedStory"), TAGGED("GraphUserTaggedStory"),
// app story_type // app story_type
COMMENT_LIKE("13"), COMMENT_LIKE("13"),

4
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" "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 // 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 // only pick the ones that has width 1440 for maximum download quality
public static final String[] devices = { public static final String[] devices = {
// https://github.com/dilame/instagram-private-api/blob/master/src/samples/devices.json // https://github.com/dilame/instagram-private-api/blob/master/src/samples/devices.json

2
app/src/main/java/awais/instagrabber/webservices/NewsService.java

@ -131,7 +131,7 @@ 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.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, data.has("media") ? data.getJSONObject("media").getString("thumbnail_src") : null,
notificationType)); notificationType));
} }

8
app/src/main/res/layout/item_notification.xml

@ -45,11 +45,11 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="username" /> tools:text="username" />
<awais.instagrabber.customviews.RamboTextView
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvComment" android:id="@+id/tvComment"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:linksClickable="true"
android:linksClickable="false"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
@ -62,13 +62,13 @@
app:layout_constraintTop_toBottomOf="@id/tvUsername" app:layout_constraintTop_toBottomOf="@id/tvUsername"
tools:text="comment comment comment comment comment comment comment comment comment comment comment comment comment " /> tools:text="comment comment comment comment comment comment comment comment comment comment comment comment comment " />
<awais.instagrabber.customviews.RamboTextView
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvSubComment" android:id="@+id/tvSubComment"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:autoLink="web|email" android:autoLink="web|email"
android:ellipsize="end" android:ellipsize="end"
android:linksClickable="true"
android:linksClickable="false"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"

13
app/src/main/res/layout/layout_location_details.xml

@ -96,16 +96,13 @@
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" />
<awais.instagrabber.customviews.RamboTextView
<awais.instagrabber.customviews.RamboTextViewV2
android:id="@+id/locationUrl" android:id="@+id/locationUrl"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/locationBiography"
android:layout_below="@id/mainBiography"
android:ellipsize="marquee" android:ellipsize="marquee"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingEnd="8dp"
android:paddingRight="8dp"
android:padding="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
@ -113,5 +110,7 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/locationBiography" app:layout_constraintTop_toBottomOf="@id/locationBiography"
tools:text="https://austinhuang.me/" tools:text="https://austinhuang.me/"
tools:textColor="@android:color/holo_blue_dark"
tools:visibility="visible" /> tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
Loading…
Cancel
Save