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

Merge pull request #2762 from nextcloud/codacy

Fix Codacy issues
Andy Scherzinger 6 жил өмнө
parent
commit
b3356b9758

+ 0 - 1
src/main/AndroidManifest.xml

@@ -243,7 +243,6 @@
         <activity android:name=".ui.activity.PassCodeActivity" />
         <activity android:name=".ui.activity.RequestCredentialsActivity" />
         <activity android:name=".ui.activity.ConflictsResolveActivity"/>
-        <activity android:name=".ui.activity.GenericExplanationActivity"/>
         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
         
         <activity android:name=".ui.activity.LogHistoryActivity"/>

+ 41 - 37
src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -379,6 +379,47 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
         mLoginWebView.loadUrl(url, headers);
 
+        setClient(progressBar);
+
+        // show snackbar after 60s to switch back to old login method
+        new Handler().postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                DisplayUtils.createSnackbar(mLoginWebView, R.string.fallback_weblogin_text, Snackbar.LENGTH_INDEFINITE)
+                        .setActionTextColor(getResources().getColor(R.color.primary_dark))
+                        .setAction(R.string.fallback_weblogin_back, new View.OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                mLoginWebView.setVisibility(View.INVISIBLE);
+                                webViewLoginMethod = false;
+
+                                setContentView(R.layout.account_setup);
+
+                                // initialize general UI elements
+                                initOverallUi();
+
+                                mPasswordInputLayout.setVisibility(View.VISIBLE);
+                                mUsernameInputLayout.setVisibility(View.VISIBLE);
+                                mUsernameInput.requestFocus();
+                                mOAuth2Check.setVisibility(View.INVISIBLE);
+                                mAuthStatusView.setVisibility(View.INVISIBLE);
+                                mServerStatusView.setVisibility(View.INVISIBLE);
+                                mTestServerButton.setVisibility(View.INVISIBLE);
+                                forceOldLoginMethod = true;
+                                mOkButton.setVisibility(View.VISIBLE);
+
+                                initServerPreFragment(null);
+
+                                mHostUrlInput.setText(baseURL);
+
+                                checkOcServer();
+                            }
+                        }).show();
+            }
+        }, 60000);
+    }
+
+    private void setClient(ProgressBar progressBar) {
         mLoginWebView.setWebViewClient(new WebViewClient() {
             @Override
             public boolean shouldOverrideUrlLoading(WebView view, String url) {
@@ -424,43 +465,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                 }
             }
         });
