package org.joinmastodon.android.ui.displayitems; import android.app.Activity; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.github.bottomSoftwareFoundation.bottom.Bottom; import com.github.bottomSoftwareFoundation.bottom.TranslationError; import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.statuses.TranslateStatus; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.StatusPrivacy; import org.joinmastodon.android.model.TranslatedStatus; import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.utils.CustomEmojiHelper; import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.views.LinkedTextView; import org.joinmastodon.android.utils.StringEncoder; import java.util.regex.Pattern; import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.imageloader.ImageLoaderViewHolder; import me.grishka.appkit.imageloader.MovieDrawable; import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; import me.grishka.appkit.utils.CubicBezierInterpolator; import me.grishka.appkit.utils.V; public class TextStatusDisplayItem extends StatusDisplayItem{ private CharSequence text; private CustomEmojiHelper emojiHelper=new CustomEmojiHelper(), spoilerEmojiHelper; private CharSequence parsedSpoilerText; public boolean textSelectable; public final Status status; public boolean disableTranslate; public boolean translated = false; public TranslatedStatus translation = null; private AccountSession session; public static final Pattern BOTTOM_TEXT_PATTERN = Pattern.compile("(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️)(?:\uD83D\uDC49\uD83D\uDC48(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️))*\uD83D\uDC49\uD83D\uDC48"); public TextStatusDisplayItem(String parentID, CharSequence text, BaseStatusListFragment parentFragment, Status status, boolean disableTranslate){ super(parentID, parentFragment); this.text=text; this.status=status; this.disableTranslate=disableTranslate; emojiHelper.setText(text); if(!TextUtils.isEmpty(status.spoilerText)){ parsedSpoilerText=HtmlParser.parseCustomEmoji(status.spoilerText, status.emojis); spoilerEmojiHelper=new CustomEmojiHelper(); spoilerEmojiHelper.setText(parsedSpoilerText); } session = AccountSessionManager.getInstance().getAccount(parentFragment.getAccountID()); } @Override public Type getType(){ return Type.TEXT; } @Override public int getImageCount(){ if(spoilerEmojiHelper!=null && !status.spoilerRevealed) return spoilerEmojiHelper.getImageCount(); return emojiHelper.getImageCount(); } @Override public ImageLoaderRequest getImageRequest(int index){ if(spoilerEmojiHelper!=null && !status.spoilerRevealed) return spoilerEmojiHelper.getImageRequest(index); return emojiHelper.getImageRequest(index); } public static class Holder extends StatusDisplayItem.Holder implements ImageLoaderViewHolder{ private final LinkedTextView text; private final LinearLayout spoilerHeader; private final TextView spoilerTitle, spoilerTitleInline, translateInfo; private final View spoilerOverlay, borderTop, borderBottom, textWrap, translateWrap, translateProgress; private final int backgroundColor, borderColor; private final Button translateButton; public Holder(Activity activity, ViewGroup parent){ super(activity, R.layout.display_item_text, parent); text=findViewById(R.id.text); spoilerTitle=findViewById(R.id.spoiler_title); spoilerTitleInline=findViewById(R.id.spoiler_title_inline); spoilerHeader=findViewById(R.id.spoiler_header); spoilerOverlay=findViewById(R.id.spoiler_overlay); borderTop=findViewById(R.id.border_top); borderBottom=findViewById(R.id.border_bottom); textWrap=findViewById(R.id.text_wrap); translateWrap=findViewById(R.id.translate_wrap); translateButton=findViewById(R.id.translate_btn); translateInfo=findViewById(R.id.translate_info); translateProgress=findViewById(R.id.translate_progress); itemView.setOnClickListener(v->item.parentFragment.onRevealSpoilerClick(this)); backgroundColor=UiUtils.getThemeColor(activity, R.attr.colorBackgroundLight); borderColor=UiUtils.getThemeColor(activity, R.attr.colorPollVoted); } @Override public void onBind(TextStatusDisplayItem item){ text.setText(item.translated ? HtmlParser.parse(item.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID()) : item.text); text.setTextIsSelectable(item.textSelectable); spoilerTitleInline.setTextIsSelectable(item.textSelectable); text.setInvalidateOnEveryFrame(false); spoilerTitleInline.setBackgroundColor(item.inset ? 0 : backgroundColor); spoilerTitleInline.setPadding(spoilerTitleInline.getPaddingLeft(), item.inset ? 0 : V.dp(14), spoilerTitleInline.getPaddingRight(), item.inset ? 0 : V.dp(14)); borderTop.setBackgroundColor(item.inset ? 0 : borderColor); borderBottom.setBackgroundColor(item.inset ? 0 : borderColor); if(!TextUtils.isEmpty(item.status.spoilerText)){ spoilerTitle.setText(item.parsedSpoilerText); spoilerTitleInline.setText(item.parsedSpoilerText); if(item.status.spoilerRevealed){ spoilerOverlay.setVisibility(View.GONE); spoilerHeader.setVisibility(View.VISIBLE); textWrap.setVisibility(View.VISIBLE); itemView.setClickable(false); }else{ spoilerOverlay.setVisibility(View.VISIBLE); spoilerHeader.setVisibility(View.GONE); textWrap.setVisibility(View.GONE); itemView.setClickable(true); } }else{ spoilerOverlay.setVisibility(View.GONE); spoilerHeader.setVisibility(View.GONE); textWrap.setVisibility(View.VISIBLE); itemView.setClickable(false); } Instance instanceInfo = AccountSessionManager.getInstance().getInstanceInfo(item.session.domain); boolean translateEnabled = !item.disableTranslate && instanceInfo != null && instanceInfo.v2 != null && instanceInfo.v2.configuration.translation != null && instanceInfo.v2.configuration.translation.enabled; boolean isBottomText = BOTTOM_TEXT_PATTERN.matcher(item.status.getStrippedText()).find(); translateWrap.setVisibility((isBottomText || ( translateEnabled && !item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) && item.status.language != null && (item.session.preferences == null || !item.status.language.equalsIgnoreCase(item.session.preferences.postingDefaultLanguage)))) && (!GlobalUserPreferences.translateButtonOpenedOnly || item.textSelectable) ? View.VISIBLE : View.GONE ); translateButton.setText(item.translated ? R.string.sk_translate_show_original : R.string.sk_translate_post); translateInfo.setText(item.translated ? itemView.getResources().getString(R.string.sk_translated_using, isBottomText ? "bottom-java" : item.translation.provider) : ""); translateButton.setOnClickListener(v->{ if (item.translation == null) { if (isBottomText) { try { item.translation = new TranslatedStatus(); item.translation.content = new StringEncoder(Bottom::decode).decode(item.status.getStrippedText(), BOTTOM_TEXT_PATTERN); item.translated = true; } catch (TranslationError err) { item.translation = null; Toast.makeText(itemView.getContext(), err.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); } rebind(); return; } translateProgress.setVisibility(View.VISIBLE); translateButton.setClickable(false); translateButton.animate().alpha(0.5f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start(); new TranslateStatus(item.status.id).setCallback(new Callback<>() { @Override public void onSuccess(TranslatedStatus translatedStatus) { item.translation = translatedStatus; item.translated = true; if (item.parentFragment.getActivity() == null) return; translateProgress.setVisibility(View.GONE); translateButton.setClickable(true); translateButton.animate().alpha(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(50).start(); rebind(); } @Override public void onError(ErrorResponse error) { translateProgress.setVisibility(View.GONE); translateButton.setClickable(true); translateButton.animate().alpha(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(50).start(); error.showToast(itemView.getContext()); } }).exec(item.parentFragment.getAccountID()); } else { item.translated = !item.translated; rebind(); } }); } @Override public void setImage(int index, Drawable image){ getEmojiHelper().setImageDrawable(index, image); text.invalidate(); spoilerTitle.invalidate(); if(image instanceof Animatable){ ((Animatable) image).start(); if(image instanceof MovieDrawable) text.setInvalidateOnEveryFrame(true); } } @Override public void clearImage(int index){ getEmojiHelper().setImageDrawable(index, null); text.invalidate(); } private CustomEmojiHelper getEmojiHelper(){ return item.spoilerEmojiHelper!=null && !item.status.spoilerRevealed ? item.spoilerEmojiHelper : item.emojiHelper; } } }