mirror of
				https://codeberg.org/tom79/Fedilab.git
				synced 2025-10-20 11:20:16 +03:00 
			
		
		
		
	Follow Twitter/X tags through Nitter
This commit is contained in:
		
							parent
							
								
									0d2ae2eedf
								
							
						
					
					
						commit
						88c18cc487
					
				
					 8 changed files with 54 additions and 17 deletions
				
			
		|  | @ -212,6 +212,10 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart | |||
|                     SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ReorderTimelinesActivity.this); | ||||
|                     String nitterHost = sharedpreferences.getString(getString(R.string.SET_NITTER_HOST), getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase(); | ||||
|                     url = "https://" + nitterHost + "/" + instanceName.replaceAll("[ ]+", ",").replaceAll("\\s", "") + "/with_replies/rss"; | ||||
|                 }else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.twitter_tags) { | ||||
|                     SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ReorderTimelinesActivity.this); | ||||
|                     String nitterHost = sharedpreferences.getString(getString(R.string.SET_NITTER_HOST), getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase(); | ||||
|                     url = "https://" + nitterHost + "/search?f=tweets&q=" + instanceName.replaceAll("[ ]+", "+or+").replaceAll("\\s", "") + "&e-nativeretweets=on"; | ||||
|                 } | ||||
|                 OkHttpClient client = new OkHttpClient.Builder() | ||||
|                         .connectTimeout(10, TimeUnit.SECONDS) | ||||
|  | @ -257,6 +261,8 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart | |||
|                                         instanceType = RemoteInstance.InstanceType.GNU; | ||||
|                                     } else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.twitter_accounts) { | ||||
|                                         instanceType = RemoteInstance.InstanceType.NITTER; | ||||
|                                     } else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.twitter_tags) { | ||||
|                                         instanceType = RemoteInstance.InstanceType.NITTER_TAG; | ||||
|                                     } | ||||
|                                     RemoteInstance remoteInstance = new RemoteInstance(); | ||||
|                                     remoteInstance.type = instanceType; | ||||
|  |  | |||
|  | @ -46,6 +46,8 @@ public class RemoteInstance implements Serializable { | |||
|         PEERTUBE("PEERTUBE"), | ||||
|         @SerializedName("NITTER") | ||||
|         NITTER("NITTER"), | ||||
|         @SerializedName("NITTER_TAG") | ||||
|         NITTER_TAG("NITTER_TAG"), | ||||
|         @SerializedName("MISSKEY") | ||||
|         MISSKEY("MISSKEY"), | ||||
|         @SerializedName("LEMMY") | ||||
|  |  | |||
|  | @ -341,10 +341,10 @@ public class PinnedTimelineHelper { | |||
|                         break; | ||||
|                     case REMOTE: | ||||
|                         name = pinnedTimeline.remoteInstance.host; | ||||
|                         if (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) { | ||||
|                         if (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG) { | ||||
|                             String remoteInstance = sharedpreferences.getString(activity.getString(R.string.SET_NITTER_HOST), activity.getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase(); | ||||
|                             //Custom name for Nitter instances | ||||
|                             if (pinnedTimeline.remoteInstance.displayName != null && pinnedTimeline.remoteInstance.displayName.trim().length() > 0) { | ||||
|                             if (pinnedTimeline.remoteInstance.displayName != null && !pinnedTimeline.remoteInstance.displayName.trim().isEmpty()) { | ||||
|                                 name = pinnedTimeline.remoteInstance.displayName; | ||||
|                             } | ||||
|                             ident = "@R@" + remoteInstance; | ||||
|  | @ -378,6 +378,7 @@ public class PinnedTimelineHelper { | |||
|                                 case MISSKEY: | ||||
|                                     tabCustomViewBinding.icon.setImageResource(R.drawable.misskey); | ||||
|                                     break; | ||||
|                                 case NITTER_TAG: | ||||
|                                 case NITTER: | ||||
|                                     tabCustomViewBinding.icon.setImageResource(R.drawable.nitter); | ||||
|                                     break; | ||||
|  | @ -471,9 +472,10 @@ public class PinnedTimelineHelper { | |||
|                             case PIXELFED: | ||||
|                                 item.setIcon(R.drawable.pixelfed); | ||||
|                                 break; | ||||
|                             case NITTER_TAG: | ||||
|                             case NITTER: | ||||
|                                 item.setIcon(R.drawable.nitter); | ||||
|                                 if (pinnedTimeline.remoteInstance.displayName != null && pinnedTimeline.remoteInstance.displayName.trim().length() > 0) { | ||||
|                                 if (pinnedTimeline.remoteInstance.displayName != null && !pinnedTimeline.remoteInstance.displayName.trim().isEmpty()) { | ||||
|                                     item.setTitle(pinnedTimeline.remoteInstance.displayName); | ||||
|                                 } else { | ||||
|                                     item.setTitle(pinnedTimeline.remoteInstance.host); | ||||
|  | @ -525,7 +527,7 @@ public class PinnedTimelineHelper { | |||
|                         bubbleClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); | ||||
|                         break; | ||||
|                     case REMOTE: | ||||
|                         if (pinnedTimelineVisibleList.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER) { | ||||
|                         if (pinnedTimelineVisibleList.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER && pinnedTimelineVisibleList.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER_TAG) { | ||||
|                             instanceClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); | ||||
|                         } else { | ||||
|                             nitterClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); | ||||
|  | @ -1528,6 +1530,12 @@ public class PinnedTimelineHelper { | |||
|         PopupMenu popup = new PopupMenu(activity, view); | ||||
|         popup.getMenuInflater() | ||||
|                 .inflate(R.menu.option_nitter_timeline, popup.getMenu()); | ||||
|         if(remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG) { | ||||
|             MenuItem item = popup.getMenu().findItem(R.id.action_nitter_manage_accounts); | ||||
|             if(item != null) { | ||||
|                 item.setTitle(R.string.manage_tags); | ||||
|             } | ||||
|         } | ||||
|         int finalOffSetPosition = offSetPosition; | ||||
|         popup.setOnMenuItemClickListener(item -> { | ||||
|             int itemId = item.getItemId(); | ||||
|  | @ -1547,7 +1555,7 @@ public class PinnedTimelineHelper { | |||
|                 } | ||||
|                 dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { | ||||
|                     String values = editTextName.getText().toString(); | ||||
|                     if (values.trim().length() == 0) { | ||||
|                     if (values.trim().isEmpty()) { | ||||
|                         values = remoteInstance.displayName; | ||||
|                     } | ||||
|                     remoteInstance.displayName = values; | ||||
|  |  | |||
|  | @ -100,14 +100,15 @@ public class ReorderTabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol | |||
|                     case GNU: | ||||
|                         holder.binding.icon.setImageResource(R.drawable.ic_gnu_social); | ||||
|                         break; | ||||
|                     case NITTER_TAG: | ||||
|                     case NITTER: | ||||
|                         holder.binding.icon.setImageResource(R.drawable.nitter); | ||||
|                         break; | ||||
|                 } | ||||
|                 if (pinned.pinnedTimelines.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER) { | ||||
|                 if (pinned.pinnedTimelines.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER && pinned.pinnedTimelines.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER_TAG) { | ||||
|                     holder.binding.text.setText(pinned.pinnedTimelines.get(position).remoteInstance.host); | ||||
|                 } else { | ||||
|                     if (pinned.pinnedTimelines.get(position).remoteInstance.displayName != null && pinned.pinnedTimelines.get(position).remoteInstance.displayName.trim().length() > 0) { | ||||
|                     if (pinned.pinnedTimelines.get(position).remoteInstance.displayName != null && !pinned.pinnedTimelines.get(position).remoteInstance.displayName.trim().isEmpty()) { | ||||
|                         holder.binding.text.setText(pinned.pinnedTimelines.get(position).remoteInstance.displayName); | ||||
|                     } else { | ||||
|                         holder.binding.text.setText(pinned.pinnedTimelines.get(position).remoteInstance.host); | ||||
|  |  | |||
|  | @ -420,7 +420,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. | |||
|             pinnedTimeline = (PinnedTimeline) bundle.getSerializable(Helper.ARG_REMOTE_INSTANCE); | ||||
|             canBeFederated = true; | ||||
|             if (pinnedTimeline != null && pinnedTimeline.remoteInstance != null) { | ||||
|                 if (pinnedTimeline.remoteInstance.type != RemoteInstance.InstanceType.NITTER) { | ||||
|                 if (pinnedTimeline.remoteInstance.type != RemoteInstance.InstanceType.NITTER && pinnedTimeline.remoteInstance.type != RemoteInstance.InstanceType.NITTER_TAG) { | ||||
|                     remoteInstance = pinnedTimeline.remoteInstance.host; | ||||
|                 } else { | ||||
|                     SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()); | ||||
|  | @ -471,7 +471,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. | |||
|         } else if (list_id != null) { | ||||
|             ident = "@l@" + list_id; | ||||
|         } else if (remoteInstance != null && !checkRemotely) { | ||||
|             if (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) { | ||||
|             if (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG) { | ||||
|                 ident = "@R@" + pinnedTimeline.remoteInstance.host; | ||||
|             } else { | ||||
|                 ident = "@R@" + remoteInstance; | ||||
|  | @ -562,7 +562,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. | |||
|             } | ||||
|             //Update the timeline with new statuses | ||||
|             int insertedStatus; | ||||
|             if(pinnedTimeline!= null && pinnedTimeline.remoteInstance != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) { | ||||
|             if(pinnedTimeline!= null && pinnedTimeline.remoteInstance != null && (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG)) { | ||||
|                 insertedStatus = fetched_statuses.statuses.size(); | ||||
|                 int fromPosition = timelineStatuses.size(); | ||||
|                 timelineStatuses.addAll(fetched_statuses.statuses); | ||||
|  | @ -685,7 +685,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. | |||
|             max_id = statuses.pagination.max_id; | ||||
|         } | ||||
|         //For Lemmy and Nitter pagination | ||||
|         if (pinnedTimeline != null && pinnedTimeline.remoteInstance != null && (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.LEMMY || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER)) { | ||||
|         if (pinnedTimeline != null && pinnedTimeline.remoteInstance != null && (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.LEMMY || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG)) { | ||||
|             max_id = statuses.pagination.max_id; | ||||
|         } | ||||
|         if (min_id == null || (statuses.pagination.min_id != null && Helper.compareTo(statuses.pagination.min_id, min_id) > 0)) { | ||||
|  | @ -1049,20 +1049,20 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. | |||
|             routeCommon(direction, fetchingMissing, fetchStatus); | ||||
|         } else if (timelineType == Timeline.TimeLineEnum.REMOTE) { //REMOTE TIMELINE | ||||
|             //NITTER TIMELINES | ||||
|             if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) { | ||||
|             if (pinnedTimeline != null && (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG)) { | ||||
|                 if (direction == null) { | ||||
|                     timelinesVM.getNitterHTML(pinnedTimeline.remoteInstance.host, null) | ||||
|                     timelinesVM.getNitterHTML(pinnedTimeline.remoteInstance.type, pinnedTimeline.remoteInstance.host, null) | ||||
|                             .observe(getViewLifecycleOwner(), nitterStatuses -> { | ||||
|                                 initialStatuses = nitterStatuses; | ||||
|                                 initializeStatusesCommonView(nitterStatuses); | ||||
|                             }); | ||||
|                 } else if (direction == DIRECTION.BOTTOM) { | ||||
|                     timelinesVM.getNitterHTML(pinnedTimeline.remoteInstance.host, max_id) | ||||
|                     timelinesVM.getNitterHTML(pinnedTimeline.remoteInstance.type, pinnedTimeline.remoteInstance.host, max_id) | ||||
|                             .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus)); | ||||
|                 } else if (direction == DIRECTION.TOP) { | ||||
|                     flagLoading = false; | ||||
|                 } else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) { | ||||
|                     timelinesVM.getNitterHTML(pinnedTimeline.remoteInstance.host, null) | ||||
|                     timelinesVM.getNitterHTML(pinnedTimeline.remoteInstance.type, pinnedTimeline.remoteInstance.host, null) | ||||
|                             .observe(getViewLifecycleOwner(), statusesRefresh -> { | ||||
|                                 if (statusAdapter != null) { | ||||
|                                     dealWithPagination(statusesRefresh, direction, true, true, fetchStatus); | ||||
|  |  | |||
|  | @ -56,6 +56,7 @@ import app.fedilab.android.mastodon.client.entities.api.Status; | |||
| import app.fedilab.android.mastodon.client.entities.api.Statuses; | ||||
| import app.fedilab.android.mastodon.client.entities.api.Tag; | ||||
| import app.fedilab.android.mastodon.client.entities.app.BaseAccount; | ||||
| import app.fedilab.android.mastodon.client.entities.app.RemoteInstance; | ||||
| import app.fedilab.android.mastodon.client.entities.app.StatusCache; | ||||
| import app.fedilab.android.mastodon.client.entities.app.StatusDraft; | ||||
| import app.fedilab.android.mastodon.client.entities.app.Timeline; | ||||
|  | @ -300,6 +301,7 @@ public class TimelinesVM extends AndroidViewModel { | |||
|      * @return {@link LiveData} containing a {@link Statuses} | ||||
|      */ | ||||
|     public LiveData<Statuses> getNitterHTML( | ||||
|             RemoteInstance.InstanceType instanceType, | ||||
|             String accountsStr, | ||||
|             String max_position) { | ||||
|         statusesMutableLiveData = new MutableLiveData<>(); | ||||
|  | @ -307,9 +309,20 @@ public class TimelinesVM extends AndroidViewModel { | |||
|         SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); | ||||
|         final String nitterInstance = sharedpreferences.getString(context.getString(R.string.SET_NITTER_HOST), context.getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase(); | ||||
|         final String fedilabInstance =  "nitter.fedilab.app"; | ||||
|         accountsStr = accountsStr.replaceAll("\\s", ",").replaceAll(",,",","); | ||||
| 
 | ||||
|         String cursor = max_position == null ? "" : max_position; | ||||
|         String url = "https://"+fedilabInstance+"/" + accountsStr + "/with_replies" +cursor; | ||||
|         String url; | ||||
|         accountsStr = accountsStr.replaceAll("\\s", ",").replaceAll(",,",","); | ||||
|         if(instanceType == RemoteInstance.InstanceType.NITTER) { | ||||
|             url = "https://"+fedilabInstance+"/" + accountsStr + "/with_replies" +cursor; | ||||
|         } else { | ||||
|             String[] tags = accountsStr.split(","); | ||||
|             StringBuilder tagsQuery = new StringBuilder(); | ||||
|             for(String tag: tags) { | ||||
|                 tagsQuery.append("%23").append(tag).append("+or+"); | ||||
|             } | ||||
|             url  = "https://"+fedilabInstance+"/search?f=tweets&q=" + tagsQuery +"&e-nativeretweets=on&" +cursor; | ||||
|         } | ||||
|         Request request = new Request.Builder() | ||||
|                 .header("User-Agent", context.getString(R.string.app_name) + "/" + BuildConfig.VERSION_NAME + "/" + BuildConfig.VERSION_CODE) | ||||
|                 .url(url) | ||||
|  |  | |||
|  | @ -65,6 +65,12 @@ | |||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:text="@string/twitter_accounts" /> | ||||
| 
 | ||||
|             <RadioButton | ||||
|                 android:id="@+id/twitter_tags" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:text="@string/twitter_tags" /> | ||||
|         </RadioGroup> | ||||
|     </ScrollView> | ||||
| </LinearLayout> | ||||
|  | @ -618,6 +618,7 @@ | |||
|     <string name="set_utm_parameters_indication">The app will automatically remove UTM parameters from URLs before visiting a link.</string> | ||||
|     <string name="talking_about">%d people talking</string> | ||||
|     <string name="twitter_accounts">Twitter accounts (via Nitter)</string> | ||||
|     <string name="twitter_tags">Twitter tags (via Nitter)</string> | ||||
|     <string name="list_of_twitter_accounts">Twitter usernames space separated</string> | ||||
|     <string name="identity_proofs">Identity proofs</string> | ||||
|     <string name="verified_user">Verified identity</string> | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue