feat(Timeline/Hashtag): show confirmation sheet when muting
Shows a MuteHashtagConfirmationSheet when muting a hashtag, similar to the MuteAccountConfirmationSheet. This also adds the option for the mute to expire.
This commit is contained in:
parent
5427b21365
commit
b0f8cbb2e3
5 changed files with 116 additions and 79 deletions
|
@ -11,7 +11,6 @@ import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
@ -32,21 +31,20 @@ import org.joinmastodon.android.model.FilterAction;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
import org.joinmastodon.android.model.FilterKeyword;
|
import org.joinmastodon.android.model.FilterKeyword;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.model.TimelineDefinition;
|
import org.joinmastodon.android.model.TimelineDefinition;
|
||||||
|
import org.joinmastodon.android.ui.sheets.MuteHashtagConfirmationSheet;
|
||||||
import org.joinmastodon.android.ui.text.SpacerSpan;
|
import org.joinmastodon.android.ui.text.SpacerSpan;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.time.Duration;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
|
@ -105,14 +103,33 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
||||||
muteMenuItem.setIcon(newMute ? R.drawable.ic_fluent_speaker_2_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
|
muteMenuItem.setIcon(newMute ? R.drawable.ic_fluent_speaker_2_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMuteDialog(boolean mute) {
|
private void showMuteDialog(boolean currentlyMuted) {
|
||||||
UiUtils.showConfirmationAlert(getContext(),
|
if (currentlyMuted) {
|
||||||
mute ? R.string.mo_unmute_hashtag : R.string.mo_mute_hashtag,
|
unmuteHashtag();
|
||||||
mute ? R.string.mo_confirm_to_unmute_hashtag : R.string.mo_confirm_to_mute_hashtag,
|
return;
|
||||||
mute ? R.string.do_unmute : R.string.do_mute,
|
}
|
||||||
mute ? R.drawable.ic_fluent_speaker_2_28_regular : R.drawable.ic_fluent_speaker_off_28_regular,
|
|
||||||
mute ? this::unmuteHashtag : this::muteHashtag
|
//pass a references, so they can be changed inside the confirmation sheet
|
||||||
);
|
AtomicReference<Duration> muteDuration=new AtomicReference<>(Duration.ZERO);
|
||||||
|
new MuteHashtagConfirmationSheet(getContext(), null, muteDuration, hashtag, (onSuccess, onError)->{
|
||||||
|
FilterKeyword hashtagFilter=new FilterKeyword();
|
||||||
|
hashtagFilter.wholeWord=true;
|
||||||
|
hashtagFilter.keyword="#"+hashtagName;
|
||||||
|
new CreateFilter("#"+hashtagName, EnumSet.of(FilterContext.HOME), FilterAction.HIDE, (int) muteDuration.get().getSeconds(), List.of(hashtagFilter)).setCallback(new Callback<>(){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Filter result){
|
||||||
|
filter=Optional.of(result);
|
||||||
|
updateMuteState(true);
|
||||||
|
onSuccess.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error){
|
||||||
|
error.showToast(getContext());
|
||||||
|
onError.run();
|
||||||
|
}
|
||||||
|
}).exec(accountID);
|
||||||
|
}).show();
|
||||||
}
|
}
|
||||||
private void unmuteHashtag() {
|
private void unmuteHashtag() {
|
||||||
//safe to get, this only called if filter is present
|
//safe to get, this only called if filter is present
|
||||||
|
@ -130,26 +147,6 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
||||||
}).exec(accountID);
|
}).exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void muteHashtag() {
|
|
||||||
FilterKeyword hashtagFilter=new FilterKeyword();
|
|
||||||
hashtagFilter.wholeWord=true;
|
|
||||||
hashtagFilter.keyword="#"+hashtagName;
|
|
||||||
new CreateFilter("#"+hashtagName, EnumSet.of(FilterContext.HOME), FilterAction.HIDE, 0 , List.of(hashtagFilter)).setCallback(new Callback<>(){
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Filter result){
|
|
||||||
filter=Optional.of(result);
|
|
||||||
updateMuteState(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(ErrorResponse error){
|
|
||||||
error.showToast(getContext());
|
|
||||||
}
|
|
||||||
}).exec(accountID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TimelineDefinition makeTimelineDefinition() {
|
protected TimelineDefinition makeTimelineDefinition() {
|
||||||
return TimelineDefinition.ofHashtag(hashtagName);
|
return TimelineDefinition.ofHashtag(hashtagName);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.joinmastodon.android.ui.sheets;
|
package org.joinmastodon.android.ui.sheets;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
@ -15,6 +16,7 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.drawables.EmptyDrawable;
|
import org.joinmastodon.android.ui.drawables.EmptyDrawable;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.AutoOrientationLinearLayout;
|
import org.joinmastodon.android.ui.views.AutoOrientationLinearLayout;
|
||||||
|
@ -23,6 +25,11 @@ import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.BottomSheet;
|
import me.grishka.appkit.views.BottomSheet;
|
||||||
|
|
||||||
|
@ -108,6 +115,51 @@ public abstract class AccountRestrictionConfirmationSheet extends BottomSheet{
|
||||||
addRow(icon, getContext().getString(text));
|
addRow(icon, getContext().getString(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addDurationRow(@NonNull Context context, AtomicReference<Duration> muteDuration) {
|
||||||
|
//Moshidon: add row to choose a duration, e.g. for muting accounts
|
||||||
|
Button muteDurationBtn=new Button(getContext());
|
||||||
|
muteDurationBtn.setOnClickListener(v->getMuteDurationDialog(context, muteDuration, muteDurationBtn).show());
|
||||||
|
muteDurationBtn.setText(R.string.sk_duration_indefinite);
|
||||||
|
addRow(R.drawable.ic_fluent_clock_20_regular, R.string.sk_mute_label, muteDurationBtn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private M3AlertDialogBuilder getMuteDurationDialog(@NonNull Context context, AtomicReference<Duration> muteDuration, Button button){
|
||||||
|
M3AlertDialogBuilder builder=new M3AlertDialogBuilder(context);
|
||||||
|
builder.setTitle(R.string.sk_mute_label);
|
||||||
|
builder.setIcon(R.drawable.ic_fluent_clock_20_regular);
|
||||||
|
List<Duration> durations =List.of(Duration.ZERO,
|
||||||
|
Duration.ofMinutes(5),
|
||||||
|
Duration.ofMinutes(30),
|
||||||
|
Duration.ofHours(1),
|
||||||
|
Duration.ofHours(6),
|
||||||
|
Duration.ofDays(1),
|
||||||
|
Duration.ofDays(3),
|
||||||
|
Duration.ofDays(7),
|
||||||
|
Duration.ofDays(7));
|
||||||
|
|
||||||
|
String[] choices = {context.getString(R.string.sk_duration_indefinite),
|
||||||
|
context.getString(R.string.sk_duration_minutes_5),
|
||||||
|
context.getString(R.string.sk_duration_minutes_30),
|
||||||
|
context.getString(R.string.sk_duration_hours_1),
|
||||||
|
context.getString(R.string.sk_duration_hours_6),
|
||||||
|
context.getString(R.string.sk_duration_days_1),
|
||||||
|
context.getString(R.string.sk_duration_days_3),
|
||||||
|
context.getString(R.string.sk_duration_days_7)};
|
||||||
|
|
||||||
|
builder.setSingleChoiceItems(choices, durations.indexOf(muteDuration.get()), (dialog, which) -> {});
|
||||||
|
|
||||||
|
builder.setPositiveButton(R.string.ok, (dialog, which)->{
|
||||||
|
int selected = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||||
|
muteDuration.set(durations.get(selected));
|
||||||
|
button.setText(choices[selected]);
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(R.string.cancel, null);
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface ConfirmCallback{
|
public interface ConfirmCallback{
|
||||||
void onConfirmed(Runnable onSuccess, Runnable onError);
|
void onConfirmed(Runnable onSuccess, Runnable onError);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
package org.joinmastodon.android.ui.sheets;
|
package org.joinmastodon.android.ui.sheets;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
|
||||||
import org.joinmastodon.android.ui.views.M3Switch;
|
import org.joinmastodon.android.ui.views.M3Switch;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
@ -39,47 +35,6 @@ public class MuteAccountConfirmationSheet extends AccountRestrictionConfirmation
|
||||||
addRow(R.drawable.ic_fluent_alert_off_24_regular, R.string.mo_mute_notifications, m3Switch);
|
addRow(R.drawable.ic_fluent_alert_off_24_regular, R.string.mo_mute_notifications, m3Switch);
|
||||||
|
|
||||||
// add mute duration (Moshidon)
|
// add mute duration (Moshidon)
|
||||||
Button muteDurationBtn=new Button(getContext());
|
addDurationRow(context, muteDuration);
|
||||||
muteDurationBtn.setOnClickListener(v->getMuteDurationDialog(context, muteDuration, muteDurationBtn).show());
|
|
||||||
muteDurationBtn.setText(R.string.sk_duration_indefinite);
|
|
||||||
addRow(R.drawable.ic_fluent_clock_20_regular, R.string.sk_mute_label, muteDurationBtn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private M3AlertDialogBuilder getMuteDurationDialog(@NonNull Context context, AtomicReference<Duration> muteDuration, Button button){
|
|
||||||
M3AlertDialogBuilder builder=new M3AlertDialogBuilder(context);
|
|
||||||
builder.setTitle(R.string.sk_mute_label);
|
|
||||||
builder.setIcon(R.drawable.ic_fluent_clock_20_regular);
|
|
||||||
List<Duration> durations =List.of(Duration.ZERO,
|
|
||||||
Duration.ofMinutes(5),
|
|
||||||
Duration.ofMinutes(30),
|
|
||||||
Duration.ofHours(1),
|
|
||||||
Duration.ofHours(6),
|
|
||||||
Duration.ofDays(1),
|
|
||||||
Duration.ofDays(3),
|
|
||||||
Duration.ofDays(7),
|
|
||||||
Duration.ofDays(7));
|
|
||||||
|
|
||||||
String[] choices = {context.getString(R.string.sk_duration_indefinite),
|
|
||||||
context.getString(R.string.sk_duration_minutes_5),
|
|
||||||
context.getString(R.string.sk_duration_minutes_30),
|
|
||||||
context.getString(R.string.sk_duration_hours_1),
|
|
||||||
context.getString(R.string.sk_duration_hours_6),
|
|
||||||
context.getString(R.string.sk_duration_days_1),
|
|
||||||
context.getString(R.string.sk_duration_days_3),
|
|
||||||
context.getString(R.string.sk_duration_days_7)};
|
|
||||||
|
|
||||||
builder.setSingleChoiceItems(choices, durations.indexOf(muteDuration.get()), (dialog, which) -> {});
|
|
||||||
|
|
||||||
builder.setPositiveButton(R.string.ok, (dialog, which)->{
|
|
||||||
int selected = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
|
||||||
muteDuration.set(durations.get(selected));
|
|
||||||
button.setText(choices[selected]);
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(R.string.cancel, null);
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package org.joinmastodon.android.ui.sheets;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
|
||||||
|
// MOSHIDON
|
||||||
|
public class MuteHashtagConfirmationSheet extends AccountRestrictionConfirmationSheet{
|
||||||
|
public MuteHashtagConfirmationSheet(@NonNull Context context, Account user, AtomicReference<Duration> muteDuration, Hashtag hashtag, ConfirmCallback confirmCallback){
|
||||||
|
super(context, user, confirmCallback);
|
||||||
|
titleView.setText(R.string.mo_mute_hashtag);
|
||||||
|
confirmBtn.setText(R.string.do_mute);
|
||||||
|
secondaryBtn.setVisibility(View.GONE);
|
||||||
|
icon.setImageResource(R.drawable.ic_fluent_speaker_off_24_regular);
|
||||||
|
subtitleView.setText("#"+hashtag.name);
|
||||||
|
addRow(R.drawable.ic_fluent_number_symbol_24_regular, R.string.mo_mute_hashtag_explanation_muted_home);
|
||||||
|
addRow(R.drawable.ic_fluent_eye_off_24_regular, R.string.mo_mute_hashtag_explanation_discreet);
|
||||||
|
addRow(R.drawable.ic_fluent_search_24_regular, R.string.mo_mute_hashtag_explanation_search);
|
||||||
|
addDurationRow(context, muteDuration);
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,9 @@
|
||||||
<string name="mo_confirm_to_mute_conversation">Are you sure you want to mute this conversation?</string>
|
<string name="mo_confirm_to_mute_conversation">Are you sure you want to mute this conversation?</string>
|
||||||
<string name="mo_confirm_to_unmute_conversation">Are you sure you want to unmute this conversation?</string>
|
<string name="mo_confirm_to_unmute_conversation">Are you sure you want to unmute this conversation?</string>
|
||||||
<string name="mo_mute_hashtag">Mute hashtag</string>
|
<string name="mo_mute_hashtag">Mute hashtag</string>
|
||||||
|
<string name="mo_mute_hashtag_explanation_muted_home">You won’t see posts mentioning this hashtag in your Home timeline.</string>
|
||||||
|
<string name="mo_mute_hashtag_explanation_discreet">Others won’t know that you’ve muted this hashtag.</string>
|
||||||
|
<string name="mo_mute_hashtag_explanation_search">You can still find posts with this hashtag on other timelines or through search.</string>
|
||||||
<string name="mo_unmute_hashtag">Unmute hashtag</string>
|
<string name="mo_unmute_hashtag">Unmute hashtag</string>
|
||||||
<string name="mo_confirm_to_mute_hashtag">Are you sure you want to mute this hashtag?</string>
|
<string name="mo_confirm_to_mute_hashtag">Are you sure you want to mute this hashtag?</string>
|
||||||
<string name="mo_confirm_to_unmute_hashtag">Are you sure you want to unmute this hashtag?</string>
|
<string name="mo_confirm_to_unmute_hashtag">Are you sure you want to unmute this hashtag?</string>
|
||||||
|
|
Loading…
Add table
Reference in a new issue