Эх сурвалжийг харах

Merge pull request #6116 from nextcloud/feature/ui-revamp/account-dialog

New design (UI) - Choose account dialog
Tobias Kaminsky 5 жил өмнө
parent
commit
196956193d

+ 1 - 1
scripts/analysis/findbugs-results.txt

@@ -1 +1 @@
-78
+370

+ 162 - 0
src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt

@@ -0,0 +1,162 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Infomaniak Network SA
+ * Copyright (C) 2020 Infomaniak Network SA
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This program 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 AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.ui
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.graphics.drawable.Drawable
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.client.account.User
+import com.nextcloud.client.account.UserAccountManager
+import com.owncloud.android.R
+import com.owncloud.android.ui.activity.BaseActivity
+import com.owncloud.android.ui.activity.DrawerActivity
+import com.owncloud.android.ui.adapter.UserListAdapter
+import com.owncloud.android.ui.adapter.UserListItem
+import com.owncloud.android.utils.DisplayUtils
+import com.owncloud.android.utils.DisplayUtils.AvatarGenerationListener
+import com.owncloud.android.utils.ThemeUtils
+import kotlinx.android.synthetic.main.account_item.*
+import kotlinx.android.synthetic.main.dialog_choose_account.*
+import java.util.ArrayList
+
+private const val ARG_CURRENT_USER_PARAM = "currentUser"
+
+class ChooseAccountDialogFragment : DialogFragment(), AvatarGenerationListener, UserListAdapter.ClickListener {
+    private lateinit var dialogView: View
+    private var currentUser: User? = null
+    private lateinit var accountManager: UserAccountManager
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        arguments?.let {
+            currentUser = it.getParcelable(ARG_CURRENT_USER_PARAM)
+        }
+    }
+
+    @SuppressLint("InflateParams")
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+        dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_choose_account, null)
+        return MaterialAlertDialogBuilder(requireContext())
+            .setView(dialogView)
+            .create()
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        accountManager = (activity as BaseActivity).userAccountManager
+        currentUser?.let { user ->
+
+            // Defining user picture
+            user_icon.tag = user.accountName
+            DisplayUtils.setAvatar(
+                user,
+                this,
+                resources.getDimension(R.dimen.list_item_avatar_icon_radius),
+                resources,
+                user_icon,
+                context)
+
+            // Defining user texts, accounts, etc.
+            user_name.text = user.toOwnCloudAccount().displayName
+            ticker.visibility = View.GONE
+            account.text = user.accountName
+
+            // Defining user right indicator
+            val icon = ThemeUtils.tintDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_check_circle),
+                ThemeUtils.primaryColor(requireContext(), true))
+            account_menu.setImageDrawable(icon)
+
+            // Creating adapter for accounts list
+            val adapter = UserListAdapter(activity as BaseActivity,
+                accountManager,
+                getAccountListItems(),
+                null,
+                this,
+                false,
+                false)
+            accounts_list.adapter = adapter
+
+            // Creating listeners for quick-actions
+            current_account.setOnClickListener {
+                dismiss()
+            }
+            add_account.setOnClickListener {
+                (activity as DrawerActivity).openAddAccount()
+            }
+            manage_accounts.setOnClickListener {
+                (activity as DrawerActivity).openManageAccounts()
+            }
+        }
+    }
+
+    private fun getAccountListItems(): List<UserListItem>? {
+        val users = accountManager.allUsers
+        val adapterUserList: MutableList<UserListItem> = ArrayList(users.size)
+        // Remove the current account from the adapter to display only other accounts
+        for (user in users) {
+            if (user != currentUser) {
+                adapterUserList.add(UserListItem(user))
+            }
+        }
+        return adapterUserList
+    }
+
+    /**
+     * Fragment creator
+     */
+    companion object {
+        @JvmStatic
+        fun newInstance(user: User) =
+            ChooseAccountDialogFragment().apply {
+                arguments = Bundle().apply {
+                    putParcelable(ARG_CURRENT_USER_PARAM, user)
+                }
+            }
+    }
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+        return dialogView
+    }
+
+    override fun shouldCallGeneratedCallback(tag: String?, callContext: Any?): Boolean {
+        return (callContext as ImageView).tag.toString() == tag
+    }
+
+    override fun avatarGenerated(avatarDrawable: Drawable?, callContext: Any?) {
+        user_icon.setImageDrawable(avatarDrawable)
+    }
+
+    override fun onAccountClicked(user: User?) {
+        (activity as DrawerActivity).accountClicked(user.hashCode())
+    }
+
+    override fun onOptionItemClicked(user: User?, view: View?) {
+        // Un-needed for this context
+    }
+}

