Browse Source

Migrate account list to new user model

Signed-off-by: Chris Narkiewicz <hello@ezaquarii.com>
Chris Narkiewicz 5 years ago
parent
commit
53024d1cd1

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

@@ -3,12 +3,12 @@
  *
  * @author Andy Scherzinger
  * @author Tobias Kaminsky
- * @author Chris Narkiewicz
+ * @author Chris Narkiewicz  <hello@ezaquarii.com>
  * Copyright (C) 2016 Andy Scherzinger
  * Copyright (C) 2017 Tobias Kaminsky
  * Copyright (C) 2016 Nextcloud
  * Copyright (C) 2016 ownCloud Inc.
- * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -63,6 +63,7 @@ import com.nextcloud.client.network.ClientFactory;
 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.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.PassCodeManager;
@@ -466,7 +467,10 @@ public abstract class DrawerActivity extends ToolbarActivity
             case R.id.nav_logout:
                 mCheckedMenuItem = -1;
                 menuItem.setChecked(false);
-                UserInfoActivity.openAccountRemovalConfirmationDialog(getAccount(), getSupportFragmentManager());
+                final Optional<User> optionalUser = getUser();
+                if (optionalUser.isPresent()) {
+                    UserInfoActivity.openAccountRemovalConfirmationDialog(optionalUser.get(), getSupportFragmentManager());
+                }
                 break;
             case R.id.nav_shared:
                 handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.SHARED_SEARCH),
