added setting to allow for white backgrounds in incoming message bubbles

Daniel Gultsch created

Change summary

art/message_bubble_received_white.svg                               | 165 
art/render.rb                                                       |   1 
src/main/java/eu/siacs/conversations/ui/ConversationActivity.java   |  11 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java   |   1 
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java |  85 
src/main/res/drawable-hdpi/message_bubble_received.9.png            |   0 
src/main/res/drawable-hdpi/message_bubble_received_warning.9.png    |   0 
src/main/res/drawable-hdpi/message_bubble_received_white.9.png      |   0 
src/main/res/drawable-hdpi/message_bubble_sent.9.png                |   0 
src/main/res/drawable-mdpi/message_bubble_received.9.png            |   0 
src/main/res/drawable-mdpi/message_bubble_received_warning.9.png    |   0 
src/main/res/drawable-mdpi/message_bubble_received_white.9.png      |   0 
src/main/res/drawable-mdpi/message_bubble_sent.9.png                |   0 
src/main/res/drawable-xhdpi/message_bubble_received.9.png           |   0 
src/main/res/drawable-xhdpi/message_bubble_received_warning.9.png   |   0 
src/main/res/drawable-xhdpi/message_bubble_received_white.9.png     |   0 
src/main/res/drawable-xhdpi/message_bubble_sent.9.png               |   0 
src/main/res/drawable-xxhdpi/message_bubble_received.9.png          |   0 
src/main/res/drawable-xxhdpi/message_bubble_received_warning.9.png  |   0 
src/main/res/drawable-xxhdpi/message_bubble_received_white.9.png    |   0 
src/main/res/drawable-xxhdpi/message_bubble_sent.9.png              |   0 
src/main/res/drawable-xxxhdpi/message_bubble_received.9.png         |   0 
src/main/res/drawable-xxxhdpi/message_bubble_received_warning.9.png |   0 
src/main/res/drawable-xxxhdpi/message_bubble_received_white.9.png   |   0 
src/main/res/drawable-xxxhdpi/message_bubble_sent.9.png             |   0 
src/main/res/values/strings.xml                                     |   2 
src/main/res/xml/preferences.xml                                    |   5 
27 files changed, 234 insertions(+), 36 deletions(-)

Detailed changes

art/message_bubble_received_white.svg 🔗

@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="36"
+   height="26"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="message_bubble_received.svg">
+  <defs
+     id="defs4">
+    <filter
+       x="-0.25"
+       y="-0.25"
+       width="1.5"
+       height="1.5"
+       inkscape:label="Drop Shadow"
+       id="filter3811"
+       color-interpolation-filters="sRGB">
+      <feFlood
+         flood-opacity="0.25"
+         flood-color="rgb(0,0,0)"
+         result="flood"
+         id="feFlood3813" />
+      <feComposite
+         in="flood"
+         in2="SourceGraphic"
+         operator="in"
+         result="composite1"
+         id="feComposite3815" />
+      <feGaussianBlur
+         stdDeviation="0.5"
+         result="blur"
+         id="feGaussianBlur3817" />
+      <feOffset
+         dx="0"
+         dy="1"
+         result="offset"
+         id="feOffset3819" />
+      <feComposite
+         in="SourceGraphic"
+         in2="offset"
+         operator="over"
+         result="composite2"
+         id="feComposite3821" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="16"
+     inkscape:cx="25.745257"
+     inkscape:cy="9.618802"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:window-width="989"
+     inkscape:window-height="755"
+     inkscape:window-x="22"
+     inkscape:window-y="16"
+     inkscape:window-maximized="0"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     guidecolor="#000000"
+     guideopacity="0.49803922">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2985"
+       empspacing="4"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       spacingx="1px"
+       spacingy="1px"
+       originx="0px"
+       originy="0px"
+       color="#0000ff"
+       opacity="0.03137255" />
+    <sodipodi:guide
+       orientation="1,0"
+       position="20,26"
+       id="guide3060" />
+    <sodipodi:guide
+       orientation="1,0"
+       position="24,26"
+       id="guide3062" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="36,22"
+       id="guide3064" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="36,6"
+       id="guide3066" />
+    <sodipodi:guide
+       orientation="1,0"
+       position="26,0"
+       id="guide3068" />
+    <sodipodi:guide
+       orientation="1,0"
+       position="18,0"
+       id="guide3070" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="0,10"
+       id="guide3074" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="0,8"
+       id="guide3076" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer"
+     inkscape:groupmode="layer"
+     id="layer"
+     transform="translate(0,-2)">
+    <g
+       id="g3759"
+       style="fill:#fafafa;fill-opacity:1;stroke:none;fill-rule:nonzero;filter:url(#filter3811)">
+      <path
+         style="display:none"
+         d="m 8,6 c 2,2 4,6 4,10 L 16,6 z"
+         id="path3805"
+         inkscape:connector-curvature="0"
+         transform="translate(0,2)"
+         sodipodi:nodetypes="cccc" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path2989"
+         d="M 4,4 16,16 16,4 z"
+         sodipodi:nodetypes="cccc" />
+      <rect
+         ry="2"
+         y="4"
+         x="12"
+         height="20"
+         width="20"
+         id="rect2987" />
+    </g>
+  </g>
+</svg>