+ 22 - 11
src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -9,6 +9,7 @@
  * Copyright (C) 2016 Nextcloud
  * Copyright (C) 2016 ownCloud Inc.
  * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
+ * Copyright (C) 2020 Infomaniak Network SA
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -62,6 +63,7 @@ import com.nextcloud.client.onboarding.FirstRunActivity;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.client.preferences.DarkMode;
 import com.nextcloud.java.util.Optional;
+import com.nextcloud.ui.ChooseAccountDialogFragment;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.PassCodeManager;
@@ -495,16 +497,7 @@ public abstract class DrawerActivity extends ToolbarActivity
     private void handleAccountItemClick(MenuItem menuItem) {
         switch (menuItem.getItemId()) {
             case R.id.drawer_menu_account_add:
-                boolean isProviderOrOwnInstallationVisible = getResources()
-                    .getBoolean(R.bool.show_provider_or_own_installation);
-
-                if (isProviderOrOwnInstallationVisible) {
-                    Intent firstRunIntent = new Intent(getApplicationContext(), FirstRunActivity.class);
-                    firstRunIntent.putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true);
-                    startActivity(firstRunIntent);
-                } else {
-                    startAccountCreation();
-                }
+                openAddAccount();
                 break;
 
             case R.id.drawer_menu_account_manage:
@@ -517,11 +510,29 @@ public abstract class DrawerActivity extends ToolbarActivity
         }
     }
 
+    public void showManageAccountsDialog() {
+        ChooseAccountDialogFragment choseAccountDialog = ChooseAccountDialogFragment.newInstance(accountManager.getUser());
+        choseAccountDialog.show(getSupportFragmentManager(), "fragment_chose_account");
+    }
+
     public void openManageAccounts() {
         Intent manageAccountsIntent = new Intent(getApplicationContext(), ManageAccountsActivity.class);
         startActivityForResult(manageAccountsIntent, ACTION_MANAGE_ACCOUNTS);
     }
 
+    public void openAddAccount() {
+        boolean isProviderOrOwnInstallationVisible = getResources()
+            .getBoolean(R.bool.show_provider_or_own_installation);
+
+        if (isProviderOrOwnInstallationVisible) {
+            Intent firstRunIntent = new Intent(getApplicationContext(), FirstRunActivity.class);
+            firstRunIntent.putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true);
+            startActivity(firstRunIntent);
+        } else {
+            startAccountCreation();
+        }
+    }
+
     private void startPhotoSearch(MenuItem menuItem) {
         SearchEvent searchEvent = new SearchEvent("image/%", SearchRemoteOperation.SearchType.PHOTO_SEARCH);
 
@@ -569,7 +580,7 @@ public abstract class DrawerActivity extends ToolbarActivity
      *
      * @param hashCode HashCode of account to be set
      */
-    private void accountClicked(int hashCode) {
+    public void accountClicked(int hashCode) {
         final User currentUser = accountManager.getUser();
         if (currentUser.hashCode() != hashCode && accountManager.setCurrentOwnCloudAccount(hashCode)) {
             fetchExternalLinks(true);

+ 1 - 1
src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -265,7 +265,7 @@ public class FileDisplayActivity extends FileActivity
         });
 
         mSwitchAccountButton.setOnClickListener(v -> {
-            openManageAccounts();
+            showManageAccountsDialog();
         });
 
         mDualPane = getResources().getBoolean(R.bool.large_land_layout);

+ 3 - 5
src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java

@@ -161,7 +161,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
                                               getUserListItems(),
                                               tintedCheck,
                                               this,
-                                              multipleAccountsSupported);
+                                              multipleAccountsSupported, true);
 
         recyclerView.setAdapter(userListAdapter);
         recyclerView.setLayoutManager(new LinearLayoutManager(this));
