Loading app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +32 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -106,6 +109,7 @@ public class ProfileActivity extends BaseActivity { private RelationShip relationship; private FamiliarFollowers familiarFollowers; private Account account; private ScheduledExecutorService scheduledExecutorService; private action doAction; Loading Loading @@ -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; Loading Loading @@ -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) { Loading app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -253,6 +254,13 @@ public interface MastodonAccountsService { @Query("id[]") List<String> ids ); //Get familiar followers @GET("accounts/familiar_followers ") Call<List<FamiliarFollowers>> getFamiliarFollowers( @Header("Authorization") String token, @Query("id[]") List<String> ids ); //Get search @GET("accounts/search") Call<List<Account>> searchAccounts( Loading app/src/main/java/app/fedilab/android/client/entities/api/FamiliarFollowers.java 0 → 100644 +28 −0 Original line number Diff line number Diff line 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 <http://www.gnu.org/licenses>. */ 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<Account> accounts; } app/src/main/java/app/fedilab/android/helper/MastodonHelper.java +49 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 * Loading app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -90,6 +91,7 @@ public class AccountsVM extends AndroidViewModel { private MutableLiveData<List<IdentityProof>> identityProofListMutableLiveData; private MutableLiveData<RelationShip> relationShipMutableLiveData; private MutableLiveData<List<RelationShip>> relationShipListMutableLiveData; private MutableLiveData<List<FamiliarFollowers>> familiarFollowersListMutableLiveData; private MutableLiveData<Filter> filterMutableLiveData; private MutableLiveData<List<Filter>> filterListMutableLiveData; private MutableLiveData<List<Tag>> tagListMutableLiveData; Loading Loading @@ -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<List<FamiliarFollowers>> getFamiliarFollowers(@NonNull String instance, String token, @NonNull List<String> ids) { familiarFollowersListMutableLiveData = new MutableLiveData<>(); MastodonAccountsService mastodonAccountsService = init(instance); new Thread(() -> { List<FamiliarFollowers> familiarFollowers = null; Call<List<FamiliarFollowers>> familiarFollowersCall = mastodonAccountsService.getFamiliarFollowers(token, ids); if (familiarFollowersCall != null) { try { Response<List<FamiliarFollowers>> familiarFollowersResponse = familiarFollowersCall.execute(); if (familiarFollowersResponse.isSuccessful()) { familiarFollowers = familiarFollowersResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); List<FamiliarFollowers> finalFamiliarFollowers = familiarFollowers; Runnable myRunnable = () -> familiarFollowersListMutableLiveData.setValue(finalFamiliarFollowers); mainHandler.post(myRunnable); }).start(); return familiarFollowersListMutableLiveData; } /** * Search for matching accounts by username or display name. * Loading Loading
app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +32 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -106,6 +109,7 @@ public class ProfileActivity extends BaseActivity { private RelationShip relationship; private FamiliarFollowers familiarFollowers; private Account account; private ScheduledExecutorService scheduledExecutorService; private action doAction; Loading Loading @@ -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; Loading Loading @@ -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) { Loading
app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -253,6 +254,13 @@ public interface MastodonAccountsService { @Query("id[]") List<String> ids ); //Get familiar followers @GET("accounts/familiar_followers ") Call<List<FamiliarFollowers>> getFamiliarFollowers( @Header("Authorization") String token, @Query("id[]") List<String> ids ); //Get search @GET("accounts/search") Call<List<Account>> searchAccounts( Loading
app/src/main/java/app/fedilab/android/client/entities/api/FamiliarFollowers.java 0 → 100644 +28 −0 Original line number Diff line number Diff line 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 <http://www.gnu.org/licenses>. */ 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<Account> accounts; }
app/src/main/java/app/fedilab/android/helper/MastodonHelper.java +49 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 * Loading
app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -90,6 +91,7 @@ public class AccountsVM extends AndroidViewModel { private MutableLiveData<List<IdentityProof>> identityProofListMutableLiveData; private MutableLiveData<RelationShip> relationShipMutableLiveData; private MutableLiveData<List<RelationShip>> relationShipListMutableLiveData; private MutableLiveData<List<FamiliarFollowers>> familiarFollowersListMutableLiveData; private MutableLiveData<Filter> filterMutableLiveData; private MutableLiveData<List<Filter>> filterListMutableLiveData; private MutableLiveData<List<Tag>> tagListMutableLiveData; Loading Loading @@ -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<List<FamiliarFollowers>> getFamiliarFollowers(@NonNull String instance, String token, @NonNull List<String> ids) { familiarFollowersListMutableLiveData = new MutableLiveData<>(); MastodonAccountsService mastodonAccountsService = init(instance); new Thread(() -> { List<FamiliarFollowers> familiarFollowers = null; Call<List<FamiliarFollowers>> familiarFollowersCall = mastodonAccountsService.getFamiliarFollowers(token, ids); if (familiarFollowersCall != null) { try { Response<List<FamiliarFollowers>> familiarFollowersResponse = familiarFollowersCall.execute(); if (familiarFollowersResponse.isSuccessful()) { familiarFollowers = familiarFollowersResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); List<FamiliarFollowers> finalFamiliarFollowers = familiarFollowers; Runnable myRunnable = () -> familiarFollowersListMutableLiveData.setValue(finalFamiliarFollowers); mainHandler.post(myRunnable); }).start(); return familiarFollowersListMutableLiveData; } /** * Search for matching accounts by username or display name. * Loading