From 098128bcd4b9be745c7243e2afd645f15c6176e8 Mon Sep 17 00:00:00 2001 From: Grishka Date: Thu, 17 Mar 2022 00:12:58 +0300 Subject: [PATCH] Compose: visibility --- .../android/fragments/ComposeFragment.java | 89 ++++++++++++++++++- .../android/ui/text/SpacerSpan.java | 28 ++++++ mastodon/src/main/res/drawable/bg_popup.xml | 6 ++ .../src/main/res/drawable/ic_at_symbol.xml | 9 ++ .../drawable/ic_fluent_earth_24_filled.xml | 3 + .../ic_fluent_people_checkmark_24_regular.xml | 3 + .../src/main/res/layout/fragment_compose.xml | 2 +- .../src/main/res/menu/compose_visibility.xml | 12 +++ mastodon/src/main/res/values/strings.xml | 3 + mastodon/src/main/res/values/styles.xml | 5 ++ 10 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/ui/text/SpacerSpan.java create mode 100644 mastodon/src/main/res/drawable/bg_popup.xml create mode 100644 mastodon/src/main/res/drawable/ic_at_symbol.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_earth_24_filled.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_people_checkmark_24_regular.xml create mode 100644 mastodon/src/main/res/menu/compose_visibility.xml 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 c17c684e..7e7f16da 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java @@ -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=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; diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/text/SpacerSpan.java b/mastodon/src/main/java/org/joinmastodon/android/ui/text/SpacerSpan.java new file mode 100644 index 00000000..bb99f7f4 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/text/SpacerSpan.java @@ -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){ + + } +} diff --git a/mastodon/src/main/res/drawable/bg_popup.xml b/mastodon/src/main/res/drawable/bg_popup.xml new file mode 100644 index 00000000..d232689d --- /dev/null +++ b/mastodon/src/main/res/drawable/bg_popup.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/ic_at_symbol.xml b/mastodon/src/main/res/drawable/ic_at_symbol.xml new file mode 100644 index 00000000..7cf7d909 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_at_symbol.xml @@ -0,0 +1,9 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_earth_24_filled.xml b/mastodon/src/main/res/drawable/ic_fluent_earth_24_filled.xml new file mode 100644 index 00000000..5e892332 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_earth_24_filled.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_people_checkmark_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_people_checkmark_24_regular.xml new file mode 100644 index 00000000..28e3cf3a --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_people_checkmark_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/layout/fragment_compose.xml b/mastodon/src/main/res/layout/fragment_compose.xml index c852cde1..81778e5a 100644 --- a/mastodon/src/main/res/layout/fragment_compose.xml +++ b/mastodon/src/main/res/layout/fragment_compose.xml @@ -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"/> + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml index ae32f301..05777182 100644 --- a/mastodon/src/main/res/values/strings.xml +++ b/mastodon/src/main/res/values/strings.xml @@ -214,4 +214,7 @@ Add alt text Alt text describes your photos for people with low or no vision. Try to only include enough detail to understand the context. e.g. A dog looking around suspiciously with narrowed eyes at the camera. + Public + Followers only + Only people I mention \ No newline at end of file diff --git a/mastodon/src/main/res/values/styles.xml b/mastodon/src/main/res/values/styles.xml index 1808810c..ba64cef3 100644 --- a/mastodon/src/main/res/values/styles.xml +++ b/mastodon/src/main/res/values/styles.xml @@ -41,6 +41,7 @@ true true + @style/Widget.Mastodon.PopupMenu + +