From a438f633be127f9e1ab0c7f0207805d20615277e Mon Sep 17 00:00:00 2001 From: Grishka Date: Wed, 15 Nov 2023 18:05:38 +0300 Subject: [PATCH] Pre-reply sheets --- .../android/GlobalUserPreferences.java | 40 ++++++ .../fragments/BaseStatusListFragment.java | 31 +++++ .../android/fragments/ThreadFragment.java | 12 +- .../settings/SettingsDebugFragment.java | 13 +- .../android/model/DisplayItemsParent.java | 4 + .../android/model/Notification.java | 5 + .../android/model/SearchResult.java | 8 ++ .../joinmastodon/android/model/Status.java | 5 + .../android/ui/NonMutualPreReplySheet.java | 123 ++++++++++++++++++ .../android/ui/OldPostPreReplySheet.java | 23 ++++ .../android/ui/PreReplySheet.java | 54 ++++++++ .../displayitems/FooterStatusDisplayItem.java | 10 +- .../displayitems/HeaderStatusDisplayItem.java | 29 +---- .../android/ui/text/HtmlParser.java | 2 +- .../android/ui/utils/UiUtils.java | 14 ++ .../src/main/res/drawable/bg_user_info.xml | 6 + .../main/res/drawable/fg_user_info_ava.xml | 5 + .../main/res/drawable/ic_waving_hand_24px.xml | 9 ++ .../res/layout/item_other_numbered_rule.xml | 50 +++++++ .../src/main/res/layout/sheet_pre_reply.xml | 82 ++++++++++++ mastodon/src/main/res/values/strings.xml | 18 +++ 21 files changed, 503 insertions(+), 40 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/ui/NonMutualPreReplySheet.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/ui/OldPostPreReplySheet.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/ui/PreReplySheet.java create mode 100644 mastodon/src/main/res/drawable/bg_user_info.xml create mode 100644 mastodon/src/main/res/drawable/fg_user_info_ava.xml create mode 100644 mastodon/src/main/res/drawable/ic_waving_hand_24px.xml create mode 100644 mastodon/src/main/res/layout/item_other_numbered_rule.xml create mode 100644 mastodon/src/main/res/layout/sheet_pre_reply.xml diff --git a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java index 5f7eaf8d5..7be513f96 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java +++ b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java @@ -3,6 +3,9 @@ package org.joinmastodon.android; import android.content.Context; import android.content.SharedPreferences; +import org.joinmastodon.android.api.session.AccountSessionManager; +import org.joinmastodon.android.model.Account; + public class GlobalUserPreferences{ public static boolean playGifs; public static boolean useCustomTabs; @@ -13,6 +16,10 @@ public class GlobalUserPreferences{ return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE); } + private static SharedPreferences getPreReplyPrefs(){ + return MastodonApp.context.getSharedPreferences("pre_reply_sheets", Context.MODE_PRIVATE); + } + public static void load(){ SharedPreferences prefs=getPrefs(); playGifs=prefs.getBoolean("playGifs", true); @@ -36,9 +43,42 @@ public class GlobalUserPreferences{ .apply(); } + public static boolean isOptedOutOfPreReplySheet(PreReplySheetType type, Account account, String accountID){ + if(getPreReplyPrefs().getBoolean("opt_out_"+type, false)) + return true; + if(account==null) + return false; + String accountKey=account.acct; + if(!accountKey.contains("@")) + accountKey+="@"+AccountSessionManager.get(accountID).domain; + return getPreReplyPrefs().getBoolean("opt_out_"+type+"_"+accountKey.toLowerCase(), false); + } + + public static void optOutOfPreReplySheet(PreReplySheetType type, Account account, String accountID){ + String key; + if(account==null){ + key="opt_out_"+type; + }else{ + String accountKey=account.acct; + if(!accountKey.contains("@")) + accountKey+="@"+AccountSessionManager.get(accountID).domain; + key="opt_out_"+type+"_"+accountKey.toLowerCase(); + } + getPreReplyPrefs().edit().putBoolean(key, true).apply(); + } + + public static void resetPreReplySheets(){ + getPreReplyPrefs().edit().clear().apply(); + } + public enum ThemePreference{ AUTO, LIGHT, DARK } + + public enum PreReplySheetType{ + OLD_POST, + NON_MUTUAL + } } 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 c1edff6f3..5d5724f04 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java @@ -14,10 +14,12 @@ import android.view.WindowInsets; import android.widget.Toolbar; import org.joinmastodon.android.E; +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; import org.joinmastodon.android.model.DisplayItemsParent; @@ -27,6 +29,8 @@ 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.NonMutualPreReplySheet; +import org.joinmastodon.android.ui.OldPostPreReplySheet; import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem; @@ -43,6 +47,8 @@ import org.joinmastodon.android.ui.utils.MediaAttachmentViewController; import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.utils.TypedObjectPool; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -106,6 +112,7 @@ public abstract class BaseStatusListFragment exten for(T s:items){ displayItems.addAll(buildDisplayItems(s)); } + loadRelationships(items.stream().map(DisplayItemsParent::getAccountID).filter(Objects::nonNull).collect(Collectors.toSet())); } @Override @@ -127,6 +134,7 @@ public abstract class BaseStatusListFragment exten } if(notify) adapter.notifyItemRangeInserted(0, offset); + loadRelationships(items.stream().map(DisplayItemsParent::getAccountID).filter(Objects::nonNull).collect(Collectors.toSet())); } protected String getMaxID(){ @@ -455,6 +463,9 @@ public abstract class BaseStatusListFragment exten } protected void loadRelationships(Set ids){ + if(ids.isEmpty()) + return; + ids=ids.stream().filter(id->!relationships.containsKey(id)).collect(Collectors.toSet()); if(ids.isEmpty()) return; // TODO somehow manage these and cancel outstanding requests on refresh @@ -641,6 +652,26 @@ public abstract class BaseStatusListFragment exten adapter.notifyDataSetChanged(); } + public void maybeShowPreReplySheet(Status status, Runnable proceed){ + Relationship rel=getRelationship(status.account.id); + if(!GlobalUserPreferences.isOptedOutOfPreReplySheet(GlobalUserPreferences.PreReplySheetType.NON_MUTUAL, status.account, accountID) && + !status.account.id.equals(AccountSessionManager.get(accountID).self.id) && rel!=null && !rel.followedBy && status.account.followingCount>=1){ + new NonMutualPreReplySheet(getActivity(), notAgain->{ + GlobalUserPreferences.optOutOfPreReplySheet(GlobalUserPreferences.PreReplySheetType.NON_MUTUAL, notAgain ? null : status.account, accountID); + proceed.run(); + }, status.account).show(); + }else if(!GlobalUserPreferences.isOptedOutOfPreReplySheet(GlobalUserPreferences.PreReplySheetType.OLD_POST, null, null) && + status.createdAt.isBefore(Instant.now().minus(90, ChronoUnit.DAYS))){ + new OldPostPreReplySheet(getActivity(), notAgain->{ + if(notAgain) + GlobalUserPreferences.optOutOfPreReplySheet(GlobalUserPreferences.PreReplySheetType.OLD_POST, null, null); + proceed.run(); + }, status).show(); + }else{ + proceed.run(); + } + } + protected void onModifyItemViewHolder(BindableViewHolder holder){} protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter> implements ImageLoaderRecyclerAdapter{ diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java index c9c405c91..8dfc9194f 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java @@ -210,11 +210,13 @@ public class ThreadFragment extends StatusListFragment{ } private void openReply(){ - Bundle args=new Bundle(); - args.putString("account", accountID); - args.putParcelable("replyTo", Parcels.wrap(mainStatus)); - args.putBoolean("fromThreadFragment", true); - Nav.go(getActivity(), ComposeFragment.class, args); + maybeShowPreReplySheet(mainStatus, ()->{ + Bundle args=new Bundle(); + args.putString("account", accountID); + args.putParcelable("replyTo", Parcels.wrap(mainStatus)); + args.putBoolean("fromThreadFragment", true); + Nav.go(getActivity(), ComposeFragment.class, args); + }); } public int getSnackbarOffset(){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java index bc3b59496..755238e83 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java @@ -1,10 +1,9 @@ package org.joinmastodon.android.fragments.settings; -import android.content.Context; -import android.content.SharedPreferences; import android.os.Bundle; +import android.widget.Toast; -import org.joinmastodon.android.MastodonApp; +import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.api.session.AccountActivationInfo; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; @@ -28,7 +27,8 @@ public class SettingsDebugFragment extends BaseSettingsFragment{ new ListItem<>("Test email confirmation flow", null, this::onTestEmailConfirmClick), selfUpdateItem=new ListItem<>("Force self-update", null, this::onForceSelfUpdateClick), resetUpdateItem=new ListItem<>("Reset self-updater", null, this::onResetUpdaterClick), - new ListItem<>("Reset search info banners", null, this::onResetDiscoverBannersClick) + new ListItem<>("Reset search info banners", null, this::onResetDiscoverBannersClick), + new ListItem<>("Reset pre-reply sheets", null, this::onResetPreReplySheetsClick) )); if(!GithubSelfUpdater.needSelfUpdating()){ resetUpdateItem.isEnabled=selfUpdateItem.isEnabled=false; @@ -65,6 +65,11 @@ public class SettingsDebugFragment extends BaseSettingsFragment{ restartUI(); } + private void onResetPreReplySheetsClick(ListItem item){ + GlobalUserPreferences.resetPreReplySheets(); + Toast.makeText(getActivity(), "Pre-reply sheets were reset", Toast.LENGTH_SHORT).show(); + } + private void restartUI(){ Bundle args=new Bundle(); args.putString("account", accountID); diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/DisplayItemsParent.java b/mastodon/src/main/java/org/joinmastodon/android/model/DisplayItemsParent.java index 911ba1ddc..25e6c408b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/DisplayItemsParent.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/DisplayItemsParent.java @@ -5,4 +5,8 @@ package org.joinmastodon.android.model; */ public interface DisplayItemsParent{ String getID(); + + default String getAccountID(){ + return null; + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/Notification.java b/mastodon/src/main/java/org/joinmastodon/android/model/Notification.java index 545028add..30a4ccc9e 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/Notification.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/Notification.java @@ -34,6 +34,11 @@ public class Notification extends BaseModel implements DisplayItemsParent{ return id; } + @Override + public String getAccountID(){ + return status!=null ? account.id : null; + } + public enum Type{ @SerializedName("follow") FOLLOW, diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/SearchResult.java b/mastodon/src/main/java/org/joinmastodon/android/model/SearchResult.java index 6e4f4a2ed..f56b757ea 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/SearchResult.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/SearchResult.java @@ -34,10 +34,18 @@ public class SearchResult extends BaseModel implements DisplayItemsParent{ generateID(); } + @Override public String getID(){ return id; } + @Override + public String getAccountID(){ + if(type==Type.STATUS) + return status.getAccountID(); + return null; + } + @Override public void postprocess() throws ObjectValidationException{ super.postprocess(); 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 2a5ccd857..2cfb2506a 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/Status.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/Status.java @@ -143,6 +143,11 @@ public class Status extends BaseModel implements DisplayItemsParent{ return id; } + @Override + public String getAccountID(){ + return getContentStatus().account.id; + } + public void update(StatusCountersUpdatedEvent ev){ favouritesCount=ev.favorites; reblogsCount=ev.reblogs; diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/NonMutualPreReplySheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/NonMutualPreReplySheet.java new file mode 100644 index 000000000..fd987b759 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/NonMutualPreReplySheet.java @@ -0,0 +1,123 @@ +package org.joinmastodon.android.ui; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Typeface; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.ForegroundColorSpan; +import android.text.style.TextAppearanceSpan; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.model.Account; +import org.joinmastodon.android.model.AccountField; +import org.joinmastodon.android.ui.text.HtmlParser; +import org.joinmastodon.android.ui.utils.UiUtils; + +import androidx.annotation.NonNull; +import me.grishka.appkit.imageloader.ViewImageLoader; +import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; +import me.grishka.appkit.utils.V; + +public class NonMutualPreReplySheet extends PreReplySheet{ + @SuppressLint("DefaultLocale") + public NonMutualPreReplySheet(@NonNull Context context, ResultListener resultListener, Account account){ + super(context, resultListener); + icon.setImageResource(R.drawable.ic_waving_hand_24px); + title.setText(R.string.non_mutual_sheet_title); + text.setText(R.string.non_mutual_sheet_text); + + LinearLayout userInfo=new LinearLayout(context); + userInfo.setOrientation(LinearLayout.HORIZONTAL); + userInfo.setBackgroundResource(R.drawable.bg_user_info); + UiUtils.setAllPaddings(userInfo, 12); + + ImageView ava=new ImageView(context); + ava.setScaleType(ImageView.ScaleType.CENTER_CROP); + ava.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + ava.setOutlineProvider(OutlineProviders.roundedRect(12)); + ava.setClipToOutline(true); + ava.setForeground(context.getResources().getDrawable(R.drawable.fg_user_info_ava, context.getTheme())); + userInfo.addView(ava, UiUtils.makeLayoutParams(56, 56, 0, 0, 12, 0)); + ViewImageLoader.loadWithoutAnimation(ava, context.getResources().getDrawable(R.drawable.image_placeholder), new UrlImageLoaderRequest(account.avatarStatic, V.dp(56), V.dp(56))); + + LinearLayout nameAndFields=new LinearLayout(context); + nameAndFields.setOrientation(LinearLayout.VERTICAL); + nameAndFields.setMinimumHeight(V.dp(56)); + nameAndFields.setGravity(Gravity.CENTER_VERTICAL); + userInfo.addView(nameAndFields, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + TextView name=new TextView(context); + name.setSingleLine(); + name.setEllipsize(TextUtils.TruncateAt.END); + name.setTextAppearance(R.style.m3_title_medium); + name.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3OnSurface)); + name.setText(account.displayName); + name.setGravity(Gravity.CENTER_VERTICAL | Gravity.START); + nameAndFields.addView(name, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(24))); + if(account.fields!=null && !account.fields.isEmpty()){ + for(AccountField field:account.fields){ + LinearLayout fieldView=new LinearLayout(context); + fieldView.setOrientation(LinearLayout.HORIZONTAL); + TextView key=new TextView(context); + key.setTextAppearance(R.style.m3_body_medium); + key.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3Secondary)); + key.setSingleLine(); + key.setEllipsize(TextUtils.TruncateAt.END); + key.setText(field.name); + key.setGravity(Gravity.CENTER_VERTICAL | Gravity.START); + key.setPaddingRelative(0, 0, V.dp(8), 0); + fieldView.addView(key, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); + TextView value=new TextView(context); + value.setTextAppearance(R.style.m3_body_medium); + value.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + value.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3Secondary)); + value.setSingleLine(); + value.setEllipsize(TextUtils.TruncateAt.END); + value.setText(HtmlParser.stripAndRemoveInvisibleSpans(field.value)); + value.setGravity(Gravity.CENTER_VERTICAL | Gravity.END); + fieldView.addView(value, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f)); + nameAndFields.addView(fieldView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(20))); + } + }else{ + TextView username=new TextView(context); + username.setTextAppearance(R.style.m3_body_medium); + username.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3Secondary)); + username.setSingleLine(); + username.setEllipsize(TextUtils.TruncateAt.END); + username.setText(account.getDisplayUsername()); + username.setGravity(Gravity.CENTER_VERTICAL | Gravity.START); + nameAndFields.addView(username, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(20))); + } + + contentWrap.addView(userInfo, UiUtils.makeLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0, 0, 0, 8)); + + for(int i=0;i<3;i++){ + View item=context.getSystemService(LayoutInflater.class).inflate(R.layout.item_other_numbered_rule, contentWrap, false); + TextView number=item.findViewById(R.id.number); + number.setText(String.format("%d", i+1)); + TextView title=item.findViewById(R.id.title); + TextView text=item.findViewById(R.id.text); + title.setText(switch(i){ + case 0 -> R.string.non_mutual_title1; + case 1 -> R.string.non_mutual_title2; + case 2 -> R.string.non_mutual_title3; + default -> throw new IllegalStateException("Unexpected value: "+i); + }); + text.setText(switch(i){ + case 0 -> R.string.non_mutual_text1; + case 1 -> R.string.non_mutual_text2; + case 2 -> R.string.non_mutual_text3; + default -> throw new IllegalStateException("Unexpected value: "+i); + }); + contentWrap.addView(item); + } + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/OldPostPreReplySheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/OldPostPreReplySheet.java new file mode 100644 index 000000000..8e402950a --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/OldPostPreReplySheet.java @@ -0,0 +1,23 @@ +package org.joinmastodon.android.ui; + +import android.content.Context; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.model.Status; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; + +import androidx.annotation.NonNull; + +public class OldPostPreReplySheet extends PreReplySheet{ + public OldPostPreReplySheet(@NonNull Context context, ResultListener resultListener, Status status){ + super(context, resultListener); + int months=(int)status.createdAt.atZone(ZoneId.systemDefault()).until(ZonedDateTime.now(), ChronoUnit.MONTHS); + String monthsStr=months>24 ? context.getString(R.string.more_than_two_years) : context.getResources().getQuantityString(R.plurals.x_months, months, months); + title.setText(context.getString(R.string.old_post_sheet_title, monthsStr)); + text.setText(R.string.old_post_sheet_text); + icon.setImageResource(R.drawable.ic_history_24px); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/PreReplySheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/PreReplySheet.java new file mode 100644 index 000000000..2fb3c9a7a --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/PreReplySheet.java @@ -0,0 +1,54 @@ +package org.joinmastodon.android.ui; + +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.ui.utils.UiUtils; + +import androidx.annotation.NonNull; +import me.grishka.appkit.views.BottomSheet; + +public abstract class PreReplySheet extends BottomSheet{ + protected ImageView icon; + protected TextView title, text; + protected Button gotItButton, dontRemindButton; + protected LinearLayout contentWrap; + + public PreReplySheet(@NonNull Context context, ResultListener resultListener){ + super(context); + + View content=context.getSystemService(LayoutInflater.class).inflate(R.layout.sheet_pre_reply, null); + setContentView(content); + + setNavigationBarBackground(new ColorDrawable(UiUtils.alphaBlendColors(UiUtils.getThemeColor(context, R.attr.colorM3Surface), + UiUtils.getThemeColor(context, R.attr.colorM3Primary), 0.05f)), !UiUtils.isDarkTheme()); + + icon=findViewById(R.id.icon); + title=findViewById(R.id.title); + text=findViewById(R.id.text); + gotItButton=findViewById(R.id.btn_got_it); + dontRemindButton=findViewById(R.id.btn_dont_remind_again); + contentWrap=findViewById(R.id.content_wrap); + + gotItButton.setOnClickListener(v->{ + dismiss(); + resultListener.onButtonClicked(false); + }); + dontRemindButton.setOnClickListener(v->{ + dismiss(); + resultListener.onButtonClicked(true); + }); + } + + @FunctionalInterface + public interface ResultListener{ + void onButtonClicked(boolean notAgain); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java index e35f34137..7d4310c72 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java @@ -129,10 +129,12 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ } private void onReplyClick(View v){ - Bundle args=new Bundle(); - args.putString("account", item.accountID); - args.putParcelable("replyTo", Parcels.wrap(item.status)); - Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); + item.parentFragment.maybeShowPreReplySheet(item.status, ()->{ + Bundle args=new Bundle(); + args.putString("account", item.accountID); + args.putParcelable("replyTo", Parcels.wrap(item.status)); + Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); + }); } private void onBoostClick(View v){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java index 42fbd79f0..b7eede20d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java @@ -115,8 +115,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ private final TextView name, timeAndUsername, extraText; private final ImageView avatar, more; private final PopupMenu optionsMenu; - private Relationship relationship; - private APIRequest currentRelationshipRequest; public Holder(Activity activity, ViewGroup parent){ this(activity, R.layout.display_item_header, parent); @@ -140,6 +138,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ optionsMenu.getMenu().setGroupDividerEnabled(true); optionsMenu.setOnMenuItemClickListener(menuItem->{ Account account=item.user; + Relationship relationship=item.parentFragment.getRelationship(account.id); int id=menuItem.getItemId(); if(id==R.id.edit){ final Bundle args=new Bundle(); @@ -192,7 +191,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ else progress.dismiss(); }, rel->{ - relationship=rel; + item.parentFragment.putRelationship(account.id, rel); Toast.makeText(activity, activity.getString(rel.following ? R.string.followed_user : rel.requested ? R.string.following_user_requested : R.string.unfollowed_user, account.getDisplayUsername()), Toast.LENGTH_SHORT).show(); }); }else if(id==R.id.bookmark){ @@ -235,10 +234,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ more.setVisibility(item.inset ? View.GONE : View.VISIBLE); avatar.setClickable(!item.inset); avatar.setContentDescription(item.parentFragment.getString(R.string.avatar_description, item.user.acct)); - if(currentRelationshipRequest!=null){ - currentRelationshipRequest.cancel(); - } - relationship=null; } @Override @@ -272,31 +267,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ private void onMoreClick(View v){ updateOptionsMenu(); optionsMenu.show(); - if(relationship==null && currentRelationshipRequest==null){ - currentRelationshipRequest=new GetAccountRelationships(Collections.singletonList(item.user.id)) - .setCallback(new Callback<>(){ - @Override - public void onSuccess(List result){ - if(!result.isEmpty()){ - relationship=result.get(0); - updateOptionsMenu(); - } - currentRelationshipRequest=null; - } - - @Override - public void onError(ErrorResponse error){ - currentRelationshipRequest=null; - } - }) - .exec(item.parentFragment.getAccountID()); - } } private void updateOptionsMenu(){ if(item.parentFragment.getActivity()==null) return; Account account=item.user; + Relationship relationship=item.parentFragment.getRelationship(account.id); Menu menu=optionsMenu.getMenu(); boolean isOwnPost=AccountSessionManager.getInstance().isSelf(item.parentFragment.getAccountID(), account); boolean canTranslate=item.status!=null && item.status.getContentStatus().isEligibleForTranslation(); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/text/HtmlParser.java b/mastodon/src/main/java/org/joinmastodon/android/ui/text/HtmlParser.java index cd21344f3..a5884926d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/text/HtmlParser.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/text/HtmlParser.java @@ -204,7 +204,7 @@ public class HtmlParser{ Document doc=Jsoup.parseBodyFragment(html); doc.body().select("span.invisible").remove(); Cleaner cleaner=new Cleaner(Safelist.none()); - return cleaner.clean(doc).body().html(); + return cleaner.clean(doc).body().text(); } public static CharSequence parseLinks(String text){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index 1d3999fc0..b08dc448c 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -835,4 +835,18 @@ public class UiUtils{ Toast.makeText(context, R.string.text_copied, Toast.LENGTH_SHORT).show(); } } + + public static void setAllPaddings(View view, int paddingDp){ + int pad=V.dp(paddingDp); + view.setPadding(pad, pad, pad, pad); + } + + public static ViewGroup.MarginLayoutParams makeLayoutParams(int width, int height, int marginStart, int marginTop, int marginEnd, int marginBottom){ + ViewGroup.MarginLayoutParams lp=new ViewGroup.MarginLayoutParams(width>0 ? V.dp(width) : width, height>0 ? V.dp(height) : height); + lp.topMargin=V.dp(marginTop); + lp.bottomMargin=V.dp(marginBottom); + lp.setMarginStart(V.dp(marginStart)); + lp.setMarginEnd(V.dp(marginEnd)); + return lp; + } } diff --git a/mastodon/src/main/res/drawable/bg_user_info.xml b/mastodon/src/main/res/drawable/bg_user_info.xml new file mode 100644 index 000000000..c0fa41703 --- /dev/null +++ b/mastodon/src/main/res/drawable/bg_user_info.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/fg_user_info_ava.xml b/mastodon/src/main/res/drawable/fg_user_info_ava.xml new file mode 100644 index 000000000..e36ace291 --- /dev/null +++ b/mastodon/src/main/res/drawable/fg_user_info_ava.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/ic_waving_hand_24px.xml b/mastodon/src/main/res/drawable/ic_waving_hand_24px.xml new file mode 100644 index 000000000..b43de6812 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_waving_hand_24px.xml @@ -0,0 +1,9 @@ + + + diff --git a/mastodon/src/main/res/layout/item_other_numbered_rule.xml b/mastodon/src/main/res/layout/item_other_numbered_rule.xml new file mode 100644 index 000000000..d36c32705 --- /dev/null +++ b/mastodon/src/main/res/layout/item_other_numbered_rule.xml @@ -0,0 +1,50 @@ + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/layout/sheet_pre_reply.xml b/mastodon/src/main/res/layout/sheet_pre_reply.xml new file mode 100644 index 000000000..8a62915d3 --- /dev/null +++ b/mastodon/src/main/res/layout/sheet_pre_reply.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + +