Some changes for quote button

- New preference with multiple options to change how quote button is displayed
- Change boost+quote popup UI
This commit is contained in:
0xd9a 2025-11-16 17:56:05 +05:30
parent 70d0f246e2
commit ea7d70ebf5
11 changed files with 204 additions and 55 deletions

View file

@ -1145,6 +1145,19 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
.putString(getString(R.string.SET_TRANSLATE_BUTTON) + currentUserID + currentInstance, newTranslateButtonValue)
.apply();
}
if (sharedpreferences.getString(getString(R.string.SET_QUOTE_BUTTON) + currentUserID + currentInstance, null) == null) {
boolean oldQuoteButtonPrefValue =
sharedpreferences.getBoolean(getString(R.string.SET_DISPLAY_QUOTE) + currentUserID + currentInstance, false);
String[] quoteButtonEntryValues = getResources().getStringArray(R.array.set_quote_button_entry_values);
String newQuoteButtonValue;
if (oldQuoteButtonPrefValue)
newQuoteButtonValue = quoteButtonEntryValues[0];
else
newQuoteButtonValue = quoteButtonEntryValues[2];
sharedpreferences.edit()
.putString(getString(R.string.SET_QUOTE_BUTTON) + currentUserID + currentInstance, newQuoteButtonValue)
.apply();
}
if (sharedpreferences.getString(getString(R.string.SET_LINK_PREVIEWS), null) == null) {
boolean oldDisplayCardValue = sharedpreferences.getBoolean(getString(R.string.SET_DISPLAY_CARD), false);

View file

@ -49,6 +49,7 @@ import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
@ -62,6 +63,7 @@ import android.text.SpannableString;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
@ -73,6 +75,7 @@ import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RadioButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
@ -145,6 +148,7 @@ import app.fedilab.android.databinding.DrawerStatusPixelfedBinding;
import app.fedilab.android.databinding.DrawerStatusReportBinding;
import app.fedilab.android.databinding.LayoutMediaBinding;
import app.fedilab.android.databinding.LayoutPollItemBinding;
import app.fedilab.android.databinding.PopupBoostQuoteBinding;
import app.fedilab.android.mastodon.activities.ComposeActivity;
import app.fedilab.android.mastodon.activities.ContextActivity;
import app.fedilab.android.mastodon.activities.CustomSharingActivity;
@ -982,7 +986,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
holder.binding.actionButtonFavorite.setInactiveImage(R.drawable.ic_round_star_border_24);
holder.binding.actionButtonBookmark.setActiveImage(R.drawable.ic_round_bookmark_24);
holder.binding.actionButtonBookmark.setInactiveImage(R.drawable.ic_round_bookmark_border_24);
if (displayQuote) {
if (quoteButton.equals(quoteButtonEntryValues[1])) {
holder.binding.actionButtonBoost.setActiveImage(R.drawable.ic_quote_or_boost_active);
holder.binding.actionButtonBoost.setInactiveImage(R.drawable.ic_quote_or_boost);
} else {
@ -1226,47 +1230,48 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
return true;
});
holder.binding.actionButtonBoost.setOnClickListener(v -> {
if(displayQuote) {
PopupMenu popupMenu = new PopupMenu(context, v);
popupMenu.getMenuInflater().inflate(R.menu.menu_boost_or_quote, popupMenu.getMenu());
if(statusToDeal.quote_approval != null && statusToDeal.quote_approval.current_user != null && statusToDeal.quote_approval.current_user.equalsIgnoreCase("denied") ) {
popupMenu.getMenu().findItem(R.id.action_quote).setEnabled(false);
} else {
popupMenu.getMenu().findItem(R.id.action_quote).setEnabled(true);
}
MenuItem reblogItem = popupMenu.getMenu().findItem(R.id.action_reblog);
if(quoteButton.equals(quoteButtonEntryValues[1])) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
PopupWindow popupWindow = new PopupWindow(context);
PopupBoostQuoteBinding popupBoostQuoteBinding = PopupBoostQuoteBinding.inflate(layoutInflater);
popupWindow.setContentView(popupBoostQuoteBinding.getRoot());
popupWindow.setWidth(LinearLayoutCompat.LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(LinearLayoutCompat.LayoutParams.WRAP_CONTENT);
popupWindow.setFocusable(true);
popupWindow.setBackgroundDrawable(new ColorDrawable());
popupWindow.setAnimationStyle(R.style.boostQuotePopupWindowAnimation);
popupBoostQuoteBinding.boostButton.setIconSize(iconSize);
popupBoostQuoteBinding.quoteButton.setIconSize(iconSize);
if(statusToDeal.reblogged) {
reblogItem.setTitle(R.string.action_unreblog);
popupBoostQuoteBinding.boostButton.setText(R.string.action_unreblog);
Helper.changeDrawableColor(context, popupBoostQuoteBinding.boostButton, R.color.boost_icon);
} else {
reblogItem.setTitle(R.string.action_reblog);
popupBoostQuoteBinding.boostButton.setText(R.string.action_reblog);
}
popupMenu.setOnMenuItemClickListener(item -> {
int itemId = item.getItemId();
if (itemId == R.id.action_reblog) {
reblogTap(context,
v,
statusesVM,
searchVM,
holder,
adapter,
statusToDeal,
warnNoMedia, confirmBoost, remote);
return true;
} else if (itemId == R.id.action_quote) {
Intent intent = new Intent(context, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_QUOTED_MESSAGE, statusToDeal);
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
context.startActivity(intent);
});
return true;
}
return false;
popupBoostQuoteBinding.boostButton.setOnClickListener(v2 -> {
popupWindow.dismiss();
reblogTap(context,
v,
statusesVM,
searchVM,
holder,
adapter,
statusToDeal,
warnNoMedia, confirmBoost, remote);
});
popupMenu.show();
if(statusToDeal.quote_approval != null && statusToDeal.quote_approval.current_user != null && statusToDeal.quote_approval.current_user.equalsIgnoreCase("denied") ) {
popupBoostQuoteBinding.quoteButton.setEnabled(false);
} else {
popupBoostQuoteBinding.quoteButton.setOnClickListener(v2 -> {
quote(context, status);
popupWindow.dismiss();
});
}
int[] actionButtonBoostLocation = new int[2];
holder.binding.actionButtonBoost.getLocationInWindow(actionButtonBoostLocation);
popupWindow.showAtLocation(holder.binding.actionButtonBoost, Gravity.NO_GRAVITY, actionButtonBoostLocation[0], actionButtonBoostLocation[1]);
} else {
reblogTap(context,
v,
@ -1280,6 +1285,13 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
});
holder.binding.actionButtonBoost.setChecked(statusToDeal.reblogged);
// Quote button
if(quoteButton.equals(quoteButtonEntryValues[0])) {
holder.binding.actionButtonQuote.setVisibility(View.VISIBLE);
holder.binding.actionButtonQuote.setOnClickListener(v -> quote(context, status));
} else {
holder.binding.actionButtonQuote.setVisibility(View.GONE);
}
//---> FAVOURITE/UNFAVOURITE
holder.binding.actionButtonFavorite.setOnLongClickListener(v -> {
if (statusToDeal.visibility.equals("direct") || (statusToDeal.visibility.equals("private"))) {
@ -2574,6 +2586,18 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}
private static void quote(Context context, Status status) {
Intent intent = new Intent(context, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_QUOTED_MESSAGE, status);
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
context.startActivity(intent);
});
}
private static void clickMoreAction(Context context,
StatusesVM statusesVM,
StatusViewHolder holder,
@ -2589,6 +2613,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
if (statusToDeal.visibility.equals("private") || statusToDeal.visibility.equals("direct")) {
popup.getMenu().findItem(R.id.action_mention).setVisible(false);
}
if (!quoteButton.equals(quoteButtonEntryValues[2])){
popup.getMenu().findItem(R.id.action_quote).setVisible(false);
}
if (statusToDeal.bookmarked)
popup.getMenu().findItem(R.id.action_bookmark).setTitle(R.string.bookmark_remove);
else
@ -2782,7 +2809,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}
return true;
}else if (itemId == R.id.action_bookmark) {
} else if (itemId == R.id.action_quote) {
quote(context, statusToDeal);
return true;
} else if (itemId == R.id.action_bookmark) {
if (statusToDeal.bookmarked) {
statusesVM.unBookmark(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id).observe((LifecycleOwner) context, status1 -> Toasty.info(context, context.getString(R.string.status_unbookmarked)).show());
} else {

View file

@ -94,10 +94,10 @@ public class FragmentTimelinesSettings extends PreferenceFragmentCompat implemen
SET_TRANSLATE_BUTTON.setValue(value);
}
SwitchPreferenceCompat SET_DISPLAY_QUOTE = findPreference(getString(R.string.SET_DISPLAY_QUOTE));
if (SET_DISPLAY_QUOTE != null) {
boolean checked = sharedpreferences.getBoolean(getString(R.string.SET_DISPLAY_QUOTE) + MainActivity.currentUserID + MainActivity.currentInstance, true);
SET_DISPLAY_QUOTE.setChecked(checked);
ListPreference SET_QUOTE_BUTTON = findPreference(getString(R.string.SET_QUOTE_BUTTON));
if (SET_QUOTE_BUTTON != null) {
String value = sharedpreferences.getString(getString(R.string.SET_QUOTE_BUTTON) + MainActivity.currentUserID + MainActivity.currentInstance, null);
SET_QUOTE_BUTTON.setValue(value);
}
SwitchPreferenceCompat SET_PIXELFED_PRESENTATION = findPreference(getString(R.string.SET_PIXELFED_PRESENTATION));
@ -131,10 +131,10 @@ public class FragmentTimelinesSettings extends PreferenceFragmentCompat implemen
editor.putString(getString(R.string.SET_TRANSLATE_BUTTON) + MainActivity.currentUserID + MainActivity.currentInstance, SET_TRANSLATE_BUTTON.getValue());
}
}
if (key.compareToIgnoreCase(getString(R.string.SET_DISPLAY_QUOTE)) == 0) {
SwitchPreferenceCompat SET_DISPLAY_QUOTE = findPreference(getString(R.string.SET_DISPLAY_QUOTE));
if (SET_DISPLAY_QUOTE != null) {
editor.putBoolean(getString(R.string.SET_DISPLAY_QUOTE) + MainActivity.currentUserID + MainActivity.currentInstance, SET_DISPLAY_QUOTE.isChecked());
if (key.compareToIgnoreCase(getString(R.string.SET_QUOTE_BUTTON)) == 0) {
ListPreference SET_QUOTE_BUTTON = findPreference(getString(R.string.SET_QUOTE_BUTTON));
if (SET_QUOTE_BUTTON != null) {
editor.putString(getString(R.string.SET_QUOTE_BUTTON) + MainActivity.currentUserID + MainActivity.currentInstance, SET_QUOTE_BUTTON.getValue());
}
}
if (key.compareToIgnoreCase(getString(R.string.SET_PIXELFED_PRESENTATION)) == 0) {

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime">
<scale
android:fromXScale="0.5"
android:fromYScale="0.5"
android:pivotX="0"
android:pivotY="0"
android:toXScale="1.0"
android:toYScale="1.0" />
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime">
<scale
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="0"
android:pivotY="0"
android:toXScale="0.5"
android:toYScale="0.5" />
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>

View file

@ -778,6 +778,20 @@
</RelativeLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/action_button_quote"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:contentDescription="@string/action_quote"
android:visibility="gone"
app:icon="@drawable/ic_baseline_format_quote_24"
app:iconGravity="textStart"
app:iconSize="28dp"
app:iconTint="?colorControlNormal"
app:layout_constraintWidth_max="48dp"
tools:visibility="visible" />
<RelativeLayout
android:id="@+id/action_button_favorite_container"
android:layout_width="0dp"
@ -901,7 +915,7 @@
android:id="@+id/action_buttons_flow"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:constraint_referenced_ids="action_button_reply_container,action_button_boost_container,action_button_favorite_container,action_button_bookmark,action_button_translate,action_button_maths,status_add_custom_emoji,status_emoji,action_button_more"
app:constraint_referenced_ids="action_button_reply_container,action_button_boost_container,action_button_quote,action_button_favorite_container,action_button_bookmark,action_button_translate,action_button_maths,status_add_custom_emoji,status_emoji,action_button_more"
app:flow_horizontalStyle="spread_inside" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.Material3.CardView.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.button.MaterialButton
android:id="@+id/boost_button"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:insetLeft="0dp"
android:insetRight="0dp"
android:textColor="?colorControlNormal"
app:icon="@drawable/ic_repeat"
app:iconTint="?colorControlNormal"
tools:text="@string/action_reblog" />
<com.google.android.material.button.MaterialButton
android:id="@+id/quote_button"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:insetLeft="0dp"
android:insetRight="0dp"
android:text="@string/action_quote"
android:textColor="?colorControlNormal"
app:icon="@drawable/ic_baseline_format_quote_24"
app:iconTint="?colorControlNormal" />
</androidx.appcompat.widget.LinearLayoutCompat>
</com.google.android.material.card.MaterialCardView>

View file

@ -5,6 +5,10 @@
android:id="@+id/action_translate"
android:title="@string/translate"
app:showAsAction="never" />
<item
android:id="@+id/action_quote"
android:title="@string/action_quote"
app:showAsAction="never" />
<item
android:id="@+id/action_bookmark"
android:title="@string/bookmark_add"

View file

@ -789,6 +789,19 @@
<item>hide</item>
</string-array>
<string-array name="set_quote_button_entries">
<item>Dedicated button</item>
<item>Combine with boost button</item>
<item>In menu</item>
<item>Disable</item>
</string-array>
<string-array name="set_quote_button_entry_values" translatable="false">
<item>dedicated</item>
<item>combine_with_boost</item>
<item>in_menu</item>
<item>disable</item>
</string-array>
<string-array name="set_link_previews_entries">
<item>Always show</item>
<item>Hide in posts with media</item>
@ -1313,6 +1326,7 @@
<string name="SET_DISPLAY_TRANSLATE" translatable="false">SET_DISPLAY_TRANSLATE</string>
<string name="SET_TRANSLATE_BUTTON" translatable="false">SET_TRANSLATE_BUTTON</string>
<string name="SET_QUOTE_BUTTON" translatable="false">SET_QUOTE_BUTTON</string>
<string name="SET_POST_FORMAT" translatable="false">SET_POST_FORMAT</string>
<string name="SET_COMPOSE_LOCAL_ONLY" translatable="false">SET_COMPOSE_LOCAL_ONLY</string>
@ -2119,7 +2133,7 @@
<string name="set_post_format">Post format</string>
<string name="icons_extra_features">Icons for extra features</string>
<string name="icons_extra_features_visibility_summary">If your instance does not accept some extra features, you can hide these icons</string>
<string name="set_display_quote_indication">Display the \"Quote\" button</string>
<string name="set_display_quote_indication">Quote button</string>
<string name="set_display_reaction_indication">Display \"Reactions\" buttons</string>
<string name="bubble">Bubble</string>
<string name="exclude_visibility">Exclude visibility</string>

View file

@ -309,4 +309,9 @@
<style name="ShapeAppearanceOverlay.Fedilab.ProfileImage.Square" parent="">
<item name="cornerSize">0dp</item>
</style>
<style name="boostQuotePopupWindowAnimation">
<item name="android:windowEnterAnimation">@anim/popup_window_enter</item>
<item name="android:windowExitAnimation">@anim/popup_window_exit</item>
</style>
</resources>

View file

@ -149,12 +149,13 @@
app:key="@string/SET_TRANSLATE_BUTTON"
app:icon="@drawable/ic_baseline_translate_24"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
android:defaultValue="true"
app:iconSpaceReserved="false"
app:key="@string/SET_DISPLAY_QUOTE"
app:singleLineTitle="false"
app:title="@string/set_display_quote_indication" />
<ListPreference
android:entries="@array/set_quote_button_entries"
android:entryValues="@array/set_quote_button_entry_values"
android:title="@string/set_display_quote_indication"
app:icon="@drawable/ic_baseline_format_quote_24"
app:key="@string/SET_QUOTE_BUTTON"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="FEDILAB"
app:dialogTitle="@string/translator"