mirror of
https://github.com/pierre42100/ComunicAndroid
synced 2024-11-23 13:59:29 +00:00
Parse URLs in conversation messages
This commit is contained in:
parent
5b46e559af
commit
50ccebfc91
@ -95,6 +95,16 @@ public class StringsUtils {
|
|||||||
return !TextUtils.isEmpty(mail) && Patterns.EMAIL_ADDRESS.matcher(mail).matches();
|
return !TextUtils.isEmpty(mail) && Patterns.EMAIL_ADDRESS.matcher(mail).matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a specified string is an URL or not
|
||||||
|
*
|
||||||
|
* @param string The string to check
|
||||||
|
* @return TRUE if the string is an URL / FALSE else
|
||||||
|
*/
|
||||||
|
public static boolean isURL(CharSequence string){
|
||||||
|
return !TextUtils.isEmpty(string) && Patterns.WEB_URL.matcher(string).matches();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the SHA-1 summary of a given string
|
* Generate the SHA-1 summary of a given string
|
||||||
*
|
*
|
||||||
|
@ -15,6 +15,7 @@ import org.communiquons.android.comunic.client.data.models.ConversationMessage;
|
|||||||
import org.communiquons.android.comunic.client.data.models.UserInfo;
|
import org.communiquons.android.comunic.client.data.models.UserInfo;
|
||||||
import org.communiquons.android.comunic.client.data.utils.StringsUtils;
|
import org.communiquons.android.comunic.client.data.utils.StringsUtils;
|
||||||
import org.communiquons.android.comunic.client.ui.listeners.OnConversationMessageActionsListener;
|
import org.communiquons.android.comunic.client.ui.listeners.OnConversationMessageActionsListener;
|
||||||
|
import org.communiquons.android.comunic.client.ui.views.ContentTextView;
|
||||||
import org.communiquons.android.comunic.client.ui.views.EnlargeableWebImageView;
|
import org.communiquons.android.comunic.client.ui.views.EnlargeableWebImageView;
|
||||||
import org.communiquons.android.comunic.client.ui.views.WebUserAccountImage;
|
import org.communiquons.android.comunic.client.ui.views.WebUserAccountImage;
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ public class ConversationMessageAdapter extends RecyclerView.Adapter {
|
|||||||
private class BaseMessageHolder extends RecyclerView.ViewHolder
|
private class BaseMessageHolder extends RecyclerView.ViewHolder
|
||||||
implements View.OnLongClickListener{
|
implements View.OnLongClickListener{
|
||||||
|
|
||||||
private TextView mMessage;
|
ContentTextView mMessage;
|
||||||
private TextView mSentDate;
|
private TextView mSentDate;
|
||||||
private EnlargeableWebImageView mImage;
|
private EnlargeableWebImageView mImage;
|
||||||
|
|
||||||
@ -133,7 +134,7 @@ public class ConversationMessageAdapter extends RecyclerView.Adapter {
|
|||||||
mImage = itemView.findViewById(R.id.messageImage);
|
mImage = itemView.findViewById(R.id.messageImage);
|
||||||
mSentDate = itemView.findViewById(R.id.text_message_time);
|
mSentDate = itemView.findViewById(R.id.text_message_time);
|
||||||
|
|
||||||
itemView.setOnLongClickListener(this);
|
mMessage.setOnLongClickListener(this);
|
||||||
mImage.setOnLongClickListener(this);
|
mImage.setOnLongClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +157,7 @@ public class ConversationMessageAdapter extends RecyclerView.Adapter {
|
|||||||
void bind(int pos){
|
void bind(int pos){
|
||||||
ConversationMessage message = mList.get(pos);
|
ConversationMessage message = mList.get(pos);
|
||||||
|
|
||||||
mMessage.setText(message.getContent());
|
mMessage.setParsedText(message.getContent());
|
||||||
mMessage.setVisibility(mMessage.getText().length() > 0 ? View.VISIBLE : View.GONE);
|
mMessage.setVisibility(mMessage.getText().length() > 0 ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
mImage.setVisibility(message.hasImage() ? View.VISIBLE : View.GONE);
|
mImage.setVisibility(message.hasImage() ? View.VISIBLE : View.GONE);
|
||||||
@ -193,6 +194,8 @@ public class ConversationMessageAdapter extends RecyclerView.Adapter {
|
|||||||
|
|
||||||
SentMessageHolder(@NonNull View itemView) {
|
SentMessageHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
|
mMessage.setLinksColor(R.color.conversation_user_links_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +212,8 @@ public class ConversationMessageAdapter extends RecyclerView.Adapter {
|
|||||||
|
|
||||||
mUserAccountImage = itemView.findViewById(R.id.account_image);
|
mUserAccountImage = itemView.findViewById(R.id.account_image);
|
||||||
mUserName = itemView.findViewById(R.id.user_name);
|
mUserName = itemView.findViewById(R.id.user_name);
|
||||||
|
|
||||||
|
mMessage.setLinksColor(R.color.conversation_otheruser_links_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUserInfoVisibility(boolean visible){
|
void setUserInfoVisibility(boolean visible){
|
||||||
|
@ -31,13 +31,23 @@ abstract class BaseFrameLayoutView extends FrameLayout {
|
|||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get hosting activity
|
* Get hosting activity
|
||||||
*
|
*
|
||||||
* @return Hosting activity, if found, null else
|
* @return Hosting activity, if found, null else
|
||||||
*/
|
*/
|
||||||
protected Activity getActivity(){
|
protected Activity getActivity(){
|
||||||
Context context = getContext();
|
return GetActivityFromContext(getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an activity from context
|
||||||
|
*
|
||||||
|
* @param context The context to parse
|
||||||
|
* @return The activity
|
||||||
|
*/
|
||||||
|
static Activity GetActivityFromContext(Context context){
|
||||||
|
|
||||||
while(context instanceof ContextWrapper){
|
while(context instanceof ContextWrapper){
|
||||||
if(context instanceof Activity)
|
if(context instanceof Activity)
|
||||||
|
@ -0,0 +1,126 @@
|
|||||||
|
package org.communiquons.android.comunic.client.ui.views;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.TextPaint;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.text.style.ClickableSpan;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.communiquons.android.comunic.client.data.utils.StringsUtils;
|
||||||
|
import org.communiquons.android.comunic.client.ui.utils.UiUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TextView extension which parses the content passed to the
|
||||||
|
* view in order to make links live
|
||||||
|
*
|
||||||
|
* @author Pierre HUBERT
|
||||||
|
*/
|
||||||
|
public class ContentTextView extends android.support.v7.widget.AppCompatTextView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug tag
|
||||||
|
*/
|
||||||
|
private static final String TAG = ContentTextView.class.getSimpleName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color of detected links
|
||||||
|
*/
|
||||||
|
private int mLinksColor = Color.BLUE;
|
||||||
|
|
||||||
|
public ContentTextView(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentTextView(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Activity getActivity(){
|
||||||
|
return BaseFrameLayoutView.GetActivityFromContext(getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the color of selected links
|
||||||
|
*
|
||||||
|
* @param res_id The ID of the target color
|
||||||
|
*/
|
||||||
|
public void setLinksColor(int res_id){
|
||||||
|
this.mLinksColor = UiUtils.getColor(getContext(), res_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set na new text, with links parsed
|
||||||
|
*
|
||||||
|
* @param text The text to parse
|
||||||
|
*/
|
||||||
|
public void setParsedText(String text) {
|
||||||
|
super.setText(text);
|
||||||
|
|
||||||
|
//Parse text
|
||||||
|
SpannableStringBuilder ssb = new SpannableStringBuilder(text);
|
||||||
|
|
||||||
|
String[] parts = text.split("\\s+");
|
||||||
|
int pos = 0;
|
||||||
|
for (String part : parts) {
|
||||||
|
|
||||||
|
//Mark it as URL
|
||||||
|
if (StringsUtils.isURL(part)) {
|
||||||
|
|
||||||
|
ClickableSpan clickableSpan = new URLClickableSpan(part);
|
||||||
|
ssb.setSpan(clickableSpan, pos, pos + part.length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += part.length() + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(ssb);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base ClickableSpan class
|
||||||
|
*/
|
||||||
|
private abstract class BaseClickableSpan extends ClickableSpan {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDrawState(TextPaint ds) {
|
||||||
|
super.updateDrawState(ds);
|
||||||
|
ds.setUnderlineText(false);
|
||||||
|
ds.setColor(mLinksColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clickable span class for URL
|
||||||
|
*/
|
||||||
|
private class URLClickableSpan extends BaseClickableSpan {
|
||||||
|
|
||||||
|
private String mURL;
|
||||||
|
|
||||||
|
private URLClickableSpan(String url){
|
||||||
|
super();
|
||||||
|
mURL = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View widget) {
|
||||||
|
getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mURL)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -39,7 +38,7 @@
|
|||||||
app:layout_constraintTop_toTopOf="@id/account_image"
|
app:layout_constraintTop_toTopOf="@id/account_image"
|
||||||
tools:text="John Doe" />
|
tools:text="John Doe" />
|
||||||
|
|
||||||
<TextView
|
<org.communiquons.android.comunic.client.ui.views.ContentTextView
|
||||||
android:id="@+id/message_body"
|
android:id="@+id/message_body"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -62,12 +61,12 @@
|
|||||||
android:layout_height="98dp"
|
android:layout_height="98dp"
|
||||||
android:layout_marginStart="60dp"
|
android:layout_marginStart="60dp"
|
||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
|
android:scaleType="fitStart"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/constraintLayout2"
|
app:layout_constraintTop_toBottomOf="@id/constraintLayout2"
|
||||||
app:layout_constraintVertical_bias="0.0"
|
app:layout_constraintVertical_bias="0.0"
|
||||||
app:srcCompat="@drawable/img_placeholder"
|
app:srcCompat="@drawable/img_placeholder" />
|
||||||
android:scaleType="fitStart"/>
|
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="16dp">
|
android:paddingTop="16dp">
|
||||||
|
|
||||||
<TextView
|
<org.communiquons.android.comunic.client.ui.views.ContentTextView
|
||||||
android:id="@+id/message_body"
|
android:id="@+id/message_body"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginRight="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:background="@drawable/conversation_message_currentuser_bg"
|
android:background="@drawable/conversation_message_currentuser_bg"
|
||||||
android:maxWidth="240dp"
|
android:maxWidth="240dp"
|
||||||
android:padding="8dp"
|
android:padding="8dp"
|
||||||
@ -45,10 +44,10 @@
|
|||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="@dimen/conversation_message_time_padding_top"
|
android:layout_marginTop="@dimen/conversation_message_time_padding_top"
|
||||||
android:text="11:40"
|
|
||||||
android:textSize="10sp"
|
android:textSize="10sp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="11:40" />
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
@ -22,8 +22,10 @@
|
|||||||
<!-- Conversation messages -->
|
<!-- Conversation messages -->
|
||||||
<color name="conversation_user_messages_background">#3F51B5</color>
|
<color name="conversation_user_messages_background">#3F51B5</color>
|
||||||
<color name="conversation_user_messages_textColor">#FFFFFF</color>
|
<color name="conversation_user_messages_textColor">#FFFFFF</color>
|
||||||
|
<color name="conversation_user_links_color">#c5cae9</color>
|
||||||
<color name="conversation_otheruser_messages_background">#D8D8D8</color>
|
<color name="conversation_otheruser_messages_background">#D8D8D8</color>
|
||||||
<color name="conversation_otheruser_messages_textColor">#000000</color>
|
<color name="conversation_otheruser_messages_textColor">#000000</color>
|
||||||
|
<color name="conversation_otheruser_links_color">@color/conversation_user_messages_background</color>
|
||||||
|
|
||||||
<!-- Conversations footer -->
|
<!-- Conversations footer -->
|
||||||
<color name="conversation_footer_bg">#8c9eff</color>
|
<color name="conversation_footer_bg">#8c9eff</color>
|
||||||
|
Loading…
Reference in New Issue
Block a user