Add options to confirm reblog/unreblog actions, close #460 (#1650)

This commit is contained in:
Ivan Kupalov 2020-03-03 21:27:26 +01:00 committed by GitHub
parent 0c159e587d
commit 67c20326f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 71 additions and 20 deletions

View File

@ -155,7 +155,7 @@ dependencies {
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
implementation "com.github.connyduck:sparkbutton:3.0.0"
implementation "com.github.connyduck:sparkbutton:4.0.0"
implementation "com.github.chrisbanes:PhotoView:2.3.0"

View File

@ -129,7 +129,7 @@ class PreferencesActivity : BaseActivity(), SharedPreferences.OnSharedPreference
}
"statusTextSize", "absoluteTimeView", "showBotOverlay", "animateGifAvatars",
"useBlurhash", "showCardsInTimelines" -> {
"useBlurhash", "showCardsInTimelines", "confirmReblogs" -> {
restartActivitiesOnExit = true
}
"language" -> {

View File

@ -232,7 +232,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
statusDisplayOptions.useAbsoluteTime(),
statusDisplayOptions.showBotOverlay(),
statusDisplayOptions.useBlurhash(),
CardViewMode.NONE
CardViewMode.NONE,
statusDisplayOptions.confirmReblogs()
);
}

View File

@ -19,6 +19,7 @@ import android.widget.Toast;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -610,7 +611,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
sensitiveMediaShow.setVisibility(View.GONE);
}
protected void setupButtons(final StatusActionListener listener, final String accountId) {
protected void setupButtons(final StatusActionListener listener, final String accountId,
final String statusContent,
StatusDisplayOptions statusDisplayOptions) {
avatar.setOnClickListener(v -> listener.onViewAccount(accountId));
replyButton.setOnClickListener(v -> {
@ -623,7 +626,13 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
reblogButton.setEventListener((button, buttonState) -> {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onReblog(buttonState, position);
listener.onReblog(!buttonState, position);
}
if (statusDisplayOptions.confirmReblogs()) {
showConfirmReblogDialog(listener, statusContent, buttonState, position);
return false;
} else {
return true;
}
});
}
@ -631,15 +640,17 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
favouriteButton.setEventListener((button, buttonState) -> {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onFavourite(buttonState, position);
listener.onFavourite(!buttonState, position);
}
return true;
});
bookmarkButton.setEventListener((button, buttonState) -> {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onBookmark(buttonState, position);
listener.onBookmark(!buttonState, position);
}
return true;
});
moreButton.setOnClickListener(v -> {
@ -662,6 +673,23 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
itemView.setOnClickListener(viewThreadListener);
}
private void showConfirmReblogDialog(StatusActionListener listener,
String statusContent,
boolean buttonState,
int position) {
int okButtonTextId = buttonState ? R.string.action_unreblog : R.string.action_reblog;
new AlertDialog.Builder(reblogButton.getContext())
.setMessage(statusContent)
.setPositiveButton(okButtonTextId, (__, ___) -> {
listener.onReblog(!buttonState, position);
if (!buttonState) {
// Play animation only when it's reblog, not unreblog
reblogButton.playAnimation();
}
})
.show();
}
public void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
StatusDisplayOptions statusDisplayOptions) {
this.setupWithStatus(status, listener, statusDisplayOptions, null);
@ -706,7 +734,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
setupCard(status, statusDisplayOptions.cardViewMode());
}
setupButtons(listener, status.getSenderId());
setupButtons(listener, status.getSenderId(), status.getContent().toString(),
statusDisplayOptions);
setRebloggingEnabled(status.getRebloggingEnabled(), status.getVisibility());
setSpoilerAndContent(status.isExpanded(), status.getContent(), status.getSpoilerText(), status.getMentions(), status.getStatusEmojis(), status.getPoll(), statusDisplayOptions, listener);

View File

@ -64,7 +64,8 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
statusDisplayOptions.useAbsoluteTime(),
statusDisplayOptions.showBotOverlay(),
statusDisplayOptions.useBlurhash(),
statusDisplayOptions.cardViewMode()
statusDisplayOptions.cardViewMode(),
statusDisplayOptions.confirmReblogs()
);
}

View File