@@ -664,16 +668,15 @@ public abstract class DrawerActivity extends ToolbarActivity
      * updates the account list in the drawer.
      */
     public void updateAccountList() {
-        Account[] accounts = AccountManager.get(this).getAccountsByType(MainApp.getAccountType(this));
-
-        ArrayList<Account> persistingAccounts = new ArrayList<>();
+        List<User> users = accountManager.getAllUsers();
+        ArrayList<User> persistingAccounts = new ArrayList<>();
 
-        for (Account acc: accounts) {
-            boolean pendingForRemoval = arbitraryDataProvider.getBooleanValue(acc,
+        for (User user: users) {
+            boolean pendingForRemoval = arbitraryDataProvider.getBooleanValue(user.toPlatformAccount(),
                     ManageAccountsActivity.PENDING_FOR_REMOVAL);
 
             if (!pendingForRemoval) {
-                persistingAccounts.add(acc);
+                persistingAccounts.add(user);
             }
         }
 
@@ -687,7 +690,7 @@ public abstract class DrawerActivity extends ToolbarActivity
                 final User secondUser = mAvatars.size() > 1 ? mAvatars.get(1) : null;
                 if (secondUser != null) {
                     mAccountEndAccountAvatar.setTag(secondUser.getAccountName());
-                    DisplayUtils.setAvatar(secondUser.toPlatformAccount(),
+                    DisplayUtils.setAvatar(secondUser,
                                            this,
                                            mOtherAccountAvatarRadiusDimension,
                                            getResources(),
@@ -702,7 +705,7 @@ public abstract class DrawerActivity extends ToolbarActivity
                 final User thirdUser = mAvatars.size() > 2 ? mAvatars.get(2) : null;
                 if (thirdUser != null) {
                     mAccountMiddleAccountAvatar.setTag(thirdUser.getAccountName());
-                    DisplayUtils.setAvatar(thirdUser.toPlatformAccount(),
+                    DisplayUtils.setAvatar(thirdUser,
                                            this,
                                            mOtherAccountAvatarRadiusDimension,
                                            getResources(),
@@ -722,34 +725,35 @@ public abstract class DrawerActivity extends ToolbarActivity
     /**
      * re-populates the account list.
      *
-     * @param accounts list of accounts
+     * @param users list of users
      */
-    private void repopulateAccountList(List<Account> accounts) {
+    private void repopulateAccountList(List<User> users) {
         // remove all accounts from list
         mNavigationView.getMenu().removeGroup(R.id.drawer_menu_accounts);
 
         // add all accounts to list
-        for (Account account: accounts) {
+        for (User user: users) {
             try {
                 // show all accounts except the currently active one and those pending for removal
 
-                if (!getAccount().name.equals(account.name)) {
+                if (!getAccount().name.equals(user.getAccountName())) {
                     MenuItem accountMenuItem = mNavigationView.getMenu().add(
                         R.id.drawer_menu_accounts,
-                        account.hashCode(),
+                        user.hashCode(),
                         MENU_ORDER_ACCOUNT,
-                        DisplayUtils.getAccountNameDisplayText(this, account, account.name, account.name))
-                        .setIcon(TextDrawable.createAvatar(account, mMenuAccountAvatarRadiusDimension));
-                    DisplayUtils.setAvatar(account, this, mMenuAccountAvatarRadiusDimension, getResources(),
+                        DisplayUtils.getAccountNameDisplayText(user))
+                        .setIcon(TextDrawable.createAvatar(user.toPlatformAccount(),
+                                                           mMenuAccountAvatarRadiusDimension));
+                    DisplayUtils.setAvatar(user, this, mMenuAccountAvatarRadiusDimension, getResources(),
                                            accountMenuItem, this);
                 }
             } catch (Exception e) {
                 Log_OC.e(TAG, "Error calculating RGB value for account menu item.", e);
                 mNavigationView.getMenu().add(
                     R.id.drawer_menu_accounts,
-                    account.hashCode(),
+                    user.hashCode(),
                     MENU_ORDER_ACCOUNT,
-                    DisplayUtils.getAccountNameDisplayText(this, account, account.name, account.name))
+                    DisplayUtils.getAccountNameDisplayText(user))
                     .setIcon(R.drawable.ic_user);
             }
         }
@@ -810,7 +814,7 @@ public abstract class DrawerActivity extends ToolbarActivity
             View currentAccountView = findNavigationViewChildById(R.id.drawer_current_account);
             currentAccountView.setTag(name);
 
-            DisplayUtils.setAvatar(user.toPlatformAccount(), this, mCurrentAccountAvatarRadiusDimension, getResources(),
+            DisplayUtils.setAvatar(user, this, mCurrentAccountAvatarRadiusDimension, getResources(),
                     currentAccountView, this);
 
             // check and show quota info if available

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

@@ -2,9 +2,9 @@
  * ownCloud Android client application
  *
  * @author Andy Scherzinger
- * @author Chris Narkiewicz
+ * @author Chris Narkiewicz  <hello@ezaquarii.com>
  * Copyright (C) 2016 ownCloud Inc.
- * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  * <p/>
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2,
@@ -41,6 +41,7 @@ import com.evernote.android.job.util.support.PersistableBundleCompat;
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.onboarding.FirstRunActivity;
+import com.nextcloud.java.util.Optional;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
@@ -51,11 +52,10 @@ import com.owncloud.android.jobs.AccountRemovalJob;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.services.OperationsService;
-import com.owncloud.android.ui.adapter.AccountListAdapter;
-import com.owncloud.android.ui.adapter.AccountListItem;
+import com.owncloud.android.ui.adapter.UserListAdapter;
+import com.owncloud.android.ui.adapter.UserListItem;
 import com.owncloud.android.ui.events.AccountRemovedEvent;
 import com.owncloud.android.ui.helpers.FileOperationsHelper;
-import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ThemeUtils;
 
 import org.greenrobot.eventbus.Subscribe;
@@ -63,7 +63,8 @@ import org.greenrobot.eventbus.ThreadMode;
 import org.parceler.Parcels;
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -74,16 +75,16 @@ import androidx.core.graphics.drawable.DrawableCompat;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
-import static com.owncloud.android.ui.adapter.AccountListAdapter.KEY_DISPLAY_NAME;
-import static com.owncloud.android.ui.adapter.AccountListAdapter.KEY_USER_INFO_REQUEST_CODE;
+import static com.owncloud.android.ui.adapter.UserListAdapter.KEY_DISPLAY_NAME;
+import static com.owncloud.android.ui.adapter.UserListAdapter.KEY_USER_INFO_REQUEST_CODE;
 
 /**
  * An Activity that allows the user to manage accounts.
  */
-public class ManageAccountsActivity extends FileActivity implements AccountListAdapter.AccountListAdapterListener,
+public class ManageAccountsActivity extends FileActivity implements UserListAdapter.Listener,
     AccountManagerCallback<Boolean>,
     ComponentsGetter,
-    AccountListAdapter.ClickListener {
+    UserListAdapter.ClickListener {
     private static final String TAG = ManageAccountsActivity.class.getSimpleName();
 
     public static final String KEY_ACCOUNT_LIST_CHANGED = "ACCOUNT_LIST_CHANGED";
@@ -97,11 +98,11 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
     private RecyclerView recyclerView;
     private final Handler handler = new Handler();
     private String accountName;
-    private AccountListAdapter accountListAdapter;
+    private UserListAdapter userListAdapter;
     private ServiceConnection downloadServiceConnection;
     private ServiceConnection uploadServiceConnection;
-    private Set<String> originalAccounts;
-    private String originalCurrentAccount;
+    private Set<String> originalUsers;
+    private String originalCurrentUser;
     private Drawable tintedCheck;
 
     private ArbitraryDataProvider arbitraryDataProvider;
@@ -124,27 +125,26 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
         setupToolbar();
         updateActionBarTitleAndHomeButtonByString(getResources().getString(R.string.prefs_manage_accounts));
 
-        Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.getAccountType(this));
-        originalAccounts = DisplayUtils.toAccountNameSet(Arrays.asList(accountList));
+        List<User> users = accountManager.getAllUsers();
+        originalUsers = toAccountNames(users);
 
-        Account currentAccount = getAccount();
-
-        if (currentAccount != null) {
-            originalCurrentAccount = currentAccount.name;
+        Optional<User> currentUser = getUser();
+        if (currentUser.isPresent()) {
+            originalCurrentUser = currentUser.get().getAccountName();
         }
 
         arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
 
         multipleAccountsSupported = getResources().getBoolean(R.bool.multiaccount_support);
 
-        accountListAdapter = new AccountListAdapter(this,
-                                                    accountManager,
-                                                    getAccountListItems(),
-                                                    tintedCheck,
-                                                    this,
-                                                    multipleAccountsSupported);
+        userListAdapter = new UserListAdapter(this,
+                                              accountManager,
+                                              getUserListItems(),
+                                              tintedCheck,
+                                              this,
+                                              multipleAccountsSupported);
 
-        recyclerView.setAdapter(accountListAdapter);
+        recyclerView.setAdapter(userListAdapter);
         recyclerView.setLayoutManager(new LinearLayoutManager(this));
         initializeComponentGetters();
     }
@@ -155,9 +155,12 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
         if (resultCode == KEY_DELETE_CODE && data != null) {
             Bundle bundle = data.getExtras();
             if (bundle != null && bundle.containsKey(UserInfoActivity.KEY_ACCOUNT)) {
-                Account account = Parcels.unwrap(bundle.getParcelable(UserInfoActivity.KEY_ACCOUNT));
-                accountName = account.name;
-                performAccountRemoval(account);
+                final Account account = Parcels.unwrap(bundle.getParcelable(UserInfoActivity.KEY_ACCOUNT));
+                if (account != null) {
+                    User user = accountManager.getUser(account.name).orElseThrow(RuntimeException::new);
+                    accountName = account.name;
+                    performAccountRemoval(user);
+                }
             }
         }
     }
@@ -178,19 +181,25 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
      * @return true if account list has changed, false if not
      */
     private boolean hasAccountListChanged() {
-        Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.getAccountType(this));
-
-        ArrayList<Account> newList = new ArrayList<>();
-        for (Account account : accountList) {
-            boolean pendingForRemoval = arbitraryDataProvider.getBooleanValue(account, PENDING_FOR_REMOVAL);
+        List<User> users = accountManager.getAllUsers();
+        List<User> newList = new ArrayList<>();
+        for (User user : users) {
+            boolean pendingForRemoval = arbitraryDataProvider.getBooleanValue(user.toPlatformAccount(), PENDING_FOR_REMOVAL);
 
             if (!pendingForRemoval) {
-                newList.add(account);
+                newList.add(user);
             }
         }
+        Set<String> actualAccounts = toAccountNames(newList);
+        return !originalUsers.equals(actualAccounts);
+    }
 
-        Set<String> actualAccounts = DisplayUtils.toAccountNameSet(newList);
-        return !originalAccounts.equals(actualAccounts);
+    private static Set<String> toAccountNames(Collection<User> users) {
+        Set<String> accountNames = new HashSet<>(users.size());
+        for (User user : users) {
+            accountNames.add(user.getAccountName());
+        }
+        return accountNames;
     }
 
     /**
@@ -199,11 +208,11 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
      * @return true if account list has changed, false if not
      */
     private boolean hasCurrentAccountChanged() {
-        User account = getUserAccountManager().getUser();
-        if (account.isAnonymous()) {
+        User user = getUserAccountManager().getUser();
+        if (user.isAnonymous()) {
             return true;
         } else {
-            return !account.getAccountName().equals(originalCurrentAccount);
+            return !user.getAccountName().equals(originalCurrentUser);
         }
     }
 
@@ -223,25 +232,20 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
         }
     }
 
-    /**
-     * creates the account list items list including the add-account action in case multiaccount_support is enabled.
-     *
-     * @return list of account list items
-     */
-    private List<AccountListItem> getAccountListItems() {
-        Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.getAccountType(this));
-        List<AccountListItem> adapterAccountList = new ArrayList<>(accountList.length);
-        for (Account account : accountList) {
-            boolean pendingForRemoval = arbitraryDataProvider.getBooleanValue(account, PENDING_FOR_REMOVAL);
-            adapterAccountList.add(new AccountListItem(account, !pendingForRemoval));
+    private List<UserListItem> getUserListItems() {
+        List<User> users = accountManager.getAllUsers();
+        List<UserListItem> userListItems = new ArrayList<>(users.size());
+        for (User user : users) {
+            boolean pendingForRemoval = arbitraryDataProvider.getBooleanValue(user.toPlatformAccount(),
+                                                                              PENDING_FOR_REMOVAL);
+            userListItems.add(new UserListItem(user, !pendingForRemoval));
         }
 
-        // Add Create Account item at the end of account list if multi-account is enabled
         if (getResources().getBoolean(R.bool.multiaccount_support)) {
-            adapterAccountList.add(new AccountListItem());
+            userListItems.add(new UserListItem());
         }
 
-        return adapterAccountList;
+        return userListItems;
     }
 
     @Override
@@ -279,16 +283,16 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
                                   Bundle result = future.getResult();
                                   String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
                                   accountManager.setCurrentOwnCloudAccount(name);
-                                  accountListAdapter = new AccountListAdapter(
+                                  userListAdapter = new UserListAdapter(
                                       this,
                                       accountManager,
-                                      getAccountListItems(),
+                                      getUserListItems(),
                                       tintedCheck,
                                       this,
                                       multipleAccountsSupported
                                   );
-                                  recyclerView.setAdapter(accountListAdapter);
-                                  runOnUiThread(() -> accountListAdapter.notifyDataSetChanged());
+                                  recyclerView.setAdapter(userListAdapter);
+                                  runOnUiThread(() -> userListAdapter.notifyDataSetChanged());
                               } catch (OperationCanceledException e) {
                                   Log_OC.d(TAG, "Account creation canceled");
                               } catch (Exception e) {
@@ -300,10 +304,10 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
 
     @Subscribe(threadMode = ThreadMode.MAIN)
     public void onAccountRemovedEvent(AccountRemovedEvent event) {
-        List<AccountListItem> accountListItemArray = getAccountListItems();
-        accountListAdapter.clear();
-        accountListAdapter.addAll(accountListItemArray);
-        accountListAdapter.notifyDataSetChanged();
+        List<UserListItem> userListItemArray = getUserListItems();
+        userListAdapter.clear();
+        userListAdapter.addAll(userListItemArray);
+        userListAdapter.notifyDataSetChanged();
     }
 
     @Override
@@ -331,16 +335,16 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
                 accountManager.setCurrentOwnCloudAccount(accountName);
             }
 
-            List<AccountListItem> accountListItemArray = getAccountListItems();
-            if (accountListItemArray.size() > SINGLE_ACCOUNT) {
-                accountListAdapter = new AccountListAdapter(this,
-                                                            accountManager,
-                                                            accountListItemArray,
-                                                            tintedCheck,
-                                                            this,
-                                                            multipleAccountsSupported
+            List<UserListItem> userListItemArray = getUserListItems();
+            if (userListItemArray.size() > SINGLE_ACCOUNT) {
+                userListAdapter = new UserListAdapter(this,
+                                                      accountManager,
+                                                      userListItemArray,
+                                                      tintedCheck,
+                                                      this,
+                                                      multipleAccountsSupported
                 );
-                recyclerView.setAdapter(accountListAdapter);
+                recyclerView.setAdapter(userListAdapter);
             } else {
                 onBackPressed();
             }
@@ -387,34 +391,34 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
         return new ManageAccountsServiceConnection();
     }
 
-    private void performAccountRemoval(Account account) {
+    private void performAccountRemoval(User user) {
         // disable account in recycler view
-        for (int i = 0; i < accountListAdapter.getItemCount(); i++) {
-            AccountListItem item = accountListAdapter.getItem(i);
+        for (int i = 0; i < userListAdapter.getItemCount(); i++) {
+            UserListItem item = userListAdapter.getItem(i);
 
-            if (item != null && item.getAccount().equals(account)) {
+            if (item != null && item.getUser().getAccountName().equalsIgnoreCase(user.getAccountName())) {
                 item.setEnabled(false);
                 break;
             }
 
-            accountListAdapter.notifyDataSetChanged();
+            userListAdapter.notifyDataSetChanged();
         }
 
         // store pending account removal
         ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
-        arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PENDING_FOR_REMOVAL, String.valueOf(true));
+        arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), PENDING_FOR_REMOVAL, String.valueOf(true));
 
         // Cancel transfers
         if (mUploaderBinder != null) {
-            mUploaderBinder.cancel(account);
+            mUploaderBinder.cancel(user.toPlatformAccount());
         }
         if (mDownloaderBinder != null) {
-            mDownloaderBinder.cancel(account);
+            mDownloaderBinder.cancel(user.toPlatformAccount());
         }
 
         // schedule job
         PersistableBundleCompat bundle = new PersistableBundleCompat();
-        bundle.putString(AccountRemovalJob.ACCOUNT, account.name);
+        bundle.putString(AccountRemovalJob.ACCOUNT, user.getAccountName());
 
         new JobRequest.Builder(AccountRemovalJob.TAG)
                 .startNow()
@@ -424,12 +428,12 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
                 .schedule();
 
         // immediately select a new account
-        Account[] accounts = AccountManager.get(this).getAccountsByType(MainApp.getAccountType(this));
+        List<User> users = accountManager.getAllUsers();
 
         String newAccountName = "";
-        for (Account acc: accounts) {
-            if (!account.name.equalsIgnoreCase(acc.name)) {
-                newAccountName = acc.name;
+        for (User u : users) {
+            if (!u.getAccountName().equalsIgnoreCase(u.getAccountName())) {
+                newAccountName = u.getAccountName();
                 break;
             }
         }
@@ -443,7 +447,7 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
         }
 
         // only one to be (deleted) account remaining
-        if (accounts.length < MIN_MULTI_ACCOUNT_SIZE) {
+        if (users.size() < MIN_MULTI_ACCOUNT_SIZE) {
             Intent resultIntent = new Intent();
             resultIntent.putExtra(KEY_ACCOUNT_LIST_CHANGED, true);
             resultIntent.putExtra(KEY_CURRENT_ACCOUNT_CHANGED, true);
@@ -454,15 +458,11 @@ public class ManageAccountsActivity extends FileActivity implements AccountListA
     }
 
     @Override
-    public void onClick(Account account) {
+    public void onClick(User user) {
         final Intent intent = new Intent(this, UserInfoActivity.class);
-        intent.putExtra(UserInfoActivity.KEY_ACCOUNT, Parcels.wrap(account));
-        try {
-            OwnCloudAccount oca = new OwnCloudAccount(account, MainApp.getAppContext());
-            intent.putExtra(KEY_DISPLAY_NAME, oca.getDisplayName());
-        } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) {
-            Log_OC.d(TAG, "Failed to find NC account");
-        }
+        intent.putExtra(UserInfoActivity.KEY_ACCOUNT, Parcels.wrap(user));
+        OwnCloudAccount oca = user.toOwnCloudAccount();
+        intent.putExtra(KEY_DISPLAY_NAME, oca.getDisplayName());
         startActivityForResult(intent, KEY_USER_INFO_REQUEST_CODE);
     }
 

+ 25 - 16
src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java

@@ -3,11 +3,11 @@
  *
  * @author Mario Danic
  * @author Andy Scherzinger
- * @author Chris Narkiewicz
+ * @author Chris Narkiewicz  <hello@ezaquarii.com>
  * Copyright (C) 2017 Mario Danic
  * Copyright (C) 2017 Andy Scherzinger
  * Copyright (C) 2017 Nextcloud GmbH.
- * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -50,8 +50,10 @@ import com.bumptech.glide.request.animation.GlideAnimation;
 import com.bumptech.glide.request.target.SimpleTarget;
 import com.evernote.android.job.JobRequest;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.di.Injectable;
 import com.nextcloud.client.preferences.AppPreferences;
+import com.nextcloud.java.util.Optional;
 import com.owncloud.android.R;
 import com.owncloud.android.jobs.AccountRemovalJob;
 import com.owncloud.android.lib.common.UserInfo;
@@ -116,7 +118,7 @@ public class UserInfoActivity extends FileActivity implements Injectable {
     private Unbinder unbinder;
 
     private UserInfo userInfo;
-    private Account account;
+    private User user;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -124,7 +126,14 @@ public class UserInfoActivity extends FileActivity implements Injectable {
         super.onCreate(savedInstanceState);
         Bundle bundle = getIntent().getExtras();
 
-        account = Parcels.unwrap(bundle.getParcelable(KEY_ACCOUNT));
+        final Account account = Parcels.unwrap(bundle.getParcelable(KEY_ACCOUNT));
+        Optional<User> optionalUser = accountManager.getUser(account != null ? account.name : "");
+        if(!optionalUser.isPresent()) {
+            finish();
+            return;
+        } else {
+            user = optionalUser.get();
+        }
 
         if (savedInstanceState != null && savedInstanceState.containsKey(KEY_USER_DATA)) {
             userInfo = Parcels.unwrap(savedInstanceState.getParcelable(KEY_USER_DATA));
@@ -169,7 +178,7 @@ public class UserInfoActivity extends FileActivity implements Injectable {
                 onBackPressed();
                 break;
             case R.id.delete_account:
-                openAccountRemovalConfirmationDialog(account, getSupportFragmentManager());
+                openAccountRemovalConfirmationDialog(user, getSupportFragmentManager());
                 break;
             default:
                 retval = super.onOptionsItemSelected(item);
@@ -209,13 +218,13 @@ public class UserInfoActivity extends FileActivity implements Injectable {
     }
 
     private void setHeaderImage() {
-        if (getStorageManager().getCapability(account.name).getServerBackground() != null) {
+        if (getStorageManager().getCapability(user.getAccountName()).getServerBackground() != null) {
             ViewGroup appBar = findViewById(R.id.appbar);
 
             if (appBar != null) {
                 ImageView backgroundImageView = appBar.findViewById(R.id.drawer_header_background);
 
-                String background = getStorageManager().getCapability(account.name).getServerBackground();
+                String background = getStorageManager().getCapability(user.getAccountName()).getServerBackground();
                 int primaryColor = ThemeUtils.primaryColor(getAccount(), false, this);
 
                 if (URLUtil.isValidUrl(background)) {
@@ -253,11 +262,11 @@ public class UserInfoActivity extends FileActivity implements Injectable {
     }
 
     private void populateUserInfoUi(UserInfo userInfo) {
-        userName.setText(account.name);
-        avatar.setTag(account.name);
-        DisplayUtils.setAvatar(account, this, mCurrentAccountAvatarRadiusDimension, getResources(), avatar, this);
+        userName.setText(user.getAccountName());
+        avatar.setTag(user.getAccountName());
+        DisplayUtils.setAvatar(user, this, mCurrentAccountAvatarRadiusDimension, getResources(), avatar, this);
 
-        int tint = ThemeUtils.primaryColor(account, true, this);
+        int tint = ThemeUtils.primaryColor(user.toPlatformAccount(), true, this);
 
         if (!TextUtils.isEmpty(userInfo.getDisplayName())) {
             fullName.setText(userInfo.getDisplayName());
@@ -299,9 +308,9 @@ public class UserInfoActivity extends FileActivity implements Injectable {
         }
     }
 
-    public static void openAccountRemovalConfirmationDialog(Account account, FragmentManager fragmentManager) {
+    public static void openAccountRemovalConfirmationDialog(User user, FragmentManager fragmentManager) {
         UserInfoActivity.AccountRemovalConfirmationDialog dialog =
-            UserInfoActivity.AccountRemovalConfirmationDialog.newInstance(account);
+            UserInfoActivity.AccountRemovalConfirmationDialog.newInstance(user);
         dialog.show(fragmentManager, "dialog");
     }
 
@@ -309,9 +318,9 @@ public class UserInfoActivity extends FileActivity implements Injectable {
 
         private Account account;
 
-        public static UserInfoActivity.AccountRemovalConfirmationDialog newInstance(Account account) {
+        public static UserInfoActivity.AccountRemovalConfirmationDialog newInstance(User user) {
             Bundle bundle = new Bundle();
-            bundle.putParcelable(KEY_ACCOUNT, account);
+            bundle.putParcelable(KEY_ACCOUNT, user.toPlatformAccount());
 
             UserInfoActivity.AccountRemovalConfirmationDialog dialog = new
                     UserInfoActivity.AccountRemovalConfirmationDialog();
@@ -366,7 +375,7 @@ public class UserInfoActivity extends FileActivity implements Injectable {
     private void fetchAndSetData() {
         Thread t = new Thread(() -> {
             RemoteOperation getRemoteUserInfoOperation = new GetUserInfoRemoteOperation();
-            RemoteOperationResult result = getRemoteUserInfoOperation.execute(account, this);
+            RemoteOperationResult result = getRemoteUserInfoOperation.execute(user.toPlatformAccount(), this);
 
             if (result.isSuccess() && result.getData() != null) {
                 userInfo = (UserInfo) result.getData().get(0);

+ 0 - 337
src/main/java/com/owncloud/android/ui/adapter/AccountListAdapter.java

@@ -1,337 +0,0 @@
-/*
- *   Nextcloud Android client application
- *
- *   @author Andy Scherzinger
- *   @author Chris Narkiewicz
- *   @author Nick Antoniou
- *   Copyright (C) 2016 Andy Scherzinger
- *   Copyright (C) 2016 ownCloud Inc.
- *   Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
- *   Copyright (C) 2019 Nick Antoniou
- *
- *   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.owncloud.android.ui.adapter;
-
-import android.accounts.Account;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.nextcloud.client.account.UserAccountManager;
-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.utils.DisplayUtils;
-import com.owncloud.android.utils.ThemeUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-
-/**
- * This Adapter populates a RecyclerView with all accounts within the app.
- */
-public class AccountListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
-                                implements DisplayUtils.AvatarGenerationListener {
-    private static final String TAG = AccountListAdapter.class.getSimpleName();
-
-    private float accountAvatarRadiusDimension;
-    private final BaseActivity context;
-    private List<AccountListItem> values;
-    private AccountListAdapterListener accountListAdapterListener;
-    private Drawable tintedCheck;
-    private UserAccountManager accountManager;
-
-    public static final String KEY_DISPLAY_NAME = "DISPLAY_NAME";
-    public static final int KEY_USER_INFO_REQUEST_CODE = 13;
-    private ClickListener clickListener;
-    private boolean showAddAccount;
-
-    public AccountListAdapter(BaseActivity context,
-                              UserAccountManager accountManager,
-                              List<AccountListItem> values,
-                              Drawable tintedCheck,
-                              ClickListener clickListener,
-                              boolean showAddAccount) {
-        this.context = context;
-        this.accountManager = accountManager;
-        this.values = values;
-        if (context instanceof AccountListAdapterListener) {
-            this.accountListAdapterListener = (AccountListAdapterListener) context;
-        }
-        this.accountAvatarRadiusDimension = context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius);
-        this.tintedCheck = tintedCheck;
-        this.clickListener = clickListener;
-        this.showAddAccount = showAddAccount;
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        if (position == values.size() - 1 && showAddAccount) {
-            return AccountListItem.TYPE_ACTION_ADD;
-        }
-        return AccountListItem.TYPE_ACCOUNT;
-    }
-
-    @Override
-    public @NonNull
-    RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-        View view;
-        if (AccountListItem.TYPE_ACCOUNT == viewType) {
-            view = LayoutInflater.from(context).inflate(R.layout.account_item, parent, false);
-            AccountViewHolderItem viewHolder = new AccountViewHolderItem(view);
-            viewHolder.checkViewItem.setImageDrawable(tintedCheck);
-            return viewHolder;
-        } else {
-            view = LayoutInflater.from(context).inflate(R.layout.account_action, parent, false);
-            return new AddAccountViewHolderItem(view);
-        }
-    }
-
-    @Override
-    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
-        AccountListItem accountListItem = values.get(position);
-
-        if (accountListItem != null) {
-            // create account item
-            if (AccountListItem.TYPE_ACCOUNT == accountListItem.getType()) {
-                Account account = accountListItem.getAccount();
-                AccountViewHolderItem item = (AccountViewHolderItem)holder;
-                item.setData(account);
-                setAccount(item, account);
-                setUsername(item, account);
-                setAvatar(item, account);
-                setCurrentlyActiveState(item, account);
-
-                TextView usernameView = item.usernameViewItem;
-                TextView accountView = item.accountViewItem;
-
-                if (!accountListItem.isEnabled()) {
-                    usernameView.setPaintFlags(usernameView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
-                    accountView.setPaintFlags(accountView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
-                } else {
-                    usernameView.setPaintFlags(usernameView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
-                    accountView.setPaintFlags(accountView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
-                }
-
-            } // create add account action item
-            else if (AccountListItem.TYPE_ACTION_ADD == accountListItem.getType() && accountListAdapterListener != null) {
-                setupAddAccountListItem((AddAccountViewHolderItem)holder);
-            }
-        }
-    }
-
-    /**
-     * Sets up a View to be used for adding a new account
-     *
-     * @param holder the add account view holder
-     */
-    private void setupAddAccountListItem(AddAccountViewHolderItem holder) {
-        View actionView = holder.itemView;
-
-        holder.usernameViewItem.setTextColor(ThemeUtils.primaryColor(context, true));
-
-        // bind action listener
-        boolean isProviderOrOwnInstallationVisible = context.getResources()
-                .getBoolean(R.bool.show_provider_or_own_installation);
-
-        if (isProviderOrOwnInstallationVisible) {
-            actionView.setOnClickListener(v -> accountListAdapterListener.showFirstRunActivity());
-        } else {
-            actionView.setOnClickListener(v -> accountListAdapterListener.startAccountCreation());
-        }
-    }
-
-    /**
-     * Sets the name of the account, in the view holder
-     *
-     * @param viewHolder the view holder that contains the account
-     * @param account the account
-     */
-    private void setAccount(AccountViewHolderItem viewHolder, Account account) {
-        viewHolder.accountViewItem.setText(DisplayUtils.convertIdn(account.name, false));
-        viewHolder.accountViewItem.setTag(account.name);
-    }
-
-    /**
-     * Sets the current active state of the account to true if it is the account being used currently,
-     * false otherwise
-     *
-     * @param viewHolder the view holder that contains the account
-     * @param account the account
-     */
-    private void setCurrentlyActiveState(AccountViewHolderItem viewHolder, Account account) {
-        Account currentAccount = accountManager.getCurrentAccount();
-        if (currentAccount != null && currentAccount.name.equals(account.name)) {
-            viewHolder.checkViewItem.setVisibility(View.VISIBLE);
-        } else {
-            viewHolder.checkViewItem.setVisibility(View.INVISIBLE);
-        }
-    }
-
-    /**
-     * Sets the avatar of the account
-     *
-     * @param viewHolder the view holder that contains the account
-     * @param account the account
-     */
-    private void setAvatar(AccountViewHolderItem viewHolder, Account account) {
-        try {
-            View viewItem = viewHolder.imageViewItem;
-            viewItem.setTag(account.name);
-            DisplayUtils.setAvatar(account, this, accountAvatarRadiusDimension, context.getResources(), viewItem,
-                                   context);
-        } catch (Exception e) {
-            Log_OC.e(TAG, "Error calculating RGB value for account list item.", e);
-            // use user icon as a fallback
-            viewHolder.imageViewItem.setImageResource(R.drawable.ic_user);
-        }
-    }
-
-    /**
-     * Sets the username of the account
-     *
-     * @param viewHolder the view holder that contains the account
-     * @param account the account
-     */
-    private void setUsername(AccountViewHolderItem viewHolder, Account account) {
-        try {
-            OwnCloudAccount oca = new OwnCloudAccount(account, context);
-            viewHolder.usernameViewItem.setText(oca.getDisplayName());
-        } catch (Exception e) {
-            Log_OC.w(TAG, "Account not found right after being read; using account name instead");
-            viewHolder.usernameViewItem.setText(UserAccountManager.getUsername(account));
-        }
-        viewHolder.usernameViewItem.setTag(account.name);
-    }
-
-    @Override
-    public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
-        ((ImageView)callContext).setImageDrawable(avatarDrawable);
-    }
-
-    @Override
-    public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
-        return String.valueOf(((ImageView)callContext).getTag()).equals(tag);
-    }
-
-    /**
-     * Returns the total number of items in the data set held by the adapter
-     *
-     * @return The total number of items in this adapter.
-     */
-    @Override
-    public int getItemCount() {
-        return this.values.size();
-    }
-
-    /**
-     * Returns an AccountListItem from the specified position in the values list
-     *
-     * @param position of the object to be returned
-     * @return An AccountListItem of the specified position
-     */
-    public AccountListItem getItem(int position) {
-        return values.get(position);
-    }
-
-    /**
-     * Deletes the elements in the values list and notifies the Adapter
-     */
-    public void clear() {
-        final int size = values.size();
-        values.clear();
-        notifyItemRangeRemoved(0, size);
-    }
-
-    /**
-     * Adds all of the items to the data set
-     *
-     * @param items The item list to be added
-     */
-    public void addAll(List<AccountListItem> items){
-        if(values == null){
-            values = new ArrayList<>();
-        }
-        values.addAll(items);
-        notifyDataSetChanged();
-    }
-
-    /**
-     * Listener interface for Activities using the {@link AccountListAdapter}
-     */
-    public interface AccountListAdapterListener {
-
-        void showFirstRunActivity();
-
-        void startAccountCreation();
-    }
-
-    /**
-     * Account ViewHolderItem to get smooth scrolling.
-     */
-    class AccountViewHolderItem extends RecyclerView.ViewHolder implements View.OnClickListener {
-        private ImageView imageViewItem;
-        private ImageView checkViewItem;
-
-        private TextView usernameViewItem;
-        private TextView accountViewItem;
-
-        private Account account;
-
-        AccountViewHolderItem(@NonNull View view) {
-            super(view);
-            this.imageViewItem = view.findViewById(R.id.user_icon);
-            this.checkViewItem = view.findViewById(R.id.ticker);
-            this.usernameViewItem = view.findViewById(R.id.user_name);
-            this.accountViewItem = view.findViewById(R.id.account);
-            view.setOnClickListener(this);
-        }
-
-        public void setData(Account account) {
-            this.account = account;
-        }
-
-        @Override
-        public void onClick(View v) {
-            if (clickListener != null && v.isEnabled()) {
-                clickListener.onClick(account);
-            }
-        }
-    }
-
-    /**
-     * Account ViewHolderItem to get smooth scrolling.
-     */
-    static class AddAccountViewHolderItem extends RecyclerView.ViewHolder {
-        private TextView usernameViewItem;
-        AddAccountViewHolderItem(@NonNull View view) {
-            super(view);
-            this.usernameViewItem = view.findViewById(R.id.user_name);
-        }
-    }
-
-    public interface ClickListener {
-        void onClick(Account account);
-    }
-}

+ 3 - 3
src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java

@@ -2,11 +2,11 @@
  * Nextcloud Android client application
  *
  * @author Tobias Kaminsky
- * @author Chris Narkiewicz
+ * @author Chris Narkiewicz <hello@ezaquarii.com>
  *
  * Copyright (C) 2018 Tobias Kaminsky
  * Copyright (C) 2018 Nextcloud
- * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -433,7 +433,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
                                 showFederatedShareAvatar(sharee.getUserId(), avatarRadius, resources, avatar);
                             } else {
                                 avatar.setTag(sharee);
-                                DisplayUtils.setAvatar(user.toPlatformAccount(),
+                                DisplayUtils.setAvatar(user,
                                                        sharee.getUserId(),
                                                        sharee.getDisplayName(),
                                                        this,

+ 453 - 0
src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java

@@ -0,0 +1,453 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author masensio
+ * @author Andy Scherzinger
+ * @author Chris Narkiewicz <hello@ezaquarii.com>
+ *
+ * Copyright (C) 2015 ownCloud GmbH
+ * Copyright (C) 2018 Andy Scherzinger
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
+ * Copyright (C) 2020 Nextcloud GmbH
+ *
+ * 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/>.
+ */
+
+package com.owncloud.android.ui.adapter;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.PopupMenu;
+import android.widget.TextView;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.AppCompatCheckBox;
+import androidx.fragment.app.FragmentManager;
+import androidx.recyclerview.widget.RecyclerView;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.lib.resources.status.OCCapability;
+import com.owncloud.android.services.OperationsService;
+import com.owncloud.android.ui.TextDrawable;
+import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
+import com.owncloud.android.ui.dialog.NoteDialogFragment;
+import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ThemeUtils;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+/**
+ * Adapter to show a user/group/email/remote in Sharing list in file details view.
+ */
+public class ShareeListAdapter extends RecyclerView.Adapter<ShareeListAdapter.UserViewHolder>
+        implements DisplayUtils.AvatarGenerationListener {
+
+    private ShareeListAdapterListener listener;
+    private OCCapability capabilities;
+    private FragmentManager fragmentManager;
+    private Context context;
+    private int accentColor;
+    private List<OCShare> shares;
+    private float avatarRadiusDimension;
+    private OCFile file;
+    private String userId;
+
+    public ShareeListAdapter(FragmentManager fragmentManager, Context context, List<OCShare> shares, Account account,
+                             OCFile file, ShareeListAdapterListener listener, String userId) {
+        this.context = context;
+        this.fragmentManager = fragmentManager;
+        this.shares = shares;
+        this.listener = listener;
+        this.file = file;
+        this.userId = userId;
+
+        accentColor = ThemeUtils.primaryAccentColor(context);
+        capabilities = new FileDataStorageManager(account, context.getContentResolver()).getCapability(account.name);
+        avatarRadiusDimension = context.getResources().getDimension(R.dimen.user_icon_radius);
+    }
+
+    @NonNull
+    @Override
+    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.file_details_share_user_item, parent, false);
+        return new UserViewHolder(v);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
+        if (shares != null && shares.size() > position) {
+            final OCShare share = shares.get(position);
+
+            String name = share.getSharedWithDisplayName();
+
+            switch (share.getShareType()) {
+                case GROUP:
+                    name = context.getString(R.string.share_group_clarification, name);
+                    setImage(holder, name, R.drawable.ic_group);
+                    break;
+                case EMAIL:
+                    name = context.getString(R.string.share_email_clarification, name);
+                    setImage(holder, name, R.drawable.ic_email);
+                    break;
+                case ROOM:
+                    name = context.getString(R.string.share_room_clarification, name);
+                    setImage(holder, name, R.drawable.ic_chat_bubble);
+                    break;
+                default:
+                    setImage(holder, name, R.drawable.ic_user);
+                    break;
+            }
+
+            holder.name.setText(name);
+
+            if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) {
+                holder.allowEditing.setVisibility(View.VISIBLE);
+                holder.editShareButton.setVisibility(View.VISIBLE);
+
+                ThemeUtils.tintCheckbox(holder.allowEditing, accentColor);
+                holder.allowEditing.setChecked(canEdit(share));
+                holder.allowEditing.setOnClickListener(v -> allowEditClick(holder.allowEditing, share));
+
+                // bind listener to edit privileges
+                holder.editShareButton.setOnClickListener(v -> onOverflowIconClicked(v, holder.allowEditing, share));
+            } else {
+                holder.allowEditing.setVisibility(View.GONE);
+                holder.editShareButton.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    private void setImage(UserViewHolder holder, String name, @DrawableRes int fallback) {
+        try {
+            holder.avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension));
+        } catch (NoSuchAlgorithmException e) {
+            holder.avatar.setImageResource(fallback);
+        }
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return shares.get(position).getId();
+    }
+
+    @Override
+    public int getItemCount() {
+        return shares.size();
+    }
+
+    private void allowEditClick(AppCompatCheckBox checkBox, @NonNull OCShare share) {
+        if (!share.isFolder()) {
+            share.setPermissions(listener.updatePermissionsToShare(
+                    share,
+                    canReshare(share),
+                    checkBox.isChecked(),
+                    false,
+                    false,
+                    false
+            ));
+        } else {
+            share.setPermissions(listener.updatePermissionsToShare(
+                    share,
+                    canReshare(share),
+                    checkBox.isChecked(),
+                    checkBox.isChecked(),
+                    checkBox.isChecked(),
+                    checkBox.isChecked()
+            ));
+        }
+    }
+
+    private void onOverflowIconClicked(View view, AppCompatCheckBox allowEditsCheckBox, OCShare share) {
+        // use grey as fallback for elements where custom theming is not available
+        if (ThemeUtils.themingEnabled(context)) {
+            context.getTheme().applyStyle(R.style.FallbackThemingTheme, true);
+        }
+        PopupMenu popup = new PopupMenu(context, view);
+        popup.inflate(R.menu.item_user_sharing_settings);
+
+        prepareOptionsMenu(popup.getMenu(), share);
+
+        popup.setOnMenuItemClickListener(item -> optionsItemSelected(popup.getMenu(), item, allowEditsCheckBox, share));
+        popup.show();
+    }
+
+    /**
+     * Updates the sharee's menu with the current permissions of the {@link OCShare}
+     *
+     * @param menu  the menu of the sharee/shared file
+     * @param share the shared file
+     */
+    private void prepareOptionsMenu(Menu menu, OCShare share) {
+
+        MenuItem editCreateItem = menu.findItem(R.id.action_can_edit_create);
+        MenuItem editChangeItem = menu.findItem(R.id.action_can_edit_change);
+        MenuItem editDeleteItem = menu.findItem(R.id.action_can_edit_delete);
+
+        MenuItem hideFileListingItem = menu.findItem(R.id.action_hide_file_listing);
+        MenuItem passwordItem = menu.findItem(R.id.action_password);
+        MenuItem expirationDateItem = menu.findItem(R.id.action_expiration_date);
+
+        MenuItem reshareItem = menu.findItem(R.id.action_can_reshare);
+
+        MenuItem sendNoteItem = menu.findItem(R.id.action_share_send_note);
+
+        if (isReshareForbidden(share)) {
+            reshareItem.setVisible(false);
+        }
+        reshareItem.setChecked(canReshare(share));
+
+        if (share.getShareType() == ShareType.EMAIL) {
+            SharingMenuHelper.setupHideFileListingMenuItem(
+                    hideFileListingItem,
+                    file.isFolder(),
+                    canEdit(share),
+                    share.getPermissions()
+            );
+            SharingMenuHelper.setupPasswordMenuItem(passwordItem, share.isPasswordProtected());
+
+            reshareItem.setVisible(false);
+            editCreateItem.setVisible(false);
+            editChangeItem.setVisible(false);
+            editDeleteItem.setVisible(false);
+        } else {
+            if (file.isFolder() && isEditOptionsAvailable(share)) {
+                /// TODO change areEditOptionsAvailable in order to delete !isFederated
+                editCreateItem.setChecked(canCreate(share));
+                editChangeItem.setChecked(canUpdate(share));
+                editDeleteItem.setChecked(canDelete(share));
+            } else {
+                editCreateItem.setVisible(false);
+                editChangeItem.setVisible(false);
+                editDeleteItem.setVisible(false);
+            }
+
+            hideFileListingItem.setVisible(false);
+            passwordItem.setVisible(false);
+            expirationDateItem.setVisible(false);
+        }
+
+        SharingMenuHelper.setupExpirationDateMenuItem(
+                menu.findItem(R.id.action_expiration_date), share.getExpirationDate(), context.getResources());
+
+        sendNoteItem.setVisible(capabilities.getVersion().isNoteOnShareSupported());
+    }
+
+    private boolean isEditOptionsAvailable(OCShare share) {
+        return !ShareType.FEDERATED.equals(share.getShareType());
+    }
+
+    private boolean isReshareForbidden(OCShare share) {
+        return ShareType.FEDERATED.equals(share.getShareType()) ||
+                (capabilities != null && capabilities.getFilesSharingResharing().isFalse());
+    }
+
+    private boolean canEdit(OCShare share) {
+        return (share.getPermissions() &
+                (OCShare.CREATE_PERMISSION_FLAG | OCShare.UPDATE_PERMISSION_FLAG | OCShare.DELETE_PERMISSION_FLAG)) > 0;
+    }
+
+    private boolean canCreate(OCShare share) {
+        return (share.getPermissions() & OCShare.CREATE_PERMISSION_FLAG) > 0;
+    }
+
+    private boolean canUpdate(OCShare share) {
+        return (share.getPermissions() & OCShare.UPDATE_PERMISSION_FLAG) > 0;
+    }
+
+    private boolean canDelete(OCShare share) {
+        return (share.getPermissions() & OCShare.DELETE_PERMISSION_FLAG) > 0;
+    }
+
+    private boolean canReshare(OCShare share) {
+        return (share.getPermissions() & OCShare.SHARE_PERMISSION_FLAG) > 0;
+    }
+
+    private boolean optionsItemSelected(Menu menu, MenuItem item, AppCompatCheckBox allowEditsCheckBox, OCShare share) {
+        switch (item.getItemId()) {
+            case R.id.action_can_edit_create:
+            case R.id.action_can_edit_change:
+            case R.id.action_can_edit_delete: {
+                item.setChecked(!item.isChecked());
+                if (item.isChecked() && !allowEditsCheckBox.isChecked()) {
+                    allowEditsCheckBox.setChecked(true);
+                }
+                share.setPermissions(
+                        updatePermissionsToShare(
+                                share,
+                                menu.findItem(R.id.action_can_reshare).isChecked(),
+                                allowEditsCheckBox.isChecked(),
+                                menu.findItem(R.id.action_can_edit_create).isChecked(),
+                                menu.findItem(R.id.action_can_edit_change).isChecked(),
+                                menu.findItem(R.id.action_can_edit_delete).isChecked())
+                );
+                return true;
+            }
+            case R.id.action_can_reshare: {
+                item.setChecked(!item.isChecked());
+                share.setPermissions(
+                        updatePermissionsToShare(
+                                share,
+                                menu.findItem(R.id.action_can_reshare).isChecked(),
+                                allowEditsCheckBox.isChecked(),
+                                menu.findItem(R.id.action_can_edit_create).isChecked(),
+                                menu.findItem(R.id.action_can_edit_change).isChecked(),
+                                menu.findItem(R.id.action_can_edit_delete).isChecked())
+                );
+                return true;
+            }
+            case R.id.action_unshare: {
+                listener.unshareWith(share);
+                shares.remove(share);
+                notifyDataSetChanged();
+                return true;
+            }
+            case R.id.action_hide_file_listing: {
+                item.setChecked(!item.isChecked());
+                if (capabilities.getFilesFileDrop().isTrue()) {
+                    listener.setHideFileListingPermissionsToShare(share, item.isChecked());
+                } else {
+                    // not supported in ownCloud
+                    listener.showNotSupportedByOcMessage();
+                }
+                return true;
+            }
+            case R.id.action_password: {
+                listener.requestPasswordForShare(share);
+                return true;
+            }
+            case R.id.action_expiration_date: {
+                ExpirationDatePickerDialogFragment dialog = ExpirationDatePickerDialogFragment
+                    .newInstance(share, share.getExpirationDate());
+                dialog.show(fragmentManager, ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG);
+                return true;
+            }
+            case R.id.action_share_send_note:
+                NoteDialogFragment dialog = NoteDialogFragment.newInstance(share);
+                dialog.show(fragmentManager, NoteDialogFragment.NOTE_FRAGMENT);
+                return true;
+            default:
+                return true;
+        }
+    }
+
+    private int updatePermissionsToShare(OCShare share, boolean canReshare, boolean canEdit, boolean canEditCreate,
+                                         boolean canEditChange, boolean canEditDelete) {
+        return listener.updatePermissionsToShare(
+                share,
+                canReshare,
+                canEdit,
+                canEditCreate,
+                canEditChange,
+                canEditDelete
+        );
+    }
+
+    @Override
+    public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
+        if (callContext instanceof ImageView) {
+            ImageView iv = (ImageView) callContext;
+            iv.setImageDrawable(avatarDrawable);
+        }
+    }
+
+    @Override
+    public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
+        if (callContext instanceof ImageView) {
+            ImageView iv = (ImageView) callContext;
+            return String.valueOf(iv.getTag()).equals(tag);
+        }
+        return false;
+    }
+
+    class UserViewHolder extends RecyclerView.ViewHolder {
+        @BindView(R.id.avatar)
+        ImageView avatar;
+        @BindView(R.id.name)
+        TextView name;
+        @BindView(R.id.allowEditing)
+        AppCompatCheckBox allowEditing;
+        @BindView(R.id.editShareButton)
+        ImageView editShareButton;
+
+        UserViewHolder(View itemView) {
+            super(itemView);
+            ButterKnife.bind(this, itemView);
+        }
+    }
+
+    public interface ShareeListAdapterListener {
+        /**
+         * unshare with given sharee {@link OCShare}.
+         *
+         * @param share the share
+         */
+        void unshareWith(OCShare share);
+
+        /**
+         * Updates the permissions of the {@link OCShare}.
+         *
+         * @param share         the share to be updated
+         * @param canReshare    reshare permission
+         * @param canEdit       edit permission
+         * @param canEditCreate create permission (folders only)
+         * @param canEditChange change permission (folders only)
+         * @param canEditDelete delete permission (folders only)
+         * @return permissions value set
+         */
+        int updatePermissionsToShare(OCShare share,
+                                     boolean canReshare,
+                                     boolean canEdit,
+                                     boolean canEditCreate,
+                                     boolean canEditChange,
+                                     boolean canEditDelete);
+
+        void updateNoteToShare(OCShare share, String note);
+
+        /**
+         * show a snackbar that this feature is not supported by ownCloud.
+         */
+        void showNotSupportedByOcMessage();
+
+        /**
+         * Starts a dialog that requests a password to the user to protect a share.
+         *
+         * @param share the share for which a password shall be configured/removed
+         */
+        void requestPasswordForShare(OCShare share);
+
+        /**
+         * Updates a public share on a folder to set its hide file listing permission.
+         * Starts a request to do it in {@link OperationsService}
+         *
+         * @param share           {@link OCShare} instance which permissions will be updated.
+         * @param hideFileListing New state of the permission for editing the folder shared via link.
+         */
+        void setHideFileListingPermissionsToShare(OCShare share, boolean hideFileListing);
+
+        void setHideFileDownloadPermissionToShare(OCFile file, boolean hideFileDownload);
+    }
+}

+ 16 - 9
src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java

@@ -2,7 +2,8 @@
  * Nextcloud Android client application
  *
  * @author Tobias Kaminsky
- * @author Chris Narkiewicz
+ * @author Chris Narkiewicz <hello@ezaquarii.com>
+ *
  * Copyright (C) 2018 Tobias Kaminsky
  * Copyright (C) 2018 Nextcloud
  * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
@@ -27,6 +28,7 @@ import android.accounts.Account;
 import android.content.ActivityNotFoundException;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.text.format.DateUtils;
 import android.view.LayoutInflater;
@@ -40,9 +42,11 @@ import android.widget.TextView;
 
 import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter;
 import com.afollestad.sectionedrecyclerview.SectionedViewHolder;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.network.ConnectivityService;
+import com.nextcloud.java.util.Optional;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
@@ -235,14 +239,11 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
         itemViewHolder.date.setText(dateString);
 
         // account
-        Account account = accountManager.getAccountByName(item.getAccountName());
+        final Optional<User> optionalUser = accountManager.getUser(item.getAccountName());
         if (showUser) {
             itemViewHolder.account.setVisibility(View.VISIBLE);
-            if (account != null) {
-                itemViewHolder.account.setText(DisplayUtils.getAccountNameDisplayText(parentActivity,
-                                                                                      account,
-                                                                                      account.name,
-                                                                                      item.getAccountName()));
+            if (optionalUser.isPresent()) {
+                itemViewHolder.account.setText(DisplayUtils.getAccountNameDisplayText(optionalUser.get()));
             } else {
                 itemViewHolder.account.setText(item.getAccountName());
             }
@@ -454,8 +455,14 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
                         .getColor(R.color.bg_default));
             }
         } else {
-            itemViewHolder.thumbnail.setImageDrawable(MimeTypeUtil.getFileTypeIcon(item.getMimeType(), fileName,
-                                                                                   account, parentActivity));
+            if (optionalUser.isPresent()) {
+                final User user = optionalUser.get();
+                final Drawable icon = MimeTypeUtil.getFileTypeIcon(item.getMimeType(),
+                                                                   fileName,
+                                                                   user.toPlatformAccount(),
+                                                                   parentActivity);
+                itemViewHolder.thumbnail.setImageDrawable(icon);
+            }
         }
     }
 

+ 252 - 367
src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java

@@ -1,449 +1,334 @@
 /*
- * Nextcloud Android client application
+ *   Nextcloud Android client application
  *
- * @author masensio
- * @author Andy Scherzinger
- * Copyright (C) 2015 ownCloud GmbH
- * Copyright (C) 2018 Andy Scherzinger
+ *   @author Andy Scherzinger
+ *   @author Chris Narkiewicz <hello@ezaquarii.com>
+ *   @author Nick Antoniou
  *
- * 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.
+ *   Copyright (C) 2016 Andy Scherzinger
+ *   Copyright (C) 2016 ownCloud Inc.
+ *   Copyright (C) 2019 Nick Antoniou
+ *   Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
- * 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.
+ *   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.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *   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.owncloud.android.ui.adapter;
 
 import android.accounts.Account;
-import android.content.Context;
+import android.graphics.Paint;
 import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
-import android.widget.PopupMenu;
 import android.widget.TextView;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.appcompat.widget.AppCompatCheckBox;
-import androidx.fragment.app.FragmentManager;
-import androidx.recyclerview.widget.RecyclerView;
-import butterknife.BindView;
-import butterknife.ButterKnife;
+
+import com.nextcloud.client.account.User;
+import com.nextcloud.client.account.UserAccountManager;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.lib.resources.shares.OCShare;
-import com.owncloud.android.lib.resources.shares.ShareType;
-import com.owncloud.android.lib.resources.status.OCCapability;
-import com.owncloud.android.services.OperationsService;
-import com.owncloud.android.ui.TextDrawable;
-import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
-import com.owncloud.android.ui.dialog.NoteDialogFragment;
-import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
+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.utils.DisplayUtils;
 import com.owncloud.android.utils.ThemeUtils;
 
-import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
 import java.util.List;
 
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
 /**
- * Adapter to show a user/group/email/remote in Sharing list in file details view.
+ * This Adapter populates a RecyclerView with all accounts within the app.
  */
-public class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.UserViewHolder>
-        implements DisplayUtils.AvatarGenerationListener {
-
-    private ShareeListAdapterListener listener;
-    private OCCapability capabilities;
-    private FragmentManager fragmentManager;
-    private Context context;
-    private int accentColor;
-    private List<OCShare> shares;
-    private float avatarRadiusDimension;
-    private OCFile file;
-    private String userId;
-
-    public UserListAdapter(FragmentManager fragmentManager, Context context, List<OCShare> shares, Account account,
-                           OCFile file, ShareeListAdapterListener listener, String userId) {
+public class UserListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
+                                implements DisplayUtils.AvatarGenerationListener {
+    private static final String TAG = UserListAdapter.class.getSimpleName();
+
+    private float accountAvatarRadiusDimension;
+    private final BaseActivity context;
+    private List<UserListItem> values;
+    private Listener accountListAdapterListener;
+    private Drawable tintedCheck;
+    private UserAccountManager accountManager;
+
+    public static final String KEY_DISPLAY_NAME = "DISPLAY_NAME";
+    public static final int KEY_USER_INFO_REQUEST_CODE = 13;
+    private ClickListener clickListener;
+    private boolean showAddAccount;
+
+    public UserListAdapter(BaseActivity context,
+                           UserAccountManager accountManager,
+                           List<UserListItem> values,
+                           Drawable tintedCheck,
+                           ClickListener clickListener,
+                           boolean showAddAccount) {
         this.context = context;
-        this.fragmentManager = fragmentManager;
-        this.shares = shares;
-        this.listener = listener;
-        this.file = file;
-        this.userId = userId;
-
-        accentColor = ThemeUtils.primaryAccentColor(context);
-        capabilities = new FileDataStorageManager(account, context.getContentResolver()).getCapability(account.name);
-        avatarRadiusDimension = context.getResources().getDimension(R.dimen.user_icon_radius);
+        this.accountManager = accountManager;
+        this.values = values;
+        if (context instanceof Listener) {
+            this.accountListAdapterListener = (Listener) context;
+        }
+        this.accountAvatarRadiusDimension = context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius);
+        this.tintedCheck = tintedCheck;
+        this.clickListener = clickListener;
+        this.showAddAccount = showAddAccount;
     }
 
-    @NonNull
     @Override
-    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.file_details_share_user_item, parent, false);
-        return new UserViewHolder(v);
+    public int getItemViewType(int position) {
+        if (position == values.size() - 1 && showAddAccount) {
+            return UserListItem.TYPE_ACTION_ADD;
+        }
+        return UserListItem.TYPE_ACCOUNT;
     }
 
     @Override
-    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
-        if (shares != null && shares.size() > position) {
-            final OCShare share = shares.get(position);
-
-            String name = share.getSharedWithDisplayName();
-
-            switch (share.getShareType()) {
-                case GROUP:
-                    name = context.getString(R.string.share_group_clarification, name);
-                    setImage(holder, name, R.drawable.ic_group);
-                    break;
-                case EMAIL:
-                    name = context.getString(R.string.share_email_clarification, name);
-                    setImage(holder, name, R.drawable.ic_email);
-                    break;
-                case ROOM:
-                    name = context.getString(R.string.share_room_clarification, name);
-                    setImage(holder, name, R.drawable.ic_chat_bubble);
-                    break;
-                default:
-                    setImage(holder, name, R.drawable.ic_user);
-                    break;
-            }
-
-            holder.name.setText(name);
-
-            if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) {
-                holder.allowEditing.setVisibility(View.VISIBLE);
-                holder.editShareButton.setVisibility(View.VISIBLE);
+    public @NonNull
+    RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        View view;
+        if (UserListItem.TYPE_ACCOUNT == viewType) {
+            view = LayoutInflater.from(context).inflate(R.layout.account_item, parent, false);
+            AccountViewHolderItem viewHolder = new AccountViewHolderItem(view);
+            viewHolder.checkViewItem.setImageDrawable(tintedCheck);
+            return viewHolder;
+        } else {
+            view = LayoutInflater.from(context).inflate(R.layout.account_action, parent, false);
+            return new AddAccountViewHolderItem(view);
+        }
+    }
 
-                ThemeUtils.tintCheckbox(holder.allowEditing, accentColor);
-                holder.allowEditing.setChecked(canEdit(share));
-                holder.allowEditing.setOnClickListener(v -> allowEditClick(holder.allowEditing, share));
+    @Override
+    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+        UserListItem userListItem = values.get(position);
+
+        if (userListItem != null) {
+            // create account item
+            if (UserListItem.TYPE_ACCOUNT == userListItem.getType()) {
+                final User user = userListItem.getUser();
+                AccountViewHolderItem item = (AccountViewHolderItem)holder;
+                item.setData(user);
+                setUser(item, user);
+                setUsername(item, user);
+                setAvatar(item, user);
+                setCurrentlyActiveState(item, user);
+
+                TextView usernameView = item.usernameViewItem;
+                TextView accountView = item.accountViewItem;
+
+                if (!userListItem.isEnabled()) {
+                    usernameView.setPaintFlags(usernameView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
+                    accountView.setPaintFlags(accountView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
+                } else {
+                    usernameView.setPaintFlags(usernameView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
+                    accountView.setPaintFlags(accountView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
+                }
 
-                // bind listener to edit privileges
-                holder.editShareButton.setOnClickListener(v -> onOverflowIconClicked(v, holder.allowEditing, share));
-            } else {
-                holder.allowEditing.setVisibility(View.GONE);
-                holder.editShareButton.setVisibility(View.GONE);
+            } // create add account action item
+            else if (UserListItem.TYPE_ACTION_ADD == userListItem.getType() && accountListAdapterListener != null) {
+                setupAddAccountListItem((AddAccountViewHolderItem)holder);
             }
         }
     }
 
-    private void setImage(UserViewHolder holder, String name, @DrawableRes int fallback) {
-        try {
-            holder.avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension));
-        } catch (NoSuchAlgorithmException e) {
-            holder.avatar.setImageResource(fallback);
-        }
-    }
+    /**
+     * Sets up a View to be used for adding a new account
+     *
+     * @param holder the add account view holder
+     */
+    private void setupAddAccountListItem(AddAccountViewHolderItem holder) {
+        View actionView = holder.itemView;
 
-    @Override
-    public long getItemId(int position) {
-        return shares.get(position).getId();
-    }
+        holder.usernameViewItem.setTextColor(ThemeUtils.primaryColor(context, true));
 
-    @Override
-    public int getItemCount() {
-        return shares.size();
-    }
+        // bind action listener
+        boolean isProviderOrOwnInstallationVisible = context.getResources()
+                .getBoolean(R.bool.show_provider_or_own_installation);
 
-    private void allowEditClick(AppCompatCheckBox checkBox, @NonNull OCShare share) {
-        if (!share.isFolder()) {
-            share.setPermissions(listener.updatePermissionsToShare(
-                    share,
-                    canReshare(share),
-                    checkBox.isChecked(),
-                    false,
-                    false,
-                    false
-            ));
+        if (isProviderOrOwnInstallationVisible) {
+            actionView.setOnClickListener(v -> accountListAdapterListener.showFirstRunActivity());
         } else {
-            share.setPermissions(listener.updatePermissionsToShare(
-                    share,
-                    canReshare(share),
-                    checkBox.isChecked(),
-                    checkBox.isChecked(),
-                    checkBox.isChecked(),
-                    checkBox.isChecked()
-            ));
+            actionView.setOnClickListener(v -> accountListAdapterListener.startAccountCreation());
         }
     }
 
-    private void onOverflowIconClicked(View view, AppCompatCheckBox allowEditsCheckBox, OCShare share) {
-        // use grey as fallback for elements where custom theming is not available
-        if (ThemeUtils.themingEnabled(context)) {
-            context.getTheme().applyStyle(R.style.FallbackThemingTheme, true);
-        }
-        PopupMenu popup = new PopupMenu(context, view);
-        popup.inflate(R.menu.item_user_sharing_settings);
-
-        prepareOptionsMenu(popup.getMenu(), share);
-
-        popup.setOnMenuItemClickListener(item -> optionsItemSelected(popup.getMenu(), item, allowEditsCheckBox, share));
-        popup.show();
+    /**
+     * Sets the name of the account, in the view holder
+     *
+     * @param viewHolder the view holder that contains the account
+     * @param user the account
+     */
+    private void setUser(AccountViewHolderItem viewHolder, User user) {
+        viewHolder.accountViewItem.setText(DisplayUtils.convertIdn(user.getAccountName(), false));
+        viewHolder.accountViewItem.setTag(user.getAccountName());
     }
 
     /**
-     * Updates the sharee's menu with the current permissions of the {@link OCShare}
+     * Sets the current active state of the account to true if it is the account being used currently,
+     * false otherwise
      *
-     * @param menu  the menu of the sharee/shared file
-     * @param share the shared file
+     * @param viewHolder the view holder that contains the account
+     * @param user the account
      */
-    private void prepareOptionsMenu(Menu menu, OCShare share) {
-
-        MenuItem editCreateItem = menu.findItem(R.id.action_can_edit_create);
-        MenuItem editChangeItem = menu.findItem(R.id.action_can_edit_change);
-        MenuItem editDeleteItem = menu.findItem(R.id.action_can_edit_delete);
-
-        MenuItem hideFileListingItem = menu.findItem(R.id.action_hide_file_listing);
-        MenuItem passwordItem = menu.findItem(R.id.action_password);
-        MenuItem expirationDateItem = menu.findItem(R.id.action_expiration_date);
-
-        MenuItem reshareItem = menu.findItem(R.id.action_can_reshare);
-
-        MenuItem sendNoteItem = menu.findItem(R.id.action_share_send_note);
-
-        if (isReshareForbidden(share)) {
-            reshareItem.setVisible(false);
-        }
-        reshareItem.setChecked(canReshare(share));
-
-        if (share.getShareType() == ShareType.EMAIL) {
-            SharingMenuHelper.setupHideFileListingMenuItem(
-                    hideFileListingItem,
-                    file.isFolder(),
-                    canEdit(share),
-                    share.getPermissions()
-            );
-            SharingMenuHelper.setupPasswordMenuItem(passwordItem, share.isPasswordProtected());
-
-            reshareItem.setVisible(false);
-            editCreateItem.setVisible(false);
-            editChangeItem.setVisible(false);
-            editDeleteItem.setVisible(false);
+    private void setCurrentlyActiveState(AccountViewHolderItem viewHolder, User user) {
+        Account currentAccount = accountManager.getCurrentAccount();
+        if (currentAccount != null && currentAccount.name.equals(user.getAccountName())) {
+            viewHolder.checkViewItem.setVisibility(View.VISIBLE);
         } else {
-            if (file.isFolder() && isEditOptionsAvailable(share)) {
-                /// TODO change areEditOptionsAvailable in order to delete !isFederated
-                editCreateItem.setChecked(canCreate(share));
-                editChangeItem.setChecked(canUpdate(share));
-                editDeleteItem.setChecked(canDelete(share));
-            } else {
-                editCreateItem.setVisible(false);
-                editChangeItem.setVisible(false);
-                editDeleteItem.setVisible(false);
-            }
-
-            hideFileListingItem.setVisible(false);
-            passwordItem.setVisible(false);
-            expirationDateItem.setVisible(false);
+            viewHolder.checkViewItem.setVisibility(View.INVISIBLE);
         }
-
-        SharingMenuHelper.setupExpirationDateMenuItem(
-                menu.findItem(R.id.action_expiration_date), share.getExpirationDate(), context.getResources());
-
-        sendNoteItem.setVisible(capabilities.getVersion().isNoteOnShareSupported());
     }
 
-    private boolean isEditOptionsAvailable(OCShare share) {
-        return !ShareType.FEDERATED.equals(share.getShareType());
+    /**
+     * Sets the avatar of the account
+     *
+     * @param viewHolder the view holder that contains the account
+     * @param user the account
+     */
+    private void setAvatar(AccountViewHolderItem viewHolder, User user) {
+        try {
+            View viewItem = viewHolder.imageViewItem;
+            viewItem.setTag(user.getAccountName());
+            DisplayUtils.setAvatar(user, this, accountAvatarRadiusDimension, context.getResources(), viewItem,
+                                   context);
+        } catch (Exception e) {
+            Log_OC.e(TAG, "Error calculating RGB value for account list item.", e);
+            // use user icon as a fallback
+            viewHolder.imageViewItem.setImageResource(R.drawable.ic_user);
+        }
     }
 
-    private boolean isReshareForbidden(OCShare share) {
-        return ShareType.FEDERATED.equals(share.getShareType()) ||
-                (capabilities != null && capabilities.getFilesSharingResharing().isFalse());
+    /**
+     * Sets the username of the account
+     *
+     * @param viewHolder the view holder that contains the account
+     * @param user the account
+     */
+    private void setUsername(AccountViewHolderItem viewHolder, User user) {
+        try {
+            OwnCloudAccount oca = user.toOwnCloudAccount();
+            viewHolder.usernameViewItem.setText(oca.getDisplayName());
+        } catch (Exception e) {
+            Log_OC.w(TAG, "Account not found right after being read; using account name instead");
+            viewHolder.usernameViewItem.setText(UserAccountManager.getUsername(user.toPlatformAccount()));
+        }
+        viewHolder.usernameViewItem.setTag(user.getAccountName());
     }
 
-    private boolean canEdit(OCShare share) {
-        return (share.getPermissions() &
-                (OCShare.CREATE_PERMISSION_FLAG | OCShare.UPDATE_PERMISSION_FLAG | OCShare.DELETE_PERMISSION_FLAG)) > 0;
+    @Override
+    public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
+        ((ImageView)callContext).setImageDrawable(avatarDrawable);
     }
 
-    private boolean canCreate(OCShare share) {
-        return (share.getPermissions() & OCShare.CREATE_PERMISSION_FLAG) > 0;
+    @Override
+    public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
+        return String.valueOf(((ImageView)callContext).getTag()).equals(tag);
     }
 
-    private boolean canUpdate(OCShare share) {
-        return (share.getPermissions() & OCShare.UPDATE_PERMISSION_FLAG) > 0;
+    /**
+     * Returns the total number of items in the data set held by the adapter
+     *
+     * @return The total number of items in this adapter.
+     */
+    @Override
+    public int getItemCount() {
+        return this.values.size();
     }
 
-    private boolean canDelete(OCShare share) {
-        return (share.getPermissions() & OCShare.DELETE_PERMISSION_FLAG) > 0;
+    /**
+     * Returns an UserListItem from the specified position in the values list
+     *
+     * @param position of the object to be returned
+     * @return An UserListItem of the specified position
+     */
+    public UserListItem getItem(int position) {
+        return values.get(position);
     }
 
-    private boolean canReshare(OCShare share) {
-        return (share.getPermissions() & OCShare.SHARE_PERMISSION_FLAG) > 0;
+    /**
+     * Deletes the elements in the values list and notifies the Adapter
+     */
+    public void clear() {
+        final int size = values.size();
+        values.clear();
+        notifyItemRangeRemoved(0, size);
     }
 
-    private boolean optionsItemSelected(Menu menu, MenuItem item, AppCompatCheckBox allowEditsCheckBox, OCShare share) {
-        switch (item.getItemId()) {
-            case R.id.action_can_edit_create:
-            case R.id.action_can_edit_change:
-            case R.id.action_can_edit_delete: {
-                item.setChecked(!item.isChecked());
-                if (item.isChecked() && !allowEditsCheckBox.isChecked()) {
-                    allowEditsCheckBox.setChecked(true);
-                }
-                share.setPermissions(
-                        updatePermissionsToShare(
-                                share,
-                                menu.findItem(R.id.action_can_reshare).isChecked(),
-                                allowEditsCheckBox.isChecked(),
-                                menu.findItem(R.id.action_can_edit_create).isChecked(),
-                                menu.findItem(R.id.action_can_edit_change).isChecked(),
-                                menu.findItem(R.id.action_can_edit_delete).isChecked())
-                );
-                return true;
-            }
-            case R.id.action_can_reshare: {
-                item.setChecked(!item.isChecked());
-                share.setPermissions(
-                        updatePermissionsToShare(
-                                share,
-                                menu.findItem(R.id.action_can_reshare).isChecked(),
-                                allowEditsCheckBox.isChecked(),
-                                menu.findItem(R.id.action_can_edit_create).isChecked(),
-                                menu.findItem(R.id.action_can_edit_change).isChecked(),
-                                menu.findItem(R.id.action_can_edit_delete).isChecked())
-                );
-                return true;
-            }
-            case R.id.action_unshare: {
-                listener.unshareWith(share);
-                shares.remove(share);
-                notifyDataSetChanged();
-                return true;
-            }
-            case R.id.action_hide_file_listing: {
-                item.setChecked(!item.isChecked());
-                if (capabilities.getFilesFileDrop().isTrue()) {
-                    listener.setHideFileListingPermissionsToShare(share, item.isChecked());
-                } else {
-                    // not supported in ownCloud
-                    listener.showNotSupportedByOcMessage();
-                }
-                return true;
-            }
-            case R.id.action_password: {
-                listener.requestPasswordForShare(share);
-                return true;
-            }
-            case R.id.action_expiration_date: {
-                ExpirationDatePickerDialogFragment dialog = ExpirationDatePickerDialogFragment
-                    .newInstance(share, share.getExpirationDate());
-                dialog.show(fragmentManager, ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG);
-                return true;
-            }
-            case R.id.action_share_send_note:
-                NoteDialogFragment dialog = NoteDialogFragment.newInstance(share);
-                dialog.show(fragmentManager, NoteDialogFragment.NOTE_FRAGMENT);
-                return true;
-            default:
-                return true;
+    /**
+     * Adds all of the items to the data set
+     *
+     * @param items The item list to be added
+     */
+    public void addAll(List<UserListItem> items){
+        if(values == null){
+            values = new ArrayList<>();
         }
+        values.addAll(items);
+        notifyDataSetChanged();
     }
 
-    private int updatePermissionsToShare(OCShare share, boolean canReshare, boolean canEdit, boolean canEditCreate,
-                                         boolean canEditChange, boolean canEditDelete) {
-        return listener.updatePermissionsToShare(
-                share,
-                canReshare,
-                canEdit,
-                canEditCreate,
-                canEditChange,
-                canEditDelete
-        );
+    public interface Listener {
+        void showFirstRunActivity();
+        void startAccountCreation();
     }
 
-    @Override
-    public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
-        if (callContext instanceof ImageView) {
-            ImageView iv = (ImageView) callContext;
-            iv.setImageDrawable(avatarDrawable);
+    /**
+     * Account ViewHolderItem to get smooth scrolling.
+     */
+    class AccountViewHolderItem extends RecyclerView.ViewHolder implements View.OnClickListener {
+        private ImageView imageViewItem;
+        private ImageView checkViewItem;
+
+        private TextView usernameViewItem;
+        private TextView accountViewItem;
+
+        private User user;
+
+        AccountViewHolderItem(@NonNull View view) {
+            super(view);
+            this.imageViewItem = view.findViewById(R.id.user_icon);
+            this.checkViewItem = view.findViewById(R.id.ticker);
+            this.usernameViewItem = view.findViewById(R.id.user_name);
+            this.accountViewItem = view.findViewById(R.id.account);
+            view.setOnClickListener(this);
         }
-    }
 
-    @Override
-    public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
-        if (callContext instanceof ImageView) {
-            ImageView iv = (ImageView) callContext;
-            return String.valueOf(iv.getTag()).equals(tag);
+        public void setData(User user) {
+            this.user = user;
+        }
+
+        @Override
+        public void onClick(View v) {
+            if (clickListener != null && v.isEnabled()) {
+                clickListener.onClick(user);
+            }
         }
-        return false;
     }
 
-    class UserViewHolder extends RecyclerView.ViewHolder {
-        @BindView(R.id.avatar)
-        ImageView avatar;
-        @BindView(R.id.name)
-        TextView name;
-        @BindView(R.id.allowEditing)
-        AppCompatCheckBox allowEditing;
-        @BindView(R.id.editShareButton)
-        ImageView editShareButton;
-
-        UserViewHolder(View itemView) {
-            super(itemView);
-            ButterKnife.bind(this, itemView);
+    /**
+     * Account ViewHolderItem to get smooth scrolling.
+     */
+    static class AddAccountViewHolderItem extends RecyclerView.ViewHolder {
+        private TextView usernameViewItem;
+        AddAccountViewHolderItem(@NonNull View view) {
+            super(view);
+            this.usernameViewItem = view.findViewById(R.id.user_name);
         }
     }
 
-    public interface ShareeListAdapterListener {
-        /**
-         * unshare with given sharee {@link OCShare}.
-         *
-         * @param share the share
-         */
-        void unshareWith(OCShare share);
-
-        /**
-         * Updates the permissions of the {@link OCShare}.
-         *
-         * @param share         the share to be updated
-         * @param canReshare    reshare permission
-         * @param canEdit       edit permission
-         * @param canEditCreate create permission (folders only)
-         * @param canEditChange change permission (folders only)
-         * @param canEditDelete delete permission (folders only)
-         * @return permissions value set
-         */
-        int updatePermissionsToShare(OCShare share,
-                                     boolean canReshare,
-                                     boolean canEdit,
-                                     boolean canEditCreate,
-                                     boolean canEditChange,
-                                     boolean canEditDelete);
-
-        void updateNoteToShare(OCShare share, String note);
-
-        /**
-         * show a snackbar that this feature is not supported by ownCloud.
-         */
-        void showNotSupportedByOcMessage();
-
-        /**
-         * Starts a dialog that requests a password to the user to protect a share.
-         *
-         * @param share the share for which a password shall be configured/removed
-         */
-        void requestPasswordForShare(OCShare share);
-
-        /**
-         * Updates a public share on a folder to set its hide file listing permission.
-         * Starts a request to do it in {@link OperationsService}
-         *
-         * @param share           {@link OCShare} instance which permissions will be updated.
-         * @param hideFileListing New state of the permission for editing the folder shared via link.
-         */
-        void setHideFileListingPermissionsToShare(OCShare share, boolean hideFileListing);
-
-        void setHideFileDownloadPermissionToShare(OCFile file, boolean hideFileDownload);
+    public interface ClickListener {
+        void onClick(User user);
     }
 }

+ 28 - 19
src/main/java/com/owncloud/android/ui/adapter/AccountListItem.java → src/main/java/com/owncloud/android/ui/adapter/UserListItem.java

@@ -2,8 +2,11 @@
  *   Nextcloud Android client application
  *
  *   @author Andy Scherzinger
+ *   @author Chris Narkiewicz <hello@ezaquarii.com>
+ *
  *   Copyright (C) 2016 Andy Scherzinger
  *   Copyright (C) 2016 ownCloud Inc.
+ *   Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -23,54 +26,60 @@ package com.owncloud.android.ui.adapter;
 
 import android.accounts.Account;
 
+import com.nextcloud.client.account.User;
+
 /**
  * Container implementation to add {@link Account}s and the add action to the list.
  */
-public class AccountListItem {
+public class UserListItem {
     static final int TYPE_ACCOUNT = 0;
     static final int TYPE_ACTION_ADD = 1;
 
-    private Account mAccount;
-    private int mType;
-    private boolean mEnabled;
+    private User user;
+    private int type;
+    private boolean enabled;
 
     /**
      * creates an account list item containing an {@link Account}.
      *
-     * @param account the account
+     * @param user the account
      */
-    public AccountListItem(Account account) {
-        mAccount = account;
-        mType = TYPE_ACCOUNT;
-        mEnabled = true;
+    public UserListItem(User user) {
+        this.user = user;
+        this.type = TYPE_ACCOUNT;
+        this.enabled = true;
     }
 
-    public AccountListItem(Account account, boolean enabled) {
-        mAccount = account;
-        mType = TYPE_ACCOUNT;
-        mEnabled = enabled;
+    public UserListItem(User user, boolean enabled) {
+        this.user = user;
+        this.type = TYPE_ACCOUNT;
+        this.enabled = enabled;
     }
 
     /**
      * creates an account list item flagged as add-action.
      */
-    public AccountListItem() {
-        mType = TYPE_ACTION_ADD;
+    public UserListItem() {
+        type = TYPE_ACTION_ADD;
     }
 
     public Account getAccount() {
-        return mAccount;
+        return user.toPlatformAccount();
+    }
+
+    public User getUser() {
+        return user;
     }
 
     public int getType() {
-        return mType;
+        return type;
     }
 
     public void setEnabled(boolean bool) {
-        mEnabled = bool;
+        enabled = bool;
     }
 
     public boolean isEnabled() {
-        return mEnabled;
+        return enabled;
     }
 }

+ 21 - 18
src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.java

@@ -3,8 +3,11 @@
  *  Nextcloud Android client application
  *
  *  @author Tobias Kaminsky
+ *  @author Chris Narkiewicz <hello@ezaquarii.com>
+ *
  *  Copyright (C) 2019 Tobias Kaminsky
  *  Copyright (C) 2019 Nextcloud GmbH
+ *  Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  *  This program is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU Affero General Public License as published by
@@ -23,7 +26,6 @@
 
 package com.owncloud.android.ui.dialog;
 
-import android.accounts.Account;
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.Dialog;
@@ -34,12 +36,13 @@ import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.di.Injectable;
 import com.owncloud.android.R;
 import com.owncloud.android.ui.activity.ReceiveExternalFilesActivity;
-import com.owncloud.android.ui.adapter.AccountListAdapter;
-import com.owncloud.android.ui.adapter.AccountListItem;
+import com.owncloud.android.ui.adapter.UserListAdapter;
+import com.owncloud.android.ui.adapter.UserListItem;
 import com.owncloud.android.utils.ThemeUtils;
 
 import java.util.ArrayList;
@@ -57,7 +60,7 @@ import androidx.recyclerview.widget.RecyclerView;
 import butterknife.BindView;
 import butterknife.ButterKnife;
 
-public class MultipleAccountsDialog extends DialogFragment implements Injectable, AccountListAdapter.ClickListener {
+public class MultipleAccountsDialog extends DialogFragment implements Injectable, UserListAdapter.ClickListener {
     @BindView(R.id.list)
     RecyclerView listView;
 
@@ -87,12 +90,12 @@ public class MultipleAccountsDialog extends DialogFragment implements Injectable
         DrawableCompat.setTint(tintedCheck, tint);
 
 
-        AccountListAdapter adapter = new AccountListAdapter(parent,
-                                         accountManager,
-                                         getAccountListItems(),
-                                         tintedCheck,
-                                         this,
-                                         false);
+        UserListAdapter adapter = new UserListAdapter(parent,
+                                                      accountManager,
+                                                      getAccountListItems(),
+                                                      tintedCheck,
+                                                      this,
+                                                      false);
 
         listView.setHasFixedSize(true);
         listView.setLayoutManager(new LinearLayoutManager(activity));
@@ -117,21 +120,21 @@ public class MultipleAccountsDialog extends DialogFragment implements Injectable
      *
      * @return list of account list items
      */
-    private List<AccountListItem> getAccountListItems() {
-        Account[] accountList = accountManager.getAccounts();
-        List<AccountListItem> adapterAccountList = new ArrayList<>(accountList.length);
-        for (Account account : accountList) {
-            adapterAccountList.add(new AccountListItem(account));
+    private List<UserListItem> getAccountListItems() {
+        List<User> users = accountManager.getAllUsers();
+        List<UserListItem> adapterUserList = new ArrayList<>(users.size());
+        for (User user : users) {
+            adapterUserList.add(new UserListItem(user));
         }
 
-        return adapterAccountList;
+        return adapterUserList;
     }
 
     @Override
-    public void onClick(Account account) {
+    public void onClick(User user) {
         final ReceiveExternalFilesActivity parentActivity = (ReceiveExternalFilesActivity) getActivity();
         if (parentActivity != null) {
-            parentActivity.changeAccount(account);
+            parentActivity.changeAccount(user.toPlatformAccount());
         }
         dismiss();
     }

+ 10 - 5
src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java

@@ -2,7 +2,10 @@
  * Nextcloud Android client application
  *
  * @author Andy Scherzinger
+ * @author Chris Narkiewicz <hello@ezaquarii.com>
+ *
  * Copyright (C) 2018 Andy Scherzinger
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -40,6 +43,7 @@ import android.widget.PopupMenu;
 import android.widget.TextView;
 
 import com.google.android.material.snackbar.Snackbar;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.di.Injectable;
 import com.owncloud.android.R;
@@ -53,7 +57,7 @@ import com.owncloud.android.lib.resources.shares.ShareType;
 import com.owncloud.android.lib.resources.status.OCCapability;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.adapter.UserListAdapter;
+import com.owncloud.android.ui.adapter.ShareeListAdapter;
 import com.owncloud.android.ui.decoration.SimpleListItemDividerDecoration;
 import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
 import com.owncloud.android.ui.dialog.NoteDialogFragment;
@@ -81,7 +85,7 @@ import butterknife.ButterKnife;
 import butterknife.OnClick;
 import butterknife.Unbinder;
 
-public class FileDetailSharingFragment extends Fragment implements UserListAdapter.ShareeListAdapterListener,
+public class FileDetailSharingFragment extends Fragment implements ShareeListAdapter.ShareeListAdapterListener,
     DisplayUtils.AvatarGenerationListener, Injectable {
 
     private static final String ARG_FILE = "FILE";
@@ -296,7 +300,8 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
             sharedWithYouUsername.setText(
                 String.format(getString(R.string.shared_with_you_by), file.getOwnerDisplayName()));
 
-            DisplayUtils.setAvatar(account, file.getOwnerId(), this, getResources().getDimension(
+            final User user = accountManager.getUser(account.name).orElseThrow(RuntimeException::new);
+            DisplayUtils.setAvatar(user, file.getOwnerId(), this, getResources().getDimension(
                 R.dimen.file_list_item_avatar_icon_radius), getResources(), sharedWithYouAvatar,
                 getContext());
             sharedWithYouAvatar.setVisibility(View.VISIBLE);
@@ -321,8 +326,8 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
                 com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
 
             usersList.setVisibility(View.VISIBLE);
-            usersList.setAdapter(new UserListAdapter(fileDisplayActivity.getSupportFragmentManager(),
-                fileDisplayActivity, shares, account, file, this, userId));
+            usersList.setAdapter(new ShareeListAdapter(fileDisplayActivity.getSupportFragmentManager(),
+                                                       fileDisplayActivity, shares, account, file, this, userId));
             usersList.setLayoutManager(new LinearLayoutManager(getContext()));
             usersList.addItemDecoration(new SimpleListItemDividerDecoration(getContext()));
             noList.setVisibility(View.GONE);

+ 31 - 41
src/main/java/com/owncloud/android/utils/DisplayUtils.java

@@ -4,9 +4,12 @@
  * @author Andy Scherzinger
  * @author Bartek Przybylski
  * @author David A. Velasco
+ * @author Chris Narkiewicz <hello@ezaquarii.com>
+ *
  * Copyright (C) 2011  Bartek Przybylski
  * Copyright (C) 2015 ownCloud Inc.
  * Copyright (C) 2016 Andy Scherzinger
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -55,6 +58,7 @@ import com.bumptech.glide.request.target.Target;
 import com.caverock.androidsvg.SVG;
 import com.google.android.material.snackbar.Snackbar;
 import com.nextcloud.client.account.CurrentAccountProvider;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.network.ClientFactory;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
@@ -275,39 +279,18 @@ public final class DisplayUtils {
     }
 
     /**
-     * creates the display string for an account.
+     * Creates the display string for a user.
      *
-     * @param context the actual activity
-     * @param savedAccount the actual, saved account
-     * @param accountName the account name
-     * @param fallbackString String to be used in case of an error
      * @return the display string for the given account data
      */
-    public static String getAccountNameDisplayText(Context context, Account savedAccount, String accountName, String
-            fallbackString) {
-        try {
-            return new OwnCloudAccount(savedAccount, context).getDisplayName()
-                    + "@"
-                    + convertIdn(accountName.substring(accountName.lastIndexOf('@') + 1), false);
-        } catch (Exception e) {
-            Log_OC.w(TAG, "Couldn't get display name for account, using old style");
-            return fallbackString;
-        }
+    public static String getAccountNameDisplayText(User user) {
+        final OwnCloudAccount ocs = user.toOwnCloudAccount();
+        final String accountName = user.getAccountName();
+        return ocs.getDisplayName()
+                + "@"
+                + convertIdn(accountName.substring(accountName.lastIndexOf('@') + 1), false);
     }
 
-    /**
-     * converts an array of accounts into a set of account names.
-     *
-     * @param accountList the account array
-     * @return set of account names
-     */
-    public static Set<String> toAccountNameSet(Collection<Account> accountList) {
-        Set<String> actualAccounts = new HashSet<>(accountList.size());
-        for (Account account : accountList) {
-            actualAccounts.add(account.name);
-        }
-        return actualAccounts;
-    }
 
     /**
      * calculates the relative time string based on the given modification timestamp.
@@ -431,46 +414,46 @@ public final class DisplayUtils {
     /**
      * fetches and sets the avatar of the given account in the passed callContext
      *
-     * @param account        the account to be used to connect to server
+     * @param user        the account to be used to connect to server
      * @param avatarRadius   the avatar radius
      * @param resources      reference for density information
      * @param callContext    which context is called to set the generated avatar
      */
-    public static void setAvatar(@NonNull Account account, AvatarGenerationListener listener,
+    public static void setAvatar(@NonNull User user, AvatarGenerationListener listener,
                                  float avatarRadius, Resources resources, Object callContext, Context context) {
 
         AccountManager accountManager = AccountManager.get(context);
-        String userId = accountManager.getUserData(account,
+        String userId = accountManager.getUserData(user.toPlatformAccount(),
                 com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
 
-        setAvatar(account, userId, listener, avatarRadius, resources, callContext, context);
+        setAvatar(user, userId, listener, avatarRadius, resources, callContext, context);
     }
 
     /**
      * fetches and sets the avatar of the given account in the passed callContext
      *
-     * @param account        the account to be used to connect to server
+     * @param user        the account to be used to connect to server
      * @param userId         the userId which avatar should be set
      * @param avatarRadius   the avatar radius
      * @param resources      reference for density information
      * @param callContext    which context is called to set the generated avatar
      */
-    public static void setAvatar(@NonNull Account account, @NonNull String userId, AvatarGenerationListener listener,
+    public static void setAvatar(@NonNull User user, @NonNull String userId, AvatarGenerationListener listener,
                                  float avatarRadius, Resources resources, Object callContext, Context context) {
-        setAvatar(account, userId, userId, listener, avatarRadius, resources, callContext, context);
+        setAvatar(user, userId, userId, listener, avatarRadius, resources, callContext, context);
     }
 
     /**
      * fetches and sets the avatar of the given account in the passed callContext
      *
-     * @param account      the account to be used to connect to server
+     * @param user         the account to be used to connect to server
      * @param userId       the userId which avatar should be set
      * @param displayName  displayName used to generate avatar with first char, only used as fallback
      * @param avatarRadius the avatar radius
      * @param resources    reference for density information
      * @param callContext  which context is called to set the generated avatar
      */
-    public static void setAvatar(@NonNull Account account,
+    public static void setAvatar(@NonNull User user,
                                  @NonNull String userId,
                                  String displayName,
                                  AvatarGenerationListener listener,
@@ -479,12 +462,13 @@ public final class DisplayUtils {
                                  Object callContext,
                                  Context context) {
         if (callContext instanceof View) {
-            ((View) callContext).setContentDescription(String.valueOf(account.hashCode()));
+            ((View) callContext).setContentDescription(String.valueOf(user.toPlatformAccount().hashCode()));
         }
 
         ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
 
-        String serverName = account.name.substring(account.name.lastIndexOf('@') + 1);
+        final String accountName = user.getAccountName();
+        String serverName = accountName.substring(accountName.lastIndexOf('@') + 1);
         String eTag = arbitraryDataProvider.getValue(userId + "@" + serverName, ThumbnailsCacheManager.AVATAR);
         String avatarKey = "a_" + userId + "_" + serverName + "_" + eTag;
 
@@ -505,8 +489,14 @@ public final class DisplayUtils {
         // check for new avatar, eTag is compared, so only new one is downloaded
         if (ThumbnailsCacheManager.cancelPotentialAvatarWork(userId, callContext)) {
             final ThumbnailsCacheManager.AvatarGenerationTask task =
-                new ThumbnailsCacheManager.AvatarGenerationTask(listener, callContext, account, resources,
-                                                                avatarRadius, userId, serverName, context);
+                new ThumbnailsCacheManager.AvatarGenerationTask(listener,
+                                                                callContext,
+                                                                user.toPlatformAccount(),
+                                                                resources,
+                                                                avatarRadius,
+                                                                userId,
+                                                                serverName,
+                                                                context);
 
             final ThumbnailsCacheManager.AsyncAvatarDrawable asyncDrawable =
                 new ThumbnailsCacheManager.AsyncAvatarDrawable(resources, avatar, task);

+ 3 - 0
src/main/java/com/owncloud/android/utils/DrawerMenuUtil.java

@@ -2,7 +2,10 @@
  * Nextcloud Android client application
  *
  * @author Andy Scherzinger
+ * @author Chris Narkiewicz <hello@ezaquarii.com>
+ *
  * Copyright (C) 2018 Andy Scherzinger
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE

+ 33 - 33
src/test/java/com/owncloud/android/ui/adapter/AccountListAdapterTest.java → src/test/java/com/owncloud/android/ui/adapter/UserListAdapterTest.java

@@ -37,9 +37,9 @@ import static org.mockito.Mockito.when;
 /**
  * Class used to test the AccountList Adapter
  */
-public class AccountListAdapterTest {
+public class UserListAdapterTest {
 
-    private AccountListAdapter accountListAdapter;
+    private UserListAdapter userListAdapter;
     private ManageAccountsActivity manageAccountsActivity;
 
     /**
@@ -58,13 +58,13 @@ public class AccountListAdapterTest {
      */
     @Test
     public void test_getItemCountEmptyList() {
-        accountListAdapter = new AccountListAdapter(manageAccountsActivity,
-                                                    null,
-                                                    new ArrayList<>(),
-                                                    null,
-                                                    null,
-                                                    true);
-        assertEquals(0, accountListAdapter.getItemCount());
+        userListAdapter = new UserListAdapter(manageAccountsActivity,
+                                              null,
+                                              new ArrayList<>(),
+                                              null,
+                                              null,
+                                              true);
+        assertEquals(0, userListAdapter.getItemCount());
     }
 
     /**
@@ -72,18 +72,18 @@ public class AccountListAdapterTest {
      */
     @Test
     public void test_getItemCountNormalCase() {
-        List<AccountListItem> accounts = new ArrayList<>();
-        accounts.add(new AccountListItem());
-        accounts.add(new AccountListItem());
-
-        accountListAdapter = new AccountListAdapter(manageAccountsActivity,
-                                                    null,
-                                                    accounts,
-                                                    null,
-                                                    null,
-                                                    true);
-
-        assertEquals(2, accountListAdapter.getItemCount());
+        List<UserListItem> accounts = new ArrayList<>();
+        accounts.add(new UserListItem());
+        accounts.add(new UserListItem());
+
+        userListAdapter = new UserListAdapter(manageAccountsActivity,
+                                              null,
+                                              accounts,
+                                              null,
+                                              null,
+                                              true);
+
+        assertEquals(2, userListAdapter.getItemCount());
     }
 
     /**
@@ -95,19 +95,19 @@ public class AccountListAdapterTest {
         when(manageAccountsActivity.getResources().getDimension(R.dimen.list_item_avatar_icon_radius))
             .thenReturn(new Float(0.1));
 
-        List<AccountListItem> accounts = new ArrayList<>();
-        accountListAdapter = new AccountListAdapter(manageAccountsActivity,
-                                                    null,
-                                                    accounts,
-                                                    null,
-                                                    null,
-                                                    true);
+        List<UserListItem> accounts = new ArrayList<>();
+        userListAdapter = new UserListAdapter(manageAccountsActivity,
+                                              null,
+                                              accounts,
+                                              null,
+                                              null,
+                                              true);
 
-        AccountListItem accountListItem1 = new AccountListItem();
-        AccountListItem accountListItem2 = new AccountListItem();
-        accounts.add(accountListItem1);
-        accounts.add(accountListItem2);
+        UserListItem userListItem1 = new UserListItem();
+        UserListItem userListItem2 = new UserListItem();
+        accounts.add(userListItem1);
+        accounts.add(userListItem2);
 
-        assertEquals(accountListItem2, accountListAdapter.getItem(1));
+        assertEquals(userListItem2, userListAdapter.getItem(1));
     }
 }