-
-        // show snackbar after 60s to switch back to old login method
-        new Handler().postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                DisplayUtils.createSnackbar(mLoginWebView, R.string.fallback_weblogin_text, Snackbar.LENGTH_INDEFINITE)
-                        .setActionTextColor(getResources().getColor(R.color.primary_dark))
-                        .setAction(R.string.fallback_weblogin_back, new View.OnClickListener() {
-                            @Override
-                            public void onClick(View v) {
-                                mLoginWebView.setVisibility(View.INVISIBLE);
-                                webViewLoginMethod = false;
-
-                                setContentView(R.layout.account_setup);
-
-                                // initialize general UI elements
-                                initOverallUi();
-
-                                mPasswordInputLayout.setVisibility(View.VISIBLE);
-                                mUsernameInputLayout.setVisibility(View.VISIBLE);
-                                mUsernameInput.requestFocus();
-                                mOAuth2Check.setVisibility(View.INVISIBLE);
-                                mAuthStatusView.setVisibility(View.INVISIBLE);
-                                mServerStatusView.setVisibility(View.INVISIBLE);
-                                mTestServerButton.setVisibility(View.INVISIBLE);
-                                forceOldLoginMethod = true;
-                                mOkButton.setVisibility(View.VISIBLE);
-
-                                initServerPreFragment(null);
-
-                                mHostUrlInput.setText(baseURL);
-
-                                checkOcServer();
-                            }
-                        }).show();
-            }
-        }, 60000);
     }
 
     private void parseAndLoginFromWebView(String dataString) {

+ 102 - 80
src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java

@@ -22,6 +22,8 @@ package com.owncloud.android.operations;
 import android.accounts.Account;
 import android.content.Context;
 import android.content.Intent;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.util.Log;
 
 import com.owncloud.android.datamodel.DecryptedFolderMetadata;
@@ -147,13 +149,12 @@ public class RefreshFolderOperation extends RemoteOperation {
         mStorageManager = dataStorageManager;
         mAccount = account;
         mContext = context;
-        mForgottenLocalFiles = new HashMap<String, String>();
+        mForgottenLocalFiles = new HashMap<>();
         mRemoteFolderChanged = false;
         mIgnoreETag = ignoreETag;
-        mFilesToSyncContents = new Vector<SynchronizeFileOperation>();
+        mFilesToSyncContents = new Vector<>();
     }
 
-
     public int getConflictsFound() {
         return mConflictsFound;
     }
@@ -183,7 +184,7 @@ public class RefreshFolderOperation extends RemoteOperation {
      */
     @Override
     protected RemoteOperationResult run(OwnCloudClient client) {
-        RemoteOperationResult result = null;
+        RemoteOperationResult result;
         mFailsInKeptInSyncFound = 0;
         mConflictsFound = 0;
         mForgottenLocalFiles.clear();
@@ -267,7 +268,7 @@ public class RefreshFolderOperation extends RemoteOperation {
 
     private RemoteOperationResult checkForChanges(OwnCloudClient client) {
         mRemoteFolderChanged = true;
-        RemoteOperationResult result = null;
+        RemoteOperationResult result;
         String remotePath = mLocalFolder.getRemotePath();
 
         Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath);
@@ -368,32 +369,18 @@ public class RefreshFolderOperation extends RemoteOperation {
 
         Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() + " changed - starting update of local data ");
 
-        List<OCFile> updatedFiles = new Vector<OCFile>(folderAndFiles.size() - 1);
+        List<OCFile> updatedFiles = new Vector<>(folderAndFiles.size() - 1);
         mFilesToSyncContents.clear();
 
         // if local folder is encrypted, download fresh metadata
-        DecryptedFolderMetadata metadata;
         boolean encryptedAncestor = FileStorageUtils.checkEncryptionStatus(mLocalFolder, mStorageManager);
         mLocalFolder.setEncrypted(encryptedAncestor);
-        
-        if (encryptedAncestor && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
-            metadata = EncryptionUtils.downloadFolderMetadata(mLocalFolder, getClient(), mContext, mAccount);
-        } else {
-            metadata = null;
-        }
 
-        // get current data about local contents of the folder to synchronize
-        List<OCFile> localFiles = mStorageManager.getFolderContent(mLocalFolder, false);
-        Map<String, OCFile> localFilesMap = new HashMap<String, OCFile>(localFiles.size());
-
-        for (OCFile file : localFiles) {
-            String remotePath = file.getRemotePath();
+        DecryptedFolderMetadata metadata = getDecryptedFolderMetadata(encryptedAncestor);
 
-            if (metadata != null && !file.isFolder()) {
-                remotePath = file.getParentRemotePath() + file.getEncryptedFileName();
-            }
-            localFilesMap.put(remotePath, file);
-        }
+        // get current data about local contents of the folder to synchronize
+        Map<String, OCFile> localFilesMap = prefillLocalFilesMap(metadata,
+                mStorageManager.getFolderContent(mLocalFolder, false));
 
         // loop to update every child
         OCFile remoteFile;
@@ -416,36 +403,8 @@ public class RefreshFolderOperation extends RemoteOperation {
             // add to updatedFile data about LOCAL STATE (not existing in server)
             updatedFile.setLastSyncDateForProperties(mCurrentSyncTime);
 
-            if (localFile != null) {
-                updatedFile.setFileId(localFile.getFileId());
-                updatedFile.setAvailableOffline(localFile.isAvailableOffline());
-                updatedFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
-                updatedFile.setModificationTimestampAtLastSyncForData(
-                        localFile.getModificationTimestampAtLastSyncForData()
-                );
-                updatedFile.setStoragePath(localFile.getStoragePath());
-                // eTag will not be updated unless file CONTENTS are synchronized
-                if (!updatedFile.isFolder() && localFile.isDown() &&
-                        !updatedFile.getEtag().equals(localFile.getEtag())) {
-                    updatedFile.setEtagInConflict(updatedFile.getEtag());
-                }
-                updatedFile.setEtag(localFile.getEtag());
-                if (updatedFile.isFolder()) {
-                    updatedFile.setFileLength(remoteFile.getFileLength());
-                    updatedFile.setMountType(remoteFile.getMountType());
-                } else if (mRemoteFolderChanged && MimeTypeUtil.isImage(remoteFile) &&
-                        remoteFile.getModificationTimestamp() !=
-                                localFile.getModificationTimestamp()) {
-                    updatedFile.setNeedsUpdateThumbnail(true);
-                    Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
-                }
-                updatedFile.setPublicLink(localFile.getPublicLink());
-                updatedFile.setShareViaLink(localFile.isSharedViaLink());
-                updatedFile.setShareWithSharee(localFile.isSharedWithSharee());
-            } else {
-                // remote eTag will not be updated unless file CONTENTS are synchronized
-                updatedFile.setEtag("");
-            }
+            // add to updatedFile data from local and remote file
+            setLocalFileDataOnUpdatedFile(remoteFile, localFile, updatedFile, mRemoteFolderChanged);
 
             // check and fix, if needed, local storage path
             FileStorageUtils.searchForLocalFileInDefaultPath(updatedFile, mAccount);
@@ -460,21 +419,7 @@ public class RefreshFolderOperation extends RemoteOperation {
 
             // update file name for encrypted files
             if (metadata != null) {
-                updatedFile.setEncryptedFileName(updatedFile.getFileName());
-                try {
-                    String decryptedFileName = metadata.getFiles().get(updatedFile.getFileName()).getEncrypted()
-                            .getFilename();
-                    String mimetype = metadata.getFiles().get(updatedFile.getFileName()).getEncrypted().getMimetype();
-                    updatedFile.setFileName(decryptedFileName);
-
-                    if (mimetype == null || mimetype.isEmpty()) {
-                        updatedFile.setMimetype("application/octet-stream");
-                    } else {
-                        updatedFile.setMimetype(mimetype);
-                    }
-                } catch (NullPointerException e) {
-                    Log_OC.e(TAG, "Metadata for file " + updatedFile.getFileId() + " not found!");
-                }
+                updateFileNameForEncryptedFile(metadata, updatedFile);
             }
 
             // we parse content, so either the folder itself or its direct parent (which we check) must be encrypted
@@ -490,6 +435,87 @@ public class RefreshFolderOperation extends RemoteOperation {
         mChildren = updatedFiles;
     }
 
+    @Nullable
+    private DecryptedFolderMetadata getDecryptedFolderMetadata(boolean encryptedAncestor) {
+        DecryptedFolderMetadata metadata;
+        if (encryptedAncestor && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+            metadata = EncryptionUtils.downloadFolderMetadata(mLocalFolder, getClient(), mContext, mAccount);
+        } else {
+            metadata = null;
+        }
+        return metadata;
+    }
+
+    private void updateFileNameForEncryptedFile(@NonNull DecryptedFolderMetadata metadata, OCFile updatedFile) {
+        updatedFile.setEncryptedFileName(updatedFile.getFileName());
+        try {
+            String decryptedFileName = metadata.getFiles().get(updatedFile.getFileName()).getEncrypted()
+                    .getFilename();
+            String mimetype = metadata.getFiles().get(updatedFile.getFileName()).getEncrypted().getMimetype();
+            updatedFile.setFileName(decryptedFileName);
+
+            if (mimetype == null || mimetype.isEmpty()) {
+                updatedFile.setMimetype("application/octet-stream");
+            } else {
+                updatedFile.setMimetype(mimetype);
+            }
+        } catch (NullPointerException e) {
+            Log_OC.e(TAG, "Metadata for file " + updatedFile.getFileId() + " not found!");
+        }
+    }
+
+    private void setLocalFileDataOnUpdatedFile(OCFile remoteFile, OCFile localFile, OCFile updatedFile, boolean remoteFolderChanged) {
+        if (localFile != null) {
+            updatedFile.setFileId(localFile.getFileId());
+            updatedFile.setAvailableOffline(localFile.isAvailableOffline());
+            updatedFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
+            updatedFile.setModificationTimestampAtLastSyncForData(
+                    localFile.getModificationTimestampAtLastSyncForData()
+            );
+            updatedFile.setStoragePath(localFile.getStoragePath());
+
+            // eTag will not be updated unless file CONTENTS are synchronized
+            if (!updatedFile.isFolder() && localFile.isDown() &&
+                    !updatedFile.getEtag().equals(localFile.getEtag())) {
+                updatedFile.setEtagInConflict(updatedFile.getEtag());
+            }
+
+            updatedFile.setEtag(localFile.getEtag());
+
+            if (updatedFile.isFolder()) {
+                updatedFile.setFileLength(remoteFile.getFileLength());
+                updatedFile.setMountType(remoteFile.getMountType());
+            } else if (remoteFolderChanged && MimeTypeUtil.isImage(remoteFile) &&
+                    remoteFile.getModificationTimestamp() !=
+                            localFile.getModificationTimestamp()) {
+                updatedFile.setNeedsUpdateThumbnail(true);
+                Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
+            }
+
+            updatedFile.setPublicLink(localFile.getPublicLink());
+            updatedFile.setShareViaLink(localFile.isSharedViaLink());
+            updatedFile.setShareWithSharee(localFile.isSharedWithSharee());
+        } else {
+            // remote eTag will not be updated unless file CONTENTS are synchronized
+            updatedFile.setEtag("");
+        }
+    }
+
+    @NonNull
+    private Map<String, OCFile> prefillLocalFilesMap(DecryptedFolderMetadata metadata, List<OCFile> localFiles) {
+        Map<String, OCFile> localFilesMap = new HashMap<>(localFiles.size());
+
+        for (OCFile file : localFiles) {
+            String remotePath = file.getRemotePath();
+
+            if (metadata != null && !file.isFolder()) {
+                remotePath = file.getParentRemotePath() + file.getEncryptedFileName();
+            }
+            localFilesMap.put(remotePath, file);
+        }
+        return localFilesMap;
+    }
+
     /**
      * Performs a list of synchronization operations, determining if a download or upload is needed
      * or if exists conflict due to changes both in local and remote contents of the each file.
@@ -520,7 +546,6 @@ public class RefreshFolderOperation extends RemoteOperation {
         }
     }
 
-
     /**
      * Syncs the Share resources for the files contained in the folder refreshed (children, not deeper descendants).
      *
@@ -538,7 +563,7 @@ public class RefreshFolderOperation extends RemoteOperation {
 
         if (result.isSuccess()) {
             // update local database
-            ArrayList<OCShare> shares = new ArrayList<OCShare>();
+            ArrayList<OCShare> shares = new ArrayList<>();
             for (Object obj : result.getData()) {
                 shares.add((OCShare) obj);
             }
@@ -548,19 +573,16 @@ public class RefreshFolderOperation extends RemoteOperation {
         return result;
     }
 
-
     /**
-     * Sends a message to any application component interested in the progress 
+     * Sends a message to any application component interested in the progress
      * of the synchronization.
      *
-     * @param event
-     * @param dirRemotePath     Remote path of a folder that was just synchronized 
-     *                          (with or without success)
-     * @param result
+     * @param event         broadcast event (Intent Action)
+     * @param dirRemotePath Remote path of a folder that was just synchronized
+     *                      (with or without success)
+     * @param result        remote operation result
      */
-    private void sendLocalBroadcast(
-            String event, String dirRemotePath, RemoteOperationResult result
-    ) {
+    private void sendLocalBroadcast(String event, String dirRemotePath, RemoteOperationResult result) {
         Log_OC.d(TAG, "Send broadcast " + event);
         Intent intent = new Intent(event);
         intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, mAccount.name);

+ 19 - 69
src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -63,7 +63,6 @@ import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.authentication.PassCodeManager;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.ExternalLinksProvider;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.ExternalLink;
 import com.owncloud.android.lib.common.ExternalLinkType;
@@ -89,6 +88,7 @@ import com.owncloud.android.ui.events.MenuItemClickEvent;
 import com.owncloud.android.ui.events.SearchEvent;
 import com.owncloud.android.ui.trashbin.TrashbinActivity;
 import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.DrawerMenuUtil;
 import com.owncloud.android.utils.FilesSyncHelper;
 import com.owncloud.android.utils.ThemeUtils;
 import com.owncloud.android.utils.svg.MenuSimpleTarget;
@@ -225,7 +225,9 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
 
         setupDrawerToggle();
 
-        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        if(getSupportActionBar() != null) {
+            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        }
     }
 
     /**
@@ -336,77 +338,25 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
         }
 
         Account account = AccountUtils.getCurrentOwnCloudAccount(this);
-        OwnCloudVersion ownCloudVersion = AccountUtils.getServerVersion(getAccount());
-        boolean searchSupported = AccountUtils.hasSearchSupport(account);
-
-        if (getResources().getBoolean(R.bool.bottom_toolbar_enabled) && account != null) {
-            navigationView.getMenu().removeItem(R.id.nav_all_files);
-            navigationView.getMenu().removeItem(R.id.nav_settings);
-            navigationView.getMenu().removeItem(R.id.nav_favorites);
-            navigationView.getMenu().removeItem(R.id.nav_photos);
-        }
-
-        if (!searchSupported && account != null) {
-            navigationView.getMenu().removeItem(R.id.nav_photos);
-            navigationView.getMenu().removeItem(R.id.nav_favorites);
-            navigationView.getMenu().removeItem(R.id.nav_videos);
-        }
-
-        if (account != null) {
-            FileDataStorageManager storageManager = new FileDataStorageManager(account, getContentResolver());
-            OCCapability capability = storageManager.getCapability(account.name);
-            
-            if (ownCloudVersion.compareTo(OwnCloudVersion.nextcloud_14) < 0 || 
-                    capability.getFilesUndelete().isFalse() || capability.getFilesUndelete().isUnknown()) {
-                navigationView.getMenu().removeItem(R.id.nav_trashbin);
-            }
-        }
-
-        if (getResources().getBoolean(R.bool.use_home) && navigationView.getMenu().findItem(R.id.nav_all_files) !=
-                null) {
-            navigationView.getMenu().findItem(R.id.nav_all_files).setTitle(getResources().
-                    getString(R.string.drawer_item_home));
-            navigationView.getMenu().findItem(R.id.nav_all_files).setIcon(R.drawable.ic_home);
-        }
-
-        if (!getResources().getBoolean(R.bool.participate_enabled)) {
-            navigationView.getMenu().removeItem(R.id.nav_participate);
-        }
-
-        if (!getResources().getBoolean(R.bool.shared_enabled)) {
-            navigationView.getMenu().removeItem(R.id.nav_shared);
-        }
+        filterDrawerMenu(navigationView.getMenu(), account);
+    }
 
-        if (!getResources().getBoolean(R.bool.contacts_backup)
-                || !getResources().getBoolean(R.bool.show_drawer_contacts_backup)) {
-            navigationView.getMenu().removeItem(R.id.nav_contacts);
-        }
+    private void filterDrawerMenu(Menu menu, Account account) {
+        DrawerMenuUtil.filterForBottomToolbarMenuItems(menu, getResources());
+        DrawerMenuUtil.filterSearchMenuItems(menu, account, getResources());
+        DrawerMenuUtil.filterTrashbinMenuItems(menu, account, getContentResolver());
 
-        if (getResources().getBoolean(R.bool.syncedFolder_light)) {
-            navigationView.getMenu().removeItem(R.id.nav_synced_folders);
-        }
+        DrawerMenuUtil.setupHomeMenuItem(menu, getResources());
 
-        if (!getResources().getBoolean(R.bool.show_drawer_logout)) {
-            navigationView.getMenu().removeItem(R.id.nav_logout);
-        }
+        DrawerMenuUtil.removeMenuItem(menu, R.id.nav_participate,
+                !getResources().getBoolean(R.bool.participate_enabled));
+        DrawerMenuUtil.removeMenuItem(menu, R.id.nav_shared, !getResources().getBoolean(R.bool.shared_enabled));
+        DrawerMenuUtil.removeMenuItem(menu, R.id.nav_contacts, !getResources().getBoolean(R.bool.contacts_backup)
+                || !getResources().getBoolean(R.bool.show_drawer_contacts_backup));
 
-        if (AccountUtils.hasSearchSupport(account)) {
-            if (!getResources().getBoolean(R.bool.recently_added_enabled)) {
-                navigationView.getMenu().removeItem(R.id.nav_recently_added);
-            }
-
-            if (!getResources().getBoolean(R.bool.recently_modified_enabled)) {
-                navigationView.getMenu().removeItem(R.id.nav_recently_modified);
-            }
-
-            if (!getResources().getBoolean(R.bool.videos_enabled)) {
-                navigationView.getMenu().removeItem(R.id.nav_videos);
-            }
-        } else if (account != null) {
-            navigationView.getMenu().removeItem(R.id.nav_recently_added);
-            navigationView.getMenu().removeItem(R.id.nav_recently_modified);
-            navigationView.getMenu().removeItem(R.id.nav_videos);
-        }
+        DrawerMenuUtil.removeMenuItem(menu, R.id.nav_synced_folders,
+                getResources().getBoolean(R.bool.syncedFolder_light));
+        DrawerMenuUtil.removeMenuItem(menu, R.id.nav_logout, !getResources().getBoolean(R.bool.show_drawer_logout));
     }
 
     @Subscribe(threadMode = ThreadMode.MAIN)

+ 0 - 116
src/main/java/com/owncloud/android/ui/activity/GenericExplanationActivity.java

@@ -1,116 +0,0 @@
-/*
- *   ownCloud Android client application
- *
- *   @author David A. Velasco
- *   Copyright (C) 2015 ownCloud Inc.
- *
- *   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.activity;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v7.app.AppCompatActivity;
-import android.text.method.ScrollingMovementMethod;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.owncloud.android.R;
-
-import java.util.ArrayList;
-
-
-/**
- * Activity showing a text message and, optionally, a couple list of single or paired text strings.
- * 
- * Added to show explanations for notifications when the user clicks on them, and there no place
- * better to show them.
- */
-public class GenericExplanationActivity  extends AppCompatActivity {
-
-    public static final String EXTRA_LIST = GenericExplanationActivity.class.getCanonicalName() + ".EXTRA_LIST";
-    public static final String EXTRA_LIST_2 = GenericExplanationActivity.class.getCanonicalName() + ".EXTRA_LIST_2";
-    public static final String MESSAGE = GenericExplanationActivity.class.getCanonicalName() + ".MESSAGE";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        
-        Intent intent = getIntent();
-        String message = intent.getStringExtra(MESSAGE); 
-        ArrayList<String> list = intent.getStringArrayListExtra(EXTRA_LIST);
-        ArrayList<String> list2 = intent.getStringArrayListExtra(EXTRA_LIST_2);
-        
-        setContentView(R.layout.generic_explanation);
-        
-        if (message != null) {
-            TextView textView = (TextView) findViewById(R.id.message);
-            textView.setText(message);
-            textView.setMovementMethod(new ScrollingMovementMethod());
-        }
-        
-        ListView listView = (ListView) findViewById(R.id.list);
-        if (list != null && list.size() > 0) {
-            //ListAdapter adapter = new ArrayAdapter<String>(this,
-            // android.R.layout.simple_list_item_1, list);
-            ListAdapter adapter = new ExplanationListAdapterView(this, list, list2);
-            listView.setAdapter(adapter);
-        } else {
-            listView.setVisibility(View.GONE);
-        }
-    }
-
-    public class ExplanationListAdapterView extends ArrayAdapter<String> {
-        
-        ArrayList<String> mList;
-        ArrayList<String> mList2;
-        
-        ExplanationListAdapterView(Context context, ArrayList<String> list,
-                                   ArrayList<String> list2) {
-            super(context, android.R.layout.two_line_list_item, android.R.id.text1, list);
-            mList = list;
-            mList2 = list2;
-        }
-
-        @Override
-        public boolean isEnabled(int position) {
-            return false;
-        }
-        
-        /**
-         * {@inheritDoc}
-         */
-        @NonNull
-        @Override
-        public View getView (int position, View convertView, @NonNull ViewGroup parent) {
-            View view = super.getView(position, convertView, parent);
-            if (mList2 != null && mList2.size() > 0 && position >= 0 &&
-                    position < mList2.size()) {
-                TextView text2 = (TextView) view.findViewById(android.R.id.text2);
-                if (text2 != null) {
-                    text2.setText(mList2.get(position));
-                }
-            }
-            return view;
-        }
-    }
-
-}

+ 40 - 125
src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java

@@ -97,21 +97,17 @@ public class PassCodeActivity extends AppCompatActivity {
         mPassCodeHdrExplanation = findViewById(R.id.explanation);
 
         mPassCodeEditTexts[0] = findViewById(R.id.txt0);
-        mPassCodeEditTexts[0].setTextColor(elementColor);
-        mPassCodeEditTexts[0].getBackground().setColorFilter(elementColor, PorterDuff.Mode.SRC_ATOP);
+        ThemeUtils.colorEditText(mPassCodeEditTexts[0], elementColor);
         mPassCodeEditTexts[0].requestFocus();
         
         mPassCodeEditTexts[1] = findViewById(R.id.txt1);
-        mPassCodeEditTexts[1].setTextColor(elementColor);
-        mPassCodeEditTexts[1].getBackground().setColorFilter(elementColor, PorterDuff.Mode.SRC_ATOP);
+        ThemeUtils.colorEditText(mPassCodeEditTexts[1], elementColor);
 
         mPassCodeEditTexts[2] = findViewById(R.id.txt2);
-        mPassCodeEditTexts[2].setTextColor(elementColor);
-        mPassCodeEditTexts[2].getBackground().setColorFilter(elementColor, PorterDuff.Mode.SRC_ATOP);
+        ThemeUtils.colorEditText(mPassCodeEditTexts[2], elementColor);
 
         mPassCodeEditTexts[3] = findViewById(R.id.txt3);
-        mPassCodeEditTexts[3].setTextColor(elementColor);
-        mPassCodeEditTexts[3].getBackground().setColorFilter(elementColor, PorterDuff.Mode.SRC_ATOP);
+        ThemeUtils.colorEditText(mPassCodeEditTexts[3], elementColor);
 
         Window window = getWindow();
         if (window != null) {
@@ -136,8 +132,7 @@ public class PassCodeActivity extends AppCompatActivity {
                 /// pass code preference has just been activated in Preferences;
                 // will receive and confirm pass code value
                 mPassCodeHdr.setText(R.string.pass_code_configure_your_pass_code);
-                //mPassCodeHdr.setText(R.string.pass_code_enter_pass_code);
-                // TODO choose a header, check iOS
+
                 mPassCodeHdrExplanation.setVisibility(View.VISIBLE);
                 setCancelButtonEnabled(true);
             }
@@ -150,8 +145,7 @@ public class PassCodeActivity extends AppCompatActivity {
             setCancelButtonEnabled(true);
 
         } else {
-            throw new IllegalArgumentException("A valid ACTION is needed in the Intent passed to "
-                    + TAG);
+            throw new IllegalArgumentException("A valid ACTION is needed in the Intent passed to " + TAG);
         }
 
         setTextListeners();
@@ -184,130 +178,53 @@ public class PassCodeActivity extends AppCompatActivity {
      * Binds the appropriate listeners to the input boxes receiving each digit of the pass code.
      */
     protected void setTextListeners() {
-    
-         ///  First input field
         mPassCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false));
-
-
-        /*------------------------------------------------
-         *  SECOND BOX 
-         -------------------------------------------------*/
         mPassCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false));
-
-        mPassCodeEditTexts[1].setOnKeyListener(new View.OnKeyListener() {
-
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {  // TODO WIP: event should be
-                // used to control what's exactly happening with DEL, not any custom field...
-                    mPassCodeEditTexts[0].setText("");
-                    mPassCodeEditTexts[0].requestFocus();
-                    if (!mConfirmingPassCode) {
-                        mPassCodeDigits[0] = "";
-                    }
-                    mBChange = false;
-
-                } else if (!mBChange) {
-                    mBChange = true;
-                }
-                return false;
-            }
-        });
-
-        mPassCodeEditTexts[1].setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                /// TODO WIP: should take advantage of hasFocus to reduce processing
-                if (mPassCodeEditTexts[0].getText().toString().equals("")) {  // TODO WIP validation
-                // could be done in a global way, with a single OnFocusChangeListener for all the
-                // input fields
-                    mPassCodeEditTexts[0].requestFocus();
-                }
-            }
-        });
-        
-        
-        /*------------------------------------------------
-         *  THIRD BOX
-         -------------------------------------------------*/
         mPassCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false));
