diff --git a/app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java b/app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java index 7d49b26d..3338d7a8 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java +++ b/app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java @@ -77,7 +77,7 @@ public class Nitter implements Serializable { public static Status convert(Context context, String instance, FeedItem feedItem) { Status status = new Status(); status.id = feedItem.pubDate; - status.content = feedItem.title; + status.content = feedItem.description; status.text = feedItem.title; status.visibility = "public"; status.created_at = Helper.stringToDateWithFormat(context, feedItem.pubDate, "EEE, dd MMM yyyy HH:mm:ss zzz"); @@ -103,8 +103,8 @@ public class Nitter implements Serializable { app.fedilab.android.client.entities.api.Account account = new app.fedilab.android.client.entities.api.Account(); String[] names = nitterAccount.image.title.split("/"); account.id = feedItem.guid; - account.acct = names[1]; - account.username = names[1]; + account.acct = names[1].replace("@", ""); + account.username = names[1].replace("@", ""); account.display_name = names[0]; account.avatar = nitterAccount.image.url; account.avatar_static = nitterAccount.image.url; 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 20b76d84..7fbddaff 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -650,8 +650,9 @@ public class Helper { } else { Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (!url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://") && !url.toLowerCase().startsWith("gemini://")) + if (url != null && !url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://") && !url.toLowerCase().startsWith("gemini://")) { url = "http://" + url; + } intent.setData(Uri.parse(url)); try { context.startActivity(intent); diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index d04ea780..222c94ab 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -1007,6 +1007,41 @@ public class SpannableHelper { return statuses; } + public static List convertNitterStatus(Context context, List statuses) { + if (statuses != null) { + for (Status status : statuses) { + convertNitterStatus(context, status); + } + } + return statuses; + } + + public static Status convertNitterStatus(Context context, Status status) { + if (status != null) { + status.span_content = SpannableHelper.convertNitter(context, status.content); + } + return status; + } + + /** + * Convert HTML content to text. Also, it handles click on link and transform emoji + * This needs to be run asynchronously + * + * @param context {@link Context} + * @param text String - text to convert, it can be content, spoiler, poll items, etc. + * @return Spannable string + */ + private static Spannable convertNitter(@NonNull Context context, String text) { + SpannableString initialContent; + if (text == null) { + return null; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); + else + initialContent = new SpannableString(Html.fromHtml(text)); + return initialContent; + } public static List convertAnnouncement(Context context, List announcements) { if (announcements != null) { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ContextAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ContextAdapter.java index b9afc7fc..8c8af5c3 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ContextAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ContextAdapter.java @@ -72,7 +72,7 @@ public class ContextAdapter extends RecyclerView.Adapter private final Timeline.TimeLineEnum timelineType; public FetchMoreCallBack fetchMoreCallBack; private Context context; + private final boolean canBeFederated; - public StatusAdapter(List statuses, Timeline.TimeLineEnum timelineType, boolean minified) { + public StatusAdapter(List statuses, Timeline.TimeLineEnum timelineType, boolean minified, boolean canBeFederated) { this.statusList = statuses; this.timelineType = timelineType; this.minified = minified; + this.canBeFederated = canBeFederated; } @@ -293,7 +295,7 @@ public class StatusAdapter extends RecyclerView.Adapter List notificationList, Status status, Timeline.TimeLineEnum timelineType, - boolean minified) { + boolean minified, boolean canBeFederated) { if (status == null) { return; } @@ -469,7 +471,7 @@ public class StatusAdapter extends RecyclerView.Adapter } else { holder.binding.card.setVisibility(View.GONE); } - if (minified) { + if (minified || !canBeFederated) { holder.binding.actionButtons.setVisibility(View.GONE); } else { holder.binding.actionButtons.setVisibility(View.VISIBLE); @@ -1298,7 +1300,7 @@ public class StatusAdapter extends RecyclerView.Adapter } return false; }); - if (!minified) { + if (!minified && canBeFederated) { holder.binding.mainContainer.setOnClickListener(v -> { holder.binding.statusContent.callOnClick(); }); @@ -1335,6 +1337,9 @@ public class StatusAdapter extends RecyclerView.Adapter } } }); + } else if (!canBeFederated) { + holder.binding.mainContainer.setOnClickListener(v -> Helper.openBrowser(context, status.url)); + holder.binding.statusContent.setOnClickListener(v -> Helper.openBrowser(context, status.url)); } @@ -1756,7 +1761,7 @@ public class StatusAdapter extends RecyclerView.Adapter StatusViewHolder holder = (StatusViewHolder) viewHolder; StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class); SearchVM searchVM = new ViewModelProvider((ViewModelStoreOwner) context).get(SearchVM.class); - statusManagement(context, statusesVM, searchVM, holder, this, statusList, null, status, timelineType, minified); + statusManagement(context, statusesVM, searchVM, holder, this, statusList, null, status, timelineType, minified, canBeFederated); if (holder.timer != null) { holder.timer.cancel(); holder.timer = null; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java index e46dc045..a807bcc9 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java @@ -169,7 +169,7 @@ public class FragmentMastodonContext extends Fragment { this.statuses = new ArrayList<>(); focusedStatus.isFocused = true; this.statuses.add(focusedStatus); - statusAdapter = new StatusAdapter(this.statuses, Timeline.TimeLineEnum.UNKNOWN, false); + statusAdapter = new StatusAdapter(this.statuses, Timeline.TimeLineEnum.UNKNOWN, false, true); binding.swipeContainer.setRefreshing(false); LinearLayoutManager mLayoutManager = new LinearLayoutManager(requireActivity()); binding.recyclerView.setLayoutManager(mLayoutManager); 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 7eb49695..7bb4f08d 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 @@ -144,6 +144,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private String ident; private String instance, user_id; private ArrayList idOfAddedStatuses; + private boolean canBeFederated; /** * Return the position of the status in the ArrayList @@ -199,6 +200,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. timelineType = Timeline.TimeLineEnum.HOME; instance = MainActivity.currentInstance; user_id = MainActivity.currentUserID; + canBeFederated = true; if (getArguments() != null) { timelineType = (Timeline.TimeLineEnum) getArguments().get(Helper.ARG_TIMELINE_TYPE); list_id = getArguments().getString(Helper.ARG_LIST_ID, null); @@ -211,6 +213,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } else { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()); remoteInstance = sharedpreferences.getString(getString(R.string.SET_NITTER_HOST), getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase(); + canBeFederated = false; } } @@ -336,12 +339,13 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (min_id == null || (statuses.pagination.min_id != null && statuses.pagination.min_id.compareTo(min_id) > 0)) { min_id = statuses.pagination.min_id; } - statusAdapter = new StatusAdapter(this.statuses, timelineType, minified); + statusAdapter = new StatusAdapter(this.statuses, timelineType, minified, canBeFederated); statusAdapter.fetchMoreCallBack = this; if (statusReport != null) { scrollToTop(); } mLayoutManager = new LinearLayoutManager(requireActivity()); + mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); binding.recyclerView.setLayoutManager(mLayoutManager); binding.recyclerView.setAdapter(statusAdapter); diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java index d5a65f74..a877e57a 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java @@ -184,11 +184,9 @@ public class TimelinesVM extends AndroidViewModel { statusList.add(status); } } - List filteredStatuses = TimelineHelper.filterStatus(getApplication(), statusList, TimelineHelper.FilterTimeLineType.PUBLIC); - statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), filteredStatuses); + statuses.statuses = SpannableHelper.convertNitterStatus(getApplication().getApplicationContext(), statusList); statuses.pagination = MastodonHelper.getPagination(publicTlResponse.headers()); } - } catch (Exception e) { e.printStackTrace(); }