diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/TranslateStatus.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/TranslateStatus.java index bb3c29888..881036272 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/TranslateStatus.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/TranslateStatus.java @@ -1,11 +1,13 @@ package org.joinmastodon.android.api.requests.statuses; import org.joinmastodon.android.api.MastodonAPIRequest; -import org.joinmastodon.android.model.TranslatedStatus; +import org.joinmastodon.android.model.Translation; -public class TranslateStatus extends MastodonAPIRequest { - public TranslateStatus(String id) { - super(HttpMethod.POST, "/statuses/"+id+"/translate", TranslatedStatus.class); - setRequestBody(new Object()); - } +import java.util.Map; + +public class TranslateStatus extends MastodonAPIRequest{ + public TranslateStatus(String id, String lang){ + super(HttpMethod.POST, "/statuses/"+id+"/translate", Translation.class); + setRequestBody(Map.of("lang", lang)); + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java index da2f43242..29881041e 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java @@ -22,6 +22,7 @@ import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships; import org.joinmastodon.android.api.requests.polls.SubmitPollVote; +import org.joinmastodon.android.api.requests.statuses.TranslateStatus; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.events.PollUpdatedEvent; import org.joinmastodon.android.model.Account; @@ -29,7 +30,9 @@ import org.joinmastodon.android.model.DisplayItemsParent; import org.joinmastodon.android.model.Poll; import org.joinmastodon.android.model.Relationship; import org.joinmastodon.android.model.Status; +import org.joinmastodon.android.model.Translation; import org.joinmastodon.android.ui.BetterItemAnimator; +import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.EmojiReactionsStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem; @@ -55,6 +58,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -772,6 +776,61 @@ public abstract class BaseStatusListFragment exten assistContent.setWebUri(getWebUri(getSession().getInstanceUri().buildUpon())); } + public void togglePostTranslation(Status status, String itemID){ + switch(status.translationState){ + case LOADING -> { + return; + } + case SHOWN -> { + status.translationState=Status.TranslationState.HIDDEN; + } + case HIDDEN -> { + if(status.translation!=null){ + status.translationState=Status.TranslationState.SHOWN; + }else{ + status.translationState=Status.TranslationState.LOADING; + new TranslateStatus(status.getContentStatus().id, Locale.getDefault().getLanguage()) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(Translation result){ + if(getActivity()==null) + return; + status.translation=result; + status.translationState=Status.TranslationState.SHOWN; + TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class); + if(text!=null){ + text.updateTranslation(true); + imgLoader.bindViewHolder((ImageLoaderRecyclerAdapter) list.getAdapter(), text, text.getAbsoluteAdapterPosition()); + } + } + + @Override + public void onError(ErrorResponse error){ + if(getActivity()==null) + return; + status.translationState=Status.TranslationState.HIDDEN; + TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class); + if(text!=null){ + text.updateTranslation(true); + } + new M3AlertDialogBuilder(getActivity()) + .setTitle(R.string.error) + .setMessage(R.string.translation_failed) + .setPositiveButton(R.string.ok, null) + .show(); + } + }) + .exec(accountID); + } + } + } + TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class); + if(text!=null){ + text.updateTranslation(true); + imgLoader.bindViewHolder((ImageLoaderRecyclerAdapter) list.getAdapter(), text, text.getAbsoluteAdapterPosition()); + } + } + public void rebuildAllDisplayItems(){ displayItems.clear(); for(T item:data){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java index c79752f12..ac8850f78 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java @@ -29,6 +29,7 @@ import android.text.TextWatcher; import android.text.format.DateFormat; import android.text.style.BackgroundColorSpan; import android.text.style.ForegroundColorSpan; +import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; @@ -826,6 +827,14 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr publishButton = wrap.findViewById(R.id.publish_btn); languageButton = wrap.findViewById(R.id.language_btn); languageButton.setOnClickListener(v->showLanguageAlert()); + languageButton.setOnLongClickListener(v->{ + languageButton.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + if(!getLocalPrefs().bottomEncoding){ + getLocalPrefs().bottomEncoding=true; + getLocalPrefs().save(); + } + return false; + }); publishButton.setOnClickListener(v -> { if(GlobalUserPreferences.altTextReminders && editingStatus==null) diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/Status.java b/mastodon/src/main/java/org/joinmastodon/android/model/Status.java index b5b326092..6c7b9cd54 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/Status.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/Status.java @@ -7,6 +7,8 @@ import android.text.TextUtils; import androidx.annotation.NonNull; +import com.github.bottomSoftwareFoundation.bottom.Bottom; +import com.github.bottomSoftwareFoundation.bottom.TranslationError; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; @@ -15,16 +17,21 @@ import com.google.gson.JsonParseException; import org.joinmastodon.android.api.ObjectValidationException; import org.joinmastodon.android.api.RequiredField; +import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent; import org.joinmastodon.android.events.StatusCountersUpdatedEvent; import org.joinmastodon.android.ui.text.HtmlParser; +import org.joinmastodon.android.utils.StatusTextEncoder; import org.parceler.Parcel; import java.lang.reflect.Type; import java.time.Instant; import java.util.ArrayList; import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.regex.Pattern; @Parcel public class Status extends BaseModel implements DisplayItemsParent, Searchable{ @@ -83,9 +90,9 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{ public transient boolean sensitiveRevealed; public transient boolean textExpanded, textExpandable; public transient boolean hasGapAfter; - public transient TranslatedStatus translation; - public transient boolean translationShown; private transient String strippedText; + public transient TranslationState translationState=TranslationState.HIDDEN; + public transient Translation translation; public Status(){} @@ -201,6 +208,38 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{ return (Status) super.clone(); } + 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 boolean isEligibleForTranslation(AccountSession session){ + Instance instanceInfo = AccountSessionManager.getInstance().getInstanceInfo(session.domain); + boolean translateEnabled = instanceInfo != null && + instanceInfo.v2 != null && instanceInfo.v2.configuration.translation != null && + instanceInfo.v2.configuration.translation.enabled; + + try { + String bottomText = BOTTOM_TEXT_PATTERN.matcher(getStrippedText()).find() + ? new StatusTextEncoder(Bottom::decode).decode(getStrippedText(), BOTTOM_TEXT_PATTERN) + : null; + if(bottomText==null || bottomText.length()==0 || bottomText.equals("\u0005")) bottomText=null; + if(bottomText!=null){ + translation=new Translation(); + translation.content=bottomText; + translation.detectedSourceLanguage="\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48"; + translation.provider="bottom-java"; + return true; + } + } catch (TranslationError ignored) {} + + return translateEnabled && !TextUtils.isEmpty(content) && !TextUtils.isEmpty(language) + && !Objects.equals(Locale.getDefault().getLanguage(), language) + && (visibility==StatusPrivacy.PUBLIC || visibility==StatusPrivacy.UNLISTED); + } + + public enum TranslationState{ + HIDDEN, + SHOWN, + LOADING + } + public boolean isReblogPermitted(String accountID){ return visibility.isReblogPermitted(account.id.equals( AccountSessionManager.getInstance().getAccount(accountID).self.id diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/TranslatedStatus.java b/mastodon/src/main/java/org/joinmastodon/android/model/TranslatedStatus.java deleted file mode 100644 index 891c86c03..000000000 --- a/mastodon/src/main/java/org/joinmastodon/android/model/TranslatedStatus.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.joinmastodon.android.model; - -public class TranslatedStatus extends BaseModel { - public String content; - public String detectedSourceLanguage; - public String provider; -} diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/Translation.java b/mastodon/src/main/java/org/joinmastodon/android/model/Translation.java new file mode 100644 index 000000000..68487451d --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/model/Translation.java @@ -0,0 +1,10 @@ +package org.joinmastodon.android.model; + +import org.joinmastodon.android.api.AllFieldsAreRequired; + +@AllFieldsAreRequired +public class Translation extends BaseModel{ + public String content; + public String detectedSourceLanguage; + public String provider; +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java index abac9185b..b47ea7e93 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java @@ -1,71 +1,52 @@ package org.joinmastodon.android.ui.displayitems; +import static org.joinmastodon.android.ui.utils.UiUtils.opacityIn; + 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.view.ViewStub; import android.widget.Button; import android.widget.LinearLayout; +import android.widget.ProgressBar; import android.widget.ScrollView; 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.fragments.ThreadFragment; -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.model.Translation; 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.StatusTextEncoder; import java.util.Locale; -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(); + private CharSequence translatedText; + private CustomEmojiHelper translationEmojiHelper=new CustomEmojiHelper(); public boolean textSelectable; public boolean reduceTopPadding; + public boolean disableTranslate; public final Status status; - public boolean disableTranslate, translationShown; - 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; - this.translationShown=status.translationShown; emojiHelper.setText(text); - session = AccountSessionManager.getInstance().getAccount(parentFragment.getAccountID()); - } - - public void setTranslationShown(boolean translationShown) { - this.translationShown = translationShown; - status.translationShown = translationShown; } @Override @@ -75,38 +56,47 @@ public class TextStatusDisplayItem extends StatusDisplayItem{ @Override public int getImageCount(){ - return emojiHelper.getImageCount(); + return getCurrentEmojiHelper().getImageCount(); } @Override public ImageLoaderRequest getImageRequest(int index){ - return emojiHelper.getImageRequest(index); + return getCurrentEmojiHelper().getImageRequest(index); + } + + public void setTranslatedText(String text){ + Status statusForContent=status.getContentStatus(); + translatedText=HtmlParser.parse(text, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, parentFragment.getAccountID()); + translationEmojiHelper.setText(translatedText); + } + + private CustomEmojiHelper getCurrentEmojiHelper(){ + return status.translationState==Status.TranslationState.SHOWN ? translationEmojiHelper : emojiHelper; } public static class Holder extends StatusDisplayItem.Holder implements ImageLoaderViewHolder{ private final LinkedTextView text; - private final TextView translateInfo, readMore; - private final View textWrap, translateWrap, translateProgress; - private final Button translateButton; - private final ScrollView textScrollView; + private final ViewStub translationFooterStub; + private View translationFooter, translationButtonWrap; + private TextView translationInfo; + private Button translationButton; + private ProgressBar translationProgress; - private final float textMaxHeight, textCollapsedHeight; + private final float textMaxHeight; private final LinearLayout.LayoutParams collapseParams, wrapParams; private final ViewGroup parent; + private final TextView readMore; + private final ScrollView textScrollView; public Holder(Activity activity, ViewGroup parent){ super(activity, R.layout.display_item_text, parent); this.parent=parent; text=findViewById(R.id.text); - textWrap = (LinearLayout) itemView; - translateWrap=findViewById(R.id.translate_wrap); - translateButton=findViewById(R.id.translate_btn); - translateInfo=findViewById(R.id.translate_info); - translateProgress=findViewById(R.id.translate_progress); + translationFooterStub=findViewById(R.id.translation_info); textScrollView=findViewById(R.id.text_scroll_view); readMore=findViewById(R.id.read_more); textMaxHeight=activity.getResources().getDimension(R.dimen.text_max_height); - textCollapsedHeight=activity.getResources().getDimension(R.dimen.text_collapsed_height); + float textCollapsedHeight=activity.getResources().getDimension(R.dimen.text_collapsed_height); collapseParams=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) textCollapsedHeight); wrapParams=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); readMore.setOnClickListener(v -> item.parentFragment.onToggleExpanded(item.status, getItemID())); @@ -114,83 +104,20 @@ public class TextStatusDisplayItem extends StatusDisplayItem{ @Override public void onBind(TextStatusDisplayItem item){ - boolean hasSpoiler = !TextUtils.isEmpty(item.status.spoilerText); - text.setText(item.translationShown - ? HtmlParser.parse(item.status.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID()) - : item.text); - text.setTextIsSelectable(item.textSelectable); - if (item.textSelectable) { - textScrollView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + if(item.status.translationState==Status.TranslationState.SHOWN){ + if(item.translatedText==null){ + item.setTranslatedText(item.status.translation.content); + } + text.setText(item.translatedText); + }else{ + text.setText(item.text); } + text.setTextIsSelectable(item.textSelectable); text.setInvalidateOnEveryFrame(false); itemView.setClickable(false); itemView.setPadding(itemView.getPaddingLeft(), item.reduceTopPadding ? V.dp(6) : V.dp(12), itemView.getPaddingRight(), itemView.getPaddingBottom()); text.setTextColor(UiUtils.getThemeColor(text.getContext(), item.inset ? R.attr.colorM3OnSurfaceVariant : R.attr.colorM3OnSurface)); - - 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; - String bottomText = null; - try { - bottomText = BOTTOM_TEXT_PATTERN.matcher(item.status.getStrippedText()).find() - ? new StatusTextEncoder(Bottom::decode).decode(item.status.getStrippedText(), BOTTOM_TEXT_PATTERN) - : null; - } catch (TranslationError ignored) {} - - boolean translateVisible = (bottomText != null || ( - translateEnabled && - !item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) && - item.status.language != null && - // todo: compare to mastodon locale instead (how do i query that?!) - !item.status.language.equalsIgnoreCase(Locale.getDefault().getLanguage()))) - && (!GlobalUserPreferences.translateButtonOpenedOnly || item.textSelectable); - translateWrap.setVisibility(translateVisible ? View.VISIBLE : View.GONE); - translateButton.setText(item.translationShown ? R.string.sk_translate_show_original : R.string.sk_translate_post); - translateInfo.setText(item.translationShown ? itemView.getResources().getString(R.string.sk_translated_using, bottomText != null ? "bottom-java" : item.status.translation.provider) : ""); - String finalBottomText = bottomText; - translateButton.setOnClickListener(v->{ - if (item.status.translation == null) { - if (finalBottomText != null) { - try { - item.status.translation = new TranslatedStatus(); - item.status.translation.content = finalBottomText; - item.setTranslationShown(true); - } catch (TranslationError err) { - item.status.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.status.translation = translatedStatus; - item.setTranslationShown(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.setTranslationShown(!item.translationShown); - rebind(); - } - }); + updateTranslation(false); readMore.setText(item.status.textExpanded ? R.string.sk_collapse : R.string.sk_expand); @@ -224,18 +151,19 @@ public class TextStatusDisplayItem extends StatusDisplayItem{ if (GlobalUserPreferences.collapseLongPosts && !item.status.textExpandable) { boolean tooBig = text.getMeasuredHeight() > textMaxHeight; - boolean expandable = tooBig && !hasSpoiler; + boolean expandable = tooBig && !item.status.hasSpoiler(); item.parentFragment.onEnableExpandable(Holder.this, expandable); } boolean expandButtonShown=item.status.textExpandable && !item.status.textExpanded; - translateWrap.setPadding(0, V.dp(expandButtonShown ? 0 : 4), 0, 0); + if(translationFooter!=null) + translationFooter.setPadding(0, V.dp(expandButtonShown ? 0 : 4), 0, 0); readMore.setVisibility(expandButtonShown ? View.VISIBLE : View.GONE); textScrollView.setLayoutParams(item.status.textExpandable && !item.status.textExpanded ? collapseParams : wrapParams); // compensate for spoiler's bottom margin ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) itemView.getLayoutParams(); - params.setMargins(params.leftMargin, item.inset && hasSpoiler ? V.dp(-16) : 0, + params.setMargins(params.leftMargin, item.inset && item.status.hasSpoiler() ? V.dp(-16) : 0, params.rightMargin, params.bottomMargin); } @@ -259,5 +187,58 @@ public class TextStatusDisplayItem extends StatusDisplayItem{ private CustomEmojiHelper getEmojiHelper(){ return item.emojiHelper; } + + public void updateTranslation(boolean updateText){ + if(item.status==null) + return; + boolean translateEnabled=!item.disableTranslate && item.status.isEligibleForTranslation(item.parentFragment.getSession()); + if(translationFooter==null && translateEnabled){ + translationFooter=translationFooterStub.inflate(); + translationInfo=findViewById(R.id.translation_info_text); + translationButton=findViewById(R.id.translation_btn); + translationButtonWrap=findViewById(R.id.translation_btn_wrap); + translationProgress=findViewById(R.id.translation_progress); + translationButton.setOnClickListener(v->item.parentFragment.togglePostTranslation(item.status, item.parentID)); + } + if(item.status.translationState==Status.TranslationState.HIDDEN){ + if(updateText) text.setText(item.text); + if(translationFooter==null) return; + translationFooter.setVisibility(translateEnabled ? View.VISIBLE : View.GONE); + translationProgress.setVisibility(View.GONE); + Translation existingTrans=item.status.getContentStatus().translation; + String lang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null; + String displayLang=Locale.forLanguageTag(lang!=null ? lang : item.status.getContentStatus().language).getDisplayLanguage(); + translationButton.setText(item.parentFragment.getString(R.string.translate_post, !displayLang.isBlank() ? displayLang : lang)); + translationButton.setEnabled(true); + translationButton.setAlpha(1); + translationInfo.setVisibility(View.GONE); + UiUtils.beginLayoutTransition((ViewGroup) translationButtonWrap); + }else{ + translationFooter.setVisibility(View.VISIBLE); + if(item.status.translationState==Status.TranslationState.SHOWN){ + translationProgress.setVisibility(View.GONE); + translationButton.setText(R.string.translation_show_original); + translationButton.setEnabled(true); + translationButton.setAlpha(1); + translationInfo.setVisibility(View.VISIBLE); + translationButton.setVisibility(View.VISIBLE); + String displayLang=Locale.forLanguageTag(item.status.translation.detectedSourceLanguage).getDisplayLanguage(); + translationInfo.setText(translationInfo.getContext().getString(R.string.post_translated, !displayLang.isBlank() ? displayLang : item.status.translation.detectedSourceLanguage, item.status.translation.provider)); + UiUtils.beginLayoutTransition((ViewGroup) translationButtonWrap); + if(updateText){ + if(item.translatedText==null){ + item.setTranslatedText(item.status.translation.content); + } + text.setText(item.translatedText); + } + }else{ // LOADING + translationProgress.setVisibility(View.VISIBLE); + translationButton.setEnabled(false); + translationButton.startAnimation(opacityIn); + translationInfo.setVisibility(View.INVISIBLE); + UiUtils.beginLayoutTransition((ViewGroup) translationButton.getParent()); + } + } + } } } diff --git a/mastodon/src/main/res/layout/display_item_text.xml b/mastodon/src/main/res/layout/display_item_text.xml index 8729b9886..145bd56ef 100644 --- a/mastodon/src/main/res/layout/display_item_text.xml +++ b/mastodon/src/main/res/layout/display_item_text.xml @@ -45,56 +45,10 @@ android:visibility="gone" android:importantForAccessibility="no"/> - - - - - - - - - - - - + android:layout="@layout/footer_text_translation"/> diff --git a/mastodon/src/main/res/layout/footer_text_translation.xml b/mastodon/src/main/res/layout/footer_text_translation.xml new file mode 100644 index 000000000..22f85cc73 --- /dev/null +++ b/mastodon/src/main/res/layout/footer_text_translation.xml @@ -0,0 +1,50 @@ + + + + + +