art/render.rb 🔗

@@ -45,6 +45,7 @@ images = {
 	'md_switch_thumb_on_pressed.svg' => ['switch_thumb_on_pressed', 48],
 	'message_bubble_received.svg' => ['message_bubble_received.9', 0],
 	'message_bubble_received_warning.svg' => ['message_bubble_received_warning.9', 0],
+	'message_bubble_received_white.svg' => ['message_bubble_received_white.9', 0],
 	'message_bubble_sent.svg' => ['message_bubble_sent.9', 0],
 	}
 

src/main/java/eu/siacs/conversations/ui/ConversationActivity.java 🔗

@@ -966,6 +966,9 @@ public class ConversationActivity extends XmppActivity
 			mPendingGeoUri = null;
 			setSelectedConversation(conversationList.get(0));
 			this.mConversationFragment.reInit(getSelectedConversation());
+		} else {
+			this.mConversationFragment.messageListAdapter.updatePreferences();
+			this.mConversationFragment.messagesView.invalidateViews();
 		}
 
 		if(!forbidProcessingPendings) {
@@ -1144,7 +1147,7 @@ public class ConversationActivity extends XmppActivity
 		}
 		prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_file), Toast.LENGTH_LONG);
 		prepareFileToast.show();
-		xmppConnectionService.attachFileToConversation(conversation,uri, new UiCallback<Message>() {
+		xmppConnectionService.attachFileToConversation(conversation, uri, new UiCallback<Message>() {
 			@Override
 			public void success(Message message) {
 				hidePrepareFileToast();
@@ -1174,7 +1177,7 @@ public class ConversationActivity extends XmppActivity
 
 					@Override
 					public void userInputRequried(PendingIntent pi,
-							Message object) {
+												  Message object) {
 						hidePrepareFileToast();
 					}
 
@@ -1256,6 +1259,10 @@ public class ConversationActivity extends XmppActivity
 		return getPreferences().getBoolean("indicate_received", false);
 	}
 
+	public boolean useWhiteBackground() {
+		return getPreferences().getBoolean("use_white_background",false);
+	}
+
 	protected boolean trustKeysIfNeeded(int requestCode) {
 		return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID);
 	}

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -662,6 +662,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
 		this.mEditMessage.setText("");
 		this.mEditMessage.append(this.conversation.getNextMessage());
 		this.mEditMessage.setKeyboardListener(this);
+		messageListAdapter.updatePreferences();
 		this.messagesView.setAdapter(messageListAdapter);
 		updateMessages();
 		this.messagesLoaded = true;

src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java 🔗

@@ -60,11 +60,14 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 			return true;
 		}
 	};
+	private boolean mIndicateReceived = false;
+	private boolean mUseWhiteBackground = false;
 
 	public MessageAdapter(ConversationActivity activity, List<Message> messages) {
 		super(activity, 0, messages);
 		this.activity = activity;
 		metrics = getContext().getResources().getDisplayMetrics();
+		updatePreferences();
 	}
 
 	public void setOnContactPictureClicked(OnContactPictureClicked listener) {
@@ -96,15 +99,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 		return this.getItemViewType(getItem(position));
 	}
 
-	private int getMessageTextColor(int type, boolean primary) {
-		if (type == SENT) {
-			return activity.getResources().getColor(primary ? R.color.black87 : R.color.black54);
-		} else {
+	private int getMessageTextColor(boolean onDark, boolean primary) {
+		if (onDark) {
 			return activity.getResources().getColor(primary ? R.color.white : R.color.white70);
+		} else {
+			return activity.getResources().getColor(primary ? R.color.black87 : R.color.black54);
 		}
 	}
 
-	private void displayStatus(ViewHolder viewHolder, Message message, int type) {
+	private void displayStatus(ViewHolder viewHolder, Message message, int type, boolean darkBackground) {
 		String filesize = null;
 		String info = null;
 		boolean error = false;
@@ -140,12 +143,12 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 				info = getContext().getString(R.string.offering);
 				break;
 			case Message.STATUS_SEND_RECEIVED:
-				if (activity.indicateReceived()) {
+				if (mIndicateReceived) {
 					viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
 				}
 				break;
 			case Message.STATUS_SEND_DISPLAYED:
-				if (activity.indicateReceived()) {
+				if (mIndicateReceived) {
 					viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
 				}
 				break;
@@ -162,11 +165,12 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 		if (error && type == SENT) {
 			viewHolder.time.setTextColor(activity.getWarningTextColor());
 		} else {
-			viewHolder.time.setTextColor(this.getMessageTextColor(type,false));
+			viewHolder.time.setTextColor(this.getMessageTextColor(darkBackground,false));
 		}
 		if (message.getEncryption() == Message.ENCRYPTION_NONE) {
 			viewHolder.indicator.setVisibility(View.GONE);
 		} else {
+			viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_secure_indicator_white : R.drawable.ic_secure_indicator);
 			viewHolder.indicator.setVisibility(View.VISIBLE);
 			if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
 				XmppAxolotlSession.Trust trust = message.getConversation()
@@ -178,18 +182,18 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 					viewHolder.indicator.setAlpha(1.0f);
 				} else {
 					viewHolder.indicator.clearColorFilter();
-					if (type == SENT) {
-						viewHolder.indicator.setAlpha(0.57f);
-					} else {
+					if (darkBackground) {
 						viewHolder.indicator.setAlpha(0.7f);
+					} else {
+						viewHolder.indicator.setAlpha(0.57f);
 					}
 				}
 			} else {
 				viewHolder.indicator.clearColorFilter();
-				if (type == SENT) {
-					viewHolder.indicator.setAlpha(0.57f);
-				} else {
+				if (darkBackground) {
 					viewHolder.indicator.setAlpha(0.7f);
+				} else {
+					viewHolder.indicator.setAlpha(0.57f);
 				}
 			}
 		}
@@ -223,19 +227,19 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 		}
 	}
 
-	private void displayInfoMessage(ViewHolder viewHolder, String text, int type) {
+	private void displayInfoMessage(ViewHolder viewHolder, String text, boolean darkBackground) {
 		if (viewHolder.download_button != null) {
 			viewHolder.download_button.setVisibility(View.GONE);
 		}
 		viewHolder.image.setVisibility(View.GONE);
 		viewHolder.messageBody.setVisibility(View.VISIBLE);
 		viewHolder.messageBody.setText(text);
-		viewHolder.messageBody.setTextColor(getMessageTextColor(type,false));
+		viewHolder.messageBody.setTextColor(getMessageTextColor(darkBackground, false));
 		viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
 		viewHolder.messageBody.setTextIsSelectable(false);
 	}
 
-	private void displayDecryptionFailed(ViewHolder viewHolder, int type) {
+	private void displayDecryptionFailed(ViewHolder viewHolder, boolean darkBackground) {
 		if (viewHolder.download_button != null) {
 			viewHolder.download_button.setVisibility(View.GONE);
 		}
@@ -243,7 +247,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 		viewHolder.messageBody.setVisibility(View.VISIBLE);
 		viewHolder.messageBody.setText(getContext().getString(
 				R.string.decryption_failed));
-		viewHolder.messageBody.setTextColor(getMessageTextColor(type,false));
+		viewHolder.messageBody.setTextColor(getMessageTextColor(darkBackground, false));
 		viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
 		viewHolder.messageBody.setTextIsSelectable(false);
 	}
@@ -261,7 +265,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 		viewHolder.messageBody.setText(span);
 	}
 
-	private void displayTextMessage(final ViewHolder viewHolder, final Message message, int type) {
+	private void displayTextMessage(final ViewHolder viewHolder, final Message message, boolean darkBackground) {
 		if (viewHolder.download_button != null) {
 			viewHolder.download_button.setVisibility(View.GONE);
 		}
@@ -303,7 +307,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 				}
 				final Spannable span = new SpannableString(privateMarker + " "
 						+ formattedBody);
-				span.setSpan(new ForegroundColorSpan(getMessageTextColor(type,false)), 0, privateMarker
+				span.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground,false)), 0, privateMarker
 						.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
 				span.setSpan(new StyleSpan(Typeface.BOLD), 0,
 						privateMarker.length(),
@@ -318,7 +322,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 		} else {
 			viewHolder.messageBody.setText("");
 		}
-		viewHolder.messageBody.setTextColor(this.getMessageTextColor(type,true));
+		viewHolder.messageBody.setTextColor(this.getMessageTextColor(darkBackground, true));
+		viewHolder.messageBody.setLinkTextColor(this.getMessageTextColor(darkBackground,true));
 		viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
 		viewHolder.messageBody.setTextIsSelectable(true);
 	}
@@ -388,7 +393,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 			scalledH = (int) (params.height / ((double) params.width / target));
 		}
 		LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(scalledW, scalledH);
-		layoutParams.setMargins(0, (int)(metrics.density * 4), 0, (int)(metrics.density * 4));
+		layoutParams.setMargins(0, (int) (metrics.density * 4), 0, (int) (metrics.density * 4));
 		viewHolder.image.setLayoutParams(layoutParams);
 		activity.loadBitmap(message, viewHolder.image);
 		viewHolder.image.setOnClickListener(new OnClickListener() {
@@ -404,6 +409,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 	@Override
 	public View getView(int position, View view, ViewGroup parent) {
 		final Message message = getItem(position);
+		final boolean isInValidSession = message.isValidInSession();
 		final Conversation conversation = message.getConversation();
 		final Account account = conversation.getAccount();
 		final int type = getItemViewType(position);
@@ -468,6 +474,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 			}
 		}
 
+		boolean darkBackground = (type == RECEIVED && (!isInValidSession || !mUseWhiteBackground));
+
 		if (type == STATUS) {
 			if (conversation.getMode() == Conversation.MODE_SINGLE) {
 				viewHolder.contact_picture.setImageBitmap(activity
@@ -497,7 +505,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 				public void onClick(View v) {
 					if (MessageAdapter.this.mOnContactPictureClickedListener != null) {
 						MessageAdapter.this.mOnContactPictureClickedListener
-							.onContactPictureClicked(message);
+								.onContactPictureClicked(message);
 					}
 
 				}
@@ -509,7 +517,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 				public boolean onLongClick(View v) {
 					if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) {
 						MessageAdapter.this.mOnContactPictureLongClickedListener
-							.onContactPictureLongClicked(message);
+								.onContactPictureLongClicked(message);
 						return true;
 					} else {
 						return false;
@@ -524,7 +532,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 			} else if (transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) {
 				displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)));
 			} else {
-				displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first,type);
+				displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first,darkBackground);
 			}
 		} else if (message.getType() == Message.TYPE_IMAGE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
 			displayImageMessage(viewHolder, message);
@@ -536,9 +544,9 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 			}
 		} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
 			if (activity.hasPgp()) {
-				displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message),type);
+				displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message),darkBackground);
 			} else {
-				displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),type);
+				displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground);
 				if (viewHolder != null) {
 					viewHolder.message_box
 						.setOnClickListener(new OnClickListener() {
@@ -551,7 +559,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 				}
 			}
 		} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
