Onboarding: replace fields with discoverability toggle (AND-100)

This commit is contained in:
Grishka 2023-11-16 12:15:17 +03:00
parent 5e99df137a
commit e5506d952c
9 changed files with 82 additions and 126 deletions

View File

@ -22,6 +22,7 @@ public class UpdateAccountCredentials extends MastodonAPIRequest<Account>{
private Uri avatar, cover; private Uri avatar, cover;
private File avatarFile, coverFile; private File avatarFile, coverFile;
private List<AccountField> fields; private List<AccountField> fields;
private Boolean discoverable, indexable;
public UpdateAccountCredentials(String displayName, String bio, Uri avatar, Uri cover, List<AccountField> fields){ public UpdateAccountCredentials(String displayName, String bio, Uri avatar, Uri cover, List<AccountField> fields){
super(HttpMethod.PATCH, "/accounts/update_credentials", Account.class); super(HttpMethod.PATCH, "/accounts/update_credentials", Account.class);
@ -41,6 +42,12 @@ public class UpdateAccountCredentials extends MastodonAPIRequest<Account>{
this.fields=fields; this.fields=fields;
} }
public UpdateAccountCredentials setDiscoverableIndexable(boolean discoverable, boolean indexable){
this.discoverable=discoverable;
this.indexable=indexable;
return this;
}
@Override @Override
public RequestBody getRequestBody() throws IOException{ public RequestBody getRequestBody() throws IOException{
MultipartBody.Builder bldr=new MultipartBody.Builder() MultipartBody.Builder bldr=new MultipartBody.Builder()
@ -58,15 +65,21 @@ public class UpdateAccountCredentials extends MastodonAPIRequest<Account>{
}else if(coverFile!=null){ }else if(coverFile!=null){
bldr.addFormDataPart("header", coverFile.getName(), new ResizedImageRequestBody(Uri.fromFile(coverFile), 1500*500, null)); bldr.addFormDataPart("header", coverFile.getName(), new ResizedImageRequestBody(Uri.fromFile(coverFile), 1500*500, null));
} }
if(fields.isEmpty()){ if(fields!=null){
bldr.addFormDataPart("fields_attributes[0][name]", "").addFormDataPart("fields_attributes[0][value]", ""); if(fields.isEmpty()){
}else{ bldr.addFormDataPart("fields_attributes[0][name]", "").addFormDataPart("fields_attributes[0][value]", "");
int i=0; }else{
for(AccountField field:fields){ int i=0;
bldr.addFormDataPart("fields_attributes["+i+"][name]", field.name).addFormDataPart("fields_attributes["+i+"][value]", field.value); for(AccountField field:fields){
i++; bldr.addFormDataPart("fields_attributes["+i+"][name]", field.name).addFormDataPart("fields_attributes["+i+"][value]", field.value);
i++;
}
} }
} }
if(discoverable!=null)
bldr.addFormDataPart("discoverable", discoverable.toString());
if(indexable!=null)
bldr.addFormDataPart("indexable", indexable.toString());
return bldr.build(); return bldr.build();
} }

View File

@ -12,6 +12,7 @@ import android.view.WindowInsets;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView; import android.widget.ScrollView;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
@ -20,12 +21,17 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.HomeFragment; import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AccountField; import org.joinmastodon.android.model.AccountField;
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.OutlineProviders; import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.adapters.GenericListItemsAdapter;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.viewholders.ListItemViewHolder;
import org.joinmastodon.android.ui.views.ReorderableLinearLayout; import org.joinmastodon.android.ui.views.ReorderableLinearLayout;
import org.joinmastodon.android.utils.ElevationOnScrollListener; import org.joinmastodon.android.utils.ElevationOnScrollListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.Callback;
@ -36,7 +42,7 @@ import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.FragmentRootLinearLayout; import me.grishka.appkit.views.FragmentRootLinearLayout;
public class OnboardingProfileSetupFragment extends ToolbarFragment implements ReorderableLinearLayout.OnDragListener{ public class OnboardingProfileSetupFragment extends ToolbarFragment{
private Button btn; private Button btn;
private View buttonBar; private View buttonBar;
private String accountID; private String accountID;
@ -44,9 +50,9 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
private ScrollView scroller; private ScrollView scroller;
private EditText nameEdit, bioEdit; private EditText nameEdit, bioEdit;
private ImageView avaImage, coverImage; private ImageView avaImage, coverImage;
private Button addRow;
private ReorderableLinearLayout profileFieldsLayout;
private Uri avatarUri, coverUri; private Uri avatarUri, coverUri;
private LinearLayout scrollContent;
private CheckableListItem<Void> discoverableItem;
private static final int AVATAR_RESULT=348; private static final int AVATAR_RESULT=348;
private static final int COVER_RESULT=183; private static final int COVER_RESULT=183;
@ -74,8 +80,6 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
bioEdit=view.findViewById(R.id.bio); bioEdit=view.findViewById(R.id.bio);
avaImage=view.findViewById(R.id.avatar); avaImage=view.findViewById(R.id.avatar);
coverImage=view.findViewById(R.id.header); coverImage=view.findViewById(R.id.header);
addRow=view.findViewById(R.id.add_row);
profileFieldsLayout=view.findViewById(R.id.profile_fields);
btn=view.findViewById(R.id.btn_next); btn=view.findViewById(R.id.btn_next);
btn.setOnClickListener(v->onButtonClick()); btn.setOnClickListener(v->onButtonClick());
@ -87,31 +91,20 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
Account account=AccountSessionManager.getInstance().getAccount(accountID).self; Account account=AccountSessionManager.getInstance().getAccount(accountID).self;
if(savedInstanceState==null){ if(savedInstanceState==null){
nameEdit.setText(account.displayName); nameEdit.setText(account.displayName);
makeFieldsRow();
}else{
ArrayList<String> fieldTitles=savedInstanceState.getStringArrayList("fieldTitles");
ArrayList<String> fieldValues=savedInstanceState.getStringArrayList("fieldValues");
for(int i=0;i<fieldTitles.size();i++){
View row=makeFieldsRow();
EditText title=row.findViewById(R.id.title);
EditText content=row.findViewById(R.id.content);
title.setText(fieldTitles.get(i));
content.setText(fieldValues.get(i));
}
if(fieldTitles.size()==4)
addRow.setVisibility(View.GONE);
} }
addRow.setOnClickListener(v->{
makeFieldsRow();
if(profileFieldsLayout.getChildCount()==4){
addRow.setVisibility(View.GONE);
}
});
profileFieldsLayout.setDragListener(this);
avaImage.setOnClickListener(v->startActivityForResult(UiUtils.getMediaPickerIntent(new String[]{"image/*"}, 1), AVATAR_RESULT)); avaImage.setOnClickListener(v->startActivityForResult(UiUtils.getMediaPickerIntent(new String[]{"image/*"}, 1), AVATAR_RESULT));
coverImage.setOnClickListener(v->startActivityForResult(UiUtils.getMediaPickerIntent(new String[]{"image/*"}, 1), COVER_RESULT)); coverImage.setOnClickListener(v->startActivityForResult(UiUtils.getMediaPickerIntent(new String[]{"image/*"}, 1), COVER_RESULT));
scrollContent=view.findViewById(R.id.scrollable_content);
discoverableItem=new CheckableListItem<>(R.string.make_profile_discoverable, 0, CheckableListItem.Style.SWITCH_SEPARATED, true, R.drawable.ic_campaign_24px, item->showDiscoverabilityAlert());
GenericListItemsAdapter<Void> fakeAdapter=new GenericListItemsAdapter<>(List.of(discoverableItem));
ListItemViewHolder<?> holder=fakeAdapter.onCreateViewHolder(scrollContent, fakeAdapter.getItemViewType(0));
fakeAdapter.bindViewHolder(holder, 0);
holder.itemView.setBackground(UiUtils.getThemeDrawable(getActivity(), android.R.attr.selectableItemBackground));
holder.itemView.setOnClickListener(v->holder.onClick());
scrollContent.addView(holder.itemView);
return view; return view;
} }
@ -130,17 +123,8 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
} }
protected void onButtonClick(){ protected void onButtonClick(){
ArrayList<AccountField> fields=new ArrayList<>(); new UpdateAccountCredentials(nameEdit.getText().toString(), bioEdit.getText().toString(), avatarUri, coverUri, null)
for(int i=0;i<profileFieldsLayout.getChildCount();i++){ .setDiscoverableIndexable(discoverableItem.checked, discoverableItem.checked)
View row=profileFieldsLayout.getChildAt(i);
EditText title=row.findViewById(R.id.title);
EditText content=row.findViewById(R.id.content);
AccountField fld=new AccountField();
fld.name=title.getText().toString();
fld.value=content.getText().toString();
fields.add(fld);
}
new UpdateAccountCredentials(nameEdit.getText().toString(), bioEdit.getText().toString(), avatarUri, coverUri, fields)
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override
public void onSuccess(Account result){ public void onSuccess(Account result){
@ -164,39 +148,6 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets)); super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
} }
private View makeFieldsRow(){
View view=LayoutInflater.from(getActivity()).inflate(R.layout.onboarding_profile_field, profileFieldsLayout, false);
profileFieldsLayout.addView(view);
view.findViewById(R.id.dragger_thingy).setOnLongClickListener(v->{
profileFieldsLayout.startDragging(view);
return true;
});
view.findViewById(R.id.delete).setOnClickListener(v->{
profileFieldsLayout.removeView(view);
if(addRow.getVisibility()==View.GONE)
addRow.setVisibility(View.VISIBLE);
});
return view;
}
@Override
public void onSwapItems(int oldIndex, int newIndex){}
@Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
ArrayList<String> fieldTitles=new ArrayList<>(), fieldValues=new ArrayList<>();
for(int i=0;i<profileFieldsLayout.getChildCount();i++){
View row=profileFieldsLayout.getChildAt(i);
EditText title=row.findViewById(R.id.title);
EditText content=row.findViewById(R.id.content);
fieldTitles.add(title.getText().toString());
fieldValues.add(content.getText().toString());
}
outState.putStringArrayList("fieldTitles", fieldTitles);
outState.putStringArrayList("fieldValues", fieldValues);
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data){ public void onActivityResult(int requestCode, int resultCode, Intent data){
if(resultCode!=Activity.RESULT_OK) if(resultCode!=Activity.RESULT_OK)
@ -216,4 +167,12 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
img.setForeground(null); img.setForeground(null);
ViewImageLoader.load(img, null, new UrlImageLoaderRequest(uri, size, size)); ViewImageLoader.load(img, null, new UrlImageLoaderRequest(uri, size, size));
} }
private void showDiscoverabilityAlert(){
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.discoverability)
.setMessage(R.string.discoverability_help)
.setPositiveButton(R.string.ok, null)
.show();
}
} }

