Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Timeline/Hashtag): show confirmation sheet when muting #520

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,21 @@
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.Snackbar;
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,22 +104,45 @@ 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
new DeleteFilter(filter.get().id).setCallback(new Callback<>(){
@Override
public void onSuccess(Void result){
filter=Optional.empty();
updateMuteState(false);
new Snackbar.Builder(getContext())
.setText(getContext().getString(R.string.unmuted_user_x, '#'+hashtagName))
.show();
}

@Override
Expand All @@ -130,26 +152,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
Loading