refactor: remove StatusFilterPredicate
Removes the deprecated StatusFilterPredicate class, as it has been replaced upstream. Client-side filters are now directly applied in the when building a StatusDisplayItem.
This commit is contained in:
parent
00726abec1
commit
28c851a630
|
@ -1,104 +0,0 @@
|
||||||
package org.joinmastodon.android.utils;
|
|
||||||
|
|
||||||
import static org.joinmastodon.android.model.FilterAction.*;
|
|
||||||
import static org.joinmastodon.android.model.FilterContext.*;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.model.Attachment;
|
|
||||||
import org.joinmastodon.android.model.LegacyFilter;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class StatusFilterPredicateTest {
|
|
||||||
|
|
||||||
private static final LegacyFilter hideMeFilter = new LegacyFilter(), warnMeFilter = new LegacyFilter();
|
|
||||||
private static final List<LegacyFilter> allFilters = List.of(hideMeFilter, warnMeFilter);
|
|
||||||
|
|
||||||
private static final Status
|
|
||||||
hideInHomePublic = Status.ofFake(null, "hide me, please", Instant.now()),
|
|
||||||
warnInHomePublic = Status.ofFake(null, "display me with a warning", Instant.now()),
|
|
||||||
noAltText = Status.ofFake(null, "display me with a warning", Instant.now()),
|
|
||||||
withAltText = Status.ofFake(null, "display me with a warning", Instant.now());
|
|
||||||
|
|
||||||
static {
|
|
||||||
hideMeFilter.phrase = "hide me";
|
|
||||||
hideMeFilter.filterAction = HIDE;
|
|
||||||
hideMeFilter.context = EnumSet.of(PUBLIC, HOME);
|
|
||||||
|
|
||||||
warnMeFilter.phrase = "warning";
|
|
||||||
warnMeFilter.filterAction = WARN;
|
|
||||||
warnMeFilter.context = EnumSet.of(PUBLIC, HOME);
|
|
||||||
|
|
||||||
// noAltText.mediaAttachments = Attachment.createFakeAttachments("fakeurl", new ColorDrawable());
|
|
||||||
// withAltText.mediaAttachments = Attachment.createFakeAttachments("fakeurl", new ColorDrawable());
|
|
||||||
// for (Attachment mediaAttachment : withAltText.mediaAttachments) {
|
|
||||||
// mediaAttachment.description = "Alt Text";
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHide() {
|
|
||||||
assertFalse("should not pass because matching filter applies to given context",
|
|
||||||
new StatusFilterPredicate(allFilters, HOME).test(hideInHomePublic));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHideRegardlessOfContext() {
|
|
||||||
assertTrue("filters without context should always pass",
|
|
||||||
new StatusFilterPredicate(allFilters, null).test(hideInHomePublic));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHideInDifferentContext() {
|
|
||||||
assertTrue("should pass because matching filter does not apply to given context",
|
|
||||||
new StatusFilterPredicate(allFilters, THREAD).test(hideInHomePublic));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHideWithWarningText() {
|
|
||||||
assertTrue("should pass because matching filter is for warnings",
|
|
||||||
new StatusFilterPredicate(allFilters, HOME).test(warnInHomePublic));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWarn() {
|
|
||||||
assertFalse("should not pass because filter applies to given context",
|
|
||||||
new StatusFilterPredicate(allFilters, HOME, WARN).test(warnInHomePublic));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWarnRegardlessOfContext() {
|
|
||||||
assertTrue("filters without context should always pass",
|
|
||||||
new StatusFilterPredicate(allFilters, null, WARN).test(warnInHomePublic));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWarnInDifferentContext() {
|
|
||||||
assertTrue("should pass because filter does not apply to given context",
|
|
||||||
new StatusFilterPredicate(allFilters, THREAD, WARN).test(warnInHomePublic));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWarnWithHideText() {
|
|
||||||
assertTrue("should pass because matching filter is for hiding",
|
|
||||||
new StatusFilterPredicate(allFilters, HOME, WARN).test(hideInHomePublic));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAltTextFilterNoPass() {
|
|
||||||
assertFalse("should not pass because of no alt text",
|
|
||||||
new StatusFilterPredicate(allFilters, HOME).test(noAltText));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAltTextFilterPass() {
|
|
||||||
assertTrue("should pass because of alt text",
|
|
||||||
new StatusFilterPredicate(allFilters, HOME).test(withAltText));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,16 +7,14 @@ import android.view.MenuInflater;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
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.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
|
@ -53,7 +51,7 @@ public class CustomLocalTimelineFragment extends PinnableStatusListFragment impl
|
||||||
if(!result.isEmpty())
|
if(!result.isEmpty())
|
||||||
maxID=result.get(result.size()-1).id;
|
maxID=result.get(result.size()-1).id;
|
||||||
if (getActivity() == null) return;
|
if (getActivity() == null) return;
|
||||||
result=result.stream().filter(new StatusFilterPredicate(accountID, FilterContext.PUBLIC)).collect(Collectors.toList());
|
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.PUBLIC);
|
||||||
result.stream().forEach(status -> {
|
result.stream().forEach(status -> {
|
||||||
status.account.acct += "@"+domain;
|
status.account.acct += "@"+domain;
|
||||||
status.mentions.forEach(mention -> mention.id = null);
|
status.mentions.forEach(mention -> mention.id = null);
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
package org.joinmastodon.android.model;
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.jsoup.internal.StringUtil;
|
import org.jsoup.internal.StringUtil;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
public class AltTextFilter extends LegacyFilter {
|
public class AltTextFilter extends LegacyFilter {
|
||||||
|
|
||||||
public AltTextFilter(FilterAction filterAction, FilterContext firstContext, FilterContext... restContexts) {
|
public AltTextFilter(FilterAction filterAction, EnumSet<FilterContext> filterContexts) {
|
||||||
this.filterAction = filterAction;
|
this.filterAction = filterAction;
|
||||||
isRemote = false;
|
isRemote = false;
|
||||||
context = EnumSet.of(firstContext, restContexts);
|
context = filterContexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Status status) {
|
public boolean matches(Status status) {
|
||||||
return status.getContentStatus().mediaAttachments.stream().map(attachment -> attachment.description).anyMatch(StringUtil::isBlank);
|
return status.getContentStatus().mediaAttachments.stream().map(attachment -> attachment.description).anyMatch(StringUtil::isBlank);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive(){
|
||||||
|
return !GlobalUserPreferences.showPostsWithoutAlt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.fragments.StatusListFragment;
|
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.AltTextFilter;
|
||||||
import org.joinmastodon.android.model.Attachment;
|
import org.joinmastodon.android.model.Attachment;
|
||||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||||
import org.joinmastodon.android.model.FilterAction;
|
import org.joinmastodon.android.model.FilterAction;
|
||||||
|
@ -40,11 +41,11 @@ import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
|
import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -168,10 +169,6 @@ public abstract class StatusDisplayItem{
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
ScheduledStatus scheduledStatus = parentObject instanceof ScheduledStatus s ? s : null;
|
ScheduledStatus scheduledStatus = parentObject instanceof ScheduledStatus s ? s : null;
|
||||||
|
|
||||||
// Hide statuses that have a filter action of hide
|
|
||||||
if(!new StatusFilterPredicate(accountID, filterContext, FilterAction.HIDE).test(status))
|
|
||||||
return new ArrayList<StatusDisplayItem>() ;
|
|
||||||
|
|
||||||
HeaderStatusDisplayItem header=null;
|
HeaderStatusDisplayItem header=null;
|
||||||
boolean hideCounts=!AccountSessionManager.get(accountID).getLocalPreferences().showInteractionCounts;
|
boolean hideCounts=!AccountSessionManager.get(accountID).getLocalPreferences().showInteractionCounts;
|
||||||
|
|
||||||
|
@ -233,20 +230,25 @@ public abstract class StatusDisplayItem{
|
||||||
|
|
||||||
LegacyFilter applyingFilter=null;
|
LegacyFilter applyingFilter=null;
|
||||||
if(status.filtered!=null){
|
if(status.filtered!=null){
|
||||||
for(FilterResult filter:status.filtered){
|
List<FilterResult> filters = status.filtered;
|
||||||
|
|
||||||
|
//add a client side filter to filter posts that have no alt text
|
||||||
|
//it only applies when activated in the settings
|
||||||
|
AltTextFilter altTextFilter=new AltTextFilter(FilterAction.WARN, EnumSet.allOf(FilterContext.class));
|
||||||
|
if(altTextFilter.matches(status)){
|
||||||
|
FilterResult filterResult=new FilterResult();
|
||||||
|
filterResult.filter=altTextFilter;
|
||||||
|
filterResult.keywordMatches=List.of();
|
||||||
|
filters.add(filterResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(FilterResult filter:filters){
|
||||||
LegacyFilter f=filter.filter;
|
LegacyFilter f=filter.filter;
|
||||||
if(f.isActive() && filterContext != null && f.context.contains(filterContext)){
|
if(f.isActive() && filterContext != null && f.context.contains(filterContext)){
|
||||||
applyingFilter=f;
|
applyingFilter=f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Moshidon
|
|
||||||
if(applyingFilter==null){
|
|
||||||
StatusFilterPredicate predicate = new StatusFilterPredicate(accountID, filterContext, FilterAction.WARN);
|
|
||||||
predicate.test(status);
|
|
||||||
applyingFilter = predicate.getApplyingFilter();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<StatusDisplayItem> contentItems;
|
ArrayList<StatusDisplayItem> contentItems;
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
package org.joinmastodon.android.utils;
|
|
||||||
|
|
||||||
import static org.joinmastodon.android.model.FilterAction.HIDE;
|
|
||||||
import static org.joinmastodon.android.model.FilterAction.WARN;
|
|
||||||
import static org.joinmastodon.android.model.FilterContext.ACCOUNT;
|
|
||||||
import static org.joinmastodon.android.model.FilterContext.HOME;
|
|
||||||
import static org.joinmastodon.android.model.FilterContext.NOTIFICATIONS;
|
|
||||||
import static org.joinmastodon.android.model.FilterContext.PUBLIC;
|
|
||||||
import static org.joinmastodon.android.model.FilterContext.THREAD;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
|
||||||
import org.joinmastodon.android.model.AltTextFilter;
|
|
||||||
import org.joinmastodon.android.model.LegacyFilter;
|
|
||||||
import org.joinmastodon.android.model.FilterAction;
|
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
// TODO: This whole class has been ditched upstream. I plan to eventually refactor it to only have the still relevant clientFilters code
|
|
||||||
|
|
||||||
public class StatusFilterPredicate implements Predicate<Status>{
|
|
||||||
private final List<LegacyFilter> clientFilters;
|
|
||||||
private final List<LegacyFilter> filters;
|
|
||||||
private final FilterContext context;
|
|
||||||
private final FilterAction action;
|
|
||||||
private LegacyFilter applyingFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context null makes the predicate pass automatically
|
|
||||||
* @param action defines what the predicate should check:
|
|
||||||
* status should not be hidden or should not display with warning
|
|
||||||
*/
|
|
||||||
public StatusFilterPredicate(List<LegacyFilter> filters, FilterContext context, FilterAction action){
|
|
||||||
this.filters = filters;
|
|
||||||
this.context = context;
|
|
||||||
this.action = action;
|
|
||||||
this.clientFilters = getClientFilters();
|
|
||||||
}
|
|
||||||
|
|
||||||
public StatusFilterPredicate(List<LegacyFilter> filters, FilterContext context){
|
|
||||||
this(filters, context, HIDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context null makes the predicate pass automatically
|
|
||||||
* @param action defines what the predicate should check:
|
|
||||||
* status should not be hidden or should not display with warning
|
|
||||||
*/
|
|
||||||
public StatusFilterPredicate(String accountID, FilterContext context, FilterAction action){
|
|
||||||
filters=AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream().filter(f->f.context.contains(context)).collect(Collectors.toList());
|
|
||||||
this.context = context;
|
|
||||||
this.action = action;
|
|
||||||
this.clientFilters = getClientFilters();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<LegacyFilter> getClientFilters() {
|
|
||||||
List<LegacyFilter> filters = new ArrayList<>();
|
|
||||||
if(!GlobalUserPreferences.showPostsWithoutAlt) {
|
|
||||||
filters.add(new AltTextFilter(WARN, HOME, PUBLIC, ACCOUNT, THREAD, NOTIFICATIONS));
|
|
||||||
}
|
|
||||||
return filters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context null makes the predicate pass automatically
|
|
||||||
*/
|
|
||||||
public StatusFilterPredicate(String accountID, FilterContext context){
|
|
||||||
this(accountID, context, HIDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return whether the status should be displayed without being hidden/warned about.
|
|
||||||
* will always return true if the context is null.
|
|
||||||
* true = display this status,
|
|
||||||
* false = filter this status
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean test(Status status){
|
|
||||||
if (context == null) return true;
|
|
||||||
|
|
||||||
Stream<LegacyFilter> matchingFilters = status.filtered != null
|
|
||||||
// use server-provided per-status info (status.filtered) if available
|
|
||||||
? status.filtered.stream().map(f -> f.filter)
|
|
||||||
// or fall back to cached filters
|
|
||||||
: filters.stream().filter(filter -> filter.matches(status));
|
|
||||||
|
|
||||||
Optional<LegacyFilter> applyingFilter = matchingFilters
|
|
||||||
// discard expired filters
|
|
||||||
.filter(filter -> filter.expiresAt == null || filter.expiresAt.isAfter(Instant.now()))
|
|
||||||
// only apply filters for given context
|
|
||||||
.filter(filter -> filter.context.contains(context))
|
|
||||||
// treating filterAction = null (from filters list) as FilterAction.HIDE
|
|
||||||
.filter(filter -> filter.filterAction == null ? action == HIDE : filter.filterAction == action)
|
|
||||||
.findAny();
|
|
||||||
|
|
||||||
//Apply client filters if no server filter is triggered
|
|
||||||
if (applyingFilter.isEmpty() && !clientFilters.isEmpty()) {
|
|
||||||
applyingFilter = clientFilters.stream()
|
|
||||||
.filter(filter -> filter.context.contains(context))
|
|
||||||
.filter(filter -> filter.filterAction == null ? action == HIDE : filter.filterAction == action)
|
|
||||||
.filter(filter -> filter.matches(status))
|
|
||||||
.findAny();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.applyingFilter = applyingFilter.orElse(null);
|
|
||||||
return applyingFilter.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LegacyFilter getApplyingFilter() {
|
|
||||||
return applyingFilter;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue