From 1b643bcb1d1ed0875fc9ed8b40e6f9a334c81714 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 11:57:41 +0100 Subject: [PATCH] Fix issue #615 - add reverse option for tags + Change label descriptions --- .../android/activities/HashTagActivity.java | 264 ++++++++++++------ .../endpoints/MastodonFiltersService.java | 2 +- .../timeline/FragmentMastodonTimeline.java | 1 - .../android/viewmodel/mastodon/FiltersVM.java | 20 ++ app/src/main/res/drawable/tag_follow.xml | 9 + app/src/main/res/drawable/tag_muted.xml | 9 + app/src/main/res/drawable/tag_pin.xml | 9 + app/src/main/res/drawable/tag_pin_off.xml | 9 + app/src/main/res/drawable/tag_unfollow.xml | 9 + app/src/main/res/drawable/tag_unmuted.xml | 9 + app/src/main/res/menu/menu_hashtag.xml | 10 +- app/src/main/res/values/strings.xml | 5 + 12 files changed, 262 insertions(+), 94 deletions(-) create mode 100644 app/src/main/res/drawable/tag_follow.xml create mode 100644 app/src/main/res/drawable/tag_muted.xml create mode 100644 app/src/main/res/drawable/tag_pin.xml create mode 100644 app/src/main/res/drawable/tag_pin_off.xml create mode 100644 app/src/main/res/drawable/tag_unfollow.xml create mode 100644 app/src/main/res/drawable/tag_unmuted.xml diff --git a/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java b/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java index d2b5d1c9..850bfac6 100644 --- a/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java @@ -26,6 +26,7 @@ import android.view.MenuItem; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; import androidx.lifecycle.ViewModelProvider; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -56,11 +57,14 @@ public class HashTagActivity extends BaseActivity { public static int position; private String tag; - private boolean pinnedTag; - private boolean followedTag; - private boolean mutedTag; + private Boolean pinnedTag; + private Boolean followedTag; + private Boolean mutedTag; private TagVM tagVM; private Filter fedilabFilter; + private Filter.KeywordsAttributes keyword; + private PinnedTimeline pinnedTimeline; + private Pinned pinned; @Override protected void onCreate(Bundle savedInstanceState) { @@ -75,9 +79,9 @@ public class HashTagActivity extends BaseActivity { } if (tag == null) finish(); - pinnedTag = false; - followedTag = false; - mutedTag = false; + pinnedTag = null; + followedTag = null; + mutedTag = null; setSupportActionBar(binding.toolbar); ActionBar actionBar = getSupportActionBar(); //Remove title @@ -100,19 +104,24 @@ public class HashTagActivity extends BaseActivity { ReorderVM reorderVM = new ViewModelProvider(HashTagActivity.this).get(ReorderVM.class); reorderVM.getAllPinned().observe(HashTagActivity.this, pinned -> { if (pinned != null) { + this.pinned = pinned; + pinnedTag = false; if (pinned.pinnedTimelines != null) { for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { if (pinnedTimeline.tagTimeline != null) { if (pinnedTimeline.tagTimeline.name.equalsIgnoreCase(tag)) { + this.pinnedTimeline = pinnedTimeline; pinnedTag = true; - invalidateOptionsMenu(); + break; } } } + invalidateOptionsMenu(); } } }); if (MainActivity.filterFetched && MainActivity.mainFilters != null) { + mutedTag = false; for (Filter filter : MainActivity.mainFilters) { if (filter.title.equalsIgnoreCase(Helper.FEDILAB_MUTED_HASHTAGS)) { fedilabFilter = filter; @@ -120,17 +129,14 @@ public class HashTagActivity extends BaseActivity { for (Filter.KeywordsAttributes keywordsAttributes : filter.keywords) { if (fetch.equalsIgnoreCase(keywordsAttributes.keyword)) { mutedTag = true; + keyword = keywordsAttributes; invalidateOptionsMenu(); break; } } - mutedTag = false; - invalidateOptionsMenu(); - break; } } - } else { - mutedTag = true; + invalidateOptionsMenu(); } Bundle bundle = new Bundle(); @@ -158,89 +164,125 @@ public class HashTagActivity extends BaseActivity { finish(); return true; } else if (item.getItemId() == R.id.action_add_timeline) { - new Thread(() -> { - try { - Pinned pinned = new Pinned(HashTagActivity.this).getPinned(currentAccount); - boolean canBeAdded = true; - boolean update = true; - if (pinned == null) { - pinned = new Pinned(); - pinned.pinnedTimelines = new ArrayList<>(); - update = false; - } else { - for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { - if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) { - if (pinnedTimeline.tagTimeline.name.compareTo(tag.trim()) == 0) { - canBeAdded = false; - } - } - } - } - if (!canBeAdded) { - Handler mainHandler = new Handler(Looper.getMainLooper()); - Runnable myRunnable = () -> Toasty.warning(HashTagActivity.this, getString(R.string.tags_already_stored), Toasty.LENGTH_SHORT).show(); - mainHandler.post(myRunnable); - return; - } - PinnedTimeline pinnedTimeline = new PinnedTimeline(); - pinnedTimeline.type = Timeline.TimeLineEnum.TAG; - pinnedTimeline.position = pinned.pinnedTimelines.size(); - pinnedTimeline.displayed = true; - TagTimeline tagTimeline = new TagTimeline(); - tagTimeline.name = tag.trim(); - tagTimeline.isNSFW = false; - tagTimeline.isART = false; - pinnedTimeline.tagTimeline = tagTimeline; - pinned.pinnedTimelines.add(pinnedTimeline); - if (update) { + + if (pinnedTag) { + AlertDialog.Builder unpinConfirm = new AlertDialog.Builder(HashTagActivity.this, Helper.dialogStyle()); + unpinConfirm.setMessage(getString(R.string.unpin_timeline_description)); + unpinConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); + unpinConfirm.setPositiveButton(R.string.yes, (dialog, which) -> { + pinned.pinnedTimelines.remove(pinnedTimeline); + try { new Pinned(HashTagActivity.this).updatePinned(pinned); - } else { - new Pinned(HashTagActivity.this).insertPinned(pinned); + } catch (DBException e) { + e.printStackTrace(); } + pinnedTag = false; + invalidateOptionsMenu(); Bundle b = new Bundle(); b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true); Intent intentBD = new Intent(Helper.BROADCAST_DATA); intentBD.putExtras(b); LocalBroadcastManager.getInstance(HashTagActivity.this).sendBroadcast(intentBD); - pinnedTag = true; - invalidateOptionsMenu(); - } catch (DBException e) { - e.printStackTrace(); - } - }).start(); + dialog.dismiss(); + }); + unpinConfirm.show(); + } else { + new Thread(() -> { + try { + Pinned pinned = new Pinned(HashTagActivity.this).getPinned(currentAccount); + boolean canBeAdded = true; + boolean update = true; + if (pinned == null) { + pinned = new Pinned(); + pinned.pinnedTimelines = new ArrayList<>(); + update = false; + } else { + for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { + if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) { + if (pinnedTimeline.tagTimeline.name.compareTo(tag.trim()) == 0) { + canBeAdded = false; + } + } + } + } + if (!canBeAdded) { + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> Toasty.warning(HashTagActivity.this, getString(R.string.tags_already_stored), Toasty.LENGTH_SHORT).show(); + mainHandler.post(myRunnable); + return; + } + pinnedTimeline = new PinnedTimeline(); + pinnedTimeline.type = Timeline.TimeLineEnum.TAG; + pinnedTimeline.position = pinned.pinnedTimelines.size(); + pinnedTimeline.displayed = true; + TagTimeline tagTimeline = new TagTimeline(); + tagTimeline.name = tag.trim(); + tagTimeline.isNSFW = false; + tagTimeline.isART = false; + pinnedTimeline.tagTimeline = tagTimeline; + pinned.pinnedTimelines.add(pinnedTimeline); + if (update) { + new Pinned(HashTagActivity.this).updatePinned(pinned); + } else { + new Pinned(HashTagActivity.this).insertPinned(pinned); + } + Bundle b = new Bundle(); + b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true); + Intent intentBD = new Intent(Helper.BROADCAST_DATA); + intentBD.putExtras(b); + LocalBroadcastManager.getInstance(HashTagActivity.this).sendBroadcast(intentBD); + pinnedTag = true; + invalidateOptionsMenu(); + } catch (DBException e) { + e.printStackTrace(); + } + }).start(); + } } else if (item.getItemId() == R.id.action_follow_tag) { - tagVM.follow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { - if (returnedTag != null) { - followedTag = returnedTag.following; - invalidateOptionsMenu(); - } - }); + if (!followedTag) { + tagVM.follow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { + if (returnedTag != null) { + followedTag = returnedTag.following; + invalidateOptionsMenu(); + } + }); + } else { + tagVM.unfollow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { + if (returnedTag != null) { + followedTag = returnedTag.following; + invalidateOptionsMenu(); + } + }); + } } else if (item.getItemId() == R.id.action_mute) { - if (MainActivity.mainFilters == null || fedilabFilter == null) { - MainActivity.mainFilters = new ArrayList<>(); - Filter.FilterParams filterParams = new Filter.FilterParams(); - filterParams.title = Helper.FEDILAB_MUTED_HASHTAGS; - filterParams.filter_action = "hide"; - filterParams.context = new ArrayList<>(); - filterParams.context.add("home"); - filterParams.context.add("public"); - filterParams.context.add("thread"); - filterParams.context.add("account"); - String finalTag = tag; - FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class); - filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) - .observe(HashTagActivity.this, filter -> { - if (filter != null) { - MainActivity.mainFilters.add(filter); - mutedTag = false; - fedilabFilter = filter; - muteTags(); - invalidateOptionsMenu(); - } - }); + if (!mutedTag) { + if (MainActivity.mainFilters == null || fedilabFilter == null) { + MainActivity.mainFilters = new ArrayList<>(); + Filter.FilterParams filterParams = new Filter.FilterParams(); + filterParams.title = Helper.FEDILAB_MUTED_HASHTAGS; + filterParams.filter_action = "hide"; + filterParams.context = new ArrayList<>(); + filterParams.context.add("home"); + filterParams.context.add("public"); + filterParams.context.add("thread"); + filterParams.context.add("account"); + FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class); + filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) + .observe(HashTagActivity.this, filter -> { + if (filter != null) { + MainActivity.mainFilters.add(filter); + mutedTag = false; + fedilabFilter = filter; + muteTags(); + invalidateOptionsMenu(); + } + }); + } else { + muteTags(); + } } else { - muteTags(); + unmuteTags(); } } @@ -249,6 +291,24 @@ public class HashTagActivity extends BaseActivity { } + private void unmuteTags() { + String search = tag.startsWith("#") ? tag : "#" + tag; + for (Filter.KeywordsAttributes keywordsAttributes : fedilabFilter.keywords) { + if (search.equalsIgnoreCase(keywordsAttributes.keyword)) { + keyword = keywordsAttributes; + break; + } + } + if (keyword != null && keyword.id != null) { + FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class); + filtersVM.removeKeyword(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, keyword.id); + fedilabFilter.keywords.remove(keyword); + mutedTag = false; + invalidateOptionsMenu(); + } + } + + private void muteTags() { Filter.FilterParams filterParams = new Filter.FilterParams(); filterParams.id = fedilabFilter.id; @@ -261,6 +321,7 @@ public class HashTagActivity extends BaseActivity { FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class); filtersVM.editFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) .observe(HashTagActivity.this, filter -> { + fedilabFilter = filter; mutedTag = true; invalidateOptionsMenu(); }); @@ -272,13 +333,42 @@ public class HashTagActivity extends BaseActivity { MenuItem pin = menu.findItem(R.id.action_add_timeline); MenuItem follow = menu.findItem(R.id.action_follow_tag); MenuItem mute = menu.findItem(R.id.action_mute); - if (pinnedTag && pin != null) { + if (pinnedTag != null) { + pin.setVisible(true); + if (pinnedTag) { + pin.setIcon(R.drawable.tag_pin_off); + pin.setTitle(getString(R.string.unpin_tag)); + } else { + pin.setTitle(getString(R.string.unpin_tag)); + pin.setIcon(R.drawable.tag_pin); + } + } else { pin.setVisible(false); } - if (followedTag && follow != null) { + if (followedTag != null) { + follow.setVisible(true); + if (followedTag) { + follow.setTitle(getString(R.string.unfollow_tag)); + follow.setIcon(R.drawable.tag_unfollow); + } else { + follow.setTitle(getString(R.string.follow_tag)); + follow.setIcon(R.drawable.tag_follow); + } + } else { follow.setVisible(false); } - mute.setVisible(!mutedTag); + if (mutedTag != null) { + mute.setVisible(true); + if (mutedTag) { + mute.setTitle(getString(R.string.unmute_tag_action)); + mute.setIcon(R.drawable.tag_unmuted); + } else { + mute.setTitle(getString(R.string.mute_tag_action)); + mute.setIcon(R.drawable.tag_muted); + } + } else { + mute.setVisible(false); + } return super.onCreateOptionsMenu(menu); } diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonFiltersService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonFiltersService.java index 88216303..8a438bbc 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonFiltersService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonFiltersService.java @@ -96,7 +96,7 @@ public interface MastodonFiltersService { ); //Remove a keyword for a filter - @DELETE("filter_keywords/{id}") + @DELETE("filters/keywords/{id}") Call removeKeywordFilter( @Header("Authorization") String token, @Path("id") String id diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 23651375..a4b57d8a 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -361,7 +361,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (timelineType != null) { slug = timelineType != Timeline.TimeLineEnum.ART ? timelineType.getValue() + (ident != null ? "|" + ident : "") : Timeline.TimeLineEnum.TAG.getValue() + (ident != null ? "|" + ident : ""); } - LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(receive_action, new IntentFilter(Helper.RECEIVE_STATUS_ACTION)); binding = FragmentPaginationBinding.inflate(inflater, container, false); return binding.getRoot(); diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/FiltersVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/FiltersVM.java index b85f587a..ca73a5e8 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/FiltersVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/FiltersVM.java @@ -212,4 +212,24 @@ public class FiltersVM extends AndroidViewModel { }).start(); } + + /** + * Remove a filter + * + * @param id ID of the filter + */ + public void removeKeyword(@NonNull String instance, String token, @NonNull String id) { + MastodonFiltersService mastodonAccountsService = initV2(instance); + new Thread(() -> { + Call removeFilterCall = mastodonAccountsService.removeKeywordFilter(token, id); + if (removeFilterCall != null) { + try { + removeFilterCall.execute(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + } + } diff --git a/app/src/main/res/drawable/tag_follow.xml b/app/src/main/res/drawable/tag_follow.xml new file mode 100644 index 00000000..247fb35c --- /dev/null +++ b/app/src/main/res/drawable/tag_follow.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_muted.xml b/app/src/main/res/drawable/tag_muted.xml new file mode 100644 index 00000000..4000c43f --- /dev/null +++ b/app/src/main/res/drawable/tag_muted.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_pin.xml b/app/src/main/res/drawable/tag_pin.xml new file mode 100644 index 00000000..07091cb1 --- /dev/null +++ b/app/src/main/res/drawable/tag_pin.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_pin_off.xml b/app/src/main/res/drawable/tag_pin_off.xml new file mode 100644 index 00000000..95d54cf5 --- /dev/null +++ b/app/src/main/res/drawable/tag_pin_off.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_unfollow.xml b/app/src/main/res/drawable/tag_unfollow.xml new file mode 100644 index 00000000..35f5cb4a --- /dev/null +++ b/app/src/main/res/drawable/tag_unfollow.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_unmuted.xml b/app/src/main/res/drawable/tag_unmuted.xml new file mode 100644 index 00000000..4fc63b7a --- /dev/null +++ b/app/src/main/res/drawable/tag_unmuted.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/menu_hashtag.xml b/app/src/main/res/menu/menu_hashtag.xml index f35647d2..610310c3 100644 --- a/app/src/main/res/menu/menu_hashtag.xml +++ b/app/src/main/res/menu/menu_hashtag.xml @@ -3,17 +3,17 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4dadf67f..de2d5e37 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2052,4 +2052,9 @@ Please, try again later. The conversation started on your instance! The app didn\'t find the remote message. + Mute tag + Unmute tag + Pin tag + Unpin tag + Unfollow tag \ No newline at end of file