+        mPassCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true));
 
-        mPassCodeEditTexts[2].setOnKeyListener(new View.OnKeyListener() {
-
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
-                    mPassCodeEditTexts[1].requestFocus();
-                    if (!mConfirmingPassCode) {
-                        mPassCodeDigits[1] = "";
-                    }
-                    mPassCodeEditTexts[1].setText("");
-                    mBChange = false;
-
-                } else if (!mBChange) {
-                    mBChange = true;
+        setOnKeyListener(1);
+        setOnKeyListener(2);
+        setOnKeyListener(3);
 
-                }
-                return false;
-            }
+        mPassCodeEditTexts[1].setOnFocusChangeListener((v, hasFocus) -> {
+            onPassCodeEditTextFocusChange(1);
         });
 
-        mPassCodeEditTexts[2].setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (mPassCodeEditTexts[0].getText().toString().equals("")) {
-                    mPassCodeEditTexts[0].requestFocus();
-                } else if (mPassCodeEditTexts[1].getText().toString().equals("")) {
-                    mPassCodeEditTexts[1].requestFocus();
-                }
-            }
+        mPassCodeEditTexts[2].setOnFocusChangeListener((v, hasFocus) -> {
+            onPassCodeEditTextFocusChange(2);
         });
 
-
-        /*------------------------------------------------
-         *  FOURTH BOX
-         -------------------------------------------------*/
-        mPassCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true));
-
-        mPassCodeEditTexts[3].setOnKeyListener(new View.OnKeyListener() {
-
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
-                    mPassCodeEditTexts[2].requestFocus();
-                    if (!mConfirmingPassCode) {
-                        mPassCodeDigits[2] = "";
-                    }
-                    mPassCodeEditTexts[2].setText("");
-                    mBChange = false;
-
-                } else if (!mBChange) {
-                    mBChange = true;
-                }
-                return false;
-            }
+        mPassCodeEditTexts[3].setOnFocusChangeListener((v, hasFocus) -> {
+            onPassCodeEditTextFocusChange(3);
         });