@ -104,7 +104,8 @@ public class ConversationViewHolder extends StatusBaseViewHolder {
hideSensitiveMediaWarning();
}
setupButtons(listener, account.getId());
setupButtons(listener, account.getId(), status.getContent().toString(),
statusDisplayOptions);
setSpoilerAndContent(status.getExpanded(), status.getContent(), status.getSpoilerText(),
status.getMentions(), status.getEmojis(),

View File

@ -66,7 +66,8 @@ class ConversationsFragment : SFragment(), StatusActionListener, Injectable, Res
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
showBotOverlay = preferences.getBoolean("showBotOverlay", true),
useBlurhash = preferences.getBoolean("useBlurhash", true),
cardViewMode = CardViewMode.NONE
cardViewMode = CardViewMode.NONE,
confirmReblogs = preferences.getBoolean("confirmReblogs", true)
)

View File

@ -117,7 +117,8 @@ class ReportStatusesFragment : Fragment(), Injectable, AdapterHandler {
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
showBotOverlay = false,
useBlurhash = preferences.getBoolean("useBlurhash", true),
cardViewMode = CardViewMode.NONE
cardViewMode = CardViewMode.NONE,
confirmReblogs = preferences.getBoolean("confirmReblogs", true)
)
adapter = StatusesAdapter(statusDisplayOptions,

View File

@ -81,7 +81,8 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
showBotOverlay = preferences.getBoolean("showBotOverlay", true),
useBlurhash = preferences.getBoolean("useBlurhash", true),
cardViewMode = CardViewMode.NONE
cardViewMode = CardViewMode.NONE,
confirmReblogs = preferences.getBoolean("confirmReblogs", true)
)
searchRecyclerView.addItemDecoration(DividerItemDecoration(searchRecyclerView.context, DividerItemDecoration.VERTICAL))

View File

@ -246,7 +246,8 @@ public class NotificationsFragment extends SFragment implements
preferences.getBoolean("absoluteTimeView", false),
preferences.getBoolean("showBotOverlay", true),
preferences.getBoolean("useBlurhash", true),
CardViewMode.NONE
CardViewMode.NONE,
preferences.getBoolean("confirmReblogs", true)
);
adapter = new NotificationsAdapter(accountManager.getActiveAccount().getAccountId(),

View File

@ -230,7 +230,8 @@ public class TimelineFragment extends SFragment implements
preferences.getBoolean("useBlurhash", true),
preferences.getBoolean("showCardsInTimelines", false) ?
CardViewMode.INDENTED :
CardViewMode.NONE
CardViewMode.NONE,
preferences.getBoolean("confirmReblogs", true)
);
adapter = new TimelineAdapter(dataSource, statusDisplayOptions, this);
@ -580,6 +581,10 @@ public class TimelineFragment extends SFragment implements
@Override
public void onReblog(final boolean reblog, final int position) {
final Status status = statuses.get(position).asRight();
doReblog(reblog, position, status);
}
private void doReblog(boolean reblog, int position, Status status) {
timelineCases.reblog(status, reblog)
.observeOn(AndroidSchedulers.mainThread())
.as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY)))

View File

@ -135,7 +135,8 @@ public final class ViewThreadFragment extends SFragment implements
preferences.getBoolean("useBlurhash", true),
preferences.getBoolean("showCardsInTimelines", false) ?
CardViewMode.INDENTED :
CardViewMode.NONE
CardViewMode.NONE,
preferences.getBoolean("confirmReblogs", true)
);
adapter = new ThreadAdapter(statusDisplayOptions, this);
}

View File

@ -12,5 +12,7 @@ data class StatusDisplayOptions(
@get:JvmName("useBlurhash")
val useBlurhash: Boolean,
@get:JvmName("cardViewMode")
val cardViewMode: CardViewMode
val cardViewMode: CardViewMode,
@get:JvmName("confirmReblogs")
val confirmReblogs: Boolean
)

View File

@ -549,5 +549,6 @@
<string name="no_scheduled_status">You don\'t have any scheduled statuses.</string>
<string name="warning_scheduling_interval">Mastodon has a minimum scheduling interval of 5 minutes.</string>
<string name="pref_title_show_cards_in_timelines">Show link previews in timelines</string>
<string name="pref_title_confirm_reblogs">Show confirmation dialog before boosting</string>
</resources>

View File

@ -78,6 +78,12 @@
android:title="@string/pref_title_show_cards_in_timelines"
app:singleLineTitle="false" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="confirmReblogs"
android:title="@string/pref_title_confirm_reblogs"
app:singleLineTitle="false" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_title_browser_settings">