Remove FloatingActionButton library and replace Contacts menu with

native Floating Action Buttons
This commit is contained in:
Zorica Stojchevska 2022-03-10 14:59:24 +01:00 committed by Zorica Stojchevska
parent 19031ab346
commit fd5d2260a2
9 changed files with 131 additions and 439 deletions

View File

@ -50,6 +50,4 @@ dependencies {
// jCard functionality not needed
exclude group: 'com.fasterxml.jackson.core'
}
implementation 'com.github.clans:fab:1.6.4'
}

View File

@ -24,14 +24,12 @@ import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.core.view.children
import androidx.core.view.doOnPreDraw
import androidx.core.view.isVisible
import androidx.viewpager.widget.ViewPager
@ -51,11 +49,9 @@ import ch.protonmail.android.databinding.ActivityContactsBinding
import ch.protonmail.android.permissions.PermissionHelper
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.extensions.showToast
import com.github.clans.fab.FloatingActionButton
import com.github.clans.fab.FloatingActionMenu
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.tabs.TabLayout
import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
// region constants
@ -74,8 +70,11 @@ class ContactsActivity :
private lateinit var progressLayoutView: View
private lateinit var viewPager: ViewPager
private lateinit var addFab: FloatingActionMenu
private lateinit var fabContactsAddMenu: FloatingActionButton
private lateinit var fabContactsAddContact: FloatingActionButton
private lateinit var fabContactsAddContactGroup: FloatingActionButton
private lateinit var tabLayoutContacts: TabLayout
private var isFabOpen: Boolean = false
private val contactsViewModel: ContactsViewModel by viewModels()
@ -117,16 +116,26 @@ class ContactsActivity :
}
binding.tablayoutContacts.setupWithViewPager(viewPager)
addFab = binding.fabContactsAddMenu
binding.fabContactsAddContact.setOnClickListener {
fabContactsAddMenu = binding.fabContactsAddMenu
fabContactsAddContact = binding.fabContactsAddContact
fabContactsAddContactGroup = binding.fabContactsAddContactGroup
fabContactsAddMenu.setOnClickListener {
if (!isFabOpen) {
showFabMenu()
} else {
closeFabMenu()
}
}
fabContactsAddContact.setOnClickListener {
startActivityForResult(
EditContactDetailsActivity.startNewContactActivity(this),
REQUEST_CODE_NEW_CONTACT
)
binding.fabContactsAddMenu.close(false)
}
binding.fabContactsAddContactGroup.setOnClickListener {
fabContactsAddContactGroup.setOnClickListener {
if (!contactsViewModel.isPaidUser()) {
showToast(R.string.paid_plan_needed)
return@setOnClickListener
@ -134,26 +143,22 @@ class ContactsActivity :
val intent =
AppUtil.decorInAppIntent(Intent(this, ContactGroupEditCreateActivity::class.java))
startActivity(intent)
binding.fabContactsAddMenu.close(false)
}
contactsViewModel.fetchContactsResult.observe(
this,
::onContactsFetchedEvent
)
contactsViewModel.hasConnectivity.observe(
this,
{ onConnectivityEvent(it) }
)
contactsViewModel.hasConnectivity.observe(this) { onConnectivityEvent(it) }
progressLayoutView = binding.layoutProgressContacts
tabLayoutContacts = binding.tablayoutContacts
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.contacts_menu, menu)
val searchItem = menu?.findItem(R.id.action_search)
searchItem?.configureSearch()
val searchItem = menu.findItem(R.id.action_search)
searchItem.configureSearch()
return super.onCreateOptionsMenu(menu)
}
@ -250,23 +255,20 @@ class ContactsActivity :
}
override fun onBackPressed() {
if (addFab.isOpened) {
addFab.close(true)
if (isFabOpen) {
closeFabMenu()
} else {
super.onBackPressed()
}
}
private fun onPageSelected(position: Int) {
addFab.visibility = ViewGroup.VISIBLE
val recyclerViewBottomPadding = {
val mainFab = addFab.children.first { it is FloatingActionButton }
mainFab.height + (window.decorView.height - addFab.bottom) * 2
}
val recyclerViewBottomPadding =
fabContactsAddMenu.height * 2
when (position) {
0 -> {
window.decorView.doOnPreDraw {
contactsListFragment.updateRecyclerViewBottomPadding(recyclerViewBottomPadding())
contactsListFragment.updateRecyclerViewBottomPadding(recyclerViewBottomPadding)
}
contactGroupsFragment.apply {
if (isAdded && actionMode != null)
@ -275,7 +277,7 @@ class ContactsActivity :
}
1 -> {
window.decorView.doOnPreDraw {
contactGroupsFragment.updateRecyclerViewBottomPadding(recyclerViewBottomPadding())
contactGroupsFragment.updateRecyclerViewBottomPadding(recyclerViewBottomPadding)
}
contactsListFragment.apply {
if (isAdded && actionMode != null)
@ -314,6 +316,22 @@ class ContactsActivity :
override fun onHasPermission(type: Constants.PermissionType) = onPermissionConfirmed(type)
}
private fun showFabMenu() {
isFabOpen = true
val rotationLeft = -45f
fabContactsAddMenu.animate().rotation(rotationLeft)
fabContactsAddContact.animate().translationY(-resources.getDimension(R.dimen.animation_translation_55))
fabContactsAddContactGroup.animate().translationY(-resources.getDimension(R.dimen.animation_translation_105))
}
private fun closeFabMenu() {
isFabOpen = false
val rotationRight = 45f
fabContactsAddMenu.animate().rotation(rotationRight)
fabContactsAddContact.animate().translationY(0f)
fabContactsAddContactGroup.animate().translationY(0f)
}
}
class ViewPagerOnPageSelected(private val pageSelected: (Int) -> Unit = {}) : ViewPager.OnPageChangeListener {

View File

@ -390,6 +390,10 @@ class ContactsListFragment : BaseFragment(), IContactsFragment {
adapter = contactsAdapter
addItemDecoration(itemDecoration)
}
contactsRecyclerView.setOnScrollChangeListener { _, _, _, _, _ ->
listener.selectPage(0)
}
}
override fun updateRecyclerViewBottomPadding(@Px size: Int) {

View File

@ -1,268 +0,0 @@
/*
* Copyright (c) 2022 Proton AG
*
* This file is part of Proton Mail.
*
* Proton Mail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Proton Mail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Proton Mail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.views.contactDetails;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewGroup;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import ch.protonmail.android.R;
public class SquareFloatingButtonView extends androidx.appcompat.widget.AppCompatTextView {
public static final int FAB_TYPE_SQUARE = 1;
public static final int FAB_TYPE_ROUNDED_SQUARE = 2;
public static final int FAB_SIZE_NORMAL = 10;
public static final int FAB_SIZE_MINI = 11;
private int fabType;
private int fabSize;
private float fabElevation;
private int fabColor;
private Drawable fabIcon;
private int fabIconColor;
private boolean isCreated;
public SquareFloatingButtonView(Context context) {
this(context, null, 0);
}
public SquareFloatingButtonView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SquareFloatingButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initTypedArray(attrs);
}
public void hide() {
this.setVisibility(GONE);
}
public void show() {
this.setVisibility(VISIBLE);
}
private void initTypedArray(AttributeSet attrs) {
TypedArray ta = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.SquareFloatingButtonView, 0, 0);
fabType = ta.getInt(R.styleable.SquareFloatingButtonView_fabType, FAB_TYPE_SQUARE);
fabSize = ta.getInt(R.styleable.SquareFloatingButtonView_fabSizes, FAB_SIZE_NORMAL);
fabElevation = ta.getDimension(R.styleable.SquareFloatingButtonView_fabElevation, getResources().getDimension(R.dimen.fab_default_elevation));
fabColor = ta.getColor(R.styleable.SquareFloatingButtonView_fabColor, ContextCompat.getColor(getContext(), R.color.new_purple));
fabIcon = ta.getDrawable(R.styleable.SquareFloatingButtonView_fabIcon);
fabIconColor = ta.getColor(R.styleable.SquareFloatingButtonView_fabIconColor, -1);
ta.recycle();
}
private void buildView() {
isCreated = true;
setGravity(Gravity.CENTER);
initFabBackground();
initFabIconColor();
initFabShadow();
createSize();
initFabPadding();
}
private void initFabBackground() {
Drawable backgroundDrawable;
switch (fabType) {
case FAB_TYPE_ROUNDED_SQUARE:
backgroundDrawable = ContextCompat.getDrawable(getContext(), R.drawable.fab_rounded_square_bg);
break;
default:
backgroundDrawable = ContextCompat.getDrawable(getContext(), R.drawable.fab_square_bg);
break;
}
if (backgroundDrawable != null)
backgroundDrawable.mutate().setColorFilter(fabColor, PorterDuff.Mode.SRC_IN);
Drawable selectableDrawable;
selectableDrawable = new RippleDrawable(ColorStateList.valueOf(Color.argb(150, 255, 255, 255)),
null, backgroundDrawable);
LayerDrawable backgroundLayers = new LayerDrawable(new Drawable[]{
backgroundDrawable,
selectableDrawable});
setBackground(backgroundLayers);
}
private void initFabIconColor() {
if (fabIcon != null && fabIconColor != -1) {
fabIcon.mutate().setColorFilter(fabIconColor, PorterDuff.Mode.SRC_IN);
}
}
private void initFabPadding() {
int h = fabIcon.getIntrinsicHeight();
int w = fabIcon.getIntrinsicWidth();
fabIcon.setBounds(0, 0, w, h);
setCompoundDrawablePadding(getResources().getDimensionPixelSize(R.dimen.fab_text_horizontal_margin_mini));
setCompoundDrawables(fabIcon, null, null, null);
int iconWidth = fabIcon != null ? fabIcon.getIntrinsicWidth() : 0;
int iconHeight = fabIcon != null ? fabIcon.getIntrinsicHeight() : 0;
int paddingSize = fabSize == FAB_SIZE_MINI
? getResources().getDimensionPixelSize(R.dimen.fab_text_horizontal_margin_mini)
: getResources().getDimensionPixelSize(R.dimen.fab_text_horizontal_margin_normal);
int normalSize = getResources().getDimensionPixelSize(R.dimen.fab_size_normal);
int miniSize = getResources().getDimensionPixelSize(R.dimen.fab_size_mini);
int horizontalPadding = iconWidth == 0 ? paddingSize
: (fabSize == FAB_SIZE_MINI ? (miniSize - iconWidth) / 2 : (normalSize - iconWidth) / 2);
int verticalPadding = iconHeight == 0 ? paddingSize
: (fabSize == FAB_SIZE_MINI ? (miniSize - iconHeight) / 2 : (normalSize - iconHeight) / 2);
setPaddingRelative(horizontalPadding, verticalPadding, horizontalPadding * 2, verticalPadding);
}
private void initFabShadow() {
ViewCompat.setElevation(this, fabElevation);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
createSize();
}
private void createSize() {
ViewGroup.LayoutParams thisParams = getLayoutParams();
if (fabSize == FAB_SIZE_MINI) {
setMinHeight(getResources().getDimensionPixelSize(R.dimen.fab_size_mini));
setMinWidth(getResources().getDimensionPixelSize(R.dimen.fab_size_mini));
thisParams.width = getResources().getDimensionPixelSize(R.dimen.fab_size_mini);
thisParams.height = getResources().getDimensionPixelSize(R.dimen.fab_size_mini);
} else {
setMinHeight(getResources().getDimensionPixelSize(R.dimen.fab_size_normal));
setMinWidth(getResources().getDimensionPixelSize(R.dimen.fab_size_normal));
thisParams.width = getResources().getDimensionPixelSize(R.dimen.fab_size_normal);
thisParams.height = getResources().getDimensionPixelSize(R.dimen.fab_size_normal);
}
this.setLayoutParams(thisParams);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!isCreated) {
buildView();
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (!isCreated) {
buildView();
}
}
public int getFabType() {
return fabType;
}
public void setFabType(int fabType) {
this.fabType = fabType;
buildView();
}
public int getFabSize() {
return fabSize;
}
public void setFabSize(int fabSize) {
this.fabSize = fabSize;
buildView();
}
public float getFabElevation() {
return fabElevation;
}
public void setFabElevation(float fabElevation) {
this.fabElevation = fabElevation;
buildView();
}
public int getFabColor() {
return fabColor;
}
public void setFabColor(int fabColor) {
this.fabColor = fabColor;
buildView();
}
public Drawable getFabIcon() {
return fabIcon;
}
public void setFabIcon(Drawable fabIcon) {
this.fabIcon = fabIcon;
buildView();
}
public int getFabIconColor() {
return fabIconColor;
}
public void setFabIconColor(int fabIconColor) {
this.fabIconColor = fabIconColor;
buildView();
}
}

View File

@ -1,35 +0,0 @@
<!--
~ Copyright (c) 2022 Proton AG
~
~ This file is part of Proton Mail.
~
~ Proton Mail is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ Proton Mail is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with Proton Mail. If not, see https://www.gnu.org/licenses/.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="@color/icon_inverted"
android:fillType="evenOdd"
android:pathData="M10.5,5.6C10.5,7.533 8.933,9.1 7,9.1C6.0717,9.1 5.1815,8.7312 4.5251,8.0749C3.8688,7.4185 3.5,6.5282 3.5,5.6C3.5,3.667 5.067,2.1 7,2.1C8.933,2.1 10.5,3.667 10.5,5.6ZM9.5,5.6C9.5,4.2193 8.3807,3.1 7,3.1C5.6193,3.1 4.5,4.2193 4.5,5.6C4.5,6.9807 5.6193,8.1 7,8.1C8.3807,8.1 9.5,6.9807 9.5,5.6Z" />
<path
android:fillColor="@color/icon_inverted"
android:pathData="M2,12.71L3.71,11H10V10H3.29L1,12.29V15H10V14H2V12.71Z" />
<path
android:fillColor="@color/icon_inverted"
android:pathData="M12,9H13V12H16V13H13V16H12V13H9V12H12V9Z" />
</vector>

View File

@ -1,41 +0,0 @@
<!--
~ Copyright (c) 2022 Proton AG
~
~ This file is part of Proton Mail.
~
~ Proton Mail is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ Proton Mail is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with Proton Mail. If not, see https://www.gnu.org/licenses/.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="@color/icon_inverted"
android:pathData="M6.59,1.54C5.5853,1.4852 4.6673,2.1072 4.3457,3.0605C4.024,4.014 4.3775,5.0649 5.21,5.63L4.65,6.46C3.4407,5.6437 2.9262,4.1198 3.3932,2.7376C3.8602,1.3553 5.1934,0.4557 6.65,0.54C7.2519,0.579 7.8322,0.7794 8.33,1.12L7.75,1.94C7.4093,1.6989 7.0069,1.5601 6.59,1.54Z" />
<path
android:fillColor="@color/icon_inverted"
android:fillType="evenOdd"
android:pathData="M6.2401,5.7666C6.2437,7.5534 7.6932,9 9.48,9C10.3428,9 11.1699,8.6559 11.7781,8.044C12.3863,7.432 12.7253,6.6028 12.72,5.74C12.709,3.9532 11.2535,2.5127 9.4668,2.52C7.68,2.5274 6.2364,3.9798 6.2401,5.7666ZM7.4087,4.9075C7.7542,4.068 8.5722,3.52 9.48,3.52V3.5C10.7171,3.5 11.72,4.5029 11.72,5.74C11.7281,6.6478 11.1875,7.4707 10.3512,7.8237C9.5148,8.1767 8.5481,7.99 7.9033,7.351C7.2585,6.712 7.0632,5.747 7.4087,4.9075Z" />
<path
android:fillColor="@color/icon_inverted"
android:pathData="M9,13V12H12V9H13V12H16V13H13V16H12V13H9Z" />
<path
android:fillColor="@color/icon_inverted"
android:pathData="M10,11V10H7.35L4,12.23V15H10V14H5V12.77L7.65,11H10Z" />
<path
android:fillColor="@color/icon_inverted"
android:pathData="M6,8H4.35L1,10.23V13H3V12H2V10.77L4.65,9H6V8Z" />
</vector>

View File

@ -17,7 +17,7 @@
~ along with Proton Mail. If not, see https://www.gnu.org/licenses/.
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_contacts_main_content"
@ -26,39 +26,54 @@
android:fitsSystemWindows="true"
tools:context=".contacts.ContactsActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_contacts"
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background_norm"
android:translationZ="@dimen/elevation_m">
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<include
android:id="@+id/toolbar_contacts"
layout="@layout/toolbar" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tablayout_contacts"
style="@style/CustomTabLayout"
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_contacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:tabGravity="fill"
app:tabIndicatorColor="@color/interaction_strong"
app:tabMode="fixed" />
android:background="@color/background_norm"
android:translationZ="@dimen/elevation_m"
app:layout_constraintTop_toTopOf="parent">
</com.google.android.material.appbar.AppBarLayout>
<include
android:id="@+id/toolbar_contacts"
layout="@layout/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tablayout_contacts"
style="@style/CustomTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:tabGravity="fill"
app:tabIndicatorColor="@color/interaction_strong"
app:tabMode="fixed" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager_contacts"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
android:layout_height="0dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/coordinatorLayout" />
<FrameLayout
android:id="@+id/layout_no_connectivity_info"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/coordinatorLayout" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_progress_contacts"
@ -66,6 +81,7 @@
android:layout_height="match_parent"
android:background="@color/background_norm"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
tools:visibility="visible">
<ProgressBar
@ -89,53 +105,50 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- TODO: library development has discontinued in 2016 -->
<com.github.clans.fab.FloatingActionMenu
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_contacts_add_contact"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_m"
android:src="@drawable/ic_proton_user_plus"
app:backgroundTint="@color/interaction_strong"
app:fabSize="mini"
app:layout_constraintBottom_toBottomOf="@id/fab_contacts_add_menu"
app:layout_constraintEnd_toEndOf="@id/fab_contacts_add_menu"
app:layout_constraintStart_toStartOf="@id/fab_contacts_add_menu"
app:layout_constraintTop_toTopOf="@id/fab_contacts_add_menu"
app:rippleColor="?attr/brand_norm"
app:tint="@color/icon_inverted"
tools:ignore="VectorDrawableCompat" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_contacts_add_contact_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_m"
android:src="@drawable/ic_proton_users_plus"
app:backgroundTint="@color/interaction_strong"
app:fabSize="mini"
app:layout_constraintBottom_toBottomOf="@id/fab_contacts_add_menu"
app:layout_constraintEnd_toEndOf="@id/fab_contacts_add_menu"
app:layout_constraintStart_toStartOf="@id/fab_contacts_add_menu"
app:layout_constraintTop_toTopOf="@id/fab_contacts_add_menu"
app:rippleColor="?attr/brand_norm"
app:tint="@color/icon_inverted"
tools:ignore="VectorDrawableCompat" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_contacts_add_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_proton_plus"
app:backgroundTint="@color/interaction_strong"
app:fabSize="normal"
app:layout_collapseMode="parallax"
app:menu_colorNormal="@color/interaction_strong"
app:menu_colorPressed="@color/dark_purple_statusbar"
app:menu_colorRipple="@color/dark_purple_statusbar"
app:menu_icon="@drawable/ic_add_inverted"
app:menu_labels_colorNormal="@color/white"
app:menu_labels_hideAnimation="@anim/fab_slide_out_to_right"
app:menu_labels_position="@integer/fab_label_start"
app:menu_labels_showAnimation="@anim/fab_slide_in_from_right"
app:menu_labels_showShadow="true"
app:menu_labels_singleLine="true"
app:menu_labels_textColor="@color/dark_purple"
app:menu_labels_textSize="14sp"
app:menu_openDirection="up"
app:menu_showShadow="true">
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:rippleColor="?attr/brand_norm"
app:tint="@color/icon_inverted" />
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fab_contacts_add_contact"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_contact_add"
app:fab_colorNormal="@color/interaction_strong"
app:fab_colorPressed="@color/dark_purple_statusbar"
app:fab_label="@string/fab_add_contact"
app:fab_size="mini"
app:menu_colorRipple="@color/dark_purple_statusbar"
tools:ignore="VectorDrawableCompat" />
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fab_contacts_add_contact_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_contacts_group_add"
app:fab_colorNormal="@color/interaction_strong"
app:fab_colorPressed="@color/dark_purple_statusbar"
app:fab_label="@string/fab_add_contact_group"
app:fab_size="mini"
app:menu_colorRipple="@color/dark_purple_statusbar"
tools:ignore="VectorDrawableCompat" />
</com.github.clans.fab.FloatingActionMenu>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -218,4 +218,7 @@
<!-- endregion -->
<dimen name="animation_translation_55">55dp</dimen>
<dimen name="animation_translation_105">105dp</dimen>
</resources>

View File

@ -29,7 +29,7 @@ import ch.protonmail.android.uitests.robots.contacts.ContactsMatchers.withContac
import ch.protonmail.android.uitests.robots.contacts.ContactsMatchers.withContactNameAndEmail
import ch.protonmail.android.uitests.robots.mailbox.composer.ComposerRobot
import ch.protonmail.android.uitests.robots.mailbox.inbox.InboxRobot
import com.github.clans.fab.FloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import me.proton.core.test.android.instrumented.Robot
import me.proton.core.test.android.instrumented.utils.StringUtils.stringFromResource
import org.hamcrest.CoreMatchers.containsString