Skip to content

Commit

Permalink
feat(Timeline/Hashtag): show confirmation sheet when muting
Browse files Browse the repository at this point in the history
Shows a MuteHashtagConfirmationSheet when muting a hashtag, similar to
the MuteAccountConfirmationSheet. This also adds the option for the mute
to expire.
  • Loading branch information
FineFindus committed Aug 25, 2024
1 parent 5427b21 commit b0f8cbb
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
Expand All @@ -32,21 +31,20 @@
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.FilterContext;
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.Status;
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.utils.UiUtils;
import org.joinmastodon.android.ui.views.ProgressBarButton;
import org.parceler.Parcels;

import java.util.ArrayList;
import java.time.Duration;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.concurrent.atomic.AtomicReference;

import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
Expand Down Expand Up @@ -105,14 +103,33 @@ private void updateMuteState(boolean newMute) {
muteMenuItem.setIcon(newMute ? R.drawable.ic_fluent_speaker_2_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
}

private void showMuteDialog(boolean mute) {
UiUtils.showConfirmationAlert(getContext(),
mute ? R.string.mo_unmute_hashtag : R.string.mo_mute_hashtag,
mute ? R.string.mo_confirm_to_unmute_hashtag : R.string.mo_confirm_to_mute_hashtag,
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
);
private void showMuteDialog(boolean currentlyMuted) {
if (currentlyMuted) {
unmuteHashtag();
return;
}

//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() {
//safe to get, this only called if filter is present
Expand All @@ -130,26 +147,6 @@ public void onError(ErrorResponse error){
}).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
protected TimelineDefinition makeTimelineDefinition() {
return TimelineDefinition.ofHashtag(hashtagName);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.joinmastodon.android.ui.sheets;

import android.app.AlertDialog;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.ColorDrawable;
Expand All @@ -15,6 +16,7 @@

import org.joinmastodon.android.R;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.drawables.EmptyDrawable;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.AutoOrientationLinearLayout;
Expand All @@ -23,6 +25,11 @@
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
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.views.BottomSheet;

Expand Down Expand Up @@ -108,6 +115,51 @@ protected void addRow(@DrawableRes int icon, @StringRes int 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{
void onConfirmed(Runnable onSuccess, Runnable onError);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package org.joinmastodon.android.ui.sheets;

import android.app.AlertDialog;
import android.content.Context;
import android.view.View;
import android.widget.Button;

import org.joinmastodon.android.R;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.views.M3Switch;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

Expand Down Expand Up @@ -39,47 +35,6 @@ public MuteAccountConfirmationSheet(@NonNull Context context, Account user, Atom
addRow(R.drawable.ic_fluent_alert_off_24_regular, R.string.mo_mute_notifications, m3Switch);

// add mute duration (Moshidon)
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);
addDurationRow(context, muteDuration);
}

@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;
}


}
Original file line number Diff line number Diff line change
@@ -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);
}
}
3 changes: 3 additions & 0 deletions mastodon/src/main/res/values/strings_mo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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_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_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_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>
Expand Down

0 comments on commit b0f8cbb

Please sign in to comment.