Detailed changes
  
  
    
    @@ -6,6 +6,8 @@ import android.net.Uri;
 import android.os.SystemClock;
 import android.util.Log;
 
+import androidx.core.graphics.ColorUtils;
+
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 
@@ -109,6 +111,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
     private String pinnedChannelBinding;
     private String fastMechanism;
     private String fastToken;
+    private Integer color = null;
 
     public Account(final Jid jid, final String password) {
         this(
@@ -236,6 +239,23 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
         return pgpDecryptionService != null && pgpDecryptionService.isConnected();
     }
 
+    public void setColor(Integer color) {
+        this.color = color;
+    }
+
+    public int getColor(boolean dark) {
+        if (color != null) return color.intValue();
+
+        return ColorUtils.setAlphaComponent(
+            getAvatarBackgroundColor(),
+            dark ? 20 : 15
+        );
+    }
+
+    public Integer getColorToSave() {
+        return color;
+    }
+
     public boolean setShowErrorNotification(boolean newValue) {
         boolean oldValue = showErrorNotification();
         setKey("show_error", Boolean.toString(newValue));
  
  
  
    
    @@ -1288,6 +1288,10 @@ public class XmppConnectionService extends Service {
         this.databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
         Log.d(Config.LOGTAG, "restoring accounts...");
         this.accounts = databaseBackend.getAccounts();
+        for (Account account : this.accounts) {
+            final int color = getPreferences().getInt("account_color:" + account.getUuid(), 0);
+            if (color != 0) account.setColor(color);
+        }
         final SharedPreferences.Editor editor = getPreferences().edit();
         if (this.accounts.size() == 0 && Arrays.asList("Sony", "Sony Ericsson").contains(Build.MANUFACTURER)) {
             editor.putBoolean(SettingsActivity.KEEP_FOREGROUND_SERVICE, true);
@@ -2577,6 +2581,12 @@ public class XmppConnectionService extends Service {
 
     public boolean updateAccount(final Account account) {
         if (databaseBackend.updateAccount(account)) {
+            Integer color = account.getColorToSave();
+            if (color == null) {
+                getPreferences().edit().remove("account_color:" + account.getUuid()).commit();
+            } else {
+                getPreferences().edit().putInt("account_color:" + account.getUuid(), color.intValue()).commit();
+            }
             account.setShowErrorNotification(true);
             this.statusListener.onStatusChanged(account);
             databaseBackend.updateAccount(account);
  
  
  
    
    @@ -7,6 +7,7 @@ import android.content.Intent;
 import android.content.IntentSender;
 import android.content.SharedPreferences;
 import android.graphics.Bitmap;
+import android.graphics.drawable.ColorDrawable;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -39,6 +40,8 @@ import androidx.databinding.DataBindingUtil;
 import com.google.android.material.textfield.TextInputLayout;
 import com.google.common.base.CharMatcher;
 
+import com.rarepebble.colorpicker.ColorPickerView;
+
 import org.openintents.openpgp.util.OpenPgpUtils;
 
 import java.util.Arrays;
@@ -146,6 +149,11 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             final boolean wasDisabled = mAccount != null && mAccount.getStatus() == Account.State.DISABLED;
             final boolean accountInfoEdited = accountInfoEdited();
 
+            ColorDrawable previewColor = (ColorDrawable) binding.colorPreview.getBackground();
+            if (previewColor != null && previewColor.getColor() != mAccount.getColor(isDarkTheme())) {
+                mAccount.setColor(previewColor.getColor());
+            }
+
             if (mInitMode && mAccount != null) {
                 mAccount.setOption(Account.OPTION_DISABLED, false);
             }
@@ -567,9 +575,11 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         if (this.mAccount == null) {
             return false;
         }
+        ColorDrawable previewColor = (ColorDrawable) binding.colorPreview.getBackground();
         return jidEdited() ||
                 !this.mAccount.getPassword().equals(this.binding.accountPassword.getText().toString()) ||
                 !this.mAccount.getHostname().equals(this.binding.hostname.getText().toString()) ||
+                this.mAccount.getColor(isDarkTheme()) != (previewColor == null ? 0 : previewColor.getColor()) ||
                 !String.valueOf(this.mAccount.getPort()).equals(this.binding.port.getText().toString());
     }
 
@@ -622,6 +632,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             this.binding.accountRegisterNew.setVisibility(View.GONE);
         }
         this.binding.actionEditYourName.setOnClickListener(this::onEditYourNameClicked);
+        binding.accountColorBox.setOnClickListener((v) -> {
+            showColorDialog();
+        });
     }
 
     private void onEditYourNameClicked(View view) {
@@ -980,6 +993,26 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         }
     }
 
+    void showColorDialog() {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final ColorPickerView picker = new ColorPickerView(this);
+
+        picker.setColor(mAccount.getColor(isDarkTheme()));
+        picker.showAlpha(true);
+        picker.showHex(true);
+        picker.showPreview(true);
+        builder
+                .setTitle(null)
+                .setView(picker)
+                .setPositiveButton(R.string.ok, (dialog, which) -> {
+                    final int color = picker.getColor();
+                    binding.colorPreview.setBackgroundColor(color);
+                    updateSaveButton();
+                })
+                .setNegativeButton(R.string.cancel, (dialog, which) -> {});
+        builder.show();
+    }
+
     private void updateAccountInformation(boolean init) {
         if (init) {
             this.binding.accountJid.getEditableText().clear();
@@ -1012,6 +1045,12 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         final String displayName = mAccount.getDisplayName();
         updateDisplayName(displayName);
 
+        if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() > 1) {
+            binding.accountColorBox.setVisibility(View.VISIBLE);
+            binding.colorPreview.setBackgroundColor(mAccount.getColor(isDarkTheme()));
+        } else {
+            binding.accountColorBox.setVisibility(View.GONE);
+        }
 
         final boolean togglePassword = mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY);
         final boolean editPassword = !mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || (!mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY) && QuickConversationsService.isConversations()) || mAccount.getLastErrorStatus() == Account.State.UNAUTHORIZED;
  
  
  
    
    @@ -82,10 +82,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
             }
         });
         if (activity.xmppConnectionService != null && activity.xmppConnectionService.getAccounts().size() > 1) {
-            viewHolder.binding.frame.setBackgroundColor(ColorUtils.setAlphaComponent(
-                UIHelper.getColorForName(account.getJid().asBareJid().toString()),
-                activity.isDarkTheme() ? 20 : 15
-            ));
+            viewHolder.binding.frame.setBackgroundColor(account.getColor(activity.isDarkTheme()));
         }
         return view;
     }
  
  
  
    
    @@ -70,10 +70,7 @@ public class ConversationAdapter
         }
 
         if (activity.xmppConnectionService != null && activity.xmppConnectionService.getAccounts().size() > 1) {
-            viewHolder.binding.frame.setBackgroundColor(ColorUtils.setAlphaComponent(
-                UIHelper.getColorForName(conversation.getAccount().getJid().asBareJid().toString()),
-                activity.isDarkTheme() ? 20 : 15
-            ));
+            viewHolder.binding.frame.setBackgroundColor(conversation.getAccount().getColor(activity.isDarkTheme()));
         }
 
         Message message = conversation.getLatestMessage();
  
  
  
    
    @@ -65,10 +65,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
 		}
 
 		if (activity.xmppConnectionService != null && activity.xmppConnectionService.getAccounts().size() > 1) {
-			view.setBackgroundColor(ColorUtils.setAlphaComponent(
-				UIHelper.getColorForName(item.getAccount().getJid().asBareJid().toString()),
-				activity.isDarkTheme() ? 20 : 15
-			));
+			view.setBackgroundColor(item.getAccount().getColor(activity.isDarkTheme()));
 		} else {
 			view.setBackground(StyledAttributes.getDrawable(view.getContext(),R.attr.list_item_background));
 		}
  
  
  
    
    @@ -536,6 +536,57 @@
                                 android:visibility="visible"/>
                         </RelativeLayout>
 
