Show tooltip to make user aware of expandable count. Fix FormattedNumberTextView animation.

This commit is contained in:
Ammar Githam 2021-05-08 20:22:26 +09:00
parent fb1f3c2cd8
commit 3dde61d91a
8 changed files with 83 additions and 22 deletions

View File

@ -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'

View File

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

View File

@ -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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

@ -503,4 +503,5 @@
<string name="recent">Recent</string>
<string name="clear">Clear</string>
<string name="no_external_map_app">No Map app found!</string>
<string name="click_to_show_full">Click to view full count</string>
</resources>