Merge pull request #399 from FineFindus/fix/apply-filter-highlight
fix: apply filter highlight
This commit is contained in:
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,6 +21,7 @@ import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
|||||||
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
|
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
|
||||||
import org.joinmastodon.android.events.NotificationsMarkerUpdatedEvent;
|
import org.joinmastodon.android.events.NotificationsMarkerUpdatedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.AltTextFilter;
|
||||||
import org.joinmastodon.android.model.Application;
|
import org.joinmastodon.android.model.Application;
|
||||||
import org.joinmastodon.android.model.FilterAction;
|
import org.joinmastodon.android.model.FilterAction;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
@@ -37,6 +38,7 @@ import org.joinmastodon.android.utils.ObjectIdComparator;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -314,7 +316,7 @@ public class AccountSession{
|
|||||||
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
|
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
|
||||||
if(getLocalPreferences().serverSideFiltersSupported){
|
if(getLocalPreferences().serverSideFiltersSupported){
|
||||||
for(FilterResult filter : s.filtered){
|
for(FilterResult filter : s.filtered){
|
||||||
if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE)
|
if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE && filter.filter.context.contains(context))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}else if(wordFilters!=null){
|
}else if(wordFilters!=null){
|
||||||
@@ -326,6 +328,21 @@ public class AccountSession{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<FilterResult> getClientSideFilters(Status status) {
|
||||||
|
List<FilterResult> filters = List.of();
|
||||||
|
|
||||||
|
// filter post 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);
|
||||||
|
}
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
public void updateAccountInfo(){
|
public void updateAccountInfo(){
|
||||||
AccountSessionManager.getInstance().updateSessionLocalInfo(this);
|
AccountSessionManager.getInstance().updateSessionLocalInfo(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -82,7 +80,7 @@ public class CustomLocalTimelineFragment extends PinnableStatusListFragment impl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FilterContext getFilterContext() {
|
protected FilterContext getFilterContext() {
|
||||||
return null;
|
return FilterContext.PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,9 @@ import org.joinmastodon.android.fragments.ThreadFragment;
|
|||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
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.LegacyFilter;
|
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
import org.joinmastodon.android.model.FilterResult;
|
import org.joinmastodon.android.model.FilterResult;
|
||||||
|
import org.joinmastodon.android.model.LegacyFilter;
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.Poll;
|
import org.joinmastodon.android.model.Poll;
|
||||||
import org.joinmastodon.android.model.ScheduledStatus;
|
import org.joinmastodon.android.model.ScheduledStatus;
|
||||||
@@ -40,7 +39,6 @@ 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;
|
||||||
@@ -168,10 +166,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 +227,16 @@ 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;
|
||||||
|
filters.addAll(AccountSessionManager.get(accountID).getClientSideFilters(status));
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -273,8 +263,9 @@ public abstract class StatusDisplayItem{
|
|||||||
boolean hasSpoiler=!TextUtils.isEmpty(statusForContent.spoilerText);
|
boolean hasSpoiler=!TextUtils.isEmpty(statusForContent.spoilerText);
|
||||||
if(!TextUtils.isEmpty(statusForContent.content)){
|
if(!TextUtils.isEmpty(statusForContent.content)){
|
||||||
SpannableStringBuilder parsedText=HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID, fragment.getContext());
|
SpannableStringBuilder parsedText=HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID, fragment.getContext());
|
||||||
|
if(applyingFilter!=null)
|
||||||
HtmlParser.applyFilterHighlights(fragment.getActivity(), parsedText, status.filtered);
|
HtmlParser.applyFilterHighlights(fragment.getActivity(), parsedText, status.filtered);
|
||||||
TextStatusDisplayItem text=new TextStatusDisplayItem(parentID, HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID, fragment.getContext()), fragment, statusForContent, (flags & FLAG_NO_TRANSLATE) != 0);
|
TextStatusDisplayItem text=new TextStatusDisplayItem(parentID, parsedText, fragment, statusForContent, (flags & FLAG_NO_TRANSLATE) != 0);
|
||||||
contentItems.add(text);
|
contentItems.add(text);
|
||||||
}else if(!hasSpoiler && header!=null){
|
}else if(!hasSpoiler && header!=null){
|
||||||
header.needBottomPadding=true;
|
header.needBottomPadding=true;
|
||||||
|
|||||||
@@ -321,12 +321,11 @@ public class HtmlParser{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void applyFilterHighlights(Context context, SpannableStringBuilder text, List<FilterResult> filters){
|
public static void applyFilterHighlights(Context context, SpannableStringBuilder text, List<FilterResult> filters){
|
||||||
if (filters == null) return;
|
|
||||||
int fgColor=UiUtils.getThemeColor(context, R.attr.colorM3Error);
|
int fgColor=UiUtils.getThemeColor(context, R.attr.colorM3Error);
|
||||||
int bgColor=UiUtils.getThemeColor(context, R.attr.colorM3ErrorContainer);
|
int bgColor=UiUtils.getThemeColor(context, R.attr.colorM3ErrorContainer);
|
||||||
for(FilterResult filter:filters){
|
for(FilterResult filter:filters){
|
||||||
if(!filter.filter.isActive())
|
if(!filter.filter.isActive())
|
||||||
continue;;
|
continue;
|
||||||
for(String word:filter.keywordMatches){
|
for(String word:filter.keywordMatches){
|
||||||
Matcher matcher=Pattern.compile("\\b"+Pattern.quote(word)+"\\b", Pattern.CASE_INSENSITIVE).matcher(text);
|
Matcher matcher=Pattern.compile("\\b"+Pattern.quote(word)+"\\b", Pattern.CASE_INSENSITIVE).matcher(text);
|
||||||
while(matcher.find()){
|
while(matcher.find()){
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user