Auto-hide FAB on scroll (#435)

* feat(composeButton): hide fab on scroll
* feat(composeButton): hide when scrolling in profile fragment
* refactor(compose-fab): show fab after small scroll distance
* refactor(compose-fab): code cleanup
* feat(composeButton): hide when scrolling in profile
* fix: duplicate fab var
* feat(fab): show when scrolled to top
* add option to turn it off

---------

Co-authored-by: FineFindus <63370021+FineFindus@users.noreply.github.com>
This commit is contained in:
sk22
2023-02-17 13:20:22 +01:00
committed by GitHub
parent 1567e5aba4
commit d20f8669e8
6 changed files with 90 additions and 3 deletions

View File

@@ -43,6 +43,7 @@ public class GlobalUserPreferences{
public static boolean bottomEncoding;
public static boolean collapseLongPosts;
public static boolean spectatorMode;
public static boolean autoHideFab;
public static String publishButtonText;
public static ThemePreference theme;
public static ColorPreference color;
@@ -91,6 +92,7 @@ public class GlobalUserPreferences{
bottomEncoding=prefs.getBoolean("bottomEncoding", false);
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
spectatorMode=prefs.getBoolean("spectatorMode", false);
autoHideFab=prefs.getBoolean("autoHideFab", true);
publishButtonText=prefs.getString("publishButtonText", "");
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
recentLanguages=fromJson(prefs.getString("recentLanguages", null), recentLanguagesType, new HashMap<>());
@@ -131,6 +133,7 @@ public class GlobalUserPreferences{
.putBoolean("prefixRepliesWithRe", prefixRepliesWithRe)
.putBoolean("collapseLongPosts", collapseLongPosts)
.putBoolean("spectatorMode", spectatorMode)
.putBoolean("autoHideFab", autoHideFab)
.putString("publishButtonText", publishButtonText)
.putBoolean("bottomEncoding", bottomEncoding)
.putInt("theme", theme.ordinal())

View File

@@ -3,6 +3,10 @@ package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.TranslateAnimation;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;

View File

@@ -13,9 +13,12 @@ import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;
import android.widget.ImageButton;
import android.widget.Toolbar;
@@ -75,10 +78,11 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
protected DisplayItemsAdapter adapter;
protected String accountID;
protected PhotoViewer currentPhotoViewer;
protected ImageButton fab;
protected int scrollDiff = 0;
protected HashMap<String, Account> knownAccounts=new HashMap<>();
protected HashMap<String, Relationship> relationships=new HashMap<>();
protected Rect tmpRect=new Rect();
protected ImageButton fab;
public BaseStatusListFragment(){
super(20);
@@ -285,11 +289,42 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
fab=view.findViewById(R.id.fab);
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
if(currentPhotoViewer!=null)
currentPhotoViewer.offsetView(-dx, -dy);
if (fab!=null && GlobalUserPreferences.autoHideFab) {
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
TranslateAnimation animate = new TranslateAnimation(
0,
0,
0,
fab.getHeight() * 2);
animate.setDuration(300);
animate.setFillAfter(true);
fab.startAnimation(animate);
fab.setVisibility(View.INVISIBLE);
scrollDiff = 0;
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
if (list.getChildLayoutPosition(list.getChildAt(0)) == 0 || scrollDiff > 400) {
fab.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
fab.getHeight() * 2,
0);
animate.setDuration(300);
animate.setFillAfter(true);
fab.startAnimation(animate);
scrollDiff = 0;
} else {
scrollDiff += Math.abs(dy);
}
}
}
}
});
list.addItemDecoration(new StatusListItemDecoration());
@@ -327,7 +362,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
updateToolbar();
if (withComposeButton()) {
fab = view.findViewById(R.id.fab);
fab.setVisibility(View.VISIBLE);
fab.setOnClickListener(this::onFabClick);
fab.setOnLongClickListener(this::onFabLongClick);

View File

@@ -19,11 +19,13 @@ import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
@@ -31,9 +33,11 @@ import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.inputmethod.InputMethodManager;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
@@ -144,10 +148,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private Uri editNewAvatar, editNewCover;
private String profileAccountID;
private boolean refreshing;
private View fab;
private ImageButton fab;
private WindowInsets childInsets;
private PhotoViewer currentPhotoViewer;
private boolean editModeLoading;
protected int scrollDiff = 0;
private static final int MAX_FIELDS=4;
@@ -749,6 +754,10 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
notifyButton.setContentDescription(getString(relationship.notifying ? R.string.sk_user_post_notifications_on : R.string.sk_user_post_notifications_off, '@'+account.username));
}
public ImageButton getFab() {
return fab;
}
private void onScrollChanged(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY){
int topBarsH=getToolbar().getHeight()+statusBarHeight;
if(scrollY>avatarBorder.getTop()-topBarsH){
@@ -779,6 +788,37 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
if(currentPhotoViewer!=null){
currentPhotoViewer.offsetView(0, oldScrollY-scrollY);
}
if (GlobalUserPreferences.autoHideFab) {
int dy = scrollY - oldScrollY;
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
TranslateAnimation animate = new TranslateAnimation(
0,
0,
0,
fab.getHeight() * 2);
animate.setDuration(300);
animate.setFillAfter(true);
fab.startAnimation(animate);
fab.setVisibility(View.INVISIBLE);
scrollDiff = 0;
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
if (v.getScrollY() == 0 || scrollDiff > 400) {
fab.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
fab.getHeight() * 2,
0);
animate.setDuration(300);
animate.setFillAfter(true);
fab.startAnimation(animate);
scrollDiff = 0;
} else {
scrollDiff += Math.abs(dy);
}
}
}
}
private Fragment getFragmentForPage(int page){

View File

@@ -248,6 +248,11 @@ public class SettingsFragment extends MastodonToolbarFragment{
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.sk_settings_hide_fab, R.drawable.ic_fluent_edit_24_regular, GlobalUserPreferences.autoHideFab, i->{
GlobalUserPreferences.autoHideFab=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.sk_settings_translate_only_opened, R.drawable.ic_fluent_translate_24_regular, GlobalUserPreferences.translateButtonOpenedOnly, i->{
GlobalUserPreferences.translateButtonOpenedOnly=i.checked;
GlobalUserPreferences.save();

View File

@@ -261,4 +261,5 @@
<string name="sk_settings_hide_interaction">Hide interaction buttons</string>
<string name="sk_follow_as">Follow from other account</string>
<string name="sk_followed_as">Followed from %s</string>
<string name="sk_settings_hide_fab">Auto-hide Compose button</string>
</resources>