-			displayDecryptionFailed(viewHolder,type);
+			displayDecryptionFailed(viewHolder,darkBackground);
 		} else {
 			if (GeoHelper.isGeoUri(message.getBody())) {
 				displayLocationMessage(viewHolder,message);
@@ -560,19 +568,23 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 			} else if (message.treatAsDownloadable() == Message.Decision.MUST) {
 				displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)));
 			} else {
-				displayTextMessage(viewHolder, message, type);
+				displayTextMessage(viewHolder, message, darkBackground);
 			}
 		}
 
 		if (type == RECEIVED) {
-			if(message.isValidInSession()) {
-				viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received);
+			if(isInValidSession) {
+				if (mUseWhiteBackground) {
+					viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_white);
+				} else {
+					viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received);
+				}
 			} else {
 				viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_warning);
 			}
 		}
 
-		displayStatus(viewHolder, message, type);
+		displayStatus(viewHolder, message, type, darkBackground);
 
 		return view;
 	}
@@ -616,12 +628,17 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 		Toast.makeText(activity,R.string.no_application_found_to_display_location,Toast.LENGTH_SHORT).show();
 	}
 
+	public void updatePreferences() {
+		this.mIndicateReceived = activity.indicateReceived();
+		this.mUseWhiteBackground = activity.useWhiteBackground();
+	}
+
 	public interface OnContactPictureClicked {
-		public void onContactPictureClicked(Message message);
+		void onContactPictureClicked(Message message);
 	}
 
 	public interface OnContactPictureLongClicked {
-		public void onContactPictureLongClicked(Message message);
+		void onContactPictureLongClicked(Message message);
 	}
 
 	private static class ViewHolder {

src/main/res/values/strings.xml 🔗

@@ -510,4 +510,6 @@
 	<string name="download_failed_server_not_found">Download failed: Server not found</string>
 	<string name="download_failed_file_not_found">Download failed: File not found</string>
 	<string name="download_failed_could_not_connect">Download failed: Could not connect to host</string>
+	<string name="pref_use_white_background">Use white background</string>
+	<string name="pref_use_white_background_summary">Show received messages as black text on a white background</string>
 </resources>

src/main/res/xml/preferences.xml 🔗

@@ -95,6 +95,11 @@
             android:key="use_subject"
             android:summary="@string/pref_conference_name_summary"
             android:title="@string/pref_conference_name"/>
+        <CheckBoxPreference
+            android:defaultValue="false"
+            android:key="use_white_background"
+            android:title="@string/pref_use_white_background"
+            android:summary="@string/pref_use_white_background_summary"/>
         <CheckBoxPreference
             android:defaultValue="false"
             android:key="use_larger_font"