mirror of
				https://codeberg.org/tom79/Fedilab.git
				synced 2025-10-20 11:20:16 +03:00 
			
		
		
		
	Follow Hashtags
This commit is contained in:
		
							parent
							
								
									170dbbd0cf
								
							
						
					
					
						commit
						cdbfb17d94
					
				
					 17 changed files with 527 additions and 16 deletions
				
			
		|  | @ -251,6 +251,11 @@ | |||
|             android:configChanges="keyboardHidden|orientation|screenSize" | ||||
|             android:label="@string/action_lists" | ||||
|             android:theme="@style/AppThemeBar" /> | ||||
|         <activity | ||||
|             android:name=".activities.FollowedTagActivity" | ||||
|             android:configChanges="keyboardHidden|orientation|screenSize" | ||||
|             android:label="@string/followed_tags" | ||||
|             android:theme="@style/AppThemeBar" /> | ||||
|         <activity | ||||
|             android:name=".activities.SettingsActivity" | ||||
|             android:configChanges="keyboardHidden|orientation|screenSize" | ||||
|  |  | |||
|  | @ -103,6 +103,7 @@ import app.fedilab.android.activities.ContextActivity; | |||
| import app.fedilab.android.activities.DraftActivity; | ||||
| import app.fedilab.android.activities.FilterActivity; | ||||
| import app.fedilab.android.activities.FollowRequestActivity; | ||||
| import app.fedilab.android.activities.FollowedTagActivity; | ||||
| import app.fedilab.android.activities.InstanceActivity; | ||||
| import app.fedilab.android.activities.InstanceHealthActivity; | ||||
| import app.fedilab.android.activities.LoginActivity; | ||||
|  | @ -359,6 +360,9 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt | |||
|             } else if (id == R.id.nav_list) { | ||||
|                 Intent intent = new Intent(this, MastodonListActivity.class); | ||||
|                 startActivity(intent); | ||||
|             } else if (id == R.id.nav_followed_tags) { | ||||
|                 Intent intent = new Intent(this, FollowedTagActivity.class); | ||||
|                 startActivity(intent); | ||||
|             } else if (id == R.id.nav_settings) { | ||||
|                 Intent intent = new Intent(this, SettingsActivity.class); | ||||
|                 startActivity(intent); | ||||
|  |  | |||
|  | @ -0,0 +1,202 @@ | |||
| package app.fedilab.android.activities; | ||||
| /* 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 android.graphics.drawable.ColorDrawable; | ||||
| import android.os.Bundle; | ||||
| import android.text.InputFilter; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.core.content.ContextCompat; | ||||
| import androidx.fragment.app.FragmentManager; | ||||
| import androidx.fragment.app.FragmentTransaction; | ||||
| import androidx.lifecycle.ViewModelProvider; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import app.fedilab.android.BaseMainActivity; | ||||
| import app.fedilab.android.R; | ||||
| import app.fedilab.android.client.entities.api.Tag; | ||||
| import app.fedilab.android.client.entities.app.Timeline; | ||||
| import app.fedilab.android.databinding.ActivityFollowedTagsBinding; | ||||
| import app.fedilab.android.databinding.PopupAddFollowedTagtBinding; | ||||
| import app.fedilab.android.helper.Helper; | ||||
| import app.fedilab.android.helper.ThemeHelper; | ||||
| import app.fedilab.android.ui.drawer.FollowedTagAdapter; | ||||
| import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline; | ||||
| import app.fedilab.android.viewmodel.mastodon.TagVM; | ||||
| import es.dmoral.toasty.Toasty; | ||||
| 
 | ||||
| 
 | ||||
| public class FollowedTagActivity extends BaseActivity implements FollowedTagAdapter.ActionOnTag { | ||||
| 
 | ||||
| 
 | ||||
|     private ActivityFollowedTagsBinding binding; | ||||
|     private boolean canGoBack; | ||||
|     private TagVM tagVM; | ||||
|     private Tag tag; | ||||
|     private ArrayList<Tag> tagList; | ||||
|     private FollowedTagAdapter followedTagAdapter; | ||||
|     private FragmentMastodonTimeline fragmentMastodonTimeline; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         ThemeHelper.applyThemeBar(this); | ||||
|         binding = ActivityFollowedTagsBinding.inflate(getLayoutInflater()); | ||||
|         setContentView(binding.getRoot()); | ||||
|         canGoBack = false; | ||||
|         if (getSupportActionBar() != null) { | ||||
|             getSupportActionBar().setDisplayHomeAsUpEnabled(true); | ||||
|             getSupportActionBar().setDisplayShowHomeEnabled(true); | ||||
|             getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary))); | ||||
|         } | ||||
|         tagVM = new ViewModelProvider(FollowedTagActivity.this).get(TagVM.class); | ||||
|         tagVM.followedTags(BaseMainActivity.currentInstance, BaseMainActivity.currentToken) | ||||
|                 .observe(FollowedTagActivity.this, tags -> { | ||||
|                     if (tags != null && tags.tags != null && tags.tags.size() > 0) { | ||||
|                         tagList = new ArrayList<>(tags.tags); | ||||
|                         followedTagAdapter = new FollowedTagAdapter(tagList); | ||||
|                         followedTagAdapter.actionOnTag = this; | ||||
|                         binding.notContent.setVisibility(View.GONE); | ||||
|                         binding.recyclerView.setAdapter(followedTagAdapter); | ||||
|                         binding.recyclerView.setLayoutManager(new LinearLayoutManager(FollowedTagActivity.this)); | ||||
|                     } else { | ||||
|                         binding.notContent.setVisibility(View.VISIBLE); | ||||
|                     } | ||||
|                 }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if (item.getItemId() == android.R.id.home) { | ||||
|             onBackPressed(); | ||||
|             return true; | ||||
|         } else if (item.getItemId() == R.id.action_unfollow && tag != null) { | ||||
|             AlertDialog.Builder alt_bld = new AlertDialog.Builder(FollowedTagActivity.this, Helper.dialogStyle()); | ||||
|             alt_bld.setTitle(R.string.action_unfollow_tag); | ||||
|             alt_bld.setMessage(R.string.action_unfollow_tag_confirm); | ||||
|             alt_bld.setPositiveButton(R.string.unfollow, (dialog, id) -> { | ||||
|                 tagVM.unfollow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, tag.name); | ||||
|                 int position = 0; | ||||
|                 for (Tag tagTmp : tagList) { | ||||
|                     if (tagTmp.name.equalsIgnoreCase(tag.name)) { | ||||
|                         break; | ||||
|                     } | ||||
|                     position++; | ||||
|                 } | ||||
|                 tagList.remove(position); | ||||
|                 followedTagAdapter.notifyItemRemoved(position); | ||||
|                 ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.recyclerView, () -> { | ||||
|                     canGoBack = false; | ||||
|                     if (fragmentMastodonTimeline != null) { | ||||
|                         fragmentMastodonTimeline.onDestroyView(); | ||||
|                     } | ||||
|                     invalidateOptionsMenu(); | ||||
|                     setTitle(R.string.action_lists); | ||||
|                 }); | ||||
|                 if (tagList.size() == 0) { | ||||
|                     binding.notContent.setVisibility(View.VISIBLE); | ||||
|                 } else { | ||||
|                     binding.notContent.setVisibility(View.GONE); | ||||
|                 } | ||||
|             }); | ||||
|             alt_bld.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); | ||||
|             AlertDialog alert = alt_bld.create(); | ||||
|             alert.show(); | ||||
|         } else if (item.getItemId() == R.id.action_follow_tag) { | ||||
|             AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(FollowedTagActivity.this, Helper.dialogStyle()); | ||||
|             PopupAddFollowedTagtBinding popupAddFollowedTagtBinding = PopupAddFollowedTagtBinding.inflate(getLayoutInflater()); | ||||
|             dialogBuilder.setView(popupAddFollowedTagtBinding.getRoot()); | ||||
|             popupAddFollowedTagtBinding.addTag.setFilters(new InputFilter[]{new InputFilter.LengthFilter(255)}); | ||||
|             dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { | ||||
|                 if (popupAddFollowedTagtBinding.addTag.getText() != null && popupAddFollowedTagtBinding.addTag.getText().toString().trim().length() > 0) { | ||||
|                     tagVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, popupAddFollowedTagtBinding.addTag.getText().toString().trim()) | ||||
|                             .observe(FollowedTagActivity.this, newTag -> { | ||||
|                                 if (tagList == null) { | ||||
|                                     tagList = new ArrayList<>(); | ||||
|                                 } | ||||
|                                 if (newTag != null && followedTagAdapter != null) { | ||||
|                                     tagList.add(0, newTag); | ||||
|                                     followedTagAdapter.notifyItemInserted(0); | ||||
|                                 } else { | ||||
|                                     Toasty.error(FollowedTagActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); | ||||
|                                 } | ||||
|                             }); | ||||
|                     dialog.dismiss(); | ||||
|                 } else { | ||||
|                     popupAddFollowedTagtBinding.addTag.setError(getString(R.string.not_valid_tag_name)); | ||||
|                 } | ||||
| 
 | ||||
|             }); | ||||
|             dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); | ||||
|             dialogBuilder.create().show(); | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(@NonNull Menu menu) { | ||||
|         if (!canGoBack) { | ||||
|             getMenuInflater().inflate(R.menu.menu_main_followed_tag, menu); | ||||
|         } else { | ||||
|             getMenuInflater().inflate(R.menu.menu_followed_tag, menu); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBackPressed() { | ||||
|         if (canGoBack) { | ||||
|             canGoBack = false; | ||||
|             ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.recyclerView, () -> { | ||||
|                 if (fragmentMastodonTimeline != null) { | ||||
|                     fragmentMastodonTimeline.onDestroyView(); | ||||
|                 } | ||||
|             }); | ||||
|             setTitle(R.string.action_lists); | ||||
|             invalidateOptionsMenu(); | ||||
|         } else { | ||||
|             super.onBackPressed(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void click(Tag tag) { | ||||
|         this.tag = tag; | ||||
|         canGoBack = true; | ||||
|         ThemeHelper.slideViewsToLeft(binding.recyclerView, binding.fragmentContainer, () -> { | ||||
|             fragmentMastodonTimeline = new FragmentMastodonTimeline(); | ||||
|             Bundle bundle = new Bundle(); | ||||
|             bundle.putSerializable(Helper.ARG_SEARCH_KEYWORD, tag.name); | ||||
|             bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TAG); | ||||
|             setTitle(tag.name); | ||||
|             fragmentMastodonTimeline.setArguments(bundle); | ||||
|             FragmentManager fragmentManager = getSupportFragmentManager(); | ||||
|             FragmentTransaction fragmentTransaction = | ||||
|                     fragmentManager.beginTransaction(); | ||||
|             fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline); | ||||
|             fragmentTransaction.commit(); | ||||
|             invalidateOptionsMenu(); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | @ -28,6 +28,7 @@ import android.view.MenuItem; | |||
| import androidx.annotation.NonNull; | ||||
| import androidx.appcompat.app.ActionBar; | ||||
| import androidx.core.content.ContextCompat; | ||||
| import androidx.lifecycle.ViewModelProvider; | ||||
| import androidx.localbroadcastmanager.content.LocalBroadcastManager; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
|  | @ -45,6 +46,8 @@ import app.fedilab.android.exception.DBException; | |||
| import app.fedilab.android.helper.Helper; | ||||
| import app.fedilab.android.helper.ThemeHelper; | ||||
| import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline; | ||||
| import app.fedilab.android.viewmodel.mastodon.ReorderVM; | ||||
| import app.fedilab.android.viewmodel.mastodon.TagVM; | ||||
| import es.dmoral.toasty.Toasty; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -53,6 +56,9 @@ public class HashTagActivity extends BaseActivity { | |||
| 
 | ||||
|     public static int position; | ||||
|     private String tag; | ||||
|     private boolean pinnedTag; | ||||
|     private boolean followedTag; | ||||
|     private TagVM tagVM; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|  | @ -67,7 +73,8 @@ public class HashTagActivity extends BaseActivity { | |||
|         } | ||||
|         if (tag == null) | ||||
|             finish(); | ||||
| 
 | ||||
|         pinnedTag = false; | ||||
|         followedTag = false; | ||||
|         setSupportActionBar(binding.toolbar); | ||||
|         ActionBar actionBar = getSupportActionBar(); | ||||
|         //Remove title | ||||
|  | @ -81,6 +88,29 @@ public class HashTagActivity extends BaseActivity { | |||
|             getSupportActionBar().setDisplayShowHomeEnabled(true); | ||||
|         } | ||||
| 
 | ||||
|         tagVM = new ViewModelProvider(HashTagActivity.this).get(TagVM.class); | ||||
|         tagVM.getTag(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { | ||||
|             if (returnedTag != null) { | ||||
|                 followedTag = returnedTag.following; | ||||
|                 invalidateOptionsMenu(); | ||||
|             } | ||||
|         }); | ||||
|         ReorderVM reorderVM = new ViewModelProvider(HashTagActivity.this).get(ReorderVM.class); | ||||
|         reorderVM.getAllPinned().observe(HashTagActivity.this, pinned -> { | ||||
|             if (pinned != null) { | ||||
|                 if (pinned.pinnedTimelines != null) { | ||||
|                     for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { | ||||
|                         if (pinnedTimeline.tagTimeline != null) { | ||||
|                             if (pinnedTimeline.tagTimeline.name.equalsIgnoreCase(tag)) { | ||||
|                                 pinnedTag = true; | ||||
|                                 invalidateOptionsMenu(); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         Bundle bundle = new Bundle(); | ||||
|         bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TAG); | ||||
|         bundle.putString(Helper.ARG_SEARCH_KEYWORD, tag); | ||||
|  | @ -151,10 +181,19 @@ public class HashTagActivity extends BaseActivity { | |||
|                     Intent intentBD = new Intent(Helper.BROADCAST_DATA); | ||||
|                     intentBD.putExtras(b); | ||||
|                     LocalBroadcastManager.getInstance(HashTagActivity.this).sendBroadcast(intentBD); | ||||
|                     pinnedTag = true; | ||||
|                     invalidateOptionsMenu(); | ||||
|                 } catch (DBException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             }).start(); | ||||
|         } else if (item.getItemId() == R.id.action_follow_tag) { | ||||
|             tagVM.follow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { | ||||
|                 if (returnedTag != null) { | ||||
|                     followedTag = returnedTag.following; | ||||
|                     invalidateOptionsMenu(); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|  | @ -163,7 +202,15 @@ public class HashTagActivity extends BaseActivity { | |||
| 
 | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(@NonNull Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.menu_reorder, menu); | ||||
|         getMenuInflater().inflate(R.menu.menu_hashtag, menu); | ||||
|         MenuItem pin = menu.findItem(R.id.action_add_timeline); | ||||
|         MenuItem follow = menu.findItem(R.id.action_follow_tag); | ||||
|         if (pinnedTag && pin != null) { | ||||
|             pin.setVisible(false); | ||||
|         } | ||||
|         if (followedTag && follow != null) { | ||||
|             follow.setVisible(false); | ||||
|         } | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,18 +23,21 @@ import retrofit2.http.GET; | |||
| import retrofit2.http.Header; | ||||
| import retrofit2.http.POST; | ||||
| import retrofit2.http.Path; | ||||
| import retrofit2.http.Query; | ||||
| 
 | ||||
| public interface MastodonTagService { | ||||
| 
 | ||||
|     //Get followed tags | ||||
|     @GET("followed_tags") | ||||
|     Call<List<Tag>> getFollowedTags( | ||||
|             @Header("Authorization") String token | ||||
|     ); | ||||
| 
 | ||||
| 
 | ||||
|     //Get followed tags | ||||
|     @GET("tags/{name}") | ||||
|     Call<Tag> getTag( | ||||
|             @Header("Authorization") String token, | ||||
|             @Query("max_id") String max_id, | ||||
|             @Query("since_id") String since_id, | ||||
|             @Query("min_id") String min_id, | ||||
|             @Query("limit") int limit | ||||
|             @Path("name") String name | ||||
|     ); | ||||
| 
 | ||||
|     //Follow tag | ||||
|  |  | |||
|  | @ -0,0 +1,79 @@ | |||
| package app.fedilab.android.ui.drawer; | ||||
| /* 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 android.view.LayoutInflater; | ||||
| import android.view.ViewGroup; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import app.fedilab.android.client.entities.api.Tag; | ||||
| import app.fedilab.android.databinding.DrawerListBinding; | ||||
| 
 | ||||
| 
 | ||||
| public class FollowedTagAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|     private final List<Tag> tagList; | ||||
|     public ActionOnTag actionOnTag; | ||||
| 
 | ||||
|     public FollowedTagAdapter(List<Tag> tagList) { | ||||
|         this.tagList = tagList; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public int getCount() { | ||||
|         return tagList.size(); | ||||
|     } | ||||
| 
 | ||||
|     public Tag getItem(int position) { | ||||
|         return tagList.get(position); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | ||||
|         DrawerListBinding itemBinding = DrawerListBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); | ||||
|         return new ListViewHolder(itemBinding); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { | ||||
|         Tag tag = tagList.get(position); | ||||
|         ListViewHolder holder = (ListViewHolder) viewHolder; | ||||
|         holder.binding.title.setText(tag.name); | ||||
|         holder.binding.title.setOnClickListener(v -> actionOnTag.click(tag)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return tagList.size(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public interface ActionOnTag { | ||||
|         void click(Tag tag); | ||||
|     } | ||||
| 
 | ||||
|     public static class ListViewHolder extends RecyclerView.ViewHolder { | ||||
|         DrawerListBinding binding; | ||||
| 
 | ||||
|         ListViewHolder(DrawerListBinding itemView) { | ||||
|             super(itemView.getRoot()); | ||||
|             binding = itemView; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -112,6 +112,25 @@ public class ReorderVM extends AndroidViewModel { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public LiveData<Pinned> getAllPinned() { | ||||
|         pinnedMutableLiveData = new MutableLiveData<>(); | ||||
|         new Thread(() -> { | ||||
|             Pinned pinned = null; | ||||
|             try { | ||||
|                 pinned = new Pinned(getApplication().getApplicationContext()).getAllPinned(currentAccount); | ||||
| 
 | ||||
|             } catch (DBException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|             Handler mainHandler = new Handler(Looper.getMainLooper()); | ||||
|             Pinned finalPinned = pinned; | ||||
|             Runnable myRunnable = () -> pinnedMutableLiveData.setValue(finalPinned); | ||||
|             mainHandler.post(myRunnable); | ||||
|         }).start(); | ||||
|         return pinnedMutableLiveData; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public LiveData<BottomMenu> getBottomMenu() { | ||||
|         bottomMenuMutableLiveData = new MutableLiveData<>(); | ||||
|         new Thread(() -> { | ||||
|  |  | |||
|  | @ -28,8 +28,6 @@ import java.util.concurrent.TimeUnit; | |||
| 
 | ||||
| import app.fedilab.android.client.endpoints.MastodonTagService; | ||||
| import app.fedilab.android.client.entities.api.Pagination; | ||||
| import app.fedilab.android.client.entities.api.Status; | ||||
| import app.fedilab.android.client.entities.api.Statuses; | ||||
| import app.fedilab.android.client.entities.api.Tag; | ||||
| import app.fedilab.android.client.entities.api.Tags; | ||||
| import app.fedilab.android.helper.Helper; | ||||
|  | @ -76,19 +74,15 @@ public class TagVM extends AndroidViewModel { | |||
|     /** | ||||
|      * Return followed tags with pagination | ||||
|      * | ||||
|      * @return {@link LiveData} containing a {@link Statuses}. Note: Not to be confused with {@link Status} | ||||
|      * @return {@link LiveData} containing a {@link Tags}. Note: Not to be confused with {@link Tag} | ||||
|      */ | ||||
|     public LiveData<Tags> followedTags(@NonNull String instance, String token, | ||||
|                                        String maxId, | ||||
|                                        String sinceId, | ||||
|                                        String minId, | ||||
|                                        int count) { | ||||
|     public LiveData<Tags> followedTags(@NonNull String instance, String token) { | ||||
|         tagsMutableLiveData = new MutableLiveData<>(); | ||||
|         MastodonTagService mastodonTagService = init(instance); | ||||
|         new Thread(() -> { | ||||
|             List<Tag> tagList = null; | ||||
|             Pagination pagination = null; | ||||
|             Call<List<Tag>> followedTagsListCall = mastodonTagService.getFollowedTags(token, maxId, sinceId, minId, count); | ||||
|             Call<List<Tag>> followedTagsListCall = mastodonTagService.getFollowedTags(token); | ||||
|             if (followedTagsListCall != null) { | ||||
|                 try { | ||||
|                     Response<List<Tag>> tagsResponse = followedTagsListCall.execute(); | ||||
|  | @ -111,6 +105,37 @@ public class TagVM extends AndroidViewModel { | |||
|         return tagsMutableLiveData; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Return tag | ||||
|      * | ||||
|      * @return {@link LiveData} containing a {@link Tag} | ||||
|      */ | ||||
|     public LiveData<Tag> getTag(@NonNull String instance, String token, | ||||
|                                 String tagName) { | ||||
|         tagMutableLiveData = new MutableLiveData<>(); | ||||
|         MastodonTagService mastodonTagService = init(instance); | ||||
|         new Thread(() -> { | ||||
|             Tag tag = null; | ||||
|             Call<Tag> tagCall = mastodonTagService.getTag(token, tagName); | ||||
|             if (tagCall != null) { | ||||
|                 try { | ||||
|                     Response<Tag> tagResponse = tagCall.execute(); | ||||
|                     if (tagResponse.isSuccessful()) { | ||||
|                         tag = tagResponse.body(); | ||||
|                     } | ||||
|                 } catch (Exception e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|             Handler mainHandler = new Handler(Looper.getMainLooper()); | ||||
|             Tag finalTag = tag; | ||||
|             Runnable myRunnable = () -> tagMutableLiveData.setValue(finalTag); | ||||
|             mainHandler.post(myRunnable); | ||||
|         }).start(); | ||||
|         return tagMutableLiveData; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Follow a tag | ||||
|      * | ||||
|  |  | |||
							
								
								
									
										22
									
								
								app/src/main/res/drawable/ic_baseline_post_add_24.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/src/main/res/drawable/ic_baseline_post_add_24.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:tint="#FFFFFF" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24"> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M17,19.22H5V7h7V5H5C3.9,5 3,5.9 3,7v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-7h-2V19.22z" /> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M19,2h-2v3h-3c0.01,0.01 0,2 0,2h3v2.99c0.01,0.01 2,0 2,0V7h3V5h-3V2z" /> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M7,9h8v2h-8z" /> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M7,12l0,2l8,0l0,-2l-3,0z" /> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M7,15h8v2h-8z" /> | ||||
| </vector> | ||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_baseline_tag_24.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/drawable/ic_baseline_tag_24.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:tint="#FFFFFF" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24"> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M20,10L20,8h-4L16,4h-2v4h-4L10,4L8,4v4L4,8v2h4v4L4,14v2h4v4h2v-4h4v4h2v-4h4v-2h-4v-4h4zM14,14h-4v-4h4v4z" /> | ||||
| </vector> | ||||
							
								
								
									
										33
									
								
								app/src/main/res/layout/activity_followed_tags.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/src/main/res/layout/activity_followed_tags.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:orientation="vertical" | ||||
|     android:padding="@dimen/fab_margin"> | ||||
| 
 | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/recycler_view" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:clipToPadding="false" | ||||
|         android:scrollbars="none" /> | ||||
| 
 | ||||
|     <TextView | ||||
|         android:id="@+id/not_content" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:layout_gravity="center" | ||||
|         android:gravity="center" | ||||
|         android:padding="10dp" | ||||
|         android:text="@string/action_followed_tag_empty" | ||||
|         android:textSize="20sp" | ||||
|         android:textStyle="bold" | ||||
|         android:typeface="serif" | ||||
|         android:visibility="gone" /> | ||||
| 
 | ||||
|     <androidx.fragment.app.FragmentContainerView | ||||
|         android:id="@+id/fragment_container" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:visibility="gone" /> | ||||
| </RelativeLayout> | ||||
							
								
								
									
										17
									
								
								app/src/main/res/layout/popup_add_followed_tagt.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/src/main/res/layout/popup_add_followed_tagt.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:layout_margin="@dimen/fab_margin" | ||||
|     android:orientation="vertical"> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatEditText | ||||
|         android:id="@+id/add_tag" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="20dp" | ||||
|         android:layout_marginBottom="20dp" | ||||
|         android:hint="@string/write_the_tag_to_follow" | ||||
|         android:inputType="text" | ||||
|         android:singleLine="true" /> | ||||
| </LinearLayout> | ||||
|  | @ -25,6 +25,10 @@ | |||
|                         android:id="@+id/nav_list" | ||||
|                         android:icon="@drawable/ic_baseline_view_list_24" | ||||
|                         android:title="@string/action_lists" /> | ||||
|                     <item | ||||
|                         android:id="@+id/nav_followed_tags" | ||||
|                         android:icon="@drawable/ic_baseline_tag_24" | ||||
|                         android:title="@string/followed_tags" /> | ||||
|                     <item | ||||
|                         android:id="@+id/nav_follow_requests" | ||||
|                         android:icon="@drawable/ic_baseline_group_add_24" | ||||
|  |  | |||
							
								
								
									
										9
									
								
								app/src/main/res/menu/menu_followed_tag.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/menu/menu_followed_tag.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|     <item | ||||
|         android:id="@+id/action_unfollow" | ||||
|         android:icon="@drawable/ic_baseline_delete_24" | ||||
|         android:title="@string/action_unfollow_tag" | ||||
|         app:showAsAction="ifRoom" /> | ||||
| </menu> | ||||
							
								
								
									
										14
									
								
								app/src/main/res/menu/menu_hashtag.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/src/main/res/menu/menu_hashtag.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|     <item | ||||
|         android:id="@+id/action_follow_tag" | ||||
|         android:icon="@drawable/ic_baseline_post_add_24" | ||||
|         android:title="@string/follow_tag" | ||||
|         app:showAsAction="ifRoom" /> | ||||
|     <item | ||||
|         android:id="@+id/action_add_timeline" | ||||
|         android:icon="@drawable/ic_baseline_add_24" | ||||
|         android:title="@string/add_instances" | ||||
|         app:showAsAction="ifRoom" /> | ||||
| </menu> | ||||
							
								
								
									
										9
									
								
								app/src/main/res/menu/menu_main_followed_tag.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/menu/menu_main_followed_tag.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|     <item | ||||
|         android:id="@+id/action_follow_tag" | ||||
|         android:icon="@drawable/ic_baseline_post_add_24" | ||||
|         android:title="@string/action_tag_follow" | ||||
|         app:showAsAction="ifRoom" /> | ||||
| </menu> | ||||
|  | @ -1974,4 +1974,13 @@ | |||
|     <string name="restart_the_app_theme">You should restart the application to apply changes.</string> | ||||
|     <string name="set_language_picker_title">Languages in picker</string> | ||||
|     <string name="set_language_picker">Allow to reduce the list of languages in the picker when composing a message.</string> | ||||
|     <string name="action_followed_tag_empty">You don\'t follow any tags!</string> | ||||
|     <string name="action_unfollow_tag">Unfollow tag</string> | ||||
|     <string name="action_unfollow_tag_confirm">Are you sure you want to unfollow this tag?</string> | ||||
|     <string name="unfollow">Unfollow</string> | ||||
|     <string name="action_tag_follow">Follow a tag</string> | ||||
|     <string name="write_the_tag_to_follow">Write the tag to follow</string> | ||||
|     <string name="not_valid_tag_name">Tag name is not valid!</string> | ||||
|     <string name="followed_tags">Followed tags</string> | ||||
|     <string name="follow_tag">Follow tag</string> | ||||
| </resources> | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue