apply styling helper to conversation overview
This commit is contained in:
parent
1fcd69ce40
commit
7ca719b8be
|
@ -548,10 +548,10 @@ public class NotificationService {
|
||||||
}
|
}
|
||||||
/** message preview for Android Auto **/
|
/** message preview for Android Auto **/
|
||||||
for (Message message : messages) {
|
for (Message message : messages) {
|
||||||
Pair<String, Boolean> preview = UIHelper.getMessagePreview(mXmppConnectionService, message);
|
Pair<CharSequence, Boolean> preview = UIHelper.getMessagePreview(mXmppConnectionService, message);
|
||||||
// only show user written text
|
// only show user written text
|
||||||
if (!preview.second) {
|
if (!preview.second) {
|
||||||
uBuilder.addMessage(preview.first);
|
uBuilder.addMessage(preview.first.toString());
|
||||||
uBuilder.setLatestTimestamp(message.getTimeSent());
|
uBuilder.setLatestTimestamp(message.getTimeSent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,9 +156,9 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte
|
||||||
viewHolder.lastMessageIcon.setVisibility(View.GONE);
|
viewHolder.lastMessageIcon.setVisibility(View.GONE);
|
||||||
showPreviewText = true;
|
showPreviewText = true;
|
||||||
}
|
}
|
||||||
final Pair<String, Boolean> preview = UIHelper.getMessagePreview(activity, message);
|
final Pair<CharSequence, Boolean> preview = UIHelper.getMessagePreview(activity, message, viewHolder.lastMessage.getCurrentTextColor());
|
||||||
if (showPreviewText) {
|
if (showPreviewText) {
|
||||||
viewHolder.lastMessage.setText(EmojiWrapper.transform(preview.first));
|
viewHolder.lastMessage.setText(EmojiWrapper.transform(UIHelper.shorten(preview.first)));
|
||||||
} else {
|
} else {
|
||||||
viewHolder.lastMessageIcon.setContentDescription(preview.first);
|
viewHolder.lastMessageIcon.setContentDescription(preview.first);
|
||||||
}
|
}
|
||||||
|
|
|
@ -360,7 +360,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayInfoMessage(ViewHolder viewHolder, String text, boolean darkBackground) {
|
private void displayInfoMessage(ViewHolder viewHolder, CharSequence text, boolean darkBackground) {
|
||||||
viewHolder.download_button.setVisibility(View.GONE);
|
viewHolder.download_button.setVisibility(View.GONE);
|
||||||
viewHolder.audioPlayer.setVisibility(View.GONE);
|
viewHolder.audioPlayer.setVisibility(View.GONE);
|
||||||
viewHolder.image.setVisibility(View.GONE);
|
viewHolder.image.setVisibility(View.GONE);
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Daniel Gultsch All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
* other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.siacs.conversations.utils;
|
||||||
|
|
||||||
|
import android.text.Spannable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CharSequenceUtils {
|
||||||
|
|
||||||
|
private static int getStartIndex(CharSequence input) {
|
||||||
|
int length = input.length();
|
||||||
|
int index = 0;
|
||||||
|
while (Character.isWhitespace(input.charAt(index))) {
|
||||||
|
++index;
|
||||||
|
if (index >= length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getEndIndex(CharSequence input) {
|
||||||
|
int index = input.length() - 1;
|
||||||
|
while (Character.isWhitespace(input.charAt(index))) {
|
||||||
|
--index;
|
||||||
|
if (index < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CharSequence trim(CharSequence input) {
|
||||||
|
int begin = getStartIndex(input);
|
||||||
|
int end = getEndIndex(input);
|
||||||
|
if (begin > end) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return StylingHelper.subSequence(input, begin, end + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<CharSequence> split(Spannable charSequence, char c) {
|
||||||
|
List<CharSequence> out = new ArrayList<>();
|
||||||
|
int begin = 0;
|
||||||
|
for (int i = 0; i < charSequence.length(); ++i) {
|
||||||
|
if (charSequence.charAt(i) == c) {
|
||||||
|
out.add(StylingHelper.subSequence(charSequence, begin, i));
|
||||||
|
begin = ++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (begin < charSequence.length()) {
|
||||||
|
out.add(StylingHelper.subSequence(charSequence, begin, charSequence.length()));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ import android.support.annotation.ColorInt;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.ParcelableSpan;
|
import android.text.ParcelableSpan;
|
||||||
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
@ -44,6 +45,7 @@ import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.StrikethroughSpan;
|
import android.text.style.StrikethroughSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.text.style.TypefaceSpan;
|
import android.text.style.TypefaceSpan;
|
||||||
|
import android.util.Log;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
@ -51,6 +53,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
import eu.siacs.conversations.ui.text.QuoteSpan;
|
import eu.siacs.conversations.ui.text.QuoteSpan;
|
||||||
|
@ -93,7 +96,7 @@ public class StylingHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void highlight(final Context context, final Editable editable, List<String> needles, boolean dark) {
|
public static void highlight(final Context context, final Editable editable, List<String> needles, boolean dark) {
|
||||||
for(String needle : needles) {
|
for (String needle : needles) {
|
||||||
if (!FtsUtils.isKeyword(needle)) {
|
if (!FtsUtils.isKeyword(needle)) {
|
||||||
highlight(context, editable, needle, dark);
|
highlight(context, editable, needle, dark);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +105,7 @@ public class StylingHelper {
|
||||||
|
|
||||||
public static List<String> filterHighlightedWords(List<String> terms) {
|
public static List<String> filterHighlightedWords(List<String> terms) {
|
||||||
List<String> words = new ArrayList<>();
|
List<String> words = new ArrayList<>();
|
||||||
for(String term : terms) {
|
for (String term : terms) {
|
||||||
if (!FtsUtils.isKeyword(term)) {
|
if (!FtsUtils.isKeyword(term)) {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
for (int codepoint, i = 0; i < term.length(); i += Character.charCount(codepoint)) {
|
for (int codepoint, i = 0; i < term.length(); i += Character.charCount(codepoint)) {
|
||||||
|
@ -132,6 +135,44 @@ public class StylingHelper {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CharSequence subSequence(CharSequence charSequence, int start, int end) {
|
||||||
|
if (start == 0 && charSequence.length() + 1 == end) {
|
||||||
|
return charSequence;
|
||||||
|
}
|
||||||
|
if (charSequence instanceof Spannable) {
|
||||||
|
Spannable spannable = (Spannable) charSequence;
|
||||||
|
Spannable sub = (Spannable) spannable.subSequence(start, end);
|
||||||
|
for (Class<? extends ParcelableSpan> clazz : SPAN_CLASSES) {
|
||||||
|
ParcelableSpan[] spannables = spannable.getSpans(start, end, clazz);
|
||||||
|
for (ParcelableSpan parcelableSpan : spannables) {
|
||||||
|
int beginSpan = spannable.getSpanStart(parcelableSpan);
|
||||||
|
int endSpan = spannable.getSpanEnd(parcelableSpan);
|
||||||
|
if (beginSpan >= start && endSpan <= end) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sub.setSpan(clone(parcelableSpan), Math.max(beginSpan - start, 0), Math.min(sub.length() - 1, endSpan), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sub;
|
||||||
|
} else {
|
||||||
|
return charSequence.subSequence(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ParcelableSpan clone(ParcelableSpan span) {
|
||||||
|
if (span instanceof ForegroundColorSpan) {
|
||||||
|
return new ForegroundColorSpan(((ForegroundColorSpan) span).getForegroundColor());
|
||||||
|
} else if (span instanceof TypefaceSpan) {
|
||||||
|
return new TypefaceSpan(((TypefaceSpan) span).getFamily());
|
||||||
|
} else if (span instanceof StyleSpan) {
|
||||||
|
return new StyleSpan(((StyleSpan) span).getStyle());
|
||||||
|
} else if (span instanceof StrikethroughSpan) {
|
||||||
|
return new StrikethroughSpan();
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unknown Span");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isDarkText(TextView textView) {
|
public static boolean isDarkText(TextView textView) {
|
||||||
int argb = textView.getCurrentTextColor();
|
int argb = textView.getCurrentTextColor();
|
||||||
return Color.red(argb) + Color.green(argb) + Color.blue(argb) == 0;
|
return Color.red(argb) + Color.green(argb) + Color.blue(argb) == 0;
|
||||||
|
@ -163,7 +204,7 @@ public class StylingHelper {
|
||||||
private static
|
private static
|
||||||
@ColorInt
|
@ColorInt
|
||||||
int transformColor(@ColorInt int c) {
|
int transformColor(@ColorInt int c) {
|
||||||
return Color.argb(Math.round(Color.alpha(c) * 0.6f), Color.red(c), Color.green(c), Color.blue(c));
|
return Color.argb(Math.round(Color.alpha(c) * 0.45f), Color.red(c), Color.green(c), Color.blue(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int indexOfIgnoreCase(final String haystack, final String needle, final int start) {
|
private static int indexOfIgnoreCase(final String haystack, final String needle, final int start) {
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package eu.siacs.conversations.utils;
|
package eu.siacs.conversations.utils;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.support.annotation.ColorInt;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
|
|
||||||
|
@ -10,6 +14,7 @@ import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -244,7 +249,11 @@ public class UIHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pair<String, Boolean> getMessagePreview(final Context context, final Message message) {
|
public static Pair<CharSequence, Boolean> getMessagePreview(final Context context, final Message message) {
|
||||||
|
return getMessagePreview(context, message, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pair<CharSequence, Boolean> getMessagePreview(final Context context, final Message message, @ColorInt int textColor) {
|
||||||
final Transferable d = message.getTransferable();
|
final Transferable d = message.getTransferable();
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
switch (d.getStatus()) {
|
switch (d.getStatus()) {
|
||||||
|
@ -293,14 +302,17 @@ public class UIHelper {
|
||||||
return new Pair<>(context.getString(R.string.x_file_offered_for_download,
|
return new Pair<>(context.getString(R.string.x_file_offered_for_download,
|
||||||
getFileDescriptionString(context, message)), true);
|
getFileDescriptionString(context, message)), true);
|
||||||
} else {
|
} else {
|
||||||
String[] lines = body.split("\n");
|
SpannableStringBuilder styledBody = new SpannableStringBuilder(body);
|
||||||
StringBuilder builder = new StringBuilder();
|
if (textColor != 0) {
|
||||||
for (String l : lines) {
|
StylingHelper.format(styledBody, 0, styledBody.length() - 1, textColor);
|
||||||
|
}
|
||||||
|
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||||
|
for (CharSequence l : CharSequenceUtils.split(styledBody, '\n')) {
|
||||||
if (l.length() > 0) {
|
if (l.length() > 0) {
|
||||||
char first = l.charAt(0);
|
char first = l.charAt(0);
|
||||||
if ((first != '>' || !isPositionFollowedByQuoteableCharacter(l, 0)) && first != '\u00bb') {
|
if ((first != '>' || !isPositionFollowedByQuoteableCharacter(l, 0)) && first != '\u00bb') {
|
||||||
String line = l.trim();
|
CharSequence line = CharSequenceUtils.trim(l);
|
||||||
if (line.isEmpty()) {
|
if (line.length() == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
char last = line.charAt(line.length() - 1);
|
char last = line.charAt(line.length() - 1);
|
||||||
|
@ -317,11 +329,15 @@ public class UIHelper {
|
||||||
if (builder.length() == 0) {
|
if (builder.length() == 0) {
|
||||||
builder.append(body.trim());
|
builder.append(body.trim());
|
||||||
}
|
}
|
||||||
return new Pair<>(builder.length() > 256 ? builder.substring(0, 256) : builder.toString(), false);
|
return new Pair<>(builder, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CharSequence shorten(CharSequence input) {
|
||||||
|
return input.length() > 256 ? StylingHelper.subSequence(input, 0, 256) : input;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isPositionFollowedByQuoteableCharacter(CharSequence body, int pos) {
|
public static boolean isPositionFollowedByQuoteableCharacter(CharSequence body, int pos) {
|
||||||
return !isPositionFollowedByNumber(body, pos)
|
return !isPositionFollowedByNumber(body, pos)
|
||||||
&& !isPositionFollowedByEmoticon(body, pos)
|
&& !isPositionFollowedByEmoticon(body, pos)
|
||||||
|
|
Loading…
Reference in a new issue