View File

@ -55,6 +55,7 @@ public class CheckableListItem<T> extends ListItem<T>{
case CHECKBOX -> R.id.list_item_checkbox; case CHECKBOX -> R.id.list_item_checkbox;
case RADIO -> R.id.list_item_radio; case RADIO -> R.id.list_item_radio;
case SWITCH -> R.id.list_item_switch; case SWITCH -> R.id.list_item_switch;
case SWITCH_SEPARATED -> R.id.list_item_switch_separated;
}; };
} }
@ -69,6 +70,7 @@ public class CheckableListItem<T> extends ListItem<T>{
public enum Style{ public enum Style{
CHECKBOX, CHECKBOX,
RADIO, RADIO,
SWITCH SWITCH,
SWITCH_SEPARATED
} }
} }

View File

@ -39,8 +39,8 @@ public class GenericListItemsAdapter<T> extends UsableRecyclerView.Adapter<ListI
public ListItemViewHolder<?> onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ public ListItemViewHolder<?> onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
if(viewType==R.id.list_item_simple || viewType==R.id.list_item_simple_tinted) if(viewType==R.id.list_item_simple || viewType==R.id.list_item_simple_tinted)
return new SimpleListItemViewHolder(parent.getContext(), parent); return new SimpleListItemViewHolder(parent.getContext(), parent);
if(viewType==R.id.list_item_switch) if(viewType==R.id.list_item_switch || viewType==R.id.list_item_switch_separated)
return new SwitchListItemViewHolder(parent.getContext(), parent); return new SwitchListItemViewHolder(parent.getContext(), parent, viewType==R.id.list_item_switch_separated);
if(viewType==R.id.list_item_checkbox) if(viewType==R.id.list_item_checkbox)
return new CheckboxOrRadioListItemViewHolder(parent.getContext(), parent, false); return new CheckboxOrRadioListItemViewHolder(parent.getContext(), parent, false);
if(viewType==R.id.list_item_radio) if(viewType==R.id.list_item_radio)