@@ -309,8 +309,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
                                       getUserListItems(),
                                       tintedCheck,
                                       this,
-                                      multipleAccountsSupported
-                                  );
+                                      multipleAccountsSupported, false);
                                   recyclerView.setAdapter(userListAdapter);
                                   runOnUiThread(() -> userListAdapter.notifyDataSetChanged());
                               } catch (OperationCanceledException e) {
@@ -362,8 +361,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
                                                       userListItemArray,
                                                       tintedCheck,
                                                       this,
-                                                      multipleAccountsSupported
-                );
+                                                      multipleAccountsSupported, false);
                 recyclerView.setAdapter(userListAdapter);
             } else {
                 onBackPressed();

+ 8 - 4
src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java

@@ -40,7 +40,6 @@ import com.owncloud.android.R;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.activity.BaseActivity;
-import com.owncloud.android.ui.activity.ReceiveExternalFilesActivity;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ThemeUtils;
 
@@ -68,13 +67,15 @@ public class UserListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
     public static final int KEY_USER_INFO_REQUEST_CODE = 13;
     private ClickListener clickListener;
     private boolean showAddAccount;
+    private boolean showDotsMenu;
 
     public UserListAdapter(BaseActivity context,
                            UserAccountManager accountManager,
                            List<UserListItem> values,
                            Drawable tintedCheck,
                            ClickListener clickListener,
-                           boolean showAddAccount) {
+                           boolean showAddAccount,
+                           boolean showDotsMenu) {
         this.context = context;
         this.accountManager = accountManager;
         this.values = values;
@@ -85,6 +86,7 @@ public class UserListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
         this.tintedCheck = tintedCheck;
         this.clickListener = clickListener;
         this.showAddAccount = showAddAccount;
+        this.showDotsMenu = showDotsMenu;
     }
 
     @Override
@@ -306,10 +308,12 @@ public class UserListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
             ImageView accountMenu = view.findViewById(R.id.account_menu);
 
             view.setOnClickListener(this);
-            if(context instanceof ReceiveExternalFilesActivity) {
+            if (showDotsMenu) {
+                accountMenu.setVisibility(View.VISIBLE);
+                accountMenu.setOnClickListener(this);
+            } else {
                 accountMenu.setVisibility(View.GONE);
             }
-            accountMenu.setOnClickListener(this);
         }
 
         public void setData(User user) {

+ 1 - 0
src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.java

@@ -95,6 +95,7 @@ public class MultipleAccountsDialog extends DialogFragment implements Injectable
                                                       getAccountListItems(),
                                                       tintedCheck,
                                                       this,
+                                                      false,
                                                       false);
 
         listView.setHasFixedSize(true);

+ 19 - 2
src/main/res/drawable/ic_check_circle.xml

@@ -1,8 +1,25 @@
+<!--
+    @author Google LLC
+    Copyright (C) 2020 Google LLC
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
+    android:tint="#4995FB"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
         android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z" />

+ 55 - 45
src/main/res/layout/account_item.xml

@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
   Nextcloud Android client application
 
   Copyright (C) 2016 Andy Scherzinger
   Copyright (C) 2016 Nextcloud
   Copyright (C) 2016 ownCloud
+  Copyright (C) 2020 Infomaniak Network SA
 
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -19,78 +19,87 @@
   You should have received a copy of the GNU Affero General Public
   License along with this program. If not, see <http://www.gnu.org/licenses/>.
 -->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<com.google.android.material.card.MaterialCardView 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:layout_width="match_parent"
     android:layout_height="@dimen/account_item_layout_height"
+    android:layout_margin="@dimen/standard_quarter_margin"
     android:orientation="horizontal"
-    android:weightSum="1">
+    app:cardBackgroundColor="@color/transparent"
+    app:cardElevation="0dp">
 
-    <FrameLayout
-        android:id="@+id/avatar_container"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerVertical="true"
-        android:layout_alignParentStart="true">
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        tools:ignore="UnusedAttribute">
 
-        <ImageView
-            android:id="@+id/user_icon"
-            android:layout_width="@dimen/user_icon_size"
-            android:layout_height="@dimen/user_icon_size"
-            android:layout_gravity="top|start"
-            android:layout_marginBottom="@dimen/account_item_layout_user_image_margin"
-            android:layout_marginStart="@dimen/account_item_layout_user_image_left_start_margin"
-            android:layout_marginEnd="@dimen/account_item_layout_user_image_margin"
-            android:layout_marginTop="@dimen/account_item_layout_user_image_margin"
-            android:src="@drawable/folder"
-            android:contentDescription="@string/avatar"/>
+        <FrameLayout
+            android:id="@+id/avatar_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentStart="true"
+            android:layout_centerVertical="true">
 
-        <ImageView
-            android:id="@+id/ticker"
-            android:layout_width="18dp"
-            android:layout_height="18dp"
-            android:layout_gravity="bottom|end"
-            android:background="@drawable/round_bgnd"
-            android:src="@drawable/account_circle_white"
-            android:contentDescription="@string/active_user"/>
-    </FrameLayout>
+            <ImageView
+                android:id="@+id/user_icon"
+                android:layout_width="@dimen/user_icon_size"
+                android:layout_height="@dimen/user_icon_size"
+                android:layout_gravity="top|start"
+                android:layout_marginStart="@dimen/account_item_layout_user_image_left_start_margin"
+                android:layout_marginTop="@dimen/account_item_layout_user_image_margin"
+                android:layout_marginEnd="@dimen/account_item_layout_user_image_margin"
+                android:layout_marginBottom="@dimen/account_item_layout_user_image_margin"
+                android:contentDescription="@string/avatar"
+                android:src="@drawable/folder" />
+
+            <ImageView
+                android:id="@+id/ticker"
+                android:layout_width="18dp"
+                android:layout_height="18dp"
+                android:layout_gravity="bottom|end"
+                android:background="@drawable/round_bgnd"
+                android:contentDescription="@string/active_user"
+                android:src="@drawable/account_circle_white" />
+        </FrameLayout>
 
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_centerInParent="true"
+            android:layout_marginEnd="25dp"
             android:layout_toEndOf="@id/avatar_container"
             android:orientation="vertical"
-            android:paddingEnd="@dimen/zero"
-            android:layout_marginEnd="25dp"
-            android:paddingStart="3dp">
+            android:paddingStart="3dp"
+            android:paddingEnd="@dimen/zero">
 
             <TextView
                 android:id="@+id/user_name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginEnd="@dimen/standard_half_margin"
-                android:layout_marginStart="@dimen/standard_margin"
+                android:layout_marginStart="@dimen/standard_half_margin"
                 android:layout_marginTop="@dimen/standard_quarter_margin"
+                android:layout_marginEnd="@dimen/standard_double_margin"
                 android:ellipsize="end"
                 android:gravity="bottom"
                 android:maxLines="1"
                 android:text="@string/placeholder_filename"
-                android:textAppearance="?android:attr/textAppearanceListItem"/>
+                android:textAppearance="?android:attr/textAppearanceListItem" />
 
             <TextView
                 android:id="@+id/account"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/standard_half_margin"
+                android:layout_marginEnd="@dimen/standard_double_margin"
                 android:layout_marginBottom="@dimen/standard_quarter_margin"
-                android:layout_marginEnd="@dimen/standard_half_margin"
-                android:layout_marginStart="@dimen/standard_margin"
                 android:ellipsize="end"
                 android:gravity="top"
-                android:maxLines="2"
+                android:maxLines="1"
                 android:text="@string/placeholder_sentence"
-                android:textColor="?android:attr/textColorSecondary"/>
+                android:textColor="?android:attr/textColorSecondary" />
 
         </LinearLayout>
 
@@ -98,13 +107,14 @@
             android:id="@+id/account_menu"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_centerVertical="true"
             android:layout_alignParentEnd="true"
+            android:layout_centerVertical="true"
             android:clickable="true"
             android:contentDescription="@string/overflow_menu"
             android:focusable="true"
-            android:paddingEnd="@dimen/alternate_padding"
             android:paddingStart="@dimen/standard_half_padding"
-            android:src="@drawable/ic_dots_vertical"/>
+            android:paddingEnd="@dimen/alternate_padding"
+            android:src="@drawable/ic_dots_vertical" />
 
-</RelativeLayout>
+    </RelativeLayout>
+</com.google.android.material.card.MaterialCardView>

+ 101 - 0
src/main/res/layout/dialog_choose_account.xml

@@ -0,0 +1,101 @@
+<!--
+  Nextcloud Android client application
+
+  Copyright (C) 2020 Infomaniak Network SA
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2,
+  as published by the Free Software Foundation.
+
+  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context="com.nextcloud.ui.ChooseAccountDialogFragment">
+
+    <include
+        android:id="@+id/current_account"
+        layout="@layout/account_item"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/account_item_layout_height"
+        android:layout_margin="@dimen/standard_quarter_margin"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <View
+        android:id="@+id/separator_line"
+        android:layout_width="0dp"
+        android:layout_height="1dp"
+        android:layout_marginTop="@dimen/standard_quarter_margin"
+        android:background="@color/list_divider_background"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/current_account" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/accounts_list"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/account_action_button_vertical_margin"
+        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+        app:layout_constrainedHeight="true"
+        app:layout_constraintBottom_toTopOf="@+id/add_account"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/separator_line" />
+
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/add_account"
+        style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/account_action_button_height"
+        android:layout_marginStart="@dimen/account_action_button_margin"
+        android:layout_marginEnd="@dimen/account_action_button_margin"
+        android:paddingStart="10dp"
+        android:paddingEnd="0dp"
+        android:text="@string/prefs_add_account"
+        android:textAlignment="textStart"
+        android:textAllCaps="false"
+        android:textColor="@color/fontAppbar"
+        app:icon="@drawable/ic_account_plus"
+        app:iconGravity="start"
+        app:iconPadding="22dp"
+        app:iconTint="@color/fontAppbar"
+        app:layout_constraintBottom_toTopOf="@+id/manage_accounts"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/manage_accounts"
+        style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/account_action_button_height"
+        android:layout_marginStart="@dimen/account_action_button_margin"
+        android:layout_marginEnd="@dimen/account_action_button_margin"
+        android:layout_marginBottom="@dimen/account_action_button_margin"
+        android:paddingStart="12dp"
+        android:paddingEnd="0dp"
+        android:text="@string/prefs_manage_accounts"
+        android:textAlignment="textStart"
+        android:textAllCaps="false"
+        android:textColor="@color/fontAppbar"
+        app:icon="@drawable/ic_settings"
+        app:iconGravity="start"
+        app:iconPadding="20dp"
+        app:iconTint="@color/fontAppbar"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 4 - 2
src/main/res/values/dims.xml

@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
   ownCloud Android client application
 
   Copyright (C) 2014 ownCloud Inc.
@@ -144,4 +143,7 @@
     <dimen name="button_corner_radius">24dp</dimen>
     <integer name="media_grid_width">4</integer>
     <dimen name="copy_internal_link_padding">10dp</dimen>
+    <dimen name="account_action_button_margin">12dp</dimen>
+    <dimen name="account_action_button_height">50dp</dimen>
+    <dimen name="account_action_button_vertical_margin">10dp</dimen>
 </resources>