+                        <RelativeLayout
+                            android:id="@+id/account_color_box"
+                            android:layout_width="wrap_content"
+                            android:layout_height="match_parent"
+                            android:layout_marginTop="12dp">
+
+                            <LinearLayout
+                                android:layout_width="wrap_content"
+                                android:layout_height="wrap_content"
+                                android:layout_alignParentLeft="true"
+                                android:layout_centerVertical="true"
+                                android:layout_toLeftOf="@+id/account_color_thumbnail"
+                                android:orientation="vertical">
+
+                                <TextView
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:text="Account Color"
+                                    android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
+
+
+                                <TextView
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:text="Used on conversation and contact lists, and notifications"
+                                    android:textAppearance="@style/TextAppearance.Conversations.Caption"/>
+                            </LinearLayout>
+
+                            <FrameLayout
+                                android:id="@+id/account_color_thumbnail"
+                                android:layout_width="48dp"
+                                android:layout_height="48dp"
+                                android:background="@drawable/thumbnail_border"
+                                android:layout_alignParentRight="true"
+                                android:layout_centerVertical="true">
+
+                                <ImageView
+                                    android:layout_margin="1dp"
+                                    android:layout_width="fill_parent"
+                                    android:layout_height="fill_parent"
+                                    android:src="@drawable/checker_background" />
+
+                                <View
+                                    android:layout_margin="1dp"
+                                    android:id="@+id/colorPreview"
+                                    android:layout_width="fill_parent"
+                                    android:layout_height="fill_parent" />
+
+                            </FrameLayout>
+                        </RelativeLayout>
+
                         <RelativeLayout
                             android:id="@+id/pgp_fingerprint_box"
                             android:layout_width="wrap_content"
  
  
  
    
    @@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
     android:background="?attr/color_background_secondary"
-    android:key="main_screen">
+    android:key="main_screen"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <PreferenceCategory
         android:key="general"
@@ -207,15 +208,18 @@
                 <com.rarepebble.colorpicker.ColorPreference
                     android:key="custom_theme_primary"
                     android:title="Custom Primary Color"
-                    android:defaultValue="@color/perpy" />
+                    android:defaultValue="@color/perpy"
+                    app:colorpicker_showAlpha="false" />
                 <com.rarepebble.colorpicker.ColorPreference
                     android:key="custom_theme_primary_dark"
                     android:title="Custom Primary Dark Color"
-                    android:defaultValue="@color/black_perpy" />
+                    android:defaultValue="@color/black_perpy"
+                    app:colorpicker_showAlpha="false" />
                 <com.rarepebble.colorpicker.ColorPreference
                     android:key="custom_theme_accent"
                     android:title="Custom Accent Color"
-                    android:defaultValue="@color/black_perpy" />
+                    android:defaultValue="@color/black_perpy"
+                    app:colorpicker_showAlpha="false" />
             </PreferenceCategory>
 
             <intent