+    }
 
-        mPassCodeEditTexts[3].setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
+    private void onPassCodeEditTextFocusChange(final int passCodeIndex) {
+        for (int i = 0; i < passCodeIndex; i++) {
+            if (mPassCodeEditTexts[i].getText().toString().equals("")) {
+                mPassCodeEditTexts[i].requestFocus();
+                break;
+            }
+        }
+    }
 
-                if (mPassCodeEditTexts[0].getText().toString().equals("")) {
-                    mPassCodeEditTexts[0].requestFocus();
-                } else if (mPassCodeEditTexts[1].getText().toString().equals("")) {
-                    mPassCodeEditTexts[1].requestFocus();
-                } else if (mPassCodeEditTexts[2].getText().toString().equals("")) {
-                    mPassCodeEditTexts[2].requestFocus();
+    private void setOnKeyListener(final int passCodeIndex) {
+        mPassCodeEditTexts[passCodeIndex].setOnKeyListener((v, keyCode, event) -> {
+            if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
+                mPassCodeEditTexts[passCodeIndex - 1].requestFocus();
+                if (!mConfirmingPassCode) {
+                    mPassCodeDigits[passCodeIndex - 1] = "";
                 }
+                mPassCodeEditTexts[passCodeIndex - 1].setText("");
+                mBChange = false;
 
+            } else if (!mBChange) {
+                mBChange = true;
             }
+            return false;
         });
-
-    } // end setTextListener
-
+    }
 
     /**
      * Processes the pass code entered by the user just after the last digit was in.
@@ -323,8 +240,7 @@ public class PassCodeActivity extends AppCompatActivity {
                 finish();
 
             }  else {
-                showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code,
-                        View.INVISIBLE);
+                showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE);
             }
 
         } else if (ACTION_CHECK_WITH_RESULT.equals(getIntent().getAction())) {
@@ -335,8 +251,7 @@ public class PassCodeActivity extends AppCompatActivity {
                 hideSoftKeyboard();
                 finish();
             } else {
-                showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code,
-                        View.INVISIBLE);
+                showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE);
             }
 
         } else if (ACTION_REQUEST_WITH_RESULT.equals(getIntent().getAction())) {
@@ -482,7 +397,7 @@ public class PassCodeActivity extends AppCompatActivity {
     private class PassCodeDigitTextWatcher implements TextWatcher {
 
         private int mIndex = -1;
-        private boolean mLastOne = false;
+        private boolean mLastOne;
 
         /**
          * Constructor

+ 76 - 88
src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java

@@ -26,6 +26,7 @@ import android.content.ActivityNotFoundException;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.support.annotation.NonNull;
 import android.text.format.DateUtils;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -413,89 +414,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
                 break;
 
             case UPLOAD_FAILED:
-                switch (upload.getLastResult()) {
-                    case CREDENTIAL_ERROR:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_failed_credentials_error
-                        );
-                        break;
-                    case FOLDER_ERROR:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_failed_folder_error
-                        );
-                        break;
-                    case FILE_NOT_FOUND:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_failed_localfile_error
-                        );
-                        break;
-                    case FILE_ERROR:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_failed_file_error
-                        );
-                        break;
-                    case PRIVILEDGES_ERROR:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_failed_permission_error
-                        );
-                        break;
-                    case NETWORK_CONNECTION:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_failed_connection_error
-                        );
-                        break;
-                    case DELAYED_FOR_WIFI:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_waiting_for_wifi
-                        );
-                        break;
-                    case DELAYED_FOR_CHARGING:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_waiting_for_charging);
-                        break;
-                    case CONFLICT_ERROR:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_conflict
-                        );
-                        break;
-                    case SERVICE_INTERRUPTED:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_service_interrupted
-                        );
-                        break;
-                    case CANCELLED:
-                        // should not get here ; cancelled uploads should be wiped out
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_cancelled
-                        );
-                        break;
-                    case UPLOADED:
-                        // should not get here ; status should be UPLOAD_SUCCESS
-                        status = mParentActivity.getString(R.string.uploads_view_upload_status_succeeded);
-                        break;
-                    case MAINTENANCE_MODE:
-                        status = mParentActivity.getString(R.string.maintenance_mode);
-                        break;
-                    case SSL_RECOVERABLE_PEER_UNVERIFIED:
-                        status =
-                                mParentActivity.getString(
-                                        R.string.uploads_view_upload_status_failed_ssl_certificate_not_trusted
-                                );
-                        break;
-                    case UNKNOWN:
-                        status = mParentActivity.getString(R.string.uploads_view_upload_status_unknown_fail);
-                        break;
-                    case DELAYED_IN_POWER_SAVE_MODE:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_waiting_exit_power_save_mode);
-                        break;
-                    case VIRUS_DETECTED:
-                        status = mParentActivity.getString(R.string.uploads_view_upload_status_virus_detected);
-                        break;
-                    default:
-                        status = "New fail result but no description for the user";
-                        break;
-                }
+                status = getUploadFailedStatusText(upload.getLastResult());
                 break;
 
             default:
@@ -504,15 +423,84 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
         return status;
     }
 
+    @NonNull
+    private String getUploadFailedStatusText(UploadResult result) {
+        String status;
+        switch (result) {
+            case CREDENTIAL_ERROR:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_failed_credentials_error);
+                break;
+            case FOLDER_ERROR:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_failed_folder_error);
+                break;
+            case FILE_NOT_FOUND:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_failed_localfile_error);
+                break;
+            case FILE_ERROR:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_failed_file_error);
+                break;
+            case PRIVILEDGES_ERROR:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_failed_permission_error);
+                break;
+            case NETWORK_CONNECTION:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_failed_connection_error);
+                break;
+            case DELAYED_FOR_WIFI:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_waiting_for_wifi);
+                break;
+            case DELAYED_FOR_CHARGING:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_waiting_for_charging);
+                break;
+            case CONFLICT_ERROR:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_conflict);
+                break;
+            case SERVICE_INTERRUPTED:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_service_interrupted);
+                break;
+            case CANCELLED:
+                // should not get here ; cancelled uploads should be wiped out
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_cancelled);
+                break;
+            case UPLOADED:
+                // should not get here ; status should be UPLOAD_SUCCESS
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_succeeded);
+                break;
+            case MAINTENANCE_MODE:
+                status = mParentActivity.getString(R.string.maintenance_mode);
+                break;
+            case SSL_RECOVERABLE_PEER_UNVERIFIED:
+                status =
+                        mParentActivity.getString(
+                                R.string.uploads_view_upload_status_failed_ssl_certificate_not_trusted
+                        );
+                break;
+            case UNKNOWN:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_unknown_fail);
+                break;
+            case DELAYED_IN_POWER_SAVE_MODE:
+                status = mParentActivity.getString(
+                        R.string.uploads_view_upload_status_waiting_exit_power_save_mode);
+                break;
+            case VIRUS_DETECTED:
+                status = mParentActivity.getString(R.string.uploads_view_upload_status_virus_detected);
+                break;
+            default:
+                status = "New fail result but no description for the user";
+                break;
+        }
+
+        return status;
+    }
 
     @Override
-    public SectionedViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+    @NonNull
+    public SectionedViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
         if (viewType == VIEW_TYPE_HEADER) {
-            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.upload_list_header, parent, false);
-            return new HeaderViewHolder(v);
+            return new HeaderViewHolder(
+                    LayoutInflater.from(parent.getContext()).inflate(R.layout.upload_list_header, parent, false));
         } else {
-            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.upload_list_item, parent, false);
-            return new ItemViewHolder(v);
+            return new ItemViewHolder(
+                    LayoutInflater.from(parent.getContext()).inflate(R.layout.upload_list_item, parent, false));
         }
     }
 

+ 5 - 3
src/main/java/com/owncloud/android/ui/dialog/SetupEncryptionDialogFragment.java

@@ -61,7 +61,6 @@ import java.util.Locale;
 /*
  *  Dialog to setup encryption
  */
