diff --git a/briar-android/res/layout/fragment_blog_post.xml b/briar-android/res/layout/fragment_blog_post.xml index 18ec1f417cd1f72ba54f917eabb8913ea2c04631..3fdce0b1c5a634db1ee967423f13ee85ae620299 100644 --- a/briar-android/res/layout/fragment_blog_post.xml +++ b/briar-android/res/layout/fragment_blog_post.xml @@ -10,7 +10,7 @@ android:descendantFocusability="beforeDescendants" android:focusable="true" android:focusableInTouchMode="true"> - <!-- Above Focusability attributes prevent automatic scroll-down, + <!-- Above focusability attributes prevent automatic scroll-down, because body text is selectable --> <include diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java b/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java index 2fb84671e28209512757d231ecc8625c709b9f57..d870db1370f04851180dac7c4b4d9b75cab3b3a2 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java @@ -8,6 +8,7 @@ import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.support.v4.view.ViewCompat; import android.support.v7.widget.RecyclerView; +import android.text.Spanned; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -110,16 +111,16 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { } // post body + Spanned bodyText = getSpanned(item.getBody()); if (listener == null) { - body.setText(getSpanned(item.getBody())); - makeLinksClickable(body); + body.setText(bodyText); body.setTextIsSelectable(true); + makeLinksClickable(body); } else { body.setTextIsSelectable(false); if (item.getBody().length() > TEASER_LENGTH) - body.setText(getTeaser(ctx, item.getBody())); - else - body.setText(item.getBody()); + bodyText = getTeaser(ctx, bodyText); + body.setText(bodyText); } // reblog button diff --git a/briar-android/src/org/briarproject/android/util/AndroidUtils.java b/briar-android/src/org/briarproject/android/util/AndroidUtils.java index 6a591f1dc638d4014977fb0dcd54a1bf37ed8a4a..759a25e6b47b56bb36af1cb51fba0bd364f3dd89 100644 --- a/briar-android/src/org/briarproject/android/util/AndroidUtils.java +++ b/briar-android/src/org/briarproject/android/util/AndroidUtils.java @@ -46,7 +46,7 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS; public class AndroidUtils { public static final long MIN_RESOLUTION = MINUTE_IN_MILLIS; - public static final int TEASER_LENGTH = 240; + public static final int TEASER_LENGTH = 320; // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; @@ -131,13 +131,13 @@ public class AndroidUtils { MIN_RESOLUTION, flags).toString(); } - public static SpannableStringBuilder getTeaser(Context ctx, String body) { + public static SpannableStringBuilder getTeaser(Context ctx, Spanned body) { if (body.length() < TEASER_LENGTH) throw new IllegalArgumentException( "String is shorter than TEASER_LENGTH"); SpannableStringBuilder builder = - new SpannableStringBuilder(body.substring(0, TEASER_LENGTH)); + new SpannableStringBuilder(body.subSequence(0, TEASER_LENGTH)); String ellipsis = ctx.getString(R.string.ellipsis); builder.append(ellipsis).append(" "); @@ -176,7 +176,7 @@ public class AndroidUtils { ssb.setSpan(cSpan, start, end, 0); } v.setText(ssb); - v.setMovementMethod(LinkMovementMethod.getInstance()); + v.setMovementMethod(ArticleMovementMethod.getInstance()); } } diff --git a/briar-android/src/org/briarproject/android/util/ArticleMovementMethod.java b/briar-android/src/org/briarproject/android/util/ArticleMovementMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..ad148a719d9e78e6e7f822c6724bd7bec9268804 --- /dev/null +++ b/briar-android/src/org/briarproject/android/util/ArticleMovementMethod.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.briarproject.android.util; + +import android.text.Layout; +import android.text.Spannable; +import android.text.method.ArrowKeyMovementMethod; +import android.text.method.MovementMethod; +import android.text.style.ClickableSpan; +import android.view.MotionEvent; +import android.widget.TextView; + +public class ArticleMovementMethod extends ArrowKeyMovementMethod { + + private static ArticleMovementMethod sInstance; + + public static MovementMethod getInstance() { + if (sInstance == null) { + sInstance = new ArticleMovementMethod(); + } + return sInstance; + } + + @Override + public boolean onTouchEvent(TextView widget, Spannable buffer, + MotionEvent event) { + int action = event.getAction(); + + if (action == MotionEvent.ACTION_UP) { + int x = (int) event.getX(); + int y = (int) event.getY(); + + x -= widget.getTotalPaddingLeft(); + y -= widget.getTotalPaddingTop(); + + x += widget.getScrollX(); + y += widget.getScrollY(); + + Layout layout = widget.getLayout(); + int line = layout.getLineForVertical(y); + int off = layout.getOffsetForHorizontal(line, x); + + ClickableSpan[] link = + buffer.getSpans(off, off, ClickableSpan.class); + + if (link.length != 0) { + link[0].onClick(widget); + } + } + return super.onTouchEvent(widget, buffer, event); + } + +} diff --git a/briar-core/src/org/briarproject/feed/FeedManagerImpl.java b/briar-core/src/org/briarproject/feed/FeedManagerImpl.java index b9263c062711a060f9157850beba70d681774a0b..f2ffa7ea9dcec3ff10a07e859dc43c0852545548 100644 --- a/briar-core/src/org/briarproject/feed/FeedManagerImpl.java +++ b/briar-core/src/org/briarproject/feed/FeedManagerImpl.java @@ -42,6 +42,7 @@ import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -437,7 +438,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener { } b.append("<p>"); if (!StringUtils.isNullOrEmpty(entry.getAuthor())) { - b.append("\n\n-- ").append(clean(entry.getAuthor(), stripAll)); + b.append("-- ").append(entry.getAuthor()); } if (entry.getPublishedDate() != null) { b.append(" (").append(entry.getPublishedDate().toString()) @@ -484,8 +485,10 @@ class FeedManagerImpl implements FeedManager, Client, EventListener { private String getPostBody(String text) { text = clean(text, article); - if (text.length() <= MAX_BLOG_POST_BODY_LENGTH) return text; - else return text.substring(0, MAX_BLOG_POST_BODY_LENGTH); + byte[] textBytes = StringUtils.toUtf8(text); + if (textBytes.length <= MAX_BLOG_POST_BODY_LENGTH) + return text; + return StringUtils.fromUtf8(textBytes, 0, MAX_BLOG_POST_BODY_LENGTH); } /**