Loading app/src/main/java/app/fedilab/android/helper/TimelineHelper.java +22 −10 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.endpoints.MastodonFiltersService; import app.fedilab.android.client.entities.api.Filter; import app.fedilab.android.client.entities.api.Notification; Loading Loading @@ -99,11 +100,10 @@ public class TimelineHelper { //Expired filter continue; } if (filterTimeLineType == Timeline.TimeLineEnum.HOME) { if (!filter.context.contains("home")) continue; } else if (filterTimeLineType == Timeline.TimeLineEnum.NOTIFICATION) { if (!filter.context.contains("notification")) continue; if (!filter.context.contains("notifications")) continue; } else if (filterTimeLineType == Timeline.TimeLineEnum.CONTEXT) { if (!filter.context.contains("thread")) continue; } else if (filterTimeLineType == Timeline.TimeLineEnum.ACCOUNT_TIMELINE) { Loading @@ -113,15 +113,18 @@ public class TimelineHelper { } if (filter.keywords != null && filter.keywords.size() > 0) { for (Filter.KeywordsAttributes filterKeyword : filter.keywords) { String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).matches() ? "\\b" : ""; String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).matches() ? "\\b" : ""; String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).find() ? "\\b" : ""; String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).find() ? "\\b" : ""; Pattern p; if (filterKeyword.whole_word) { p = Pattern.compile(sb + "(" + Pattern.quote(filterKeyword.keyword) + ")" + eb, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); p = Pattern.compile(sb + "(" + Pattern.quote(filterKeyword.keyword) + ")" + eb, Pattern.CASE_INSENSITIVE); } else { p = Pattern.compile("#" + Pattern.quote(filterKeyword.keyword), Pattern.CASE_INSENSITIVE); } for (Status status : statuses) { if (status.account.id.equals(MainActivity.currentUserID)) { continue; } String content; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) content = Html.fromHtml(status.reblog != null ? status.reblog.content : status.content, Html.FROM_HTML_MODE_LEGACY).toString(); Loading @@ -129,6 +132,7 @@ public class TimelineHelper { content = Html.fromHtml(status.reblog != null ? status.reblog.content : status.content).toString(); Matcher m = p.matcher(content); if (m.find()) { if (filter.filter_action.equalsIgnoreCase("warn")) { status.filteredByApp = filter; } else { Loading Loading @@ -170,9 +174,10 @@ public class TimelineHelper { * @param notifications - List of {@link Notification} * @return filtered List<Status> */ public static List<Notification> filterNotification(Context context, List<Notification> notifications, boolean cached) { public static List<Notification> filterNotification(Context context, List<Notification> notifications) { //A security to make sure filters have been fetched before displaying messages List<Notification> notificationToRemove = new ArrayList<>(); if (!BaseMainActivity.filterFetched) { try { FiltersVM filtersVM = new ViewModelProvider((ViewModelStoreOwner) context).get(FiltersVM.class); Loading @@ -189,25 +194,32 @@ public class TimelineHelper { //Loop through filters for (Filter filter : BaseMainActivity.mainFilters) { if (filter.expires_at != null && filter.expires_at.before(new Date())) { //Expired filter continue; } if (!filter.context.contains("notification")) continue; if (!filter.context.contains("notifications")) continue; if (filter.keywords != null && filter.keywords.size() > 0) { for (Filter.KeywordsAttributes filterKeyword : filter.keywords) { String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).matches() ? "\\b" : ""; String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).matches() ? "\\b" : ""; String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).find() ? "\\b" : ""; String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).find() ? "\\b" : ""; Pattern p; if (filterKeyword.whole_word) { p = Pattern.compile(sb + "(" + Pattern.quote(filterKeyword.keyword) + ")" + eb, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); p = Pattern.compile(sb + "(" + Pattern.quote(filterKeyword.keyword) + ")" + eb, Pattern.CASE_INSENSITIVE); } else { p = Pattern.compile("#" + Pattern.quote(filterKeyword.keyword), Pattern.CASE_INSENSITIVE); } for (Notification notification : notifications) { if (notification.status == null) { continue; } if (notification.status.account.id.equals(MainActivity.currentUserID)) { continue; } String content; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) content = Html.fromHtml(notification.status.reblog != null ? notification.status.reblog.content : notification.status.content, Html.FROM_HTML_MODE_LEGACY).toString(); Loading app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java +16 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import app.fedilab.android.activities.ProfileActivity; import app.fedilab.android.client.entities.api.Notification; import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.databinding.DrawerFollowBinding; import app.fedilab.android.databinding.DrawerStatusFilteredBinding; import app.fedilab.android.databinding.DrawerStatusNotificationBinding; import app.fedilab.android.databinding.NotificationsRelatedAccountsBinding; import app.fedilab.android.helper.Helper; Loading @@ -65,6 +66,7 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH private final int TYPE_STATUS = 6; private final int TYPE_REACTION = 8; private final int TYPE_UPDATE = 9; private final int TYPE_FILERED = 10; public FetchMoreCallBack fetchMoreCallBack; private Context context; Loading @@ -82,6 +84,10 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH @Override public int getItemViewType(int position) { if (notificationList.get(position).filteredByApp != null) { return TYPE_FILERED; } String type = notificationList.get(position).type; if (type != null) { switch (type) { Loading Loading @@ -115,6 +121,9 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH if (viewType == TYPE_FOLLOW || viewType == TYPE_FOLLOW_REQUEST) { DrawerFollowBinding itemBinding = DrawerFollowBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new ViewHolderFollow(itemBinding); } else if (viewType == TYPE_FILERED) { DrawerStatusFilteredBinding itemBinding = DrawerStatusFilteredBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new StatusAdapter.StatusViewHolder(itemBinding); } else { DrawerStatusNotificationBinding itemBinding = DrawerStatusNotificationBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new StatusAdapter.StatusViewHolder(itemBinding); Loading Loading @@ -218,6 +227,13 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH } else { holderFollow.binding.cacheIndicator.setVisibility(View.GONE); } } else if (getItemViewType(position) == TYPE_FILERED) { StatusAdapter.StatusViewHolder holder = (StatusAdapter.StatusViewHolder) viewHolder; holder.bindingFiltered.filteredText.setText(context.getString(R.string.filtered_by, notification.filteredByApp.title)); holder.bindingFiltered.displayButton.setOnClickListener(v -> { notification.filteredByApp = null; notifyItemChanged(position); }); } else { StatusAdapter.StatusViewHolder holderStatus = (StatusAdapter.StatusViewHolder) viewHolder; holderStatus.bindingNotification.status.typeOfNotification.setVisibility(View.VISIBLE); Loading app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java +2 −2 Original line number Diff line number Diff line Loading @@ -111,7 +111,7 @@ public class NotificationsVM extends AndroidViewModel { Response<List<Notification>> notificationsResponse = notificationsCall.execute(); if (notificationsResponse.isSuccessful()) { List<Notification> notFiltered = notificationsResponse.body(); notifications.notifications = TimelineHelper.filterNotification(getApplication().getApplicationContext(), notFiltered, false); notifications.notifications = TimelineHelper.filterNotification(getApplication().getApplicationContext(), notFiltered); addFetchMoreNotifications(notifications.notifications, notificationList, timelineParams); notifications.pagination = MastodonHelper.getPagination(notificationsResponse.headers()); Loading Loading @@ -166,7 +166,7 @@ public class NotificationsVM extends AndroidViewModel { //Only not already present statuses are added notifications.notifications = notPresentNotifications; } TimelineHelper.filterNotification(getApplication().getApplicationContext(), notifications.notifications, true); TimelineHelper.filterNotification(getApplication().getApplicationContext(), notifications.notifications); if (notifications.notifications.size() > 0) { addFetchMoreNotifications(notifications.notifications, notificationList, timelineParams); notifications.pagination = new Pagination(); Loading Loading
app/src/main/java/app/fedilab/android/helper/TimelineHelper.java +22 −10 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.endpoints.MastodonFiltersService; import app.fedilab.android.client.entities.api.Filter; import app.fedilab.android.client.entities.api.Notification; Loading Loading @@ -99,11 +100,10 @@ public class TimelineHelper { //Expired filter continue; } if (filterTimeLineType == Timeline.TimeLineEnum.HOME) { if (!filter.context.contains("home")) continue; } else if (filterTimeLineType == Timeline.TimeLineEnum.NOTIFICATION) { if (!filter.context.contains("notification")) continue; if (!filter.context.contains("notifications")) continue; } else if (filterTimeLineType == Timeline.TimeLineEnum.CONTEXT) { if (!filter.context.contains("thread")) continue; } else if (filterTimeLineType == Timeline.TimeLineEnum.ACCOUNT_TIMELINE) { Loading @@ -113,15 +113,18 @@ public class TimelineHelper { } if (filter.keywords != null && filter.keywords.size() > 0) { for (Filter.KeywordsAttributes filterKeyword : filter.keywords) { String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).matches() ? "\\b" : ""; String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).matches() ? "\\b" : ""; String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).find() ? "\\b" : ""; String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).find() ? "\\b" : ""; Pattern p; if (filterKeyword.whole_word) { p = Pattern.compile(sb + "(" + Pattern.quote(filterKeyword.keyword) + ")" + eb, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); p = Pattern.compile(sb + "(" + Pattern.quote(filterKeyword.keyword) + ")" + eb, Pattern.CASE_INSENSITIVE); } else { p = Pattern.compile("#" + Pattern.quote(filterKeyword.keyword), Pattern.CASE_INSENSITIVE); } for (Status status : statuses) { if (status.account.id.equals(MainActivity.currentUserID)) { continue; } String content; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) content = Html.fromHtml(status.reblog != null ? status.reblog.content : status.content, Html.FROM_HTML_MODE_LEGACY).toString(); Loading @@ -129,6 +132,7 @@ public class TimelineHelper { content = Html.fromHtml(status.reblog != null ? status.reblog.content : status.content).toString(); Matcher m = p.matcher(content); if (m.find()) { if (filter.filter_action.equalsIgnoreCase("warn")) { status.filteredByApp = filter; } else { Loading Loading @@ -170,9 +174,10 @@ public class TimelineHelper { * @param notifications - List of {@link Notification} * @return filtered List<Status> */ public static List<Notification> filterNotification(Context context, List<Notification> notifications, boolean cached) { public static List<Notification> filterNotification(Context context, List<Notification> notifications) { //A security to make sure filters have been fetched before displaying messages List<Notification> notificationToRemove = new ArrayList<>(); if (!BaseMainActivity.filterFetched) { try { FiltersVM filtersVM = new ViewModelProvider((ViewModelStoreOwner) context).get(FiltersVM.class); Loading @@ -189,25 +194,32 @@ public class TimelineHelper { //Loop through filters for (Filter filter : BaseMainActivity.mainFilters) { if (filter.expires_at != null && filter.expires_at.before(new Date())) { //Expired filter continue; } if (!filter.context.contains("notification")) continue; if (!filter.context.contains("notifications")) continue; if (filter.keywords != null && filter.keywords.size() > 0) { for (Filter.KeywordsAttributes filterKeyword : filter.keywords) { String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).matches() ? "\\b" : ""; String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).matches() ? "\\b" : ""; String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).find() ? "\\b" : ""; String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).find() ? "\\b" : ""; Pattern p; if (filterKeyword.whole_word) { p = Pattern.compile(sb + "(" + Pattern.quote(filterKeyword.keyword) + ")" + eb, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); p = Pattern.compile(sb + "(" + Pattern.quote(filterKeyword.keyword) + ")" + eb, Pattern.CASE_INSENSITIVE); } else { p = Pattern.compile("#" + Pattern.quote(filterKeyword.keyword), Pattern.CASE_INSENSITIVE); } for (Notification notification : notifications) { if (notification.status == null) { continue; } if (notification.status.account.id.equals(MainActivity.currentUserID)) { continue; } String content; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) content = Html.fromHtml(notification.status.reblog != null ? notification.status.reblog.content : notification.status.content, Html.FROM_HTML_MODE_LEGACY).toString(); Loading
app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java +16 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import app.fedilab.android.activities.ProfileActivity; import app.fedilab.android.client.entities.api.Notification; import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.databinding.DrawerFollowBinding; import app.fedilab.android.databinding.DrawerStatusFilteredBinding; import app.fedilab.android.databinding.DrawerStatusNotificationBinding; import app.fedilab.android.databinding.NotificationsRelatedAccountsBinding; import app.fedilab.android.helper.Helper; Loading @@ -65,6 +66,7 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH private final int TYPE_STATUS = 6; private final int TYPE_REACTION = 8; private final int TYPE_UPDATE = 9; private final int TYPE_FILERED = 10; public FetchMoreCallBack fetchMoreCallBack; private Context context; Loading @@ -82,6 +84,10 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH @Override public int getItemViewType(int position) { if (notificationList.get(position).filteredByApp != null) { return TYPE_FILERED; } String type = notificationList.get(position).type; if (type != null) { switch (type) { Loading Loading @@ -115,6 +121,9 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH if (viewType == TYPE_FOLLOW || viewType == TYPE_FOLLOW_REQUEST) { DrawerFollowBinding itemBinding = DrawerFollowBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new ViewHolderFollow(itemBinding); } else if (viewType == TYPE_FILERED) { DrawerStatusFilteredBinding itemBinding = DrawerStatusFilteredBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new StatusAdapter.StatusViewHolder(itemBinding); } else { DrawerStatusNotificationBinding itemBinding = DrawerStatusNotificationBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new StatusAdapter.StatusViewHolder(itemBinding); Loading Loading @@ -218,6 +227,13 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH } else { holderFollow.binding.cacheIndicator.setVisibility(View.GONE); } } else if (getItemViewType(position) == TYPE_FILERED) { StatusAdapter.StatusViewHolder holder = (StatusAdapter.StatusViewHolder) viewHolder; holder.bindingFiltered.filteredText.setText(context.getString(R.string.filtered_by, notification.filteredByApp.title)); holder.bindingFiltered.displayButton.setOnClickListener(v -> { notification.filteredByApp = null; notifyItemChanged(position); }); } else { StatusAdapter.StatusViewHolder holderStatus = (StatusAdapter.StatusViewHolder) viewHolder; holderStatus.bindingNotification.status.typeOfNotification.setVisibility(View.VISIBLE); Loading
app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java +2 −2 Original line number Diff line number Diff line Loading @@ -111,7 +111,7 @@ public class NotificationsVM extends AndroidViewModel { Response<List<Notification>> notificationsResponse = notificationsCall.execute(); if (notificationsResponse.isSuccessful()) { List<Notification> notFiltered = notificationsResponse.body(); notifications.notifications = TimelineHelper.filterNotification(getApplication().getApplicationContext(), notFiltered, false); notifications.notifications = TimelineHelper.filterNotification(getApplication().getApplicationContext(), notFiltered); addFetchMoreNotifications(notifications.notifications, notificationList, timelineParams); notifications.pagination = MastodonHelper.getPagination(notificationsResponse.headers()); Loading Loading @@ -166,7 +166,7 @@ public class NotificationsVM extends AndroidViewModel { //Only not already present statuses are added notifications.notifications = notPresentNotifications; } TimelineHelper.filterNotification(getApplication().getApplicationContext(), notifications.notifications, true); TimelineHelper.filterNotification(getApplication().getApplicationContext(), notifications.notifications); if (notifications.notifications.size() > 0) { addFetchMoreNotifications(notifications.notifications, notificationList, timelineParams); notifications.pagination = new Pagination(); Loading