Loading app/src/main/java/app/fedilab/android/mastodon/client/entities/api/Status.java +11 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package app.fedilab.android.mastodon.client.entities.api; import android.content.Context; import android.text.Spannable; import android.util.Log; import android.view.View; import androidx.annotation.NonNull; Loading @@ -28,6 +29,7 @@ import java.lang.ref.WeakReference; import java.util.Date; import java.util.List; import app.fedilab.android.mastodon.helper.Helper; import app.fedilab.android.mastodon.helper.SpannableHelper; import de.timfreiheit.mathjax.android.MathJaxView; Loading Loading @@ -139,6 +141,8 @@ public class Status implements Serializable, Cloneable { public boolean spoilerChecked = false; public Filter filteredByApp; public transient Spannable contentSpan; public transient String[] bottomTags; public transient Spannable contentSpoilerSpan; public transient Spannable contentTranslateSpan; public transient MathJaxView mathJaxView; Loading @@ -162,6 +166,13 @@ public class Status implements Serializable, Cloneable { return contentSpan; } public synchronized String[] getBottomTags() { if(bottomTags == null) { bottomTags = SpannableHelper.hasBottomTags(content); } return bottomTags; } public synchronized Spannable getSpanSpoiler(Context context, WeakReference<View> viewWeakReference, Callback callback) { if (contentSpoilerSpan == null) { contentSpoilerSpan = SpannableHelper.convert(context, spoiler_text, this, null, null, viewWeakReference, callback, true, false); Loading app/src/main/java/app/fedilab/android/mastodon/helper/SpannableHelper.java +38 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.text.TextPaint; import android.text.style.ClickableSpan; import android.text.style.QuoteSpan; import android.text.style.URLSpan; import android.util.Log; import android.util.Patterns; import android.view.LayoutInflater; import android.view.View; Loading Loading @@ -107,6 +108,28 @@ public class SpannableHelper { private static int linkColor; private static boolean underlineLinks; private static final String patternBottomTags = "\\n{2,}((#[\\w_À-ú-]+)\\s?)+$"; public static String[] hasBottomTags(String text) { if (text == null) { return new String[]{}; } SpannableString initialContent; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); } else { initialContent = new SpannableString(Html.fromHtml(text)); } final Pattern bottomTagsPattern = Pattern.compile(patternBottomTags, Pattern.CASE_INSENSITIVE); Matcher matcherBottomTags = bottomTagsPattern.matcher(initialContent); String[] tags = new String[]{}; while (matcherBottomTags.find()) { String stringTags = Objects.requireNonNull(matcherBottomTags.group()).trim(); tags = stringTags.split("\\s"); } return tags; } public static Spannable convert(Context context, String text, Status status, Account account, Announcement announcement, WeakReference<View> viewWeakReference, Status.Callback callback, boolean convertHtml, boolean convertMarkdown) { Loading Loading @@ -162,6 +185,7 @@ public class SpannableHelper { } else { initialContent = new SpannableString(text); } boolean markdownSupport = sharedpreferences.getBoolean(context.getString(R.string.SET_MARKDOWN_SUPPORT), false); //Get all links SpannableStringBuilder content; Loading Loading @@ -393,6 +417,20 @@ public class SpannableHelper { } } } boolean underlineBottomHashTags = sharedpreferences.getBoolean(context.getString(R.string.SET_UNDERLINE_BOTTOM_HASHTAGS), true); if(underlineBottomHashTags) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); final Pattern bottomTagsPattern = Pattern.compile(patternBottomTags, Pattern.CASE_INSENSITIVE); Matcher matcherBottomTags = bottomTagsPattern.matcher(content); int length = 0; while (matcherBottomTags.find()) { length = Objects.requireNonNull(matcherBottomTags.group()).length(); } spannableStringBuilder.append(content,0, content.length()-length); return trimSpannable(spannableStringBuilder); } return trimSpannable(new SpannableStringBuilder(content)); } Loading app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java +36 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ import com.bumptech.glide.ListPreloader; import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.request.RequestOptions; import com.github.stom79.mytransl.MyTransL; import com.google.android.material.chip.Chip; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.smarteist.autoimageslider.SliderAnimations; import com.smarteist.autoimageslider.SliderView; Loading Loading @@ -143,6 +144,7 @@ import app.fedilab.android.databinding.LayoutPollItemBinding; import app.fedilab.android.mastodon.activities.ComposeActivity; import app.fedilab.android.mastodon.activities.ContextActivity; import app.fedilab.android.mastodon.activities.CustomSharingActivity; import app.fedilab.android.mastodon.activities.HashTagActivity; import app.fedilab.android.mastodon.activities.MediaActivity; import app.fedilab.android.mastodon.activities.ProfileActivity; import app.fedilab.android.mastodon.activities.ReportActivity; Loading Loading @@ -508,6 +510,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> LinearLayoutCompat.MarginLayoutParams psc = (LinearLayoutCompat.MarginLayoutParams) holder.binding.statusContent.getLayoutParams(); psc.setMarginStart((int) Helper.convertDpToPixel(6, context)); holder.binding.statusContent.setLayoutParams(psc); LinearLayoutCompat.MarginLayoutParams pst = (LinearLayoutCompat.MarginLayoutParams) holder.binding.statusHashtags.getLayoutParams(); pst.setMarginStart((int) Helper.convertDpToPixel(6, context)); holder.binding.statusHashtags.setLayoutParams(pst); LinearLayoutCompat.MarginLayoutParams psq = (LinearLayoutCompat.MarginLayoutParams) holder.binding.quotedMessage.cardviewContainer.getLayoutParams(); psq.setMarginStart((int) Helper.convertDpToPixel(6, context)); holder.binding.quotedMessage.cardviewContainer.setLayoutParams(psq); Loading Loading @@ -1510,6 +1515,37 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> recyclerView.post(() -> adapter.notifyItemChanged(holder.getBindingAdapterPosition())); }), TextView.BufferType.SPANNABLE); boolean underlineBottomHashTags = sharedpreferences.getBoolean(context.getString(R.string.SET_UNDERLINE_BOTTOM_HASHTAGS), true); if(underlineBottomHashTags) { if (statusToDeal.getBottomTags().length > 0) { holder.binding.statusHashtags.setVisibility(View.VISIBLE); holder.binding.statusHashtags.removeAllViews(); for (String tag : statusToDeal.getBottomTags()) { Chip chip = new Chip(context); chip.setClickable(true); chip.setEnsureMinTouchTargetSize(false); chip.setText(tag); chip.setTextColor(ThemeHelper.getAttColor(context, R.attr.colorPrimary)); chip.setOnClickListener(v -> { Intent intentTag = new Intent(context, HashTagActivity.class); Bundle args = new Bundle(); args.putString(Helper.ARG_SEARCH_KEYWORD, tag.replace("#", "")); new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> { Bundle bundle = new Bundle(); bundle.putLong(Helper.ARG_INTENT_ID, bundleId); intentTag.putExtras(bundle); intentTag.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intentTag); }); }); holder.binding.statusHashtags.addView(chip); } } else { holder.binding.statusHashtags.setVisibility(View.GONE); } } else { holder.binding.statusHashtags.setVisibility(View.GONE); } if (truncate_toots_size > 0) { holder.binding.statusContent.setMaxLines(truncate_toots_size); holder.binding.statusContent.setEllipsize(TextUtils.TruncateAt.END); Loading app/src/main/res/layouts/mastodon/layout/drawer_status.xml +12 −0 Original line number Diff line number Diff line Loading @@ -281,6 +281,18 @@ tools:maxLines="10" tools:text="@tools:sample/lorem/random" /> <com.google.android.material.chip.ChipGroup android:id="@+id/status_hashtags" android:visibility="gone" tools:visibility="visible" android:layout_marginStart="48dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" app:chipSpacingHorizontal="6dp" app:chipSpacingVertical="6dp" app:layout_constraintTop_toBottomOf="@id/description"/> <androidx.core.widget.NestedScrollView android:id="@+id/status_content_maths" android:layout_width="match_parent" Loading app/src/main/res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -1265,6 +1265,7 @@ <string name="SET_TIMELINE_SCROLLBAR" translatable="false">SET_TIMELINE_SCROLLBAR</string> <string name="SET_MARKDOWN_SUPPORT" translatable="false">SET_MARKDOWN_SUPPORT</string> <string name="SET_TRUNCATE_LINKS" translatable="false">SET_TRUNCATE_LINKS</string> <string name="SET_UNDERLINE_BOTTOM_HASHTAGS" translatable="false">SET_UNDERLINE_BOTTOM_HASHTAGS</string> <string name="SET_UNDERLINE_CLICKABLE" translatable="false">SET_UNDERLINE_CLICKABLE</string> <string name="SET_PRONOUNS_SUPPORT" translatable="false">SET_PRONOUNS_SUPPORT</string> <string name="SET_TRUNCATE_LINKS_MAX" translatable="false">SET_TRUNCATE_LINKS_MAX</string> Loading Loading @@ -2081,6 +2082,7 @@ <string name="toot_error_no_media_description">There are missing media descriptions</string> <string name="truncate_links">Truncate links</string> <string name="underline_bottom_hashtags">Highlight bottom hashtags</string> <string name="underline_links">Underline clickable elements</string> <string name="truncate_links_max">Max chars in links</string> Loading Loading
app/src/main/java/app/fedilab/android/mastodon/client/entities/api/Status.java +11 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package app.fedilab.android.mastodon.client.entities.api; import android.content.Context; import android.text.Spannable; import android.util.Log; import android.view.View; import androidx.annotation.NonNull; Loading @@ -28,6 +29,7 @@ import java.lang.ref.WeakReference; import java.util.Date; import java.util.List; import app.fedilab.android.mastodon.helper.Helper; import app.fedilab.android.mastodon.helper.SpannableHelper; import de.timfreiheit.mathjax.android.MathJaxView; Loading Loading @@ -139,6 +141,8 @@ public class Status implements Serializable, Cloneable { public boolean spoilerChecked = false; public Filter filteredByApp; public transient Spannable contentSpan; public transient String[] bottomTags; public transient Spannable contentSpoilerSpan; public transient Spannable contentTranslateSpan; public transient MathJaxView mathJaxView; Loading @@ -162,6 +166,13 @@ public class Status implements Serializable, Cloneable { return contentSpan; } public synchronized String[] getBottomTags() { if(bottomTags == null) { bottomTags = SpannableHelper.hasBottomTags(content); } return bottomTags; } public synchronized Spannable getSpanSpoiler(Context context, WeakReference<View> viewWeakReference, Callback callback) { if (contentSpoilerSpan == null) { contentSpoilerSpan = SpannableHelper.convert(context, spoiler_text, this, null, null, viewWeakReference, callback, true, false); Loading
app/src/main/java/app/fedilab/android/mastodon/helper/SpannableHelper.java +38 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.text.TextPaint; import android.text.style.ClickableSpan; import android.text.style.QuoteSpan; import android.text.style.URLSpan; import android.util.Log; import android.util.Patterns; import android.view.LayoutInflater; import android.view.View; Loading Loading @@ -107,6 +108,28 @@ public class SpannableHelper { private static int linkColor; private static boolean underlineLinks; private static final String patternBottomTags = "\\n{2,}((#[\\w_À-ú-]+)\\s?)+$"; public static String[] hasBottomTags(String text) { if (text == null) { return new String[]{}; } SpannableString initialContent; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); } else { initialContent = new SpannableString(Html.fromHtml(text)); } final Pattern bottomTagsPattern = Pattern.compile(patternBottomTags, Pattern.CASE_INSENSITIVE); Matcher matcherBottomTags = bottomTagsPattern.matcher(initialContent); String[] tags = new String[]{}; while (matcherBottomTags.find()) { String stringTags = Objects.requireNonNull(matcherBottomTags.group()).trim(); tags = stringTags.split("\\s"); } return tags; } public static Spannable convert(Context context, String text, Status status, Account account, Announcement announcement, WeakReference<View> viewWeakReference, Status.Callback callback, boolean convertHtml, boolean convertMarkdown) { Loading Loading @@ -162,6 +185,7 @@ public class SpannableHelper { } else { initialContent = new SpannableString(text); } boolean markdownSupport = sharedpreferences.getBoolean(context.getString(R.string.SET_MARKDOWN_SUPPORT), false); //Get all links SpannableStringBuilder content; Loading Loading @@ -393,6 +417,20 @@ public class SpannableHelper { } } } boolean underlineBottomHashTags = sharedpreferences.getBoolean(context.getString(R.string.SET_UNDERLINE_BOTTOM_HASHTAGS), true); if(underlineBottomHashTags) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); final Pattern bottomTagsPattern = Pattern.compile(patternBottomTags, Pattern.CASE_INSENSITIVE); Matcher matcherBottomTags = bottomTagsPattern.matcher(content); int length = 0; while (matcherBottomTags.find()) { length = Objects.requireNonNull(matcherBottomTags.group()).length(); } spannableStringBuilder.append(content,0, content.length()-length); return trimSpannable(spannableStringBuilder); } return trimSpannable(new SpannableStringBuilder(content)); } Loading
app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java +36 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ import com.bumptech.glide.ListPreloader; import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.request.RequestOptions; import com.github.stom79.mytransl.MyTransL; import com.google.android.material.chip.Chip; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.smarteist.autoimageslider.SliderAnimations; import com.smarteist.autoimageslider.SliderView; Loading Loading @@ -143,6 +144,7 @@ import app.fedilab.android.databinding.LayoutPollItemBinding; import app.fedilab.android.mastodon.activities.ComposeActivity; import app.fedilab.android.mastodon.activities.ContextActivity; import app.fedilab.android.mastodon.activities.CustomSharingActivity; import app.fedilab.android.mastodon.activities.HashTagActivity; import app.fedilab.android.mastodon.activities.MediaActivity; import app.fedilab.android.mastodon.activities.ProfileActivity; import app.fedilab.android.mastodon.activities.ReportActivity; Loading Loading @@ -508,6 +510,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> LinearLayoutCompat.MarginLayoutParams psc = (LinearLayoutCompat.MarginLayoutParams) holder.binding.statusContent.getLayoutParams(); psc.setMarginStart((int) Helper.convertDpToPixel(6, context)); holder.binding.statusContent.setLayoutParams(psc); LinearLayoutCompat.MarginLayoutParams pst = (LinearLayoutCompat.MarginLayoutParams) holder.binding.statusHashtags.getLayoutParams(); pst.setMarginStart((int) Helper.convertDpToPixel(6, context)); holder.binding.statusHashtags.setLayoutParams(pst); LinearLayoutCompat.MarginLayoutParams psq = (LinearLayoutCompat.MarginLayoutParams) holder.binding.quotedMessage.cardviewContainer.getLayoutParams(); psq.setMarginStart((int) Helper.convertDpToPixel(6, context)); holder.binding.quotedMessage.cardviewContainer.setLayoutParams(psq); Loading Loading @@ -1510,6 +1515,37 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> recyclerView.post(() -> adapter.notifyItemChanged(holder.getBindingAdapterPosition())); }), TextView.BufferType.SPANNABLE); boolean underlineBottomHashTags = sharedpreferences.getBoolean(context.getString(R.string.SET_UNDERLINE_BOTTOM_HASHTAGS), true); if(underlineBottomHashTags) { if (statusToDeal.getBottomTags().length > 0) { holder.binding.statusHashtags.setVisibility(View.VISIBLE); holder.binding.statusHashtags.removeAllViews(); for (String tag : statusToDeal.getBottomTags()) { Chip chip = new Chip(context); chip.setClickable(true); chip.setEnsureMinTouchTargetSize(false); chip.setText(tag); chip.setTextColor(ThemeHelper.getAttColor(context, R.attr.colorPrimary)); chip.setOnClickListener(v -> { Intent intentTag = new Intent(context, HashTagActivity.class); Bundle args = new Bundle(); args.putString(Helper.ARG_SEARCH_KEYWORD, tag.replace("#", "")); new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> { Bundle bundle = new Bundle(); bundle.putLong(Helper.ARG_INTENT_ID, bundleId); intentTag.putExtras(bundle); intentTag.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intentTag); }); }); holder.binding.statusHashtags.addView(chip); } } else { holder.binding.statusHashtags.setVisibility(View.GONE); } } else { holder.binding.statusHashtags.setVisibility(View.GONE); } if (truncate_toots_size > 0) { holder.binding.statusContent.setMaxLines(truncate_toots_size); holder.binding.statusContent.setEllipsize(TextUtils.TruncateAt.END); Loading
app/src/main/res/layouts/mastodon/layout/drawer_status.xml +12 −0 Original line number Diff line number Diff line Loading @@ -281,6 +281,18 @@ tools:maxLines="10" tools:text="@tools:sample/lorem/random" /> <com.google.android.material.chip.ChipGroup android:id="@+id/status_hashtags" android:visibility="gone" tools:visibility="visible" android:layout_marginStart="48dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" app:chipSpacingHorizontal="6dp" app:chipSpacingVertical="6dp" app:layout_constraintTop_toBottomOf="@id/description"/> <androidx.core.widget.NestedScrollView android:id="@+id/status_content_maths" android:layout_width="match_parent" Loading
app/src/main/res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -1265,6 +1265,7 @@ <string name="SET_TIMELINE_SCROLLBAR" translatable="false">SET_TIMELINE_SCROLLBAR</string> <string name="SET_MARKDOWN_SUPPORT" translatable="false">SET_MARKDOWN_SUPPORT</string> <string name="SET_TRUNCATE_LINKS" translatable="false">SET_TRUNCATE_LINKS</string> <string name="SET_UNDERLINE_BOTTOM_HASHTAGS" translatable="false">SET_UNDERLINE_BOTTOM_HASHTAGS</string> <string name="SET_UNDERLINE_CLICKABLE" translatable="false">SET_UNDERLINE_CLICKABLE</string> <string name="SET_PRONOUNS_SUPPORT" translatable="false">SET_PRONOUNS_SUPPORT</string> <string name="SET_TRUNCATE_LINKS_MAX" translatable="false">SET_TRUNCATE_LINKS_MAX</string> Loading Loading @@ -2081,6 +2082,7 @@ <string name="toot_error_no_media_description">There are missing media descriptions</string> <string name="truncate_links">Truncate links</string> <string name="underline_bottom_hashtags">Highlight bottom hashtags</string> <string name="underline_links">Underline clickable elements</string> <string name="truncate_links_max">Max chars in links</string> Loading