-
 public class SetupEncryptionDialogFragment extends DialogFragment {
 
     public static final String SUCCESS = "SUCCESS";
@@ -143,7 +142,11 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
         DrawableCompat.setTint(wrappedDrawable, accentColor);
         passwordField.setBackgroundDrawable(wrappedDrawable);
 
-        // Build the dialog  
+        return createDialog(accentColor, v);
+    }
+
+    @NonNull
+    private Dialog createDialog(int accentColor, View v) {
         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
         builder.setView(v).setPositiveButton(R.string.common_ok, null)
                 .setNegativeButton(R.string.common_cancel, null)
@@ -224,7 +227,6 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
                 });
             }
         });
-
         return dialog;
     }
 

+ 69 - 70
src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactListFragment.java

@@ -627,53 +627,13 @@ class ContactListAdapter extends RecyclerView.Adapter<ContactListFragment.Contac
 
         if (vcard != null) {
 
-            if (checkedVCards.contains(position)) {
-                holder.getName().setChecked(true);
-
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-                    holder.getName().getCheckMarkDrawable()
-                            .setColorFilter(ThemeUtils.primaryAccentColor(context), PorterDuff.Mode.SRC_ATOP);
-                }
-            } else {
-                holder.getName().setChecked(false);
-
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-                    holder.getName().getCheckMarkDrawable().clearColorFilter();
-                }
-            }
+            setChecked(checkedVCards.contains(position), holder.getName());
 
             holder.getName().setText(getDisplayName(vcard));
 
             // photo
             if (vcard.getPhotos().size() > 0) {
-                Photo firstPhoto = vcard.getPhotos().get(0);
-                String url = firstPhoto.getUrl();
-                byte[] data = firstPhoto.getData();
-
-                if (data != null && data.length > 0) {
-                    Bitmap thumbnail = BitmapFactory.decodeByteArray(data, 0, data.length);
-                    RoundedBitmapDrawable drawable = BitmapUtils.bitmapToCircularBitmapDrawable(context.getResources(),
-                            thumbnail);
-
-                    holder.getBadge().setImageDrawable(drawable);
-                } else if (url != null) {
-                    ImageView badge = holder.getBadge();
-                    SimpleTarget target = new SimpleTarget<Drawable>() {
-                        @Override
-                        public void onResourceReady(Drawable resource, GlideAnimation
-                                glideAnimation) {
-                            holder.getBadge().setImageDrawable(resource);
-                        }
-
-                        @Override
-                        public void onLoadFailed(Exception e, Drawable errorDrawable) {
-                            super.onLoadFailed(e, errorDrawable);
-                            holder.getBadge().setImageDrawable(errorDrawable);
-                        }
-                    };
-                    DisplayUtils.downloadIcon(context, url, target, R.drawable.ic_user,
-                            badge.getWidth(), badge.getHeight());
-                }
+                setPhoto(holder.getBadge(), vcard.getPhotos().get(0));
             } else {
                 try {
                     holder.getBadge().setImageDrawable(
@@ -687,39 +647,78 @@ class ContactListAdapter extends RecyclerView.Adapter<ContactListFragment.Contac
                 }
             }
 
-            // Checkbox
-            holder.setVCardListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    holder.getName().setChecked(!holder.getName().isChecked());
+            holder.setVCardListener(v -> toggleVCard(holder, verifiedPosition));
+        }
+    }
 
