From c37f4bb643789d220c74bf204719080d1f69aaaf Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 12 Jan 2023 11:13:52 +0100 Subject: Familiar followers on profiles --- .../android/activities/ProfileActivity.java | 32 ++++++++++++++ .../client/endpoints/MastodonAccountsService.java | 8 ++++ .../client/entities/api/FamiliarFollowers.java | 28 +++++++++++++ .../app/fedilab/android/helper/MastodonHelper.java | 49 ++++++++++++++++++++++ .../android/viewmodel/mastodon/AccountsVM.java | 34 +++++++++++++++ app/src/main/res/layout/activity_profile.xml | 40 +++++++++++++++++- app/src/main/res/values/strings.xml | 1 + .../metadata/android/en/changelogs/464.txt | 2 +- 8 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/client/entities/api/FamiliarFollowers.java diff --git a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java index 1ab57d6d8..27e59b80d 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -34,6 +34,7 @@ import android.text.method.LinkMovementMethod; import android.text.style.ForegroundColorSpan; import android.text.style.UnderlineSpan; import android.util.TypedValue; +import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -76,6 +77,7 @@ import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.entities.api.Account; import app.fedilab.android.client.entities.api.Attachment; +import app.fedilab.android.client.entities.api.FamiliarFollowers; import app.fedilab.android.client.entities.api.Field; import app.fedilab.android.client.entities.api.IdentityProof; import app.fedilab.android.client.entities.api.MastodonList; @@ -86,6 +88,7 @@ import app.fedilab.android.client.entities.app.RemoteInstance; import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.client.entities.app.WellKnownNodeinfo; import app.fedilab.android.databinding.ActivityProfileBinding; +import app.fedilab.android.databinding.NotificationsRelatedAccountsBinding; import app.fedilab.android.exception.DBException; import app.fedilab.android.helper.CrossActionHelper; import app.fedilab.android.helper.Helper; @@ -106,6 +109,7 @@ public class ProfileActivity extends BaseActivity { private RelationShip relationship; + private FamiliarFollowers familiarFollowers; private Account account; private ScheduledExecutorService scheduledExecutorService; private action doAction; @@ -255,6 +259,13 @@ public class ProfileActivity extends BaseActivity { updateAccount(); } }); + accountsVM.getFamiliarFollowers(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountListToCheck).observe(ProfileActivity.this, familiarFollowersList -> { + if (familiarFollowersList != null && familiarFollowersList.size() > 0) { + this.familiarFollowers = familiarFollowersList.get(0); + updateAccount(); + } + }); + //Retrieve identity proofs accountsVM.getIdentityProofs(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id).observe(ProfileActivity.this, identityProofs -> { this.identityProofList = identityProofs; @@ -567,6 +578,27 @@ public class ProfileActivity extends BaseActivity { } } + if (familiarFollowers != null && familiarFollowers.accounts != null && familiarFollowers.accounts.size() > 0) { + binding.relatedAccounts.removeAllViews(); + for (Account account : familiarFollowers.accounts) { + NotificationsRelatedAccountsBinding notificationsRelatedAccountsBinding = NotificationsRelatedAccountsBinding.inflate(LayoutInflater.from(ProfileActivity.this)); + MastodonHelper.loadProfileMediaMastodonRound(ProfileActivity.this, notificationsRelatedAccountsBinding.profilePicture, account); + notificationsRelatedAccountsBinding.acc.setText(account.username); + notificationsRelatedAccountsBinding.relatedAccountContainer.setOnClickListener(v -> { + Intent intent = new Intent(ProfileActivity.this, ProfileActivity.class); + Bundle b = new Bundle(); + b.putSerializable(Helper.ARG_ACCOUNT, account); + intent.putExtras(b); + ActivityOptionsCompat options = ActivityOptionsCompat + .makeSceneTransitionAnimation(ProfileActivity.this, notificationsRelatedAccountsBinding.profilePicture, getString(R.string.activity_porfile_pp)); + // start the new activity + startActivity(intent, options.toBundle()); + }); + binding.relatedAccounts.addView(notificationsRelatedAccountsBinding.getRoot()); + } + binding.familiarFollowers.setVisibility(View.VISIBLE); + } + binding.accountFollow.setEnabled(true); //Visibility depending of the relationship if (relationship != null) { diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java index 398c43dcc..28b10231d 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java @@ -18,6 +18,7 @@ package app.fedilab.android.client.endpoints; import java.util.List; import app.fedilab.android.client.entities.api.Account; +import app.fedilab.android.client.entities.api.FamiliarFollowers; import app.fedilab.android.client.entities.api.FeaturedTag; import app.fedilab.android.client.entities.api.IdentityProof; import app.fedilab.android.client.entities.api.MastodonList; @@ -253,6 +254,13 @@ public interface MastodonAccountsService { @Query("id[]") List ids ); + //Get familiar followers + @GET("accounts/familiar_followers ") + Call> getFamiliarFollowers( + @Header("Authorization") String token, + @Query("id[]") List ids + ); + //Get search @GET("accounts/search") Call> searchAccounts( diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/FamiliarFollowers.java b/app/src/main/java/app/fedilab/android/client/entities/api/FamiliarFollowers.java new file mode 100644 index 000000000..1d753c55e --- /dev/null +++ b/app/src/main/java/app/fedilab/android/client/entities/api/FamiliarFollowers.java @@ -0,0 +1,28 @@ +package app.fedilab.android.client.entities.api; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +public class FamiliarFollowers implements Serializable { + + @SerializedName("id") + public String id; + @SerializedName("accounts") + public List accounts; +} diff --git a/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java b/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java index b86a9ecd7..8212dc74b 100644 --- a/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java @@ -40,6 +40,9 @@ import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestOptions; import com.google.gson.annotations.SerializedName; import java.text.SimpleDateFormat; @@ -268,6 +271,52 @@ public class MastodonHelper { } } + public static void loadProfileMediaMastodonRound(Activity activity, ImageView view, Account account) { + Context context = view.getContext(); + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + boolean disableGif = sharedpreferences.getBoolean(context.getString(R.string.SET_DISABLE_GIF), false); + @DrawableRes int placeholder = R.drawable.ic_person; + if (Helper.isValidContextForGlide(activity != null ? activity : context)) { + if (account == null) { + Glide.with(activity != null ? activity : context) + .asDrawable() + .load(placeholder) + .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(16))) + .thumbnail(0.1f) + .placeholder(placeholder) + .into(view); + return; + } + String targetedUrl = disableGif ? account.avatar_static : account.avatar; + if (targetedUrl != null) { + if (disableGif || (!targetedUrl.endsWith(".gif"))) { + Glide.with(activity != null ? activity : context) + .asDrawable() + .load(targetedUrl) + .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10))) + .thumbnail(0.1f) + .placeholder(placeholder) + .into(view); + } else { + Glide.with(activity != null ? activity : context) + .asGif() + .load(targetedUrl) + .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10))) + .thumbnail(0.1f) + .placeholder(placeholder) + .into(view); + } + } else { + Glide.with(activity != null ? activity : context) + .asDrawable() + .load(placeholder) + .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10))) + .thumbnail(0.1f) + .into(view); + } + } + } + /** * Convert a date in String -> format yyyy-MM-dd HH:mm:ss * diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java index fbf377466..e9f23ec1a 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java @@ -38,6 +38,7 @@ import app.fedilab.android.client.endpoints.MastodonAccountsService; import app.fedilab.android.client.entities.api.Account; import app.fedilab.android.client.entities.api.Accounts; import app.fedilab.android.client.entities.api.Domains; +import app.fedilab.android.client.entities.api.FamiliarFollowers; import app.fedilab.android.client.entities.api.FeaturedTag; import app.fedilab.android.client.entities.api.Field; import app.fedilab.android.client.entities.api.Filter; @@ -90,6 +91,7 @@ public class AccountsVM extends AndroidViewModel { private MutableLiveData> identityProofListMutableLiveData; private MutableLiveData relationShipMutableLiveData; private MutableLiveData> relationShipListMutableLiveData; + private MutableLiveData> familiarFollowersListMutableLiveData; private MutableLiveData filterMutableLiveData; private MutableLiveData> filterListMutableLiveData; private MutableLiveData> tagListMutableLiveData; @@ -1025,6 +1027,38 @@ public class AccountsVM extends AndroidViewModel { return relationShipListMutableLiveData; } + + /** + * Obtain a list of all accounts that follow a given account, filtered for accounts you follow. + * + * @param ids {@link List} of account IDs to check + * @return {@link LiveData} containing a {@link List} of {@link FamiliarFollowers}s to given account(s) + */ + public LiveData> getFamiliarFollowers(@NonNull String instance, String token, @NonNull List ids) { + familiarFollowersListMutableLiveData = new MutableLiveData<>(); + MastodonAccountsService mastodonAccountsService = init(instance); + new Thread(() -> { + List familiarFollowers = null; + Call> familiarFollowersCall = mastodonAccountsService.getFamiliarFollowers(token, ids); + + if (familiarFollowersCall != null) { + try { + Response> familiarFollowersResponse = familiarFollowersCall.execute(); + if (familiarFollowersResponse.isSuccessful()) { + familiarFollowers = familiarFollowersResponse.body(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + Handler mainHandler = new Handler(Looper.getMainLooper()); + List finalFamiliarFollowers = familiarFollowers; + Runnable myRunnable = () -> familiarFollowersListMutableLiveData.setValue(finalFamiliarFollowers); + mainHandler.post(myRunnable); + }).start(); + return familiarFollowersListMutableLiveData; + } + /** * Search for matching accounts by username or display name. * diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index f98dcda65..79f8910ce 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -341,6 +341,44 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/info" /> + + + + + + + + + + + + Pixelfed presentation for media Compact action buttons Buttons at the bottom of messages will not take the whole width + Followed by: \ No newline at end of file diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt index e53c48692..4ced9f605 100644 --- a/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt @@ -1,5 +1,5 @@ Added: - +- Display familiar followers on profiles Changed: -- cgit v1.2.3