From cf864e6f495917c1f7ec3ef28a339820fa2fef09 Mon Sep 17 00:00:00 2001 From: sk Date: Wed, 9 Nov 2022 15:48:01 +0100 Subject: [PATCH] Implement following hashtags --- .../android/api/requests/tags/GetHashtag.java | 11 ++++ .../api/requests/tags/SetHashtagFollowed.java | 11 ++++ .../fragments/HashtagTimelineFragment.java | 64 ++++++++++++++++++- .../fragments/discover/SearchFragment.java | 2 +- .../discover/TrendingHashtagsFragment.java | 2 +- .../joinmastodon/android/model/Hashtag.java | 2 + .../android/ui/text/LinkSpan.java | 2 +- .../android/ui/utils/UiUtils.java | 4 +- .../ic_fluent_person_delete_24_filled.xml | 3 + .../src/main/res/menu/hashtag_timeline.xml | 8 +++ 10 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/api/requests/tags/GetHashtag.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/api/requests/tags/SetHashtagFollowed.java create mode 100644 mastodon/src/main/res/drawable/ic_fluent_person_delete_24_filled.xml create mode 100644 mastodon/src/main/res/menu/hashtag_timeline.xml diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/tags/GetHashtag.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/tags/GetHashtag.java new file mode 100644 index 000000000..2b4cf8f5c --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/tags/GetHashtag.java @@ -0,0 +1,11 @@ +package org.joinmastodon.android.api.requests.tags; + +import org.joinmastodon.android.api.MastodonAPIRequest; +import org.joinmastodon.android.model.Hashtag; + +public class GetHashtag extends MastodonAPIRequest { + public GetHashtag(String name){ + super(HttpMethod.GET, "/tags/"+name, Hashtag.class); + } +} + diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/tags/SetHashtagFollowed.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/tags/SetHashtagFollowed.java new file mode 100644 index 000000000..362e6f40d --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/tags/SetHashtagFollowed.java @@ -0,0 +1,11 @@ +package org.joinmastodon.android.api.requests.tags; + +import org.joinmastodon.android.api.MastodonAPIRequest; +import org.joinmastodon.android.model.Hashtag; + +public class SetHashtagFollowed extends MastodonAPIRequest{ + public SetHashtagFollowed(String name, boolean followed){ + super(HttpMethod.POST, "/tags/"+name+"/"+(followed ? "follow" : "unfollow"), Hashtag.class); + setRequestBody(new Object()); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java index 70f132173..03704082b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java @@ -2,23 +2,34 @@ package org.joinmastodon.android.fragments; import android.app.Activity; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; +import android.widget.Toast; import org.joinmastodon.android.R; +import org.joinmastodon.android.api.requests.tags.GetHashtag; +import org.joinmastodon.android.api.requests.tags.SetHashtagFollowed; import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline; +import org.joinmastodon.android.model.Hashtag; import org.joinmastodon.android.model.Status; import java.util.List; import me.grishka.appkit.Nav; +import me.grishka.appkit.api.Callback; +import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.SimpleCallback; import me.grishka.appkit.utils.V; public class HashtagTimelineFragment extends StatusListFragment{ private String hashtag; + private boolean following; private ImageButton fab; + private MenuItem followButton; public HashtagTimelineFragment(){ setListLayoutId(R.layout.recycler_fragment_with_fab); @@ -27,10 +38,61 @@ public class HashtagTimelineFragment extends StatusListFragment{ @Override public void onAttach(Activity activity){ super.onAttach(activity); - hashtag=getArguments().getString("hashtag"); + updateTitle(getArguments().getString("hashtag")); + following=getArguments().getBoolean("following", false); + + setHasOptionsMenu(true); + } + + private void updateTitle(String hashtagName) { + hashtag = hashtagName; setTitle('#'+hashtag); } + private void updateFollowingState(boolean newFollowing) { + this.following = newFollowing; + followButton.setTitle(getString(newFollowing ? R.string.unfollow_user : R.string.follow_user, "#" + hashtag)); + followButton.setIcon(newFollowing ? R.drawable.ic_fluent_person_delete_24_filled : R.drawable.ic_fluent_person_add_24_regular); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.hashtag_timeline, menu); + followButton = menu.findItem(R.id.follow_hashtag); + updateFollowingState(following); + + followButton.setOnMenuItemClickListener(i -> { + updateFollowingState(!following); + new SetHashtagFollowed(hashtag, following).setCallback(new Callback<>() { + @Override + public void onSuccess(Hashtag i) { + updateFollowingState(i.following); + Toast.makeText(getActivity(), getString(i.following ? R.string.followed_user : R.string.unfollowed_user, "#" + i.name), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onError(ErrorResponse error) { + error.showToast(getActivity()); + updateFollowingState(!following); + } + }).exec(accountID); + return true; + }); + + new GetHashtag(hashtag).setCallback(new Callback<>() { + @Override + public void onSuccess(Hashtag hashtag) { + updateTitle(hashtag.name); + updateFollowingState(hashtag.following); + } + + @Override + public void onError(ErrorResponse error) { + error.showToast(getActivity()); + } + }).exec(accountID); + } + @Override protected void doLoadData(int offset, int count){ currentRequest=new GetHashtagTimeline(hashtag, offset==0 ? null : getMaxID(), null, count) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/SearchFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/SearchFragment.java index 9f3f80c52..e65f8c9be 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/SearchFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/SearchFragment.java @@ -100,7 +100,7 @@ public class SearchFragment extends BaseStatusListFragment{ args.putParcelable("profileAccount", Parcels.wrap(res.account)); Nav.go(getActivity(), ProfileFragment.class, args); } - case HASHTAG -> UiUtils.openHashtagTimeline(getActivity(), accountID, res.hashtag.name); + case HASHTAG -> UiUtils.openHashtagTimeline(getActivity(), accountID, res.hashtag.name, res.hashtag.following); case STATUS -> { Status status=res.status.getContentStatus(); Bundle args=new Bundle(); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java index bcb3d7442..091f3d0bf 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java @@ -107,7 +107,7 @@ public class TrendingHashtagsFragment extends BaseRecyclerFragment impl @Override public void onClick(){ - UiUtils.openHashtagTimeline(getActivity(), accountID, item.name); + UiUtils.openHashtagTimeline(getActivity(), accountID, item.name, item.following); } } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/Hashtag.java b/mastodon/src/main/java/org/joinmastodon/android/model/Hashtag.java index 77d90f9ad..b525b3de3 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/Hashtag.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/Hashtag.java @@ -11,6 +11,7 @@ public class Hashtag extends BaseModel{ public String name; @RequiredField public String url; + public boolean following; public List history; @Override @@ -18,6 +19,7 @@ public class Hashtag extends BaseModel{ return "Hashtag{"+ "name='"+name+'\''+ ", url='"+url+'\''+ + ", following="+following+ ", history="+history+ '}'; } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java b/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java index fd07755e9..34eff3073 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java @@ -34,7 +34,7 @@ public class LinkSpan extends CharacterStyle { switch(getType()){ case URL -> UiUtils.openURL(context, accountID, link); case MENTION -> UiUtils.openProfileByID(context, accountID, link); - case HASHTAG -> UiUtils.openHashtagTimeline(context, accountID, link); + case HASHTAG -> UiUtils.openHashtagTimeline(context, accountID, link, null); } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index 84436cca2..615f61622 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -71,6 +71,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import androidx.annotation.AttrRes; +import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.browser.customtabs.CustomTabsIntent; import androidx.recyclerview.widget.DiffUtil; @@ -296,10 +297,11 @@ public class UiUtils{ Nav.go((Activity)context, ProfileFragment.class, args); } - public static void openHashtagTimeline(Context context, String accountID, String hashtag){ + public static void openHashtagTimeline(Context context, String accountID, String hashtag, @Nullable Boolean following){ Bundle args=new Bundle(); args.putString("account", accountID); args.putString("hashtag", hashtag); + if (following != null) args.putBoolean("following", following); Nav.go((Activity)context, HashtagTimelineFragment.class, args); } diff --git a/mastodon/src/main/res/drawable/ic_fluent_person_delete_24_filled.xml b/mastodon/src/main/res/drawable/ic_fluent_person_delete_24_filled.xml new file mode 100644 index 000000000..7bca7a7e5 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_person_delete_24_filled.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/menu/hashtag_timeline.xml b/mastodon/src/main/res/menu/hashtag_timeline.xml new file mode 100644 index 000000000..98d963ba8 --- /dev/null +++ b/mastodon/src/main/res/menu/hashtag_timeline.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file