-                    if (holder.getName().isChecked()) {
-                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-                            holder.getName().getCheckMarkDrawable()
-                                    .setColorFilter(ThemeUtils.primaryAccentColor(context), PorterDuff.Mode.SRC_ATOP);
-                        }
+    private void setPhoto(ImageView imageView, Photo firstPhoto) {
+        String url = firstPhoto.getUrl();
+        byte[] data = firstPhoto.getData();
 
-                        if (!checkedVCards.contains(verifiedPosition)) {
-                            checkedVCards.add(verifiedPosition);
-                        }
-                        if (checkedVCards.size() == 1) {
-                            EventBus.getDefault().post(new VCardToggleEvent(true));
-                        }
-                    } else {
-                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-                            holder.getName().getCheckMarkDrawable().clearColorFilter();
-                        }
+        if (data != null && data.length > 0) {
+            Bitmap thumbnail = BitmapFactory.decodeByteArray(data, 0, data.length);
+            RoundedBitmapDrawable drawable = BitmapUtils.bitmapToCircularBitmapDrawable(context.getResources(),
+                    thumbnail);
 
-                        if (checkedVCards.contains(verifiedPosition)) {
-                            checkedVCards.remove(verifiedPosition);
-                        }
+            imageView.setImageDrawable(drawable);
+        } else if (url != null) {
+            SimpleTarget target = new SimpleTarget<Drawable>() {
+                @Override
+                public void onResourceReady(Drawable resource, GlideAnimation glideAnimation) {
+                    imageView.setImageDrawable(resource);
+                }
 
-                        if (checkedVCards.size() == 0) {
-                            EventBus.getDefault().post(new VCardToggleEvent(false));
-                        }
-                    }
+                @Override
+                public void onLoadFailed(Exception e, Drawable errorDrawable) {
+                    super.onLoadFailed(e, errorDrawable);
+                    imageView.setImageDrawable(errorDrawable);
                 }
-            });
+            };
+            DisplayUtils.downloadIcon(context, url, target, R.drawable.ic_user, imageView.getWidth(),
+                    imageView.getHeight());
+        }
+    }
+
+    private void setChecked(boolean checked, CheckedTextView checkedTextView) {
+        checkedTextView.setChecked(checked);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+            if (checked) {
+                checkedTextView.getCheckMarkDrawable()
+                        .setColorFilter(ThemeUtils.primaryAccentColor(context), PorterDuff.Mode.SRC_ATOP);
+            } else {
+                checkedTextView.getCheckMarkDrawable().clearColorFilter();
+            }
+        }
+    }
+
+    private void toggleVCard(ContactListFragment.ContactItemViewHolder holder, int verifiedPosition) {
+        holder.getName().setChecked(!holder.getName().isChecked());
+
+        if (holder.getName().isChecked()) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                holder.getName().getCheckMarkDrawable()
+                        .setColorFilter(ThemeUtils.primaryAccentColor(context), PorterDuff.Mode.SRC_ATOP);
+            }
+
+            if (!checkedVCards.contains(verifiedPosition)) {
+                checkedVCards.add(verifiedPosition);
+            }
+            if (checkedVCards.size() == 1) {
+                EventBus.getDefault().post(new VCardToggleEvent(true));
+            }
+        } else {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                holder.getName().getCheckMarkDrawable().clearColorFilter();
+            }
+
+            if (checkedVCards.contains(verifiedPosition)) {
+                checkedVCards.remove(verifiedPosition);
+            }
+
+            if (checkedVCards.size() == 0) {
+                EventBus.getDefault().post(new VCardToggleEvent(false));
+            }
         }
     }
 

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

