From fd6d4870604eae6a5fd31311fc0fbe326db0b678 Mon Sep 17 00:00:00 2001 From: ssantos Date: Thu, 12 Jan 2023 03:50:57 +0100 Subject: Translated using Weblate (Portuguese) Currently translated at 73.6% (765 of 1039 strings) Co-authored-by: ssantos Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/ Translation: Fedilab/Strings --- app/src/main/res/values-pt/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 2e549a744..6f2dbf56a 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -13,7 +13,7 @@ Baixar Baixar %1$s Mídia salva - Arquivo: %1$s + Ficheiro: %1$s Senha E-mail Contas @@ -547,7 +547,7 @@ Toque aqui para importar um tema exportado previamente Exportar o tema Toque aqui para exportar o tema atual - Ocorreu um erro ao selecionar o arquivo do tema + Ocorreu um erro ao selecionar o ficheiro do tema Número de usuários Número de status Número de instâncias -- cgit v1.2.3 From 098e2d87ec1270db6defc9537ec035cb0aaf91cd Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 12 Jan 2023 09:54:43 +0100 Subject: Some fixes --- .../java/app/fedilab/android/helper/PinnedTimelineHelper.java | 2 +- .../main/java/app/fedilab/android/ui/drawer/StatusAdapter.java | 2 +- src/fdroid/fastlane/metadata/android/en/changelogs/464.txt | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/464.txt diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index 7a39946da..4f92c1e84 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -464,7 +464,7 @@ public class PinnedTimelineHelper { break; case NITTER: item.setIcon(R.drawable.nitter); - if (pinnedTimeline.remoteInstance.displayName.trim().length() > 0) { + if (pinnedTimeline.remoteInstance.displayName != null && pinnedTimeline.remoteInstance.displayName.trim().length() > 0) { item.setTitle(pinnedTimeline.remoteInstance.displayName); } else { item.setTitle(pinnedTimeline.remoteInstance.host); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index baa1a162c..24d837d5f 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -2615,7 +2615,7 @@ public class StatusAdapter extends RecyclerView.Adapter holder.bindingArt.artMedia.setScaleType(ImageView.ScaleType.FIT_CENTER); holder.bindingArt.artMedia.setLayoutParams(lp); RequestBuilder requestBuilder = prepareRequestBuilder(context, status.art_attachment, mediaW * ratio, mediaH * ratio, 1.0f, 1.0f, status.sensitive, true); - requestBuilder.into(holder.bindingArt.artMedia); + requestBuilder.load(status.art_attachment.preview_url).into(holder.bindingArt.artMedia); } } diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt new file mode 100644 index 000000000..e53c48692 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt @@ -0,0 +1,9 @@ +Added: + + +Changed: + + +Fixed: +- Fix a crash with Art timelines +- Fix a crash with pinned timelines \ No newline at end of file -- cgit v1.2.3 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 From d5a5f0872798fcd7e58e57c10b21549736e9b86d Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 12 Jan 2023 14:35:44 +0100 Subject: Instance directory --- app/src/main/AndroidManifest.xml | 5 ++ .../java/app/fedilab/android/BaseMainActivity.java | 4 ++ .../android/activities/DirectoryActivity.java | 83 ++++++++++++++++++++++ .../client/endpoints/MastodonAccountsService.java | 11 +++ .../android/client/entities/app/Timeline.java | 2 + .../java/app/fedilab/android/helper/Helper.java | 2 + .../fragment/timeline/FragmentMastodonAccount.java | 20 +++++- .../android/viewmodel/mastodon/AccountsVM.java | 33 ++++++++- .../ic_baseline_perm_contact_calendar_24.xml | 10 +++ app/src/main/res/layout/activity_directory.xml | 31 ++++++++ app/src/main/res/menu/activity_main_drawer.xml | 5 ++ app/src/main/res/menu/menu_directory.xml | 23 ++++++ app/src/main/res/values/strings.xml | 2 + .../metadata/android/en/changelogs/464.txt | 1 + 14 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/activities/DirectoryActivity.java create mode 100644 app/src/main/res/drawable/ic_baseline_perm_contact_calendar_24.xml create mode 100644 app/src/main/res/layout/activity_directory.xml create mode 100644 app/src/main/res/menu/menu_directory.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6543017c5..61a0d0a4a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -249,6 +249,11 @@ android:configChanges="keyboardHidden|orientation|screenSize" android:label="@string/Suggestions" android:theme="@style/AppThemeBar" /> + . */ + +import static app.fedilab.android.client.entities.app.Timeline.TimeLineEnum.ACCOUNT_DIRECTORY; + +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; + +import org.jetbrains.annotations.NotNull; + +import app.fedilab.android.R; +import app.fedilab.android.databinding.ActivityDirectoryBinding; +import app.fedilab.android.helper.Helper; +import app.fedilab.android.ui.fragment.timeline.FragmentMastodonAccount; + + +public class DirectoryActivity extends BaseBarActivity { + + private static boolean local = false; + private static String order = "active"; + private FragmentMastodonAccount fragmentMastodonAccount; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ActivityDirectoryBinding binding = ActivityDirectoryBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + fragmentMastodonAccount = new FragmentMastodonAccount(); + Bundle bundle = new Bundle(); + bundle.putBoolean(Helper.ARG_DIRECTORY_LOCAL, local); + bundle.putString(Helper.ARG_DIRECTORY_ORDER, order); + bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, ACCOUNT_DIRECTORY); + Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_directory, fragmentMastodonAccount, bundle, null, null); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_directory, menu); + if (order.equals("active")) { + menu.findItem(R.id.order_active).setChecked(true); + } else { + menu.findItem(R.id.order_new).setChecked(true); + } + menu.findItem(R.id.action_local).setChecked(local); + return true; + } + + @Override + public boolean onOptionsItemSelected(@NotNull MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } else if (item.getItemId() == R.id.action_local) { + item.setChecked(!item.isChecked()); + local = item.isChecked(); + } else if (item.getItemId() == R.id.order_active) { + order = "active"; + } else if (item.getItemId() == R.id.order_new) { + order = "new"; + } + recreate(); + return super.onOptionsItemSelected(item); + } + +} 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 28b10231d..b7cba8995 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 @@ -417,4 +417,15 @@ public interface MastodonAccountsService { @Header("Authorization") String token, @Path("account_id") String account_id ); + + + //Get user suggestions + @GET("directory") + Call> getDirectory( + @Header("Authorization") String token, + @Query("offset") Integer offset, + @Query("limit") Integer limit, + @Query("order") String order, + @Query("local") Boolean local + ); } diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java index e3c5fa665..c4196055c 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java @@ -382,6 +382,8 @@ public class Timeline { TREND_MESSAGE("TREND_MESSAGE"), @SerializedName("ACCOUNT_SUGGESTION") ACCOUNT_SUGGESTION("ACCOUNT_SUGGESTION"), + @SerializedName("ACCOUNT_DIRECTORY") + ACCOUNT_DIRECTORY("ACCOUNT_DIRECTORY"), @SerializedName("PUBLIC_TREND_MESSAGE") TREND_MESSAGE_PUBLIC("TREND_MESSAGE_PUBLIC"), @SerializedName("STATUS_HISTORY") diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index 2d31e6059..23fd97a3a 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -253,6 +253,8 @@ public class Helper { public static final String ARG_WORK_ID = "ARG_WORK_ID"; public static final String ARG_LIST_ID = "ARG_LIST_ID"; public static final String ARG_SEARCH_KEYWORD = "ARG_SEARCH_KEYWORD"; + public static final String ARG_DIRECTORY_ORDER = "ARG_DIRECTORY_ORDER"; + public static final String ARG_DIRECTORY_LOCAL = "ARG_DIRECTORY_LOCAL"; public static final String ARG_SEARCH_TYPE = "ARG_SEARCH_TYPE"; public static final String ARG_SEARCH_KEYWORD_CACHE = "ARG_SEARCH_KEYWORD_CACHE"; public static final String ARG_VIEW_MODEL_KEY = "ARG_VIEW_MODEL_KEY"; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java index b71ef24c5..e8270311d 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java @@ -15,6 +15,8 @@ package app.fedilab.android.ui.fragment.timeline; * see . */ +import static app.fedilab.android.helper.MastodonHelper.ACCOUNTS_PER_CALL; + import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -63,6 +65,8 @@ public class FragmentMastodonAccount extends Fragment { private FedilabProfileTLPageAdapter.follow_type followType; private String viewModelKey; private Timeline.TimeLineEnum timelineType; + private String order; + private Boolean local; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -72,6 +76,8 @@ public class FragmentMastodonAccount extends Fragment { followType = (FedilabProfileTLPageAdapter.follow_type) getArguments().getSerializable(Helper.ARG_FOLLOW_TYPE); viewModelKey = getArguments().getString(Helper.ARG_VIEW_MODEL_KEY, ""); timelineType = (Timeline.TimeLineEnum) getArguments().get(Helper.ARG_TIMELINE_TYPE); + order = getArguments().getString(Helper.ARG_DIRECTORY_ORDER, "active"); + local = getArguments().getBoolean(Helper.ARG_DIRECTORY_LOCAL, false); } flagLoading = false; binding = FragmentPaginationBinding.inflate(inflater, container, false); @@ -159,7 +165,15 @@ public class FragmentMastodonAccount extends Fragment { .observe(getViewLifecycleOwner(), this::initializeAccountCommonView); } else { accountsVM.getBlocks(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, String.valueOf(MastodonHelper.accountsPerCall(requireActivity())), max_id, null) + .observe(getViewLifecycleOwner(), this::dealWithPagination); + } + } else if (timelineType == Timeline.TimeLineEnum.ACCOUNT_DIRECTORY) { + if (firstLoad) { + accountsVM.getDirectory(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, 0, ACCOUNTS_PER_CALL, order, local) .observe(getViewLifecycleOwner(), this::initializeAccountCommonView); + } else { + accountsVM.getDirectory(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, offset, ACCOUNTS_PER_CALL, order, local) + .observe(getViewLifecycleOwner(), this::dealWithPagination); } } } @@ -223,8 +237,10 @@ public class FragmentMastodonAccount extends Fragment { this.accounts = accounts.accounts; accountAdapter = new AccountAdapter(this.accounts, timelineType == Timeline.TimeLineEnum.MUTED_TIMELINE_HOME); - if (search == null) { + if (search == null && timelineType != Timeline.TimeLineEnum.ACCOUNT_DIRECTORY) { flagLoading = accounts.pagination.max_id == null; + } else if (timelineType != Timeline.TimeLineEnum.ACCOUNT_DIRECTORY) { + offset += ACCOUNTS_PER_CALL; } else { offset += MastodonHelper.SEARCH_PER_CALL; } @@ -288,6 +304,8 @@ public class FragmentMastodonAccount extends Fragment { max_id = fetched_accounts.pagination.max_id; if (search != null) { offset += MastodonHelper.SEARCH_PER_CALL; + } else if (timelineType == Timeline.TimeLineEnum.ACCOUNT_DIRECTORY) { + offset += ACCOUNTS_PER_CALL; } accountAdapter.notifyItemRangeInserted(startId, fetched_accounts.accounts.size()); } else { 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 e9f23ec1a..1567a5024 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 @@ -1595,7 +1595,7 @@ public class AccountsVM extends AndroidViewModel { * Accounts the user has had past positive interactions with, but is not yet following. * * @param limit Maximum number of results to return. Defaults to 40. - * @return {@link LiveData} containing a {@link List} of {@link Account}s + * @return {@link LiveData} containing a {@link List} of {@link Suggestion}s */ public LiveData getSuggestions(@NonNull String instance, String token, String limit) { suggestionsMutableLiveData = new MutableLiveData<>(); @@ -1621,6 +1621,37 @@ public class AccountsVM extends AndroidViewModel { return suggestionsMutableLiveData; } + /** + * List accounts visible in the directory. + * + * @param limit Maximum number of results to return. Defaults to 40. + * @return {@link LiveData} containing a {@link List} of {@link Account}s + */ + public LiveData getDirectory(@NonNull String instance, String token, Integer offset, Integer limit, String order, Boolean local) { + accountsMutableLiveData = new MutableLiveData<>(); + MastodonAccountsService mastodonAccountsService = init(instance); + new Thread(() -> { + Call> accountsCall = mastodonAccountsService.getDirectory(token, offset, limit, order, local); + Accounts accounts = new Accounts(); + + if (accountsCall != null) { + try { + Response> directoryResponse = accountsCall.execute(); + if (directoryResponse.isSuccessful()) { + accounts.pagination = MastodonHelper.getOffSetPagination(directoryResponse.headers()); + accounts.accounts = directoryResponse.body(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> accountsMutableLiveData.setValue(accounts); + mainHandler.post(myRunnable); + }).start(); + return accountsMutableLiveData; + } + /** * Remove an account from follow suggestions. * diff --git a/app/src/main/res/drawable/ic_baseline_perm_contact_calendar_24.xml b/app/src/main/res/drawable/ic_baseline_perm_contact_calendar_24.xml new file mode 100644 index 000000000..ea5ff25ad --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_perm_contact_calendar_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_directory.xml b/app/src/main/res/layout/activity_directory.xml new file mode 100644 index 000000000..c56531852 --- /dev/null +++ b/app/src/main/res/layout/activity_directory.xml @@ -0,0 +1,31 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index 63e6efefa..d415eb68c 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -63,6 +63,11 @@ android:icon="@drawable/ic_baseline_account_circle_24" android:title="@string/Suggestions" android:visible="true" /> + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 52f4e2280..3567f9442 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -486,6 +486,7 @@ Unresolved Remote Active + New Pending Disabled Suspended @@ -2206,4 +2207,5 @@ Compact action buttons Buttons at the bottom of messages will not take the whole width Followed by: + Directory \ 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 4ced9f605..b3e900aa2 100644 --- a/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/464.txt @@ -1,5 +1,6 @@ Added: - Display familiar followers on profiles +- Display and filter Instance directory Changed: -- cgit v1.2.3 From 1ef01af199510749758f10d53313c0cf83253677 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 12 Jan 2023 14:55:53 +0100 Subject: Some cleaning --- .../android/activities/DirectoryActivity.java | 4 +- .../fedilab/android/ui/drawer/StatusAdapter.java | 129 ++++++++++----------- .../timeline/FragmentMastodonTimeline.java | 4 +- 3 files changed, 67 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/activities/DirectoryActivity.java b/app/src/main/java/app/fedilab/android/activities/DirectoryActivity.java index 73c14fb0e..1b68d213f 100644 --- a/app/src/main/java/app/fedilab/android/activities/DirectoryActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/DirectoryActivity.java @@ -32,7 +32,6 @@ public class DirectoryActivity extends BaseBarActivity { private static boolean local = false; private static String order = "active"; - private FragmentMastodonAccount fragmentMastodonAccount; @Override protected void onCreate(Bundle savedInstanceState) { @@ -43,12 +42,11 @@ public class DirectoryActivity extends BaseBarActivity { if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); } - fragmentMastodonAccount = new FragmentMastodonAccount(); Bundle bundle = new Bundle(); bundle.putBoolean(Helper.ARG_DIRECTORY_LOCAL, local); bundle.putString(Helper.ARG_DIRECTORY_ORDER, order); bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, ACCOUNT_DIRECTORY); - Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_directory, fragmentMastodonAccount, bundle, null, null); + Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_directory, new FragmentMastodonAccount(), bundle, null, null); } @Override diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 24d837d5f..f1ed7df88 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -163,6 +163,8 @@ public class StatusAdapter extends RecyclerView.Adapter public static final int STATUS_FILTERED = 3; public static final int STATUS_FILTERED_HIDE = 4; public static final int STATUS_PIXELFED = 5; + private static float measuredWidth = -1; + private static float measuredWidthArt = -1; private final List statusList; private final boolean minified; private final Timeline.TimeLineEnum timelineType; @@ -171,10 +173,7 @@ public class StatusAdapter extends RecyclerView.Adapter public FetchMoreCallBack fetchMoreCallBack; private Context context; private boolean visiblePixelfed; - private RecyclerView mRecyclerView; - private static float measuredWidth = -1; - private static float measuredWidthArt = -1; public StatusAdapter(List statuses, Timeline.TimeLineEnum timelineType, boolean minified, boolean canBeFederated, boolean checkRemotely) { this.statusList = statuses; @@ -2246,53 +2245,6 @@ public class StatusAdapter extends RecyclerView.Adapter } - @NonNull - @Override - public List getPreloadItems(int position) { - List attachments = new ArrayList<>(); - if (position == 0 && statusList.size() > 0) { - for (Status status : statusList.subList(0, 1)) { - Status statusToDeal = status.reblog != null ? status.reblog : status; - if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0) { - attachments.addAll(statusToDeal.media_attachments); - } - } - } else if (position > 0 && position < (statusList.size() - 1)) { - for (Status status : statusList.subList(position - 1, position + 1)) { - Status statusToDeal = status.reblog != null ? status.reblog : status; - if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0) { - attachments.addAll(statusToDeal.media_attachments); - } - } - } else { - for (Status status : statusList.subList(position, position)) { - Status statusToDeal = status.reblog != null ? status.reblog : status; - if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0) { - attachments.addAll(statusToDeal.media_attachments); - } - } - } - return attachments; - } - - @Nullable - @Override - public RequestBuilder getPreloadRequestBuilder(@NonNull Attachment attachment) { - float focusX = 0.f; - float focusY = 0.f; - if (attachment.meta != null && attachment.meta.focus != null) { - focusX = attachment.meta.focus.x; - focusY = attachment.meta.focus.y; - } - int mediaH = 0; - int mediaW = 0; - if (attachment.meta != null && attachment.meta.small != null) { - mediaH = attachment.meta.small.height; - mediaW = attachment.meta.small.width; - } - return prepareRequestBuilder(context, attachment, mediaW, mediaH, focusX, focusY, attachment.sensitive, timelineType == Timeline.TimeLineEnum.ART).load(attachment); - } - /** * Send a broadcast to other open fragments that content a timeline * @@ -2317,21 +2269,6 @@ public class StatusAdapter extends RecyclerView.Adapter LocalBroadcastManager.getInstance(context).sendBroadcast(intentBC); } - /* private static boolean mediaObfuscated(Status status) { - //Media is not sensitive and doesn't have a spoiler text - if (!status.isMediaObfuscated) { - return false; - } - if (!status.sensitive && (status.spoiler_text == null || status.spoiler_text.trim().isEmpty())) { - return false; - } - if (status.isMediaObfuscated && status.spoiler_text != null && !status.spoiler_text.trim().isEmpty()) { - return true; - } else { - return status.sensitive; - } - }*/ - public static void applyColor(Context context, StatusViewHolder holder) { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; @@ -2418,6 +2355,68 @@ public class StatusAdapter extends RecyclerView.Adapter } } + @NonNull + @Override + public List getPreloadItems(int position) { + List attachments = new ArrayList<>(); + if (position == 0 && statusList.size() > 0) { + for (Status status : statusList.subList(0, 1)) { + Status statusToDeal = status.reblog != null ? status.reblog : status; + if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0) { + attachments.addAll(statusToDeal.media_attachments); + } + } + } else if (position > 0 && position < (statusList.size() - 1)) { + for (Status status : statusList.subList(position - 1, position + 1)) { + Status statusToDeal = status.reblog != null ? status.reblog : status; + if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0) { + attachments.addAll(statusToDeal.media_attachments); + } + } + } else { + for (Status status : statusList.subList(position, position)) { + Status statusToDeal = status.reblog != null ? status.reblog : status; + if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0) { + attachments.addAll(statusToDeal.media_attachments); + } + } + } + return attachments; + } + + /* private static boolean mediaObfuscated(Status status) { + //Media is not sensitive and doesn't have a spoiler text + if (!status.isMediaObfuscated) { + return false; + } + if (!status.sensitive && (status.spoiler_text == null || status.spoiler_text.trim().isEmpty())) { + return false; + } + if (status.isMediaObfuscated && status.spoiler_text != null && !status.spoiler_text.trim().isEmpty()) { + return true; + } else { + return status.sensitive; + } + }*/ + + @Nullable + @Override + public RequestBuilder getPreloadRequestBuilder(@NonNull Attachment attachment) { + float focusX = 0.f; + float focusY = 0.f; + if (attachment.meta != null && attachment.meta.focus != null) { + focusX = attachment.meta.focus.x; + focusY = attachment.meta.focus.y; + } + int mediaH = 0; + int mediaW = 0; + if (attachment.meta != null && attachment.meta.small != null) { + mediaH = attachment.meta.small.height; + mediaW = attachment.meta.small.width; + } + return prepareRequestBuilder(context, attachment, mediaW, mediaH, focusX, focusY, attachment.sensitive, timelineType == Timeline.TimeLineEnum.ART).load(attachment); + } + @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); 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 d4a84a5fd..030215302 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 @@ -76,6 +76,7 @@ import es.dmoral.toasty.Toasty; public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.FetchMoreCallBack { + private static final int PRELOAD_AHEAD_ITEMS = 10; public UpdateCounters update; private FragmentPaginationBinding binding; private TimelinesVM timelinesVM; @@ -88,8 +89,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private StatusAdapter statusAdapter; private Timeline.TimeLineEnum timelineType; private List timelineStatuses; - private static final int PRELOAD_AHEAD_ITEMS = 10; - private ViewPreloadSizeProvider preloadSizeProvider; //Handle actions that can be done in other fragments private final BroadcastReceiver receive_action = new BroadcastReceiver() { @Override @@ -179,6 +178,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } } }; + private ViewPreloadSizeProvider preloadSizeProvider; private boolean checkRemotely; private String accountIDInRemoteInstance; private boolean isViewInitialized; -- cgit v1.2.3 From 80927bfa9c3f4ee71c82abf947d36beea6e3ccbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Thu, 12 Jan 2023 14:39:10 +0100 Subject: Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 99.7% (1037 of 1040 strings) Co-authored-by: Lukáš Jelínek Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/ Translation: Fedilab/Strings --- app/src/main/res/values-cs/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 67ecae103..d4df276b9 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -973,4 +973,7 @@ Ztišen(a) Kompaktní tlačítka akcí Tlačítka v dolní části zpráv nezaberou celou šířku + Viditelnost odpovědí + Viditelnost vyloučení + Sledován(a): \ No newline at end of file -- cgit v1.2.3 From ae31abaa3bc0531e3fe82a0261369a9bea890fba Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 12 Jan 2023 15:58:59 +0100 Subject: Bot and reply icon indicators more visible --- .../main/res/drawable/ic_baseline_android_24.xml | 10 ++++++ app/src/main/res/layout/drawer_status.xml | 40 +++++++++++++--------- .../metadata/android/en/changelogs/464.txt | 2 +- 3 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 app/src/main/res/drawable/ic_baseline_android_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_android_24.xml b/app/src/main/res/drawable/ic_baseline_android_24.xml new file mode 100644 index 000000000..b812e1ed0 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_android_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/drawer_status.xml b/app/src/main/res/layout/drawer_status.xml index d28cfe2bb..443a3e57d 100644 --- a/app/src/main/res/layout/drawer_status.xml +++ b/app/src/main/res/layout/drawer_status.xml @@ -119,23 +119,6 @@ app:layout_constraintTop_toTopOf="parent" tools:src="@tools:sample/avatars" /> - - - @@ -147,8 +130,31 @@ + + + + Date: Thu, 12 Jan 2023 17:11:27 +0100 Subject: Fix media cannot be downloaded --- app/src/main/java/app/fedilab/android/helper/MediaHelper.java | 11 ++++++++--- src/fdroid/fastlane/metadata/android/en/changelogs/464.txt | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/helper/MediaHelper.java b/app/src/main/java/app/fedilab/android/helper/MediaHelper.java index b6f65f7c7..1a60e74af 100644 --- a/app/src/main/java/app/fedilab/android/helper/MediaHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/MediaHelper.java @@ -100,7 +100,10 @@ public class MediaHelper { } try { String mime = getMimeType(url); - final String fileName = URLUtil.guessFileName(url, null, null); + String fileName = URLUtil.guessFileName(url, null, null); + if (fileName.endsWith(".bin")) { + fileName = fileName.replace(".bin", ".mp4"); + } re