diff --git a/app/build.gradle b/app/build.gradle index b0bfcc64..017529b7 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -169,6 +169,8 @@ dependencies { implementation 'org.apache.commons:commons-imaging:1.0-alpha2' + implementation 'com.github.skydoves:balloon:1.3.4' + implementation 'com.github.ammargitham:AutoLinkTextViewV2:v3.1.0' implementation 'com.github.ammargitham:uCrop:2.3-native-beta-2' implementation 'com.github.ammargitham:android-gpuimage:2.1.1-beta4' diff --git a/app/src/main/java/awais/instagrabber/customviews/FormattedNumberTextView.java b/app/src/main/java/awais/instagrabber/customviews/FormattedNumberTextView.java index 77696e17..99c2a216 100644 --- a/app/src/main/java/awais/instagrabber/customviews/FormattedNumberTextView.java +++ b/app/src/main/java/awais/instagrabber/customviews/FormattedNumberTextView.java @@ -8,7 +8,10 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatTextView; +import androidx.transition.ChangeBounds; +import androidx.transition.Transition; import androidx.transition.TransitionManager; +import androidx.transition.TransitionSet; import java.time.Duration; @@ -17,16 +20,23 @@ import awais.instagrabber.utils.NumberUtils; public class FormattedNumberTextView extends AppCompatTextView { private static final String TAG = FormattedNumberTextView.class.getSimpleName(); - private static final ChangeText TRANSITION = new ChangeText().setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN); + private static final Transition TRANSITION; private long number = Long.MIN_VALUE; private boolean showAbbreviation = true; - private boolean animateChanges = true; + private boolean animateChanges = false; private boolean toggleOnClick = true; private boolean autoToggleToAbbreviation = true; private long autoToggleTimeoutMs = Duration.ofSeconds(2).toMillis(); private boolean initDone = false; + static { + final TransitionSet transitionSet = new TransitionSet(); + final ChangeText changeText = new ChangeText().setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN); + transitionSet.addTransition(changeText).addTransition(new ChangeBounds()); + TRANSITION = transitionSet; + } + public FormattedNumberTextView(@NonNull final Context context) { super(context); @@ -152,6 +162,4 @@ public class FormattedNumberTextView extends AppCompatTextView { } }); } - - } diff --git a/app/src/main/java/awais/instagrabber/customviews/Tooltip.java b/app/src/main/java/awais/instagrabber/customviews/Tooltip.java index 91a07e42..42bbbb6e 100644 --- a/app/src/main/java/awais/instagrabber/customviews/Tooltip.java +++ b/app/src/main/java/awais/instagrabber/customviews/Tooltip.java @@ -9,20 +9,20 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewPropertyAnimator; +import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatTextView; import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.ViewUtils; - public class Tooltip extends AppCompatTextView { private View anchor; private ViewPropertyAnimator animator; private boolean showing; - private final AppExecutors appExecutors; + private final AppExecutors appExecutors = AppExecutors.getInstance(); private final Runnable dismissRunnable = () -> { animator = animate().alpha(0).setListener(new AnimatorListenerAdapter() { @Override @@ -33,7 +33,7 @@ public class Tooltip extends AppCompatTextView { animator.start(); }; - public Tooltip(Context context, ViewGroup parentView, int backgroundColor, int textColor) { + public Tooltip(@NonNull Context context, @NonNull ViewGroup parentView, int backgroundColor, int textColor) { super(context); setBackgroundDrawable(ViewUtils.createRoundRectDrawable(Utils.convertDpToPx(3), backgroundColor)); setTextColor(textColor); @@ -43,7 +43,6 @@ public class Tooltip extends AppCompatTextView { parentView.addView(this, ViewUtils.createFrame( ViewUtils.WRAP_CONTENT, ViewUtils.WRAP_CONTENT, Gravity.START | Gravity.TOP, 5, 0, 5, 3)); setVisibility(GONE); - appExecutors = AppExecutors.getInstance(); } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index cd2d845f..fc3c4a7e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.content.res.Resources; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; @@ -45,6 +46,14 @@ import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; +import com.skydoves.balloon.ArrowOrientation; +import com.skydoves.balloon.ArrowPositionRules; +import com.skydoves.balloon.Balloon; +import com.skydoves.balloon.BalloonAnimation; +import com.skydoves.balloon.BalloonHighlightAnimation; +import com.skydoves.balloon.BalloonSizeSpec; +import com.skydoves.balloon.overlay.BalloonOverlayAnimation; +import com.skydoves.balloon.overlay.BalloonOverlayCircle; import java.io.Serializable; import java.util.List; @@ -81,6 +90,7 @@ import awais.instagrabber.viewmodels.PostViewV2ViewModel; import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; +import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_SHOWN_COUNT_TOOLTIP; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.Utils.getAttrValue; import static awais.instagrabber.utils.Utils.settingsHelper; @@ -278,17 +288,16 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme bottom.date.setText(date); })); viewModel.getLikeCount().observe(getViewLifecycleOwner(), count -> { - bottom.likesCount.setAnimateChanges(false); bottom.likesCount.setNumber(getSafeCount(count)); - // final String likesString = getResources().getQuantityString(R.plurals.likes_count, (int) safeCount, safeCount); - // bottom.likesCount.setText(likesString); + binding.getRoot().postDelayed(() -> bottom.likesCount.setAnimateChanges(true), 1000); + if (count > 1000 && !settingsHelper.getBoolean(PREF_SHOWN_COUNT_TOOLTIP)) { + binding.getRoot().postDelayed(this::showCountTooltip, 1000); + } }); if (!viewModel.getMedia().isCommentsDisabled()) { viewModel.getCommentCount().observe(getViewLifecycleOwner(), count -> { - bottom.commentsCount.setAnimateChanges(false); bottom.commentsCount.setNumber(getSafeCount(count)); - // final String likesString = getResources().getQuantityString(R.plurals.comments_count, (int) safeCount, safeCount); - // bottom.commentsCount.setText(likesString); + binding.getRoot().postDelayed(() -> bottom.commentsCount.setAnimateChanges(true), 1000); }); } viewModel.getViewCount().observe(getViewLifecycleOwner(), count -> { @@ -310,6 +319,45 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme })); } + private void showCountTooltip() { + final Context context = getContext(); + if (context == null) return; + final Rect rect = new Rect(); + bottom.likesCount.getGlobalVisibleRect(rect); + final Balloon balloon = new Balloon.Builder(context) + .setArrowSize(8) + .setArrowOrientation(ArrowOrientation.TOP) + .setArrowPositionRules(ArrowPositionRules.ALIGN_ANCHOR) + .setArrowPosition(0.5f) + .setWidth(BalloonSizeSpec.WRAP) + .setHeight(BalloonSizeSpec.WRAP) + .setPadding(4) + .setTextSize(16) + .setAlpha(0.9f) + .setBalloonAnimation(BalloonAnimation.ELASTIC) + .setBalloonHighlightAnimation(BalloonHighlightAnimation.HEARTBEAT, 0) + .setIsVisibleOverlay(true) + .setOverlayColorResource(R.color.black_a50) + .setOverlayShape(new BalloonOverlayCircle((float) Math.max( + bottom.likesCount.getMeasuredWidth(), + bottom.likesCount.getMeasuredHeight() + ) / 2f)) + .setBalloonOverlayAnimation(BalloonOverlayAnimation.FADE) + .setLifecycleOwner(getViewLifecycleOwner()) + .setTextResource(R.string.click_to_show_full) + .setDismissWhenTouchOutside(false) + .setDismissWhenOverlayClicked(false) + .build(); + balloon.showAlignBottom(bottom.likesCount); + settingsHelper.putBoolean(PREF_SHOWN_COUNT_TOOLTIP, true); + balloon.setOnBalloonOutsideTouchListener((view, motionEvent) -> { + if (rect.contains((int) motionEvent.getRawX(), (int) motionEvent.getRawY())) { + bottom.likesCount.setShowAbbreviation(false); + } + balloon.dismiss(); + }); + } + @NonNull private Long getSafeCount(final Long count) { Long safeCount = count; diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java index 5287a1a5..dacf80f6 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java @@ -7,4 +7,5 @@ public final class PreferenceKeys { public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER = "enable_dm_auto_refresh_freq_number"; public static final String PREF_ENABLE_SENTRY = "enable_sentry"; public static final String PREF_TAB_ORDER = "tab_order"; + public static final String PREF_SHOWN_COUNT_TOOLTIP = "shown_count_tooltip"; } diff --git a/app/src/main/java/awais/instagrabber/utils/CombinedDrawable.java b/app/src/main/java/awais/instagrabber/utils/CombinedDrawable.java index a7016e95..6aa9b9b6 100644 --- a/app/src/main/java/awais/instagrabber/utils/CombinedDrawable.java +++ b/app/src/main/java/awais/instagrabber/utils/CombinedDrawable.java @@ -36,11 +36,6 @@ public class CombinedDrawable extends Drawable implements Drawable.Callback { } } - public void setIconSize(int width, int height) { - iconWidth = width; - iconHeight = height; - } - public CombinedDrawable(Drawable backgroundDrawable, Drawable iconDrawable) { background = backgroundDrawable; icon = iconDrawable; @@ -49,6 +44,11 @@ public class CombinedDrawable extends Drawable implements Drawable.Callback { } } + public void setIconSize(int width, int height) { + iconWidth = width; + iconHeight = height; + } + public void setCustomSize(int width, int height) { backWidth = width; backHeight = height; @@ -82,11 +82,12 @@ public class CombinedDrawable extends Drawable implements Drawable.Callback { } @Override - public boolean setState(int[] stateSet) { + public boolean setState(@NonNull int[] stateSet) { icon.setState(stateSet); return true; } + @NonNull @Override public int[] getState() { return icon.getState(); @@ -108,7 +109,7 @@ public class CombinedDrawable extends Drawable implements Drawable.Callback { } @Override - public void draw(Canvas canvas) { + public void draw(@NonNull Canvas canvas) { background.setBounds(getBounds()); background.draw(canvas); if (icon != null) { diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java index 659070a9..d98e6b37 100755 --- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java +++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java @@ -16,6 +16,7 @@ import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_D import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT; import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_NOTIFICATIONS; import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY; +import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_SHOWN_COUNT_TOOLTIP; import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_TAB_ORDER; import static awais.instagrabber.utils.Constants.APP_LANGUAGE; import static awais.instagrabber.utils.Constants.APP_THEME; @@ -165,7 +166,7 @@ public final class SettingsHelper { @StringDef({DOWNLOAD_USER_FOLDER, DOWNLOAD_PREPEND_USER_NAME, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, SHOW_CAPTIONS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, CHECK_ACTIVITY, CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED, PREF_ENABLE_DM_NOTIFICATIONS, PREF_ENABLE_DM_AUTO_REFRESH, - FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY, HIDE_MUTED_REELS, PLAY_IN_BACKGROUND}) + FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY, HIDE_MUTED_REELS, PLAY_IN_BACKGROUND, PREF_SHOWN_COUNT_TOOLTIP}) public @interface BooleanSettings {} @StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER}) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8cc84a91..36fa5042 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -503,4 +503,5 @@ Recent Clear No Map app found! + Click to view full count