Compose: language selection
This commit is contained in:
@@ -1,19 +1,29 @@
|
||||
package org.joinmastodon.android.api.session;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.joinmastodon.android.api.CacheController;
|
||||
import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.api.PushSubscriptionManager;
|
||||
import org.joinmastodon.android.api.StatusInteractionController;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetPreferences;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Application;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Preferences;
|
||||
import org.joinmastodon.android.model.PushSubscription;
|
||||
import org.joinmastodon.android.model.Token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
|
||||
public class AccountSession{
|
||||
private static final String TAG="AccountSession";
|
||||
|
||||
public Token token;
|
||||
public Account self;
|
||||
public String domain;
|
||||
@@ -29,6 +39,7 @@ public class AccountSession{
|
||||
public List<Filter> wordFilters=new ArrayList<>();
|
||||
public String pushAccountID;
|
||||
public AccountActivationInfo activationInfo;
|
||||
public Preferences preferences;
|
||||
private transient MastodonAPIController apiController;
|
||||
private transient StatusInteractionController statusInteractionController;
|
||||
private transient CacheController cacheController;
|
||||
@@ -77,4 +88,22 @@ public class AccountSession{
|
||||
public String getFullUsername(){
|
||||
return '@'+self.username+'@'+domain;
|
||||
}
|
||||
|
||||
public void reloadPreferences(Consumer<Preferences> callback){
|
||||
new GetPreferences()
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Preferences result){
|
||||
preferences=result;
|
||||
callback.accept(result);
|
||||
AccountSessionManager.getInstance().writeAccountsFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
Log.w(TAG, "Failed to load preferences for account "+getID()+": "+error);
|
||||
}
|
||||
})
|
||||
.exec(getID());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.viewcontrollers.ComposeAutocompleteViewController;
|
||||
import org.joinmastodon.android.ui.viewcontrollers.ComposeLanguageAlertViewController;
|
||||
import org.joinmastodon.android.ui.viewcontrollers.ComposeMediaViewController;
|
||||
import org.joinmastodon.android.ui.viewcontrollers.ComposePollViewController;
|
||||
import org.joinmastodon.android.ui.views.ComposeEditText;
|
||||
@@ -122,7 +123,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
private String accountID;
|
||||
private int charCount, charLimit, trimmedCharCount;
|
||||
|
||||
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn;
|
||||
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, languageBtn;
|
||||
private TextView replyText;
|
||||
private Button visibilityBtn;
|
||||
private LinearLayout bottomBar;
|
||||
@@ -142,6 +143,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
private StatusPrivacy statusVisibility=StatusPrivacy.PUBLIC;
|
||||
private ComposeAutocompleteSpan currentAutocompleteSpan;
|
||||
private FrameLayout mainEditTextWrap;
|
||||
private ComposeLanguageAlertViewController.SelectedOption postLang;
|
||||
|
||||
private ComposeAutocompleteViewController autocompleteViewController;
|
||||
private ComposePollViewController pollViewController=new ComposePollViewController(this);
|
||||
@@ -190,9 +192,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
else
|
||||
charLimit=500;
|
||||
|
||||
if(editingStatus==null)
|
||||
loadDefaultStatusVisibility(savedInstanceState);
|
||||
setTitle(editingStatus==null ? R.string.new_post : R.string.edit_post);
|
||||
if(savedInstanceState!=null)
|
||||
postLang=Parcels.unwrap(savedInstanceState.getParcelable("postLang"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -251,12 +253,14 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
emojiBtn=view.findViewById(R.id.btn_emoji);
|
||||
spoilerBtn=view.findViewById(R.id.btn_spoiler);
|
||||
visibilityBtn=view.findViewById(R.id.btn_visibility);
|
||||
languageBtn=view.findViewById(R.id.btn_language);
|
||||
replyText=view.findViewById(R.id.reply_text);
|
||||
|
||||
mediaBtn.setOnClickListener(v->openFilePicker());
|
||||
pollBtn.setOnClickListener(v->togglePoll());
|
||||
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
|
||||
spoilerBtn.setOnClickListener(v->toggleSpoiler());
|
||||
languageBtn.setOnClickListener(v->showLanguageAlert());
|
||||
visibilityBtn.setOnClickListener(this::onVisibilityClick);
|
||||
Drawable arrow=getResources().getDrawable(R.drawable.ic_baseline_arrow_drop_down_18, getActivity().getTheme()).mutate();
|
||||
arrow.setTint(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnSurface));
|
||||
@@ -343,6 +347,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
mediaViewController.onSaveInstanceState(outState);
|
||||
outState.putBoolean("hasSpoiler", hasSpoiler);
|
||||
outState.putSerializable("visibility", statusVisibility);
|
||||
outState.putParcelable("postLang", Parcels.wrap(postLang));
|
||||
if(currentAutocompleteSpan!=null){
|
||||
Editable e=mainEditText.getText();
|
||||
outState.putInt("autocompleteStart", e.getSpanStart(currentAutocompleteSpan));
|
||||
@@ -358,6 +363,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if(editingStatus==null)
|
||||
loadDefaultStatusVisibility(savedInstanceState);
|
||||
contentView.setSizeListener(emojiKeyboard::onContentViewSizeChanged);
|
||||
InputMethodManager imm=getActivity().getSystemService(InputMethodManager.class);
|
||||
mainEditText.requestFocus();
|
||||
@@ -650,6 +657,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
if(hasSpoiler && spoilerEdit.length()>0){
|
||||
req.spoilerText=spoilerEdit.getText().toString();
|
||||
}
|
||||
if(postLang!=null){
|
||||
req.language=postLang.locale.toLanguageTag();
|
||||
}
|
||||
if(uuid==null)
|
||||
uuid=UUID.randomUUID().toString();
|
||||
|
||||
@@ -867,45 +877,43 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
menu.show();
|
||||
}
|
||||
|
||||
private void loadDefaultStatusVisibility(Bundle savedInstanceState) {
|
||||
private void loadDefaultStatusVisibility(Bundle savedInstanceState){
|
||||
if(getArguments().containsKey("replyTo")){
|
||||
replyTo=Parcels.unwrap(getArguments().getParcelable("replyTo"));
|
||||
statusVisibility = replyTo.visibility;
|
||||
statusVisibility=replyTo.visibility;
|
||||
}
|
||||
|
||||
// A saved privacy setting from a previous compose session wins over the reply visibility
|
||||
if(savedInstanceState !=null){
|
||||
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
|
||||
if(savedInstanceState!=null){
|
||||
statusVisibility=(StatusPrivacy) savedInstanceState.getSerializable("visibility");
|
||||
}
|
||||
|
||||
new GetPreferences()
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Preferences result){
|
||||
// Only override the reply visibility if our preference is more private
|
||||
if (result.postingDefaultVisibility.isLessVisibleThan(statusVisibility)) {
|
||||
// Map unlisted from the API onto public, because we don't have unlisted in the UI
|
||||
statusVisibility = switch (result.postingDefaultVisibility) {
|
||||
case PUBLIC, UNLISTED -> StatusPrivacy.PUBLIC;
|
||||
case PRIVATE -> StatusPrivacy.PRIVATE;
|
||||
case DIRECT -> StatusPrivacy.DIRECT;
|
||||
};
|
||||
}
|
||||
Preferences prevPrefs=AccountSessionManager.getInstance().getAccount(accountID).preferences;
|
||||
if(prevPrefs!=null){
|
||||
applyPreferencesForPostVisibility(prevPrefs, savedInstanceState);
|
||||
}
|
||||
AccountSessionManager.getInstance().getAccount(accountID).reloadPreferences(prefs->{
|
||||
applyPreferencesForPostVisibility(prefs, savedInstanceState);
|
||||
});
|
||||
}
|
||||
|
||||
// A saved privacy setting from a previous compose session wins over all
|
||||
if(savedInstanceState !=null){
|
||||
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
|
||||
}
|
||||
private void applyPreferencesForPostVisibility(Preferences prefs, Bundle savedInstanceState){
|
||||
// Only override the reply visibility if our preference is more private
|
||||
if(prefs.postingDefaultVisibility.isLessVisibleThan(statusVisibility)){
|
||||
// Map unlisted from the API onto public, because we don't have unlisted in the UI
|
||||
statusVisibility=switch(prefs.postingDefaultVisibility){
|
||||
case PUBLIC, UNLISTED -> StatusPrivacy.PUBLIC;
|
||||
case PRIVATE -> StatusPrivacy.PRIVATE;
|
||||
case DIRECT -> StatusPrivacy.DIRECT;
|
||||
};
|
||||
}
|
||||
|
||||
updateVisibilityIcon ();
|
||||
}
|
||||
// A saved privacy setting from a previous compose session wins over all
|
||||
if(savedInstanceState!=null){
|
||||
statusVisibility=(StatusPrivacy) savedInstanceState.getSerializable("visibility");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
Log.w(TAG, "Unable to get user preferences to set default post privacy");
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
updateVisibilityIcon();
|
||||
}
|
||||
|
||||
private void updateVisibilityIcon(){
|
||||
@@ -1037,4 +1045,19 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
public void addFakeMediaAttachment(Uri uri, String description){
|
||||
mediaViewController.addFakeMediaAttachment(uri, description);
|
||||
}
|
||||
|
||||
private void showLanguageAlert(){
|
||||
Preferences prefs=AccountSessionManager.getInstance().getAccount(accountID).preferences;
|
||||
ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), prefs!=null ? prefs.postingDefaultLanguage : null, postLang, mainEditText.getText().toString());
|
||||
new M3AlertDialogBuilder(getActivity())
|
||||
.setTitle(R.string.language)
|
||||
.setView(vc.getView())
|
||||
.setPositiveButton(R.string.ok, (dialog, which)->setPostLanguage(vc.getSelectedOption()))
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void setPostLanguage(ComposeLanguageAlertViewController.SelectedOption language){
|
||||
postLang=language;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
package org.joinmastodon.android.ui.viewcontrollers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.textclassifier.TextClassificationManager;
|
||||
import android.view.textclassifier.TextLanguage;
|
||||
import android.widget.Checkable;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.CheckableLinearLayout;
|
||||
import org.parceler.Parcel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class ComposeLanguageAlertViewController{
|
||||
private Context context;
|
||||
private UsableRecyclerView list;
|
||||
private List<LocaleInfo> allLocales;
|
||||
private List<SpecialLocaleInfo> specialLocales=new ArrayList<>();
|
||||
private int selectedIndex=0;
|
||||
private Locale selectedLocale;
|
||||
|
||||
public ComposeLanguageAlertViewController(Context context, String preferred, SelectedOption previouslySelected, String postText){
|
||||
this.context=context;
|
||||
|
||||
allLocales=Arrays.stream(Locale.getAvailableLocales())
|
||||
.map(Locale::getLanguage)
|
||||
.distinct()
|
||||
.map(code->{
|
||||
Locale l=Locale.forLanguageTag(code);
|
||||
String name=l.getDisplayLanguage(Locale.getDefault());
|
||||
return new LocaleInfo(l, capitalizeLanguageName(name));
|
||||
})
|
||||
.sorted(Comparator.comparing(a->a.displayName))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if(!TextUtils.isEmpty(preferred)){
|
||||
Locale l=Locale.forLanguageTag(preferred);
|
||||
SpecialLocaleInfo pref=new SpecialLocaleInfo();
|
||||
pref.locale=l;
|
||||
pref.displayName=capitalizeLanguageName(l.getDisplayLanguage(Locale.getDefault()));
|
||||
pref.title=context.getString(R.string.language_default);
|
||||
specialLocales.add(pref);
|
||||
}
|
||||
|
||||
Locale def=Locale.forLanguageTag(Locale.getDefault().getLanguage());
|
||||
if(!def.getLanguage().equals(preferred)){
|
||||
SpecialLocaleInfo d=new SpecialLocaleInfo();
|
||||
d.locale=def;
|
||||
d.displayName=capitalizeLanguageName(def.getDisplayName());
|
||||
d.title=context.getString(R.string.language_system);
|
||||
specialLocales.add(d);
|
||||
}
|
||||
|
||||
if(Build.VERSION.SDK_INT>=29 && !TextUtils.isEmpty(postText)){
|
||||
SpecialLocaleInfo detected=new SpecialLocaleInfo();
|
||||
detected.displayName=context.getString(R.string.language_detecting);
|
||||
detected.enabled=false;
|
||||
specialLocales.add(detected);
|
||||
detectLanguage(detected, postText);
|
||||
}
|
||||
|
||||
if(previouslySelected!=null){
|
||||
if((previouslySelected.index<specialLocales.size() && Objects.equals(previouslySelected.locale, specialLocales.get(previouslySelected.index).locale)) ||
|
||||
(previouslySelected.index<specialLocales.size()+allLocales.size() && Objects.equals(previouslySelected.locale, allLocales.get(previouslySelected.index-specialLocales.size()).locale))){
|
||||
selectedIndex=previouslySelected.index;
|
||||
selectedLocale=previouslySelected.locale;
|
||||
}
|
||||
}else{
|
||||
selectedLocale=specialLocales.get(0).locale;
|
||||
}
|
||||
|
||||
list=new UsableRecyclerView(context);
|
||||
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
|
||||
adapter.addAdapter(new SpecialLanguagesAdapter());
|
||||
adapter.addAdapter(new AllLocalesAdapter());
|
||||
list.setAdapter(adapter);
|
||||
list.setLayoutManager(new LinearLayoutManager(context));
|
||||
|
||||
list.addItemDecoration(new DividerItemDecoration(context, R.attr.colorM3OutlineVariant, 1, 16, 16, vh->vh.getAbsoluteAdapterPosition()==specialLocales.size()-1));
|
||||
list.addItemDecoration(new RecyclerView.ItemDecoration(){
|
||||
private Paint paint=new Paint();
|
||||
|
||||
{
|
||||
paint.setColor(UiUtils.getThemeColor(context, R.attr.colorM3OutlineVariant));
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(V.dp(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
||||
if(parent.canScrollVertically(1)){
|
||||
float y=parent.getHeight()-paint.getStrokeWidth()/2f;
|
||||
c.drawLine(0, y, parent.getWidth(), y, paint);
|
||||
}
|
||||
if(parent.canScrollVertically(-1)){
|
||||
float y=paint.getStrokeWidth()/2f;
|
||||
c.drawLine(0, y, parent.getWidth(), y, paint);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(previouslySelected!=null && selectedIndex>0){
|
||||
list.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
|
||||
@Override
|
||||
public boolean onPreDraw(){
|
||||
list.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
|
||||
if(list.findViewHolderForAdapterPosition(selectedIndex)==null)
|
||||
list.scrollToPosition(selectedIndex);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.Q)
|
||||
private void detectLanguage(SpecialLocaleInfo info, String text){
|
||||
MastodonAPIController.runInBackground(()->{
|
||||
TextLanguage lang=context.getSystemService(TextClassificationManager.class).getTextClassifier().detectLanguage(new TextLanguage.Request.Builder(text).build());
|
||||
list.post(()->{
|
||||
SpecialLanguageViewHolder holder=(SpecialLanguageViewHolder) list.findViewHolderForAdapterPosition(specialLocales.indexOf(info));
|
||||
if(lang.getLocaleHypothesisCount()==0 || lang.getConfidenceScore(lang.getLocale(0))<0.75f){
|
||||
info.displayName=context.getString(R.string.language_cant_detect);
|
||||
}else{
|
||||
Locale locale=lang.getLocale(0).toLocale();
|
||||
info.locale=locale;
|
||||
info.displayName=capitalizeLanguageName(locale.getDisplayName(Locale.getDefault()));
|
||||
info.title=context.getString(R.string.language_detected);
|
||||
info.enabled=true;
|
||||
if(holder!=null)
|
||||
UiUtils.beginLayoutTransition(holder.view);
|
||||
}
|
||||
if(holder!=null)
|
||||
holder.rebind();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public View getView(){
|
||||
return list;
|
||||
}
|
||||
|
||||
// Needed because in some languages (e.g. Slavic ones) these names returned by the system start with a lowercase letter
|
||||
private String capitalizeLanguageName(String name){
|
||||
return name.substring(0, 1).toUpperCase(Locale.getDefault())+name.substring(1);
|
||||
}
|
||||
|
||||
public SelectedOption getSelectedOption(){
|
||||
return new SelectedOption(selectedIndex, selectedLocale);
|
||||
}
|
||||
|
||||
private void selectItem(int index){
|
||||
if(index==selectedIndex)
|
||||
return;
|
||||
if(selectedIndex!=-1){
|
||||
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(selectedIndex);
|
||||
if(holder!=null && holder.itemView instanceof Checkable checkable)
|
||||
checkable.setChecked(false);
|
||||
}
|
||||
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(index);
|
||||
if(holder!=null && holder.itemView instanceof Checkable checkable)
|
||||
checkable.setChecked(true);
|
||||
selectedIndex=index;
|
||||
}
|
||||
|
||||
private class AllLocalesAdapter extends RecyclerView.Adapter<SimpleLanguageViewHolder>{
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SimpleLanguageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
return new SimpleLanguageViewHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull SimpleLanguageViewHolder holder, int position){
|
||||
holder.bind(allLocales.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(){
|
||||
return allLocales.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private class SimpleLanguageViewHolder extends BindableViewHolder<LocaleInfo> implements UsableRecyclerView.Clickable{
|
||||
private final CheckedTextView text;
|
||||
|
||||
public SimpleLanguageViewHolder(){
|
||||
super(context, R.layout.item_alert_single_choice_1line, list);
|
||||
text=(CheckedTextView) itemView;
|
||||
text.setCompoundDrawablesRelativeWithIntrinsicBounds(new RadioButton(context).getButtonDrawable(), null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(LocaleInfo item){
|
||||
text.setText(item.displayName);
|
||||
text.setChecked(selectedIndex==getAbsoluteAdapterPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(){
|
||||
selectItem(getAbsoluteAdapterPosition());
|
||||
selectedLocale=item.locale;
|
||||
}
|
||||
}
|
||||
|
||||
private class SpecialLanguagesAdapter extends RecyclerView.Adapter<SpecialLanguageViewHolder>{
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SpecialLanguageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
return new SpecialLanguageViewHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull SpecialLanguageViewHolder holder, int position){
|
||||
holder.bind(specialLocales.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(){
|
||||
return specialLocales.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position){
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
private class SpecialLanguageViewHolder extends BindableViewHolder<SpecialLocaleInfo> implements UsableRecyclerView.DisableableClickable{
|
||||
private final TextView text, title;
|
||||
private final CheckableLinearLayout view;
|
||||
|
||||
public SpecialLanguageViewHolder(){
|
||||
super(context, R.layout.item_alert_single_choice_2lines, list);
|
||||
text=findViewById(R.id.text);
|
||||
title=findViewById(R.id.title);
|
||||
view=((CheckableLinearLayout) itemView);
|
||||
findViewById(R.id.radiobutton).setBackground(new RadioButton(context).getButtonDrawable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(SpecialLocaleInfo item){
|
||||
text.setText(item.displayName);
|
||||
if(!TextUtils.isEmpty(item.title)){
|
||||
title.setVisibility(View.VISIBLE);
|
||||
title.setText(item.title);
|
||||
}else{
|
||||
title.setVisibility(View.GONE);
|
||||
}
|
||||
text.setEnabled(item.enabled);
|
||||
view.setEnabled(item.enabled);
|
||||
view.setChecked(selectedIndex==getAbsoluteAdapterPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(){
|
||||
selectItem(getAbsoluteAdapterPosition());
|
||||
selectedLocale=item.locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(){
|
||||
return item.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LocaleInfo{
|
||||
public final Locale locale;
|
||||
public final String displayName;
|
||||
|
||||
private LocaleInfo(Locale locale, String displayName){
|
||||
this.locale=locale;
|
||||
this.displayName=displayName;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SpecialLocaleInfo{
|
||||
public Locale locale;
|
||||
public String displayName;
|
||||
public String title;
|
||||
public boolean enabled=true;
|
||||
}
|
||||
|
||||
@Parcel
|
||||
public static class SelectedOption{
|
||||
public int index;
|
||||
public Locale locale;
|
||||
|
||||
public SelectedOption(){}
|
||||
|
||||
public SelectedOption(int index, Locale locale){
|
||||
this.index=index;
|
||||
this.locale=locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user