@@ -0,0 +1,102 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2018 Andy Scherzinger
+ *
+ * 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.utils;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.content.res.Resources;
+import android.view.Menu;
+
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.lib.resources.status.OCCapability;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+
+/**
+ * A helper class for drawer menu related operations.
+ */
+public class DrawerMenuUtil {
+    private DrawerMenuUtil() {
+    }
+
+    public static void filterForBottomToolbarMenuItems(Menu menu, Resources resources) {
+        if (resources.getBoolean(R.bool.bottom_toolbar_enabled)) {
+            filterMenuItems(menu, R.id.nav_all_files, R.id.nav_settings, R.id.nav_favorites, R.id.nav_photos);
+        }
+    }
+
+    public static void filterSearchMenuItems(Menu menu, Account account, Resources resources) {
+        boolean hasSearchSupport = AccountUtils.hasSearchSupport(account);
+        if (account != null && !hasSearchSupport) {
+            filterMenuItems(menu, R.id.nav_photos, R.id.nav_favorites, R.id.nav_videos);
+        }
+
+        if (hasSearchSupport) {
+            if (!resources.getBoolean(R.bool.recently_added_enabled)) {
+                menu.removeItem(R.id.nav_recently_added);
+            }
+
+            if (!resources.getBoolean(R.bool.recently_modified_enabled)) {
+                menu.removeItem(R.id.nav_recently_modified);
+            }
+
+            if (!resources.getBoolean(R.bool.videos_enabled)) {
+                menu.removeItem(R.id.nav_videos);
+            }
+        } else if (account != null) {
+            filterMenuItems(menu, R.id.nav_recently_added, R.id.nav_recently_modified, R.id.nav_videos);
+        }
+    }
+
+    public static void filterTrashbinMenuItems(Menu menu, Account account, ContentResolver contentResolver) {
+        if (account != null) {
+            FileDataStorageManager storageManager = new FileDataStorageManager(account, contentResolver);
+            OCCapability capability = storageManager.getCapability(account.name);
+
+            if (AccountUtils.getServerVersion(account).compareTo(OwnCloudVersion.nextcloud_14) < 0 ||
+                    capability.getFilesUndelete().isFalse() || capability.getFilesUndelete().isUnknown()) {
+                filterMenuItems(menu, R.id.nav_trashbin);
+            }
+        }
+    }
+
+    public static void removeMenuItem(Menu menu, int id, boolean remove) {
+        if (remove) {
+            menu.removeItem(id);
+        }
+    }
+
+    public static void setupHomeMenuItem(Menu menu, Resources resources) {
+        if (resources.getBoolean(R.bool.use_home) && menu.findItem(R.id.nav_all_files) != null) {
+            menu.findItem(R.id.nav_all_files).setTitle(resources.getString(R.string.drawer_item_home));
+            menu.findItem(R.id.nav_all_files).setIcon(R.drawable.ic_home);
+        }
+    }
+
+    private static void filterMenuItems(Menu menu, int... menuIds) {
+        if (menuIds != null) {
+            for (int menuId : menuIds) {
+                menu.removeItem(menuId);
+            }
+        }
+    }
+}

+ 8 - 0
src/main/java/com/owncloud/android/utils/ThemeUtils.java

@@ -47,6 +47,7 @@ import android.support.v7.widget.SwitchCompat;
 import android.text.Html;
 import android.text.Spanned;
 import android.view.Window;
+import android.widget.EditText;
 import android.widget.ImageButton;
 import android.widget.ProgressBar;
 import android.widget.SeekBar;
@@ -270,6 +271,13 @@ public class ThemeUtils {
         }
     }
 
+    public static void colorEditText(EditText editText, int elementColor) {
+        if (editText != null) {
+            editText.setTextColor(elementColor);
+            editText.getBackground().setColorFilter(elementColor, PorterDuff.Mode.SRC_ATOP);
+        }
+    }
+
     /**
      * sets the coloring of the given progress bar to color_accent.
      *