Skip to content
This repository has been archived by the owner on Apr 12, 2022. It is now read-only.

Floating actions menu #2335

Merged
merged 21 commits into from
Jul 2, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0d48801
Migrate RelativeLayouts in activity_home.xml to a single ConstraintLa…
Dominaezzz Jun 2, 2018
b60c6c6
Migrate AlertDialog for VectorHomeActivity to use a FloatingActionMenu.
Dominaezzz Jun 3, 2018
c738e96
Migrate RelativeLayouts in activity_home.xml to a single ConstraintLa…
Dominaezzz Jun 2, 2018
8f00609
Migrate AlertDialog for VectorHomeActivity to use a FloatingActionMenu.
Dominaezzz Jun 3, 2018
d5043fc
Add credit to the library "FloatingActionMenu".
Dominaezzz Jun 8, 2018
e965e19
Rename and create new methods handling the Floating Action Menu for c…
Dominaezzz Jun 8, 2018
7511580
Make Floating Action Menu collapse after selection.
Dominaezzz Jun 8, 2018
7a7186b
Remove unnecessary comment.
Dominaezzz Jun 8, 2018
5f7489d
Remove previous FloatingActionButton onClick() handler.
Dominaezzz Jun 8, 2018
603e4ef
Get main Floating Action Button only once.
Dominaezzz Jun 8, 2018
9a0de73
Better handling of touch guard.
Dominaezzz Jun 8, 2018
958e425
Remove old click listener.
Dominaezzz Jun 8, 2018
d396dd3
Remove unnecessary barrier.
Dominaezzz Jun 8, 2018
e3cb8ae
Use existing tinting utility.
Dominaezzz Jun 9, 2018
329a813
Improve on hiding Floating Action Button on scroll.
Dominaezzz Jun 9, 2018
1f7310f
Merge remote-tracking branch 'origin/floating_actions_menu' into floa…
Dominaezzz Jun 9, 2018
b0c1905
Merge remote-tracking branch 'remotes/upstream/develop' into floating…
t3chguy Jun 9, 2018
b1a038d
post-merge fix
t3chguy Jun 10, 2018
dc8a80c
fix merge-broken indentation and split intermediate variable for linter
t3chguy Jun 10, 2018
e95b4b4
Fix touchGuard to not be clickable when floating action menu is closed.
Dominaezzz Jun 11, 2018
83e2a85
Remove unused 'mFabDialog' member variable.
Dominaezzz Jun 11, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions vector/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ dependencies {

// UI
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
implementation 'com.getbase:floatingactionbutton:1.10.1'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you credit this library in the file open_source_licenses.html please? There is already a section for Apache 2.0 license

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have credited the library as requested.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks


// Network
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
Expand Down
153 changes: 133 additions & 20 deletions vector/src/main/java/im/vector/activity/VectorHomeActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
Expand All @@ -38,13 +39,14 @@
import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TextInputEditText;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.SearchView;
Expand All @@ -68,6 +70,10 @@
import android.widget.TextView;
import android.widget.Toast;

import com.getbase.floatingactionbutton.AddFloatingActionButton;
import com.getbase.floatingactionbutton.FloatingActionButton;
import com.getbase.floatingactionbutton.FloatingActionsMenu;

import org.matrix.androidsdk.MXDataHandler;
import org.matrix.androidsdk.MXSession;
import org.matrix.androidsdk.call.IMXCall;
Expand Down Expand Up @@ -187,8 +193,17 @@ public class VectorHomeActivity extends RiotAppCompatActivity implements SearchV
@BindView(R.id.listView_spinner_views)
View waitingView;

@BindView(R.id.floating_action_button)
FloatingActionButton mFloatingActionButton;
@BindView(R.id.floating_action_menu)
FloatingActionsMenu mFloatingActionsMenu;

@BindView(R.id.button_start_chat)
FloatingActionButton mFabStartChat;

@BindView(R.id.button_create_room)
FloatingActionButton mFabCreateRoom;

@BindView(R.id.button_join_room)
FloatingActionButton mFabJoinRoom;

// mFloatingActionButton is hidden for 1s when there is scroll
private Timer mFloatingActionButtonTimer;
Expand Down Expand Up @@ -217,6 +232,9 @@ public class VectorHomeActivity extends RiotAppCompatActivity implements SearchV
@BindView(R.id.search_view)
SearchView mSearchView;

@BindView(R.id.floating_action_menu_touch_guard)
View touchGuard;

private boolean mStorePermissionCheck = false;

// a shared files intent is waiting the store init
Expand Down Expand Up @@ -473,11 +491,14 @@ public void run() {
* Display the TAB if it is required
*/
private void showFloatingActionButton() {
if (null != mFloatingActionButton) {
if (null != mFloatingActionsMenu) {
if ((mCurrentMenuId == R.id.bottom_action_favourites) || (mCurrentMenuId == R.id.bottom_action_groups)) {
mFloatingActionButton.setVisibility(View.GONE);
mFloatingActionsMenu.collapse();
mFloatingActionsMenu.setVisibility(View.GONE);
} else {
mFloatingActionButton.show();
mFloatingActionsMenu.collapse();
mFloatingActionsMenu.setVisibility(View.VISIBLE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

show() display the button with an animation. Is the animation still there with setVisibility() on a FloatingActionsMenu?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented animations.

// mFloatingActionButton.show();
}
}
}
Expand Down Expand Up @@ -954,7 +975,33 @@ private void updateSelectedFragment(final MenuItem item) {
*/
public void updateTabStyle(final int primaryColor, final int secondaryColor) {
mToolbar.setBackgroundColor(primaryColor);
mFloatingActionButton.setBackgroundTintList(ColorStateList.valueOf(primaryColor));

AddFloatingActionButton menuButton = mFloatingActionsMenu.findViewById(com.getbase.floatingactionbutton.R.id.fab_expand_menu_button);

Class menuClass = FloatingActionsMenu.class;
try {
Field normal = menuClass.getDeclaredField("mAddButtonColorNormal");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you obliged to do that? Isn't it possible using styles?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Styles could be used but only for a one time setup.
Since the color changes at runtime, reflection was the easiest way.

normal.setAccessible(true);
Field pressed = menuClass.getDeclaredField("mAddButtonColorPressed");
pressed.setAccessible(true);

normal.set(mFloatingActionsMenu, primaryColor);
pressed.set(mFloatingActionsMenu, secondaryColor);

menuButton.setColorNormal(primaryColor);
menuButton.setColorPressed(secondaryColor);
// mFloatingActionsMenu.invalidate();
} catch (Exception ignored) {

}

mFabJoinRoom.setColorNormal(secondaryColor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intended to exchange primary and secondary color for the 3 small FABs (regarding the colors for the main FAB)? It is more visible on the "Contact" tab

mFabJoinRoom.setColorPressed(primaryColor);
mFabCreateRoom.setColorNormal(secondaryColor);
mFabCreateRoom.setColorPressed(primaryColor);
mFabStartChat.setColorNormal(secondaryColor);
mFabStartChat.setColorPressed(primaryColor);

mVectorPendingCallView.updateBackgroundColor(primaryColor);
mSyncInProgressView.setBackgroundColor(primaryColor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Expand All @@ -963,7 +1010,7 @@ public void updateTabStyle(final int primaryColor, final int secondaryColor) {
mSyncInProgressView.getIndeterminateDrawable().setColorFilter(
secondaryColor, android.graphics.PorterDuff.Mode.SRC_IN);
}
mFloatingActionButton.setRippleColor(secondaryColor);
// mFloatingActionButton.setRippleColor(secondaryColor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(secondaryColor);
}
Expand Down Expand Up @@ -1022,15 +1069,80 @@ public void run() {
mSearchView.setIconifiedByDefault(false);
mSearchView.setOnQueryTextListener(this);

if (null != mFloatingActionButton) {
mFloatingActionButton.setOnClickListener(new View.OnClickListener() {
// if (null != mFloatingActionButton) {
// mFloatingActionButton.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// Fragment fragment = getSelectedFragment();
//
// if (!(fragment instanceof AbsHomeFragment) || !((AbsHomeFragment) fragment).onFabClick()) {
// onFloatingButtonClick();
// }
// }
// });
// }

Drawable drawable;

drawable = getResources().getDrawable(R.drawable.ic_person_black_24dp).mutate();
DrawableCompat.setTint(drawable, getResources().getColor(android.R.color.white));
mFabStartChat.setIconDrawable(drawable);

drawable = getResources().getDrawable(R.drawable.ic_add_white).mutate();
DrawableCompat.setTint(drawable, getResources().getColor(android.R.color.white));
mFabCreateRoom.setIconDrawable(drawable);

drawable = getResources().getDrawable(R.drawable.riot_tab_rooms).mutate();
DrawableCompat.setTint(drawable, getResources().getColor(android.R.color.white));
mFabJoinRoom.setIconDrawable(drawable);

// Pre-Lollipop does not support elevation so cannot have touch guard
// above bottomNavigationView.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The touch guard is not shown on PreLollipop, it is a bit annoying. If there is no elevation before API 21, I think this is not a problem to show the touchguard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only reason why I've disabled the touch guard pre-lollipop is because the touch guard shows up behind the Bottom Navigation View. No matter the order of views in the constraint layout, the Bottom Navigation View shows up on top of everything.
Would it be okay to have the Bottom Navigation View not be covered by the touch guard?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so it means that the Bottom Navigation View is able to use elevation, maybe by using app: namespace. If it is not possible to do better, yes, I think it is better to have the touch guard in all cases

mFloatingActionsMenu.setOnFloatingActionsMenuUpdateListener(new FloatingActionsMenu.OnFloatingActionsMenuUpdateListener() {
@Override
public void onClick(View v) {
Fragment fragment = getSelectedFragment();
public void onMenuExpanded() {
touchGuard.setAlpha(0.6f);

if (!(fragment instanceof AbsHomeFragment) || !((AbsHomeFragment) fragment).onFabClick()) {
onFloatingButtonClick();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove onFloatingButtonClick() method then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think mFabDialog member can also be removed then

}
touchGuard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mFloatingActionsMenu.collapse();
}
});
}

@Override
public void onMenuCollapsed() {
touchGuard.setAlpha(0);

touchGuard.setOnClickListener(null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not remove the interception of click event, so the user will be stuck :)
You also have to call setClickable(false)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is still bugged. You have to call setClickable() AFTER setOnClickListener(). Look in setOnClickListener implementation

}
});
}

if (null != mFabStartChat) {
mFabStartChat.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
invitePeopleToNewRoom();
}
});
}
if (null != mFabCreateRoom) {
mFabCreateRoom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mFloatingActionsMenu.collapse();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two other cases does not call collapse(). So if it is necessary, add the 2 missing calls and if it is not, remove this one :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added missing calls.

createRoom();
}
});
}
if (null != mFabJoinRoom) {
mFabJoinRoom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
joinARoom();
}
});
}
Expand Down Expand Up @@ -1227,7 +1339,7 @@ private void onFloatingButtonClick() {
if (!isWaitingViewVisible()) {
CharSequence items[] = new CharSequence[]{getString(R.string.room_recents_start_chat), getString(R.string.room_recents_create_room), getString(R.string.room_recents_join_room)};
mFabDialog = new AlertDialog.Builder(this)
.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int n) {
d.cancel();
Expand Down Expand Up @@ -1261,9 +1373,10 @@ public void hideFloatingActionButton(String fragmentTag) {
mFloatingActionButtonTimer.cancel();
}

if (null != mFloatingActionButton) {
mFloatingActionButton.hide();

if (null != mFloatingActionsMenu) {
// mFloatingActionButton.hide();
mFloatingActionsMenu.setVisibility(View.GONE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question about FAB animation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented the animation.

mFloatingActionsMenu.collapse();
try {
mFloatingActionButtonTimer = new Timer();
mFloatingActionButtonTimer.schedule(new TimerTask() {
Expand Down Expand Up @@ -1310,7 +1423,7 @@ public void run() {
* @return fab view
*/
public FloatingActionButton getFloatingActionButton() {
return mFloatingActionButton;
return null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This remove a feature: the FAB is automatically hidden during a few seconds when the user scroll the page.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gracefully swapped it out for a View. Since only the 'Top' of the button is queried for.

}

/**
Expand Down
11 changes: 11 additions & 0 deletions vector/src/main/res/drawable/vector_background_fab_label.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?attr/multi_selection_background_color"/>
<padding
android:left="16dp"
android:top="4dp"
android:right="16dp"
android:bottom="4dp"/>
<corners
android:radius="3dp"/>
</shape>
Loading