Compose: visibility

This commit is contained in:
Grishka 2022-03-17 00:12:58 +03:00
parent 6ecd1cfe68
commit 098128bcd4
10 changed files with 156 additions and 4 deletions

View File

@ -6,9 +6,12 @@ import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ClipData;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
import android.icu.text.BreakIterator;
import android.net.Uri;
@ -16,8 +19,10 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -60,11 +65,13 @@ import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.EmojiCategory;
import org.joinmastodon.android.model.Mention;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.CustomEmojiPopupKeyboard;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.PopupKeyboard;
import org.joinmastodon.android.ui.drawables.SpoilerStripesDrawable;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.text.SpacerSpan;
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.ComposeMediaLayout;
@ -73,6 +80,8 @@ import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
import org.parceler.Parcel;
import org.parceler.Parcels;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@ -153,6 +162,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
private ImageView sendError;
private View sendingOverlay;
private WindowManager wm;
private StatusPrivacy statusVisibility=StatusPrivacy.PUBLIC;
@Override
public void onCreate(Bundle savedInstanceState){
@ -167,8 +177,13 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
self=session.self;
instanceDomain=session.domain;
customEmojis=AccountSessionManager.getInstance().getCustomEmojis(instanceDomain);
if(getArguments().containsKey("replyTo"))
if(getArguments().containsKey("replyTo")){
replyTo=Parcels.unwrap(getArguments().getParcelable("replyTo"));
statusVisibility=replyTo.visibility;
}
if(savedInstanceState!=null){
statusVisibility=(StatusPrivacy) savedInstanceState.getSerializable("visibility");
}
}
@Override
@ -214,6 +229,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
pollBtn.setOnClickListener(v->togglePoll());
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
spoilerBtn.setOnClickListener(v->toggleSpoiler());
visibilityBtn.setOnClickListener(this::onVisibilityClick);
emojiKeyboard.setOnIconChangedListener(new PopupKeyboard.OnIconChangeListener(){
@Override
public void onIconChanged(int icon){
@ -254,9 +270,10 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
}
spoilerEdit=view.findViewById(R.id.content_warning);
LayerDrawable spoilerBg=(LayerDrawable) spoilerEdit.getBackground();
LayerDrawable spoilerBg=(LayerDrawable) spoilerEdit.getBackground().mutate();
spoilerBg.setDrawableByLayerId(R.id.left_drawable, new SpoilerStripesDrawable());
spoilerBg.setDrawableByLayerId(R.id.right_drawable, new SpoilerStripesDrawable());
spoilerEdit.setBackground(spoilerBg);
if((savedInstanceState!=null && savedInstanceState.getBoolean("hasSpoiler", false)) || hasSpoiler){
spoilerEdit.setVisibility(View.VISIBLE);
spoilerBtn.setSelected(true);
@ -276,6 +293,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
attachmentsView.addView(createMediaAttachmentView(att));
}
}
updateVisibilityIcon();
return view;
}
@ -299,6 +317,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
}
outState.putParcelableArrayList("attachments", serializedAttachments);
}
outState.putSerializable("visibility", statusVisibility);
}
}
@ -454,12 +473,12 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
String text=mainEditText.getText().toString();
CreateStatus.Request req=new CreateStatus.Request();
req.status=text;
req.visibility=statusVisibility;
if(!attachments.isEmpty()){
req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList());
}
if(replyTo!=null){
req.inReplyToId=replyTo.id;
req.visibility=replyTo.visibility; // TODO
}
if(!pollOptions.isEmpty()){
req.poll=new CreateStatus.Request.Poll();
@ -850,6 +869,70 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
return allAttachments.size();
}
private void onVisibilityClick(View v){
PopupMenu menu=new PopupMenu(getActivity(), v);
menu.inflate(R.menu.compose_visibility);
Menu m=menu.getMenu();
if(Build.VERSION.SDK_INT>=29){
menu.setForceShowIcon(true);
}else{
try{
Method setOptionalIconsVisible=m.getClass().getDeclaredMethod("setOptionalIconsVisible", boolean.class);
setOptionalIconsVisible.setAccessible(true);
setOptionalIconsVisible.invoke(m, true);
}catch(Exception ignore){}
}
ColorStateList iconTint=ColorStateList.valueOf(UiUtils.getThemeColor(getActivity(), android.R.attr.textColorSecondary));
for(int i=0;i<m.size();i++){
MenuItem item=m.getItem(i);
Drawable icon=item.getIcon().mutate();
if(Build.VERSION.SDK_INT>=26){
item.setIconTintList(iconTint);
}else{
icon.setTintList(iconTint);
}
icon=new InsetDrawable(icon, V.dp(8), 0, 0, 0);
item.setIcon(icon);
SpannableStringBuilder ssb=new SpannableStringBuilder(item.getTitle());
ssb.insert(0, " ");
ssb.setSpan(new SpacerSpan(V.dp(24), 1), 0, 1, 0);
ssb.append(" ", new SpacerSpan(V.dp(8), 1), 0);
item.setTitle(ssb);
}
m.setGroupCheckable(0, true, true);
m.findItem(switch(statusVisibility){
case PUBLIC, UNLISTED -> R.id.vis_public;
case PRIVATE -> R.id.vis_followers;
case DIRECT -> R.id.vis_private;
}).setChecked(true);
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){
@Override
public boolean onMenuItemClick(MenuItem item){
int id=item.getItemId();
if(id==R.id.vis_public){
statusVisibility=StatusPrivacy.PUBLIC;
}else if(id==R.id.vis_followers){
statusVisibility=StatusPrivacy.PRIVATE;
}else if(id==R.id.vis_private){
statusVisibility=StatusPrivacy.DIRECT;
}
item.setChecked(true);
updateVisibilityIcon();
return true;
}
});
menu.show();
}
private void updateVisibilityIcon(){
visibilityBtn.setImageResource(switch(statusVisibility){
case PUBLIC -> R.drawable.ic_fluent_earth_24_filled;
case UNLISTED -> R.drawable.ic_fluent_people_community_24_regular;
case PRIVATE -> R.drawable.ic_fluent_people_checkmark_24_regular;
case DIRECT -> R.drawable.ic_at_symbol;
});
}
@Parcel
static class DraftMediaAttachment{
public Attachment serverAttachment;

View File

@ -0,0 +1,28 @@
package org.joinmastodon.android.ui.text;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.style.ReplacementSpan;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class SpacerSpan extends ReplacementSpan{
private int width, height;
public SpacerSpan(int width, int height){
this.width=width;
this.height=height;
}
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm){
// TODO height
return width;
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint){
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?colorBackgroundLightest"/>
<corners android:radius="10dp"/>
<padding android:top="8dp" android:bottom="8dp"/>
</shape>

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:pathData="M14.0653,14.9329C14.0639,14.9132 14.0475,14.8978 14.0278,14.8978C14.0125,14.8978 13.9987,14.9072 13.993,14.9214C13.6711,15.7244 13.2265,16.3336 12.6594,16.7489C12.0948,17.1603 11.4132,17.366 10.6146,17.366C9.5096,17.366 8.6183,16.9587 7.9407,16.144C7.2632,15.3293 6.9244,14.2202 6.9244,12.8167C6.9244,10.9857 7.3922,9.4773 8.3279,8.2916C9.2716,7.1059 10.4574,6.513 11.8851,6.513C12.4658,6.513 12.9659,6.6421 13.3854,6.9002C13.8048,7.1583 14.0992,7.489 14.2686,7.8923H14.317L14.3417,7.6527C14.3964,7.122 14.8435,6.7187 15.3769,6.7187C15.9898,6.7187 16.4699,7.246 16.4136,7.8562C16.2791,9.3148 16.1731,10.4964 16.0956,11.4011C16.0069,12.5223 15.9625,13.216 15.9625,13.4822C15.9544,14.1839 16.0512,14.7082 16.2529,15.0551C16.4545,15.4019 16.761,15.5753 17.1724,15.5753C17.9226,15.5753 18.5477,15.1276 19.0478,14.2323C19.5479,13.337 19.7979,12.1754 19.7979,10.7477C19.7979,8.7151 19.1446,7.0494 17.8379,5.7508C16.5312,4.4521 14.7284,3.8028 12.4295,3.8028C10.0177,3.8028 8.0415,4.6094 6.5009,6.2226C4.9683,7.8358 4.2021,9.8484 4.2021,12.2601C4.2021,14.6316 4.9159,16.5191 6.3436,17.9226C7.7713,19.318 9.7193,20.0157 12.1875,20.0157C13.1393,20.0157 14.0307,19.923 14.8615,19.7374C15.3602,19.6309 15.8386,19.4953 16.2966,19.3307C16.7909,19.153 17.3563,19.3639 17.5632,19.8467C17.7578,20.3007 17.5634,20.8314 17.1019,21.0073C16.5257,21.2269 15.9039,21.4046 15.2365,21.5402C14.2525,21.75 13.1837,21.8548 12.0302,21.8548C9.0135,21.8548 6.5856,20.9837 4.7465,19.2414C2.9155,17.4991 2,15.1922 2,12.3206C2,9.3765 2.9679,6.9204 4.9038,4.9522C6.8397,2.9841 9.3442,2 12.4174,2C15.2002,2 17.491,2.7985 19.2898,4.3956C21.0966,5.9847 22,8.0738 22,10.663C22,12.6473 21.4878,14.2605 20.4634,15.5027C19.4471,16.7449 18.217,17.366 16.7731,17.366C15.9504,17.366 15.3051,17.1482 14.8373,16.7126C14.3765,16.2837 14.1192,15.6904 14.0653,14.9329ZM12.1512,8.2674C11.2398,8.2674 10.5098,8.707 9.9613,9.5862C9.4128,10.4573 9.1385,11.5342 9.1385,12.8167C9.1385,13.6798 9.32,14.3573 9.683,14.8494C10.054,15.3333 10.542,15.5753 11.147,15.5753C12.0423,15.5753 12.7481,15.1236 13.2644,14.2202C13.7806,13.3087 14.0387,12.0988 14.0387,10.5904C14.0387,9.8403 13.8734,9.2676 13.5426,8.8723C13.2119,8.4691 12.7481,8.2674 12.1512,8.2674Z"
android:fillColor="#667085"/>
</vector>

View File

@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M10.946 2.047l0.005 0.007C11.296 2.02 11.646 2 12 2c5.522 0 10 4.477 10 10s-4.478 10-10 10c-3.21 0-6.066-1.512-7.896-3.862H4.102v-0.003C2.786 16.441 2 14.312 2 12c0-5.162 3.911-9.41 8.932-9.944l0.014-0.009zM12 3.5c-0.053 0-0.106 0-0.16 0.002 0.123 0.244 0.255 0.532 0.374 0.85 0.347 0.921 0.666 2.28 0.1 3.486-0.522 1.113-1.424 1.4-2.09 1.573L10.14 9.432c-0.657 0.17-0.91 0.235-1.093 0.514-0.17 0.257-0.144 0.582 0.061 1.25l0.046 0.148c0.082 0.258 0.18 0.57 0.23 0.863 0.064 0.364 0.082 0.827-0.152 1.275-0.231 0.444-0.538 0.747-0.9 0.945-0.341 0.185-0.694 0.256-0.958 0.302l-0.093 0.017c-0.515 0.09-0.761 0.134-1 0.39-0.187 0.2-0.307 0.553-0.377 1.079-0.029 0.214-0.046 0.427-0.064 0.646l-0.01 0.117c-0.02 0.242-0.044 0.521-0.099 0.76v0.002c1.554 1.696 3.787 2.76 6.27 2.76 1.576 0 3.053-0.43 4.319-1.178-0.099-0.1-0.205-0.218-0.31-0.35-0.34-0.428-0.786-1.164-0.631-2.033 0.074-0.418 0.298-0.768 0.515-1.036 0.22-0.274 0.486-0.526 0.72-0.74l0.158-0.146c0.179-0.163 0.33-0.301 0.46-0.437 0.172-0.18 0.21-0.262 0.212-0.267 0.068-0.224-0.015-0.384-0.106-0.454-0.046-0.035-0.107-0.06-0.19-0.061-0.084 0-0.22 0.024-0.401 0.14-0.21 0.132-0.515 0.214-0.836 0.085-0.267-0.108-0.415-0.314-0.486-0.432-0.144-0.237-0.225-0.546-0.278-0.772-0.04-0.174-0.08-0.372-0.115-0.553l-0.04-0.206c-0.05-0.25-0.094-0.428-0.134-0.54l-0.02-0.037c-0.014-0.027-0.035-0.062-0.064-0.105-0.058-0.089-0.133-0.192-0.227-0.317l-0.11-0.143c-0.16-0.212-0.353-0.463-0.516-0.712-0.196-0.298-0.417-0.688-0.487-1.104-0.037-0.22-0.036-0.475 0.055-0.734 0.094-0.264 0.265-0.482 0.487-0.649 0.483-0.362 1.193-1.172 1.823-1.959 0.288-0.359 0.544-0.695 0.736-0.95C15.222 3.98 13.667 3.5 12 3.5z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M12.81 13H4c-1.104 0-2 0.896-2 2v1.5l0.006 0.23C2.164 20.044 5.777 21 8.5 21c1.03 0 2.189-0.137 3.239-0.487-0.23-0.44-0.413-0.91-0.537-1.403-0.698 0.224-1.52 0.359-2.385 0.385L8.5 19.5l-0.317-0.005c-1.263-0.039-2.44-0.308-3.266-0.753C3.95 18.222 3.5 17.509 3.5 16.5v-1.501l0.01-0.101c0.025-0.125 0.093-0.209 0.136-0.253 0.044-0.043 0.129-0.11 0.253-0.136L4 14.499h7.732c0.287-0.55 0.651-1.055 1.077-1.499zM13 6.5C13 4.015 10.985 2 8.5 2S4 4.015 4 6.5 6.015 11 8.5 11 13 8.985 13 6.5zm-7.5 0c0-1.654 1.346-3 3-3s3 1.346 3 3-1.346 3-3 3-3-1.346-3-3zm15.5 1C21 5.567 19.433 4 17.5 4S14 5.567 14 7.5s1.567 3.5 3.5 3.5S21 9.433 21 7.5zm-5.5 0c0-1.103 0.897-2 2-2s2 0.897 2 2-0.897 2-2 2-2-0.897-2-2zm7.5 10c0 3.038-2.462 5.5-5.5 5.5S12 20.538 12 17.5s2.462-5.5 5.5-5.5 5.5 2.462 5.5 5.5zm-2.146-2.354c-0.196-0.195-0.512-0.195-0.708 0L16.5 18.793l-1.646-1.647c-0.196-0.195-0.512-0.195-0.708 0-0.195 0.196-0.195 0.512 0 0.708l2 2c0.196 0.195 0.512 0.195 0.708 0l4-4c0.195-0.196 0.195-0.512 0-0.708z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@ -212,7 +212,7 @@
android:padding="0px"
android:tint="@color/compose_button"
android:tintMode="src_in"
android:src="@drawable/ic_fluent_people_community_24_regular"/>
android:src="@drawable/ic_fluent_earth_24_filled"/>
<Space
android:layout_width="0px"

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/vis_public"
android:icon="@drawable/ic_fluent_earth_24_filled"
android:title="@string/visibility_public"/>
<item android:id="@+id/vis_followers"
android:icon="@drawable/ic_fluent_people_checkmark_24_regular"
android:title="@string/visibility_followers_only"/>
<item android:id="@+id/vis_private"
android:icon="@drawable/ic_at_symbol"
android:title="@string/visibility_private"/>
</menu>

View File

@ -214,4 +214,7 @@
<string name="add_alt_text">Add alt text</string>
<string name="alt_text_subtitle">Alt text describes your photos for people with low or no vision. Try to only include enough detail to understand the context.</string>
<string name="alt_text_hint">e.g. A dog looking around suspiciously with narrowed eyes at the camera.</string>
<string name="visibility_public">Public</string>
<string name="visibility_followers_only">Followers only</string>
<string name="visibility_private">Only people I mention</string>
</resources>

View File

@ -41,6 +41,7 @@
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
<item name="android:popupMenuStyle">@style/Widget.Mastodon.PopupMenu</item>
</style>
<style name="Theme.Mastodon.Dark" parent="Theme.AppKit">
@ -213,6 +214,10 @@
<item name="android:textColor">?android:textColorPrimary</item>
</style>
<style name="Widget.Mastodon.PopupMenu" parent="android:Widget.Material.Light.PopupMenu">
<item name="android:popupBackground">@drawable/bg_popup</item>
</style>
<style name="alert_title">
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:textSize">24dp</item>