View File

@ -2,10 +2,13 @@ package org.joinmastodon.android.ui.viewholders;
import android.content.Context; import android.content.Context;
import android.view.Gravity; import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.viewmodel.CheckableListItem; import org.joinmastodon.android.model.viewmodel.CheckableListItem;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.M3Switch; import org.joinmastodon.android.ui.views.M3Switch;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
@ -14,8 +17,17 @@ public class SwitchListItemViewHolder extends CheckableListItemViewHolder{
private final M3Switch sw; private final M3Switch sw;
private boolean ignoreListener; private boolean ignoreListener;
public SwitchListItemViewHolder(Context context, ViewGroup parent){ public SwitchListItemViewHolder(Context context, ViewGroup parent, boolean separated){
super(context, parent); super(context, parent);
if(separated){
View separator=new View(context);
separator.setBackgroundColor(UiUtils.getThemeColor(context, R.attr.colorM3OutlineVariant));
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(V.dp(1), V.dp(32));
lp.gravity=Gravity.TOP;
lp.setMarginStart(V.dp(16));
lp.setMarginEnd(V.dp(-1));
checkableLayout.addView(separator, lp);
}
sw=new M3Switch(context); sw=new M3Switch(context);
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(V.dp(52), V.dp(32)); LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(V.dp(52), V.dp(32));
lp.gravity=Gravity.TOP; lp.gravity=Gravity.TOP;

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18,13V11H22V13ZM19.2,20 L16,17.6 17.2,16 20.4,18.4ZM17.2,8 L16,6.4 19.2,4 20.4,5.6ZM5,19V15H4Q3.175,15 2.588,14.412Q2,13.825 2,13V11Q2,10.175 2.588,9.587Q3.175,9 4,9H8L13,6V18L8,15H7V19ZM14,15.35V8.65Q14.675,9.25 15.088,10.113Q15.5,10.975 15.5,12Q15.5,13.025 15.088,13.887Q14.675,14.75 14,15.35ZM4,11Q4,11 4,11Q4,11 4,11V13Q4,13 4,13Q4,13 4,13H8.55L11,14.45V9.55L8.55,11ZM7.5,12Q7.5,12 7.5,12Q7.5,12 7.5,12Q7.5,12 7.5,12Q7.5,12 7.5,12Z"/>
</vector>

View File

@ -11,6 +11,7 @@
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1"> android:layout_weight="1">
<LinearLayout <LinearLayout
android:id="@+id/scrollable_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingBottom="16dp" android:paddingBottom="16dp"
@ -34,6 +35,7 @@
android:foregroundGravity="center" android:foregroundGravity="center"
android:foregroundTint="?colorM3OnSecondaryContainer" android:foregroundTint="?colorM3OnSecondaryContainer"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:contentDescription="@string/profile_header"
android:background="?colorM3SecondaryContainer"/> android:background="?colorM3SecondaryContainer"/>
<FrameLayout <FrameLayout
@ -51,6 +53,7 @@
android:foregroundGravity="center" android:foregroundGravity="center"
android:foregroundTint="?colorM3OnSecondaryContainer" android:foregroundTint="?colorM3OnSecondaryContainer"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:contentDescription="@string/profile_picture"
android:background="?colorM3SecondaryContainer"/> android:background="?colorM3SecondaryContainer"/>
</FrameLayout> </FrameLayout>
@ -104,39 +107,6 @@
android:hint="@string/profile_bio"/> android:hint="@string/profile_bio"/>
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout> </org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
<org.joinmastodon.android.ui.views.ReorderableLinearLayout
android:id="@+id/profile_fields"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<Button
android:id="@+id/add_row"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="24dp"
android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurface"
android:drawableEnd="@drawable/ic_add_24px"
android:drawableTint="?colorM3OnSurface"
android:drawablePadding="16dp"
android:singleLine="true"
android:ellipsize="end"
android:background="?android:attr/selectableItemBackground"
android:stateListAnimator="@null"
android:text="@string/profile_add_row"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:textAppearance="@style/m3_body_small"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/profile_setup_explanation"/>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@ -23,6 +23,7 @@
<item name="list_item_switch" type="id"/> <item name="list_item_switch" type="id"/>
<item name="list_item_checkbox" type="id"/> <item name="list_item_checkbox" type="id"/>
<item name="list_item_radio" type="id"/> <item name="list_item_radio" type="id"/>
<item name="list_item_switch_separated" type="id"/>
<item name="list_item_account" type="id"/> <item name="list_item_account" type="id"/>
<item name="list_item_options" type="id"/> <item name="list_item_options" type="id"/>
<item name="list_item_avatar_pile" type="id"/> <item name="list_item_avatar_pile" type="id"/>

View File

@ -168,19 +168,7 @@
<string name="password">Password</string> <string name="password">Password</string>
<string name="confirm_password">Confirm password</string> <string name="confirm_password">Confirm password</string>
<string name="password_note">Include capital letters, special characters, and numbers to increase your password strength.</string> <string name="password_note">Include capital letters, special characters, and numbers to increase your password strength.</string>
<string name="category_academia">Academia</string>
<string name="category_activism">Activism</string>
<string name="category_all">All</string>
<string name="category_art">Art</string>
<string name="category_food">Food</string>
<string name="category_furry">Furry</string>
<string name="category_games">Games</string>
<string name="category_general">General</string> <string name="category_general">General</string>
<string name="category_journalism">Journalism</string>
<string name="category_lgbt">LGBT</string>
<string name="category_music">Music</string>
<string name="category_regional">Regional</string>
<string name="category_tech">Tech</string>
<string name="confirm_email_title">Check Your Inbox</string> <string name="confirm_email_title">Check Your Inbox</string>
<!-- %s is the email address --> <!-- %s is the email address -->
<string name="confirm_email_subtitle">Tap the link we sent you to verify %s. Well wait right here.</string> <string name="confirm_email_subtitle">Tap the link we sent you to verify %s. Well wait right here.</string>
@ -362,7 +350,6 @@
<string name="profile_add_row">Add row</string> <string name="profile_add_row">Add row</string>
<string name="profile_setup">Profile setup</string> <string name="profile_setup">Profile setup</string>
<string name="profile_setup_subtitle">You can always complete this later in the Profile tab.</string> <string name="profile_setup_subtitle">You can always complete this later in the Profile tab.</string>
<string name="profile_setup_explanation">You can add up to four profile fields for anything you want. Location, links, pronouns — the sky is the limit.</string>
<string name="popular_on_mastodon">Popular on Mastodon</string> <string name="popular_on_mastodon">Popular on Mastodon</string>
<string name="follow_all">Follow all</string> <string name="follow_all">Follow all</string>
<string name="server_rules_disagree">Disagree</string> <string name="server_rules_disagree">Disagree</string>
@ -673,4 +660,7 @@
<string name="non_mutual_text2">A positive tone is always appreciated.</string> <string name="non_mutual_text2">A positive tone is always appreciated.</string>
<string name="non_mutual_title3">Be open</string> <string name="non_mutual_title3">Be open</string>
<string name="non_mutual_text3">Everyones conversation style is unique. Be ready to adapt.</string> <string name="non_mutual_text3">Everyones conversation style is unique. Be ready to adapt.</string>
<string name="make_profile_discoverable">Make my profile discoverable</string>
<string name="discoverability">Discoverability</string>
<string name="discoverability_help">When you opt into discoverability on Mastodon, your posts may appear in search results and trending.\n\nYour profile may be suggested to people with similar interests to you.\n\nOpting out does not hide your profile if someone searches for you by name.</